aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Brown2004-10-15 06:06:47 +0000
committerJames Brown2004-10-15 06:06:47 +0000
commit8f65711a28b0cdedca29cdd1787b40546d448575 (patch)
treefeafc61c0bdbd529ef1eb52acf743033395f3547
parent9e40ef7d29ccaca45708b39e1da92bbca088d6ac (diff)
downloadscummvm-rg350-8f65711a28b0cdedca29cdd1787b40546d448575.tar.gz
scummvm-rg350-8f65711a28b0cdedca29cdd1787b40546d448575.tar.bz2
scummvm-rg350-8f65711a28b0cdedca29cdd1787b40546d448575.zip
Merge in some of LordHotos kyra code, with some changes.
It's still non-functional, but once I merge in some more of my local changes things should actually be moving a long a bit. svn-id: r15554
-rw-r--r--kyra/codecs.cpp322
-rw-r--r--kyra/codecs.h43
-rw-r--r--kyra/cpsimage.cpp183
-rw-r--r--kyra/font.cpp329
-rw-r--r--kyra/kyra.cpp142
-rw-r--r--kyra/kyra.h35
-rw-r--r--kyra/module.mk3
-rw-r--r--kyra/palette.cpp80
-rw-r--r--kyra/resource.cpp254
-rw-r--r--kyra/resource.h201
-rw-r--r--kyra/script.cpp506
-rw-r--r--kyra/script.h155
-rw-r--r--kyra/script_v1.cpp220
-rw-r--r--kyra/wsamovie.cpp119
-rw-r--r--kyra/wsamovie.h82
15 files changed, 2646 insertions, 28 deletions
diff --git a/kyra/codecs.cpp b/kyra/codecs.cpp
new file mode 100644
index 0000000000..96404f0679
--- /dev/null
+++ b/kyra/codecs.cpp
@@ -0,0 +1,322 @@
+/* ScummVM - Kyrandia Interpreter
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+
+#include "stdafx.h"
+#include "codecs.h"
+
+/*****************************************************************************
+ * decode.c - Decoding routines for format80, format40, format20
+ * and format3 type graphics
+ * Author: Olaf van der spek
+ * Modified for FreeCNC by Kareem Dana
+ * Modified for Kyra by Jack Burton
+ * Format3 decoding added by Jack Burton
+ * Modified for ScummVM by Johannes Schickel
+ ****************************************************************************/
+
+/** decompress format 80 compressed data.
+ * @param compressed data.
+ * @param pointer to output uncompressed data.
+ * @returns size of uncompressed data.
+ */
+namespace Kyra {
+int Compression::decode80(const uint8* image_in, uint8* image_out) {
+ /*
+ 0 copy 0cccpppp p
+ 1 copy 10cccccc
+ 2 copy 11cccccc p p
+ 3 fill 11111110 c c v
+ 4 copy 11111111 c c p p
+ */
+
+ const uint8* copyp;
+ const uint8* readp = image_in;
+ uint8* writep = image_out;
+ uint16 code;
+ uint16 count;
+
+#ifdef SCUMM_BIG_ENDIAN
+ uint16 bigend; /* temporary big endian var */
+#endif
+
+ while (1)
+ {
+ code = *readp++;
+ if (~code & 0x80)
+ {
+ //bit 7 = 0
+ //command 0 (0cccpppp p): copy
+ count = (code >> 4) + 3;
+ copyp = writep - (((code & 0xf) << 8) + *readp++);
+ while (count--)
+ *writep++ = *copyp++;
+ }
+ else
+ {
+ //bit 7 = 1
+ count = code & 0x3f;
+ if (~code & 0x40)
+ {
+ //bit 6 = 0
+ if (!count)
+ //end of image
+ break;
+ //command 1 (10cccccc): copy
+ while (count--)
+ *writep++ = *readp++;
+ }
+ else
+ {
+ //bit 6 = 1
+ if (count < 0x3e)
+ {
+ //command 2 (11cccccc p p): copy
+ count += 3;
+
+#ifdef SCUMM_BIG_ENDIAN
+ memcpy(&bigend, readp, 2);
+ copyp = (const uint8*)&image_out[*(const_cast<uint16*>((const uint16*)SWAP_BYTES_16(bigend))];
+#else
+ copyp = (const uint8*)&image_out[*(const_cast<uint16*>((const uint16*)readp))];
+#endif
+
+ readp += 2;
+ while (count--)
+ *writep++ = *copyp++;
+ }
+ else if (count == 0x3e)
+ {
+ //command 3 (11111110 c c v): fill
+
+#ifdef SCUMM_BIG_ENDIAN
+ memset(&count, 0, sizeof(uint32));
+ memcpy(&count, readp, 2);
+ count = const_cast<uint16*>((const uint16*)SWAP_BYTES_16(count));
+#else
+ count = *(const_cast<uint16*>((const uint16*)readp));
+#endif
+ readp += 2;
+ code = *readp++;
+ while (count--)
+ *writep++ = code;
+ }
+ else
+ {
+ //command 4 (copy 11111111 c c p p): copy
+
+#ifdef SCUMM_BIG_ENDIAN
+ memset(&count, 0, sizeof(uint32));
+ memcpy(&count, readp, 2);
+ count = const_cast<uint16*>((const uint16*)SWAP_BYTES_16(count));
+#else
+ count = *(const_cast<uint16*>((const uint16*)readp));
+#endif
+ readp += 2;
+
+#ifdef SCUMM_BIG_ENDIAN
+ memcpy(&bigend, readp, 2);
+ copyp = (const uint8*)&image_out[*(const_cast<uint16*>((const uint16*)SWAP_BYTES_16(bigend))];
+#else
+ copyp = (const uint8*)&image_out[*(const_cast<uint16*>((const uint16*)readp))];
+#endif
+ readp += 2;
+ while (count--)
+ *writep++ = *copyp++;
+ }
+ }
+ }
+ }
+
+ return (writep - image_out);
+}
+
+/** decompress format 40 compressed data.
+ * @param compressed data.
+ * @param pointer to put uncompressed data in.
+ * @returns size of uncompressed data.
+ */
+int Compression::decode40(const uint8* image_in, uint8* image_out) {
+ /*
+ 0 fill 00000000 c v
+ 1 copy 0ccccccc
+ 2 skip 10000000 c 0ccccccc
+ 3 copy 10000000 c 10cccccc
+ 4 fill 10000000 c 11cccccc v
+ 5 skip 1ccccccc
+ */
+
+ const uint8* readp = image_in;
+ uint8* writep = image_out;
+ uint16 code;
+ uint16 count;
+
+ while (1) {
+ code = *readp++;
+ if (~code & 0x80)
+ {
+ //bit 7 = 0
+ if (!code)
+ {
+ //command 0 (00000000 c v): fill
+ count = *readp++;
+ code = *readp++;
+ while (count--)
+ *writep++ ^= code;
+ }
+ else
+ {
+ //command 1 (0ccccccc): copy
+ count = code;
+ while (count--)
+ *writep++ ^= *readp++;
+ }
+
+ }
+ else
+ {
+ //bit 7 = 1
+ if (!(count = code & 0x7f))
+ {
+
+#ifdef SCUMM_BIG_ENDIAN
+ memset(&count, 0, sizeof(uint32));
+ memcpy(&count, readp, 2);
+ count = const_cast<uint16*>((const uint16*)SWAP_BYTES_16(count));
+#else
+ count = *(const_cast<uint16*>((const uint16*)readp));
+#endif
+ readp += 2;
+ code = count >> 8;
+ if (~code & 0x80)
+ {
+ //bit 7 = 0
+ //command 2 (10000000 c 0ccccccc): skip
+ if (!count)
+ // end of image
+ break;
+ writep += count;
+ }
+ else
+ {
+ //bit 7 = 1
+ count &= 0x3fff;
+ if (~code & 0x40)
+ {
+ //bit 6 = 0
+ //command 3 (10000000 c 10cccccc): copy
+ while (count--)
+ *writep++ ^= *readp++;
+ }
+ else
+ {
+ //bit 6 = 1
+ //command 4 (10000000 c 11cccccc v): fill
+ code = *readp++;
+ while (count--)
+ *writep++ ^= code;
+ }
+ }
+ }
+ else //command 5 (1ccccccc): skip
+ writep += count;
+ }
+ }
+ return (writep - image_out);
+}
+
+/** decompress format 3 compressed data.
+ * @param compressed data.
+ * @param pointer to put uncompressed data in.
+ * @param size of uncompressed image.
+ */
+int Compression::decode3(const uint8* image_in, uint8* image_out, int size)
+{ /* Untested on BIG-Endian machines */
+
+ /*
+ 0 copy
+ 1 fill
+ 2 fill
+ */
+ const uint8* readp = image_in;
+ uint8* writep = image_out;
+ int16 code;
+ int16 count;
+
+ do {
+ code = *const_cast<int8*>((const int8*)readp++);
+ if (code > 0) // Copy
+ {
+ count = code ;
+ while (count--)
+ *writep++ = *readp++;
+ }
+ else if (code == 0) // Fill(1)
+ {
+ count = *(const_cast<uint16*>((const uint16*)readp));
+
+#ifdef SCUMM_LITTLE_ENDIAN
+ count = SWAP_BYTES_16(count);
+#endif
+
+ readp += 2;
+ code = *readp++;
+ while (count--)
+ *writep++ = (uint8)code;
+ }
+ else if (code < 0) // Fill (2)
+ {
+ count = -code;
+ code = *readp++;
+ while (count--)
+ *writep++ = (uint8)code;
+ }
+ } while ((writep - image_out) < size);
+
+ //and, to be uniform to other decomp. functions...
+ return (writep - image_out);
+}
+
+/** decompress format 20 compressed data.
+ * @param compressed data.
+ * @param pointer to pu uncompressed data in.
+ * @param size of compressed data?
+ * @returns size of uncompressed data?
+ */
+int Compression::decode2(const uint8* s, uint8* d, int cb_s) {
+ const uint8* r = s;
+ const uint8* r_end = s + cb_s;
+ uint8* w = d;
+ while (r < r_end) {
+ int v = *r++;
+ if (v)
+ *w++ = v;
+ else {
+ v = *r++;
+ memset(w, 0, v);
+ w += v;
+ }
+ }
+ return w - d;
+
+}
+} // end of namespace Kyra
+
diff --git a/kyra/codecs.h b/kyra/codecs.h
new file mode 100644
index 0000000000..58447d1a10
--- /dev/null
+++ b/kyra/codecs.h
@@ -0,0 +1,43 @@
+/* ScummVM - Kyrandia Interpreter
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+/** Various decompression routines */
+#ifndef __COMPRESSION_H
+#define __COMPRESSION_H
+
+// THIS CODE WAS TAKEN FROM FreeKyra Tools Module
+
+#include "common/stdafx.h"
+#include "common/scummsys.h"
+
+namespace Kyra {
+ class Compression
+ {
+ public:
+ static int decode80(const uint8* image_in, uint8* image_out);
+ static int decode40(const uint8* image_in, uint8* image_out);
+ static int decode3(const uint8* image_in, uint8* image_out, int s);
+ static int decode2(const uint8* s, uint8* d, int cb_s);
+ };
+} // end of namespace Kyra
+
+#endif
+
diff --git a/kyra/cpsimage.cpp b/kyra/cpsimage.cpp
new file mode 100644
index 0000000000..20b72438fe
--- /dev/null
+++ b/kyra/cpsimage.cpp
@@ -0,0 +1,183 @@
+/* ScummVM - Kyrandia Interpreter
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+#include "resource.h"
+#include "codecs.h"
+
+#include "common/stream.h"
+
+namespace Kyra {
+
+ struct CPSResource {
+ uint32 size;
+ uint16 width;
+ };
+
+ static const CPSResource CPSResourceTable[] = {
+ { 64000, 320 }, { 7740, 180 }, { 46080, 320 }, { 0, 0 }
+ };
+
+ static int16 getWidthFromCPSRes(uint32 size) {
+ int16 c = 0;
+
+ for (; CPSResourceTable[c].size; ++c) {
+ if (CPSResourceTable[c].size == size)
+ return CPSResourceTable[c].width;
+ }
+
+ return -1;
+ }
+
+ CPSImage::CPSImage(uint8* buffer, uint32 size) {
+ if (!buffer) {
+ error("resource created without data");
+ }
+ Common::MemoryReadStream bufferstream(buffer, size);
+
+ // reads in the Header
+ _cpsHeader._filesize = bufferstream.readUint16LE() + 2;
+ _cpsHeader._format = bufferstream.readUint16LE();
+ _cpsHeader._imagesize = bufferstream.readUint16LE();
+ _cpsHeader._pal = bufferstream.readUint32LE();
+
+ // lets check a bit
+ if(_cpsHeader._pal == 0x3000000) {
+ warning("CPS images with a palette aren't supported");
+
+ // skip 768 bytes
+ // if this was a compressed palette you should have strange graphics
+ bufferstream.seek(bufferstream.pos() + 768);
+ }
+
+ _image = new uint8[_cpsHeader._imagesize];
+ assert(_image);
+
+ uint8* imagebuffer = &buffer[bufferstream.pos()];
+ assert(imagebuffer);
+
+ if(_cpsHeader._format == 4) {
+ Compression::decode80(imagebuffer, _image);
+ } else if(_cpsHeader._format == 3) {
+ Compression::decode3(imagebuffer, _image, _cpsHeader._imagesize);
+ } else {
+ error("unknown CPS format %d", _cpsHeader._format);
+ }
+
+ int16 width = getWidthFromCPSRes(_cpsHeader._imagesize);
+
+ if(width == -1) {
+ warning("unknown CPS width(imagesize: %d)", _cpsHeader._imagesize);
+ delete [] buffer;
+ return;
+ }
+
+ _width = (uint16)width;
+ _height = _cpsHeader._imagesize / _width;
+
+ _transparency = -1;
+
+ delete [] buffer;
+ }
+
+ CPSImage::~CPSImage() {
+ delete [] _image;
+ delete _ownPalette;
+ }
+
+ void CPSImage::drawToPlane(uint8* plane, uint16 planepitch, uint16 planeheight, uint16 x, uint16 y) {
+ if (_transparency == -1) {
+ // 'fast' blitting
+
+ uint8* src = _image;
+ uint8* dst = &plane[y * planepitch + x];
+ uint32 copysize = planepitch - x;
+
+ if (copysize > _width)
+ copysize = _width;
+
+ for (uint16 y_ = 0; y_ < _height && y + y_ < planeheight; ++y_) {
+ memcpy(dst, src, copysize * sizeof(uint8));
+ dst += planepitch;
+ src += _width;
+ }
+
+ } else {
+ // oh no! we have transparency so we have a very slow copy :/
+ uint8* src = _image;
+ uint8* dst = &plane[y * planepitch + x];
+
+ for (uint16 yadd = 0; yadd < _height; ++yadd) {
+ for (uint16 xadd = 0; xadd < _width; ++xadd) {
+ if (*src == _transparency) {
+ ++dst;
+ ++src;
+ } else {
+ *dst++ = *src++;
+ }
+ }
+
+ dst += planepitch - _width;
+ }
+ }
+ }
+
+ void CPSImage::drawToPlane(uint8* plane, uint16 planepitch, uint16 planeheight, uint16 x, uint16 y,
+ uint16 srcx, uint16 srcy, uint16 srcwidth, uint16 srcheight) {
+ if (_transparency == -1) {
+ // 'fast' blitting
+
+ uint8* src = &_image[srcy * _width + srcx];
+ uint8* dst = &plane[y * planepitch + x];
+ uint32 copysize = planepitch - x;
+
+ if (copysize > srcwidth)
+ copysize = srcwidth;
+
+ for (uint16 y_ = 0; y_ < srcheight && y + y_ < planeheight; ++y_) {
+ memcpy(dst, src, copysize * sizeof(uint8));
+ dst += planepitch;
+ src += _width;
+ }
+
+ } else {
+ // oh no! we have transparency so we have a very slow copy :/
+ // blit it without transparency
+ uint8* src = &_image[srcy * _width + srcx];
+ uint8* dst = &plane[y * planepitch + x];
+
+ for (uint16 yadd = 0; yadd < _height; ++yadd) {
+ for (uint16 xadd = 0; xadd < _width; ++xadd) {
+ if (*src == _transparency) {
+ ++dst;
+ ++src;
+ } else {
+ *dst++ = *src++;
+ }
+ }
+
+ dst += planepitch - _width;
+ src += _width - srcwidth;
+ }
+ }
+ }
+} // end of namespace Kyra
+
diff --git a/kyra/font.cpp b/kyra/font.cpp
new file mode 100644
index 0000000000..2131774073
--- /dev/null
+++ b/kyra/font.cpp
@@ -0,0 +1,329 @@
+/* ScummVM - Kyrandia Interpreter
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+#include "resource.h"
+#include "common/stream.h"
+#include "common/array.h"
+
+#ifdef DUMP_FILES
+#include <cstdio>
+#endif
+
+namespace Kyra {
+ const uint16 FontHeader_Magic1 = 0x0500;
+ const uint16 FontHeader_Magic2 = 0x000e;
+ const uint16 FontHeader_Magic3 = 0x0014;
+
+ Font::Font(uint8* buffer, uint32 size) {
+ if (!buffer) {
+ error("resource created without data");
+ }
+
+ _buffer = buffer;
+
+ Common::MemoryReadStream bufferstream(buffer, size);
+
+ bufferstream.read(&_fontHeader, sizeof(_fontHeader));
+
+ // tests for the magic values
+ if(_fontHeader._magic1 != FontHeader_Magic1 || _fontHeader._magic2 != FontHeader_Magic2 ||
+ _fontHeader._magic3 != FontHeader_Magic3) {
+ error("magic vars in the fontheader are corrupt\n"
+ "_magic1 = 0x%x, _magic2 = 0x%x, _magic3 = 0x%x",
+ _fontHeader._magic1, _fontHeader._magic2, _fontHeader._magic3);
+ }
+
+ // init all the pointers
+ _offsetTable = (uint16*)&buffer[bufferstream.pos()];
+ _charWidth = &buffer[_fontHeader._charWidthOffset];
+ _charHeight = (uint16*)&buffer[_fontHeader._charHeightOffset];
+ _charBits = &buffer[_fontHeader._charBitsOffset];
+
+ // now prerender =)
+ preRenderAllChars(bufferstream.pos());
+
+ // This value seems to be a version or language variable
+ // Known Values
+ // ------------
+ // Russian Floppy: 0x1010
+ // German Floppy and English CD: 0x1011
+ // Kyrandia 2 should be 0x1012
+ debug("_version = 0x%x", _fontHeader._version);
+
+ delete [] _buffer;
+ _buffer = 0;
+ _offsetTable = 0;
+ _charHeight = 0;
+ _charWidth = 0;
+ _charBits = 0;
+ }
+
+ Font::~Font() {
+
+ }
+
+ uint32 Font::getStringWidth(const char* string, char terminator) {
+ uint32 strsize;
+
+ for (strsize = 0; string[strsize] != terminator; ++strsize)
+ ;
+
+ uint32 stringwidth = 0;
+
+ for (uint32 pos = 0; pos < strsize; ++pos) {
+ stringwidth += _preRenderedChars[string[pos]].width;
+ }
+
+ return stringwidth;
+ }
+
+ const uint8* Font::getChar(char c, uint8* width, uint8* height, uint8* heightadd) {
+ PreRenderedChar& c_ = _preRenderedChars[c];
+
+ *width = c_.width;
+ *height = c_.height;
+ *heightadd = c_.heightadd;
+
+ return c_.c;
+ }
+
+ // splits up the String in a word
+ const char* Font::getNextWord(const char* string, uint32* size) {
+ uint32 startpos = 0;
+ *size = 0;
+
+ // gets start of the word
+ for (; string[startpos] == ' '; ++startpos)
+ ;
+
+ // not counting size
+ for (*size = 0; string[startpos + *size] != ' ' && string[startpos + *size] != '\0'; ++(*size))
+ ;
+
+ ++(*size);
+
+ return &string[startpos];
+ }
+
+ // Move this to Font declaration?
+ struct WordChunk {
+ const char* _string;
+ uint32 _size;
+ };
+
+ void Font::drawStringToPlane(const char* string,
+ uint8* plane, uint16 planewidth, uint16 planeheight,
+ uint16 x, uint16 y, uint8 color) {
+
+ // lets do it word after word
+ Common::Array<WordChunk> words;
+
+ uint32 lastPos = 0;
+ uint32 lastSize = 0;
+ uint32 strlgt = strlen(string);
+
+ while (true) {
+ WordChunk newchunk;
+ newchunk._string = getNextWord(&string[lastPos], &lastSize);
+ newchunk._size = lastSize;
+
+ lastPos += lastSize;
+
+ words.push_back(newchunk);
+
+ if (lastPos >= strlgt)
+ break;
+ }
+
+ uint16 current_x = x, current_y = y;
+ uint8 heighest = 0;
+
+ const uint8* src = 0;
+ uint8 width = 0, height = 0, heightadd = 0;
+
+ // now the have alle of these words
+ for (uint32 tmp = 0; tmp < words.size(); ++tmp) {
+ lastSize = getStringWidth(words[tmp]._string, ' ');
+
+ // adjust x position
+ if (current_x + lastSize >= planewidth) {
+ // hmm lets move it a bit to the left
+ if (current_x == x && (int16)planewidth - (int16)lastSize >= 0) {
+ current_x = planewidth - lastSize;
+ } else {
+ current_x = x;
+ if (heighest)
+ current_y += heighest + 2;
+ else // now we are using just the fist char :)
+ current_y += _preRenderedChars[words[tmp]._string[0]].height;
+ heighest = 0;
+ }
+ }
+
+ // TODO: maybe test if current_y >= planeheight ?
+
+ // output word :)
+ for (lastPos = 0; lastPos < words[tmp]._size; ++lastPos) {
+ if (words[tmp]._string[lastPos] == '\0')
+ break;
+
+ // gets our char :)
+ src = getChar(words[tmp]._string[lastPos], &width, &height, &heightadd);
+
+ // lets draw our char
+ drawCharToPlane(src, color, width, height, plane, planewidth, planeheight, current_x, current_y + heightadd);
+
+ current_x += width;
+ heighest = MAX(heighest, height);
+ }
+ }
+ }
+
+ void Font::drawCharToPlane(const uint8* c, uint8 color, uint8 width, uint8 height,
+ uint8* plane, uint16 planewidth, uint16 planeheight, uint16 x, uint16 y) {
+ const uint8* src = c;
+
+ // blit them to the screen
+ for (uint8 yadd = 0; yadd < height; ++yadd) {
+ for (uint8 xadd = 0; xadd < width; ++xadd) {
+ switch(*src) {
+ case 1:
+ plane[(y + yadd) * planewidth + x + xadd] = color;
+ break;
+
+ case 2:
+ plane[(y + yadd) * planewidth + x + xadd] = 14;
+ break;
+
+ case 3:
+ plane[(y + yadd) * planewidth + x + xadd] = 0;
+ break;
+
+ default:
+ // nothing to do now
+ break;
+ };
+
+ ++src;
+ }
+ }
+ }
+
+ void Font::preRenderAllChars(uint16 offsetTableOffset) {
+ uint16 startOffset = _offsetTable[0];
+ uint16 currentOffset = offsetTableOffset;
+ uint8 currentChar = 0;
+
+ for (; currentOffset < startOffset; ++currentChar, currentOffset += sizeof(uint16)) {
+ // lets prerender the char :)
+
+ PreRenderedChar newChar;
+
+ newChar.c = new uint8[(_charHeight[currentChar] >> 8) * _charWidth[currentChar]];
+ assert(newChar.c);
+ memset(newChar.c, 0, sizeof(uint8) * (_charHeight[currentChar] >> 8) * _charWidth[currentChar]);
+ newChar.height = (_charHeight[currentChar] >> 8);
+ newChar.width = _charWidth[currentChar];
+ newChar.heightadd = _charHeight[currentChar] & 0xFF;
+
+ uint8* src = _buffer + _offsetTable[currentChar];
+ uint8* dst = &newChar.c[0];
+ uint8 index = 0;
+
+#ifdef DUMP_FILES
+ static char filename[32] = { 0 };
+ sprintf(filename, "dumps/char%d.dmp", currentChar);
+ FILE* dump = fopen(filename, "w+");
+ assert(dump);
+
+ fprintf(dump, "This should be a '%c'\n", currentChar);
+#endif
+
+ // prerender the char
+ for (uint8 yadd = 0; yadd < newChar.height; ++yadd) {
+ for (uint8 xadd = 0; xadd < newChar.width; ++xadd) {
+ if (xadd % 2) {
+ index = ((*src) & 0xF0) >> 4;
+ ++src;
+ } else {
+ index = (*src) & 0x0F;
+ }
+
+ switch(index) {
+ case 1:
+#ifdef DUMP_FILES
+ fprintf(dump, "#");
+#endif
+ dst[yadd * newChar.width + xadd] = 1;
+ break;
+
+ case 2:
+#ifdef DUMP_FILES
+ fprintf(dump, "$");
+#endif
+ dst[yadd * newChar.width + xadd] = 2;
+ break;
+
+ case 3:
+#ifdef DUMP_FILES
+ fprintf(dump, "§");
+#endif
+ dst[yadd * newChar.width + xadd] = 3;
+ break;
+
+ default:
+#ifdef DUMP_FILES
+ fprintf(dump, "%d", index);
+#endif
+ break;
+ };
+ }
+
+ if (newChar.width % 2) {
+ ++src;
+ }
+#ifdef DUMP_FILES
+ fprintf(dump, "\n");
+#endif
+ }
+
+#ifdef DUMP_FILES
+ fprintf(dump, "\nThis is the created map:\n");
+ // now print the whole thing again
+ for (uint8 yadd = 0; yadd < newChar.height; ++yadd) {
+ for (uint8 xadd = 0; xadd < newChar.width; ++xadd) {
+ fprintf(dump, "%d", dst[yadd * newChar.width + xadd]);
+ }
+ fprintf(dump, "\n");
+ }
+ fclose(dump);
+#endif
+
+ _preRenderedChars[currentChar] = newChar;
+
+ if (currentChar == 255) {
+ break;
+ }
+ }
+ }
+} // end of namespace Kyra
+
diff --git a/kyra/kyra.cpp b/kyra/kyra.cpp
index b7875cb76a..a1ae6449c2 100644
--- a/kyra/kyra.cpp
+++ b/kyra/kyra.cpp
@@ -1,5 +1,5 @@
-/* ScummVM - Scumm Interpreter
- * Copyright (C) 2003 The ScummVM project
+/* ScummVM - Kyrandia Interpreter
+ * Copyright (C) 2003-2004 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
@@ -8,7 +8,7 @@
* 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
+ * 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
@@ -28,35 +28,58 @@
#include "sound/mixer.h"
#include "common/file.h"
#include "common/config-manager.h"
-#include "kyra.h"
-static const GameSettings kyra_setting =
- { "kyra", "Legend of Kyrandia", 0 };
+#include "kyra.h"
+#include "resource.h"
+#include "script.h"
+
+struct KyraGameSettings {
+ const char *name;
+ const char *description;
+ uint32 features;
+ const char *detectName;
+ GameSettings toGameSettings() const {
+ GameSettings dummy = { name, description, features };
+ return dummy;
+ }
+};
+
+static const KyraGameSettings kyra_settings[] = {
+ {"kyra1cd", "Legend of Kyrandia (CD)", GF_TALKIE & GF_KYRA1, "CHAPTER1.VRM"},
+ {"kyra1", "Legend of Kyrandia (Floppy)", GF_FLOPPY & GF_KYRA1, "INTRO.SND"},
+ { 0, 0, 0, 0}
+};
GameList Engine_KYRA_gameList() {
GameList games;
+ const KyraGameSettings *g = kyra_settings;
+
+ while (g->name) {
+ games.push_back(g->toGameSettings());
+ g++;
+ }
- games.push_back(kyra_setting);
return games;
}
-// TODO: Improve this :)
DetectedGameList Engine_KYRA_detectGames(const FSList &fslist) {
+ const KyraGameSettings *game;
DetectedGameList detectedGames;
- File test_file;
-
- // Iterate over all files in the given directory
- for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
- const char *name = file->displayName().c_str();
- if ((0 == scumm_stricmp("chapter1.vrm", name)) ||
- (0 == scumm_stricmp("chapter5.vrm", name))) {
- detectedGames.push_back(kyra_setting);
- printf("Detecting Kyra...\n");
- break;
+
+ for (game = kyra_settings; game->name; ++game) {
+ if (game->detectName == NULL)
+ continue;
+
+ for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+ const char *name = file->displayName().c_str();
+ if ((!scumm_stricmp(game->detectName, name))) {
+ detectedGames.push_back(game->toGameSettings());
+ break;
+ }
}
}
- return detectedGames;
+ return detectedGames;
}
Engine *Engine_KYRA_create(GameDetector *detector, OSystem *syst) {
@@ -78,11 +101,37 @@ KyraEngine::KyraEngine(GameDetector *detector, OSystem *syst)
//getGameDataPath();
- // Initialize backend
- syst->initSize(320, 240);
+ // Initialize backen
+ syst->initSize(320, 200);
+ _screen = new uint8[320*200];
+ memset((void*)_screen, 0, sizeof(_screen));
+
+ _resMgr = new Resourcemanager(this, getGameDataPath());
+ assert(_resMgr);
+
+ setCurrentPalette(_resMgr->loadPalette("PALETTE.COL"));
+
+ // loads the 2 cursors
+ _mouse = _resMgr->loadImage("MOUSE.CPS"); //startup.pak
+ _items = _resMgr->loadImage("ITEMS.CPS");
+
+ // loads the Font
+ _font = _resMgr->loadFont("8FAT.FNT");
+ printf("loading scripts\n");
+ // loads out scripts
+ _npcScript = _resMgr->loadScript("_NPC.EMC");
+ _currentScript = _resMgr->loadScript("_STARTUP.EMC");
+ printf("done\n");
+
}
KyraEngine::~KyraEngine() {
+ delete _resMgr;
+ delete _mouse;
+ delete _items;
+ delete _npcScript;
+ delete _currentScript;
+ delete _font;
}
void KyraEngine::errorString(const char *buf1, char *buf2) {
@@ -91,10 +140,61 @@ void KyraEngine::errorString(const char *buf1, char *buf2) {
void KyraEngine::go() {
warning("Kyrandia Engine ::go()");
+ // starts the init script
+ if (!_currentScript->startScript(kSetupScene)) {
+ error("couldn't init '_STARTUP.EMC' script");
+ }
+
+ if (_currentScript->contScript() != kScriptStopped) {
+ if (_currentScript->state() == kScriptError) {
+ error("couldn't run script");
+ } else {
+ warning("init script returned: %d", _currentScript->state());
+ }
+ }
+
+ while(true) {
+ OSystem::Event event;
+ //if (_debugger->isAttached())
+ // _debugger->onFrame();
+
+ updateScreen();
+ while (g_system->pollEvent(event)) {
+ switch (event.event_code) {
+ case OSystem::EVENT_QUIT:
+ g_system->quit();
+ break;
+ default:
+ break;
+ }
+ }
+ _system->delayMillis(10);
+ }
}
void KyraEngine::shutdown() {
_system->quit();
}
+
+void KyraEngine::updateScreen(void) {
+ _system->copyRectToScreen(_screen, 320, 0, 0, 320, 240);
+ _system->updateScreen();
+}
+
+void KyraEngine::setCurrentPalette(Palette* pal, bool delNextTime) {
+// if (_delPalNextTime)
+// delete _currentPal;
+
+// _delPalNextTime = delNextTime;
+
+// _currentPal = pal;
+
+ if (pal->getData()) {
+ _system->setPalette(pal->getData(), 0, 256);
+ } else {
+ warning("palette contains no data");
+ }
+}
+
} // End of namespace KYRA
diff --git a/kyra/kyra.h b/kyra/kyra.h
index 9bcf09e3c4..14a5c7855e 100644
--- a/kyra/kyra.h
+++ b/kyra/kyra.h
@@ -22,26 +22,49 @@
#ifndef KYRA_H
#define KYRA_H
-#include "common/scummsys.h"
+//#include "common/scummsys.h"
#include "base/engine.h"
#include "base/gameDetector.h"
#include "common/util.h"
+enum {
+ GF_FLOPPY = 1 << 0,
+ GF_TALKIE = 1 << 1,
+ GF_KYRA1 = 1 << 2,
+ GF_KYRA2 = 1 << 3
+};
+
namespace Kyra {
+ class Resourcemanager;
+ class CPSImage;
+ class Font;
+ class Palette;
+ class VMContext;
class KyraEngine : public Engine {
-
+public:
+ KyraEngine(GameDetector *detector, OSystem *syst);
+ ~KyraEngine();
void errorString( const char *buf_input, char *buf_output);
+ void updateScreen(void);
+ void setCurrentPalette(Palette* pal, bool delNextTime = true);
+
+ Resourcemanager* resManager(void) { return _resMgr; }
+// MidiDriver* midiDriver(void) { return _midiDriver; }
+
protected:
void go();
void shutdown();
+ Resourcemanager* _resMgr;
+ uint8 *_screen;
-public:
-
- KyraEngine(GameDetector *detector, OSystem *syst);
- virtual ~KyraEngine();
+ Font* _font;
+ CPSImage* _mouse;
+ CPSImage* _items;
+ VMContext* _currentScript; // our current script
+ VMContext* _npcScript; // script from NPCs
};
} // End of namespace Kyra
diff --git a/kyra/module.mk b/kyra/module.mk
index bf81faf477..5c4cf5d18b 100644
--- a/kyra/module.mk
+++ b/kyra/module.mk
@@ -1,7 +1,8 @@
MODULE := kyra
MODULE_OBJS = \
- kyra/kyra.o
+ kyra/kyra.o kyra/codecs.o kyra/script.o kyra/script_v1.o kyra/resource.o \
+ kyra/wsamovie.o kyra/palette.o kyra/cpsimage.o kyra/font.o
MODULE_DIRS += \
kyra
diff --git a/kyra/palette.cpp b/kyra/palette.cpp
new file mode 100644
index 0000000000..a9836c8ef9
--- /dev/null
+++ b/kyra/palette.cpp
@@ -0,0 +1,80 @@
+/* ScummVM - Kyrandia Interpreter
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+#include "resource.h"
+
+#include "common/stream.h"
+#include "codecs.h"
+
+namespace Kyra {
+
+ Palette::Palette(uint8* data, uint32 size) {
+ if (!data) {
+ error("resource created without data");
+ }
+
+ if (size != 768) {
+ Common::MemoryReadStream datastream(data, size);
+
+ datastream.readSint32LE();
+ int imageSize = datastream.readSint16LE();
+
+ if (imageSize != 768) {
+ error("decompresed palette is not 768 byte long!");
+ }
+
+ // lets uncompress this palette :)
+ _palette = new uint8[imageSize];
+ assert(_palette);
+
+ // made decompression
+ if (Compression::decode80(data + 10, _palette) != 768) {
+ error("decode80 decompressesize != 768 bytes");
+ }
+
+ delete [] data;
+ data = _palette;
+ }
+
+ // hmm.. common/system.h Docu is wrong or SDL Backend has a bug :)
+ // a palette should have this order:
+ // R1-G1-B1-A1-R2-G2-B2-A2-...
+ // so we need 4 bytes per color
+ _palette = new uint8[256 * 4];
+
+ uint8* currentpossrc = &data[0];
+ uint8* currentposdst = &_palette[0];
+
+ // creates the original pallette (only first 6 bits are used)
+ for (uint32 i = 0; i < 256; i++) {
+ currentposdst[0] = currentpossrc[0] << 2;
+ currentposdst[1] = currentpossrc[1] << 2;
+ currentposdst[2] = currentpossrc[2] << 2;
+ currentpossrc += 3;
+ currentposdst += 4;
+ }
+
+ delete [] data;
+ }
+
+} // end of namespace Kyra
+
diff --git a/kyra/resource.cpp b/kyra/resource.cpp
new file mode 100644
index 0000000000..6e56ff3a08
--- /dev/null
+++ b/kyra/resource.cpp
@@ -0,0 +1,254 @@
+/* ScummVM - Kyrandia Interpreter
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+#include "resource.h"
+#include "wsamovie.h"
+
+#include "common/file.h"
+#include "script.h"
+
+namespace Kyra {
+ Resourcemanager::Resourcemanager(KyraEngine* engine, const char* gamedir) {
+ _gameDir = gamedir;
+
+ // prefetches all PAK Files
+
+ // ugly a hardcoded list
+ // TODO: use the FS Backend to get all .PAK Files and load them
+ static const char* kyraFilelist[] = {
+ "A_E.PAK", "DAT.PAK", "F_L.PAK", "MAP_5.PAK", "MSC.PAK", "M_S.PAK",
+ "S_Z.PAK", "WSA1.PAK", "WSA2.PAK", "WSA3.PAK", "WSA4.PAK", "WSA5.PAK",
+ "WSA6.PAK", "startup.pak", "intro1.pak", 0
+ };
+
+ for (uint32 tmp = 0; kyraFilelist[tmp]; ++tmp) {
+
+ // prefetch file
+ PAKFile* file = new PAKFile(getPath() + kyraFilelist[tmp]);
+ assert(file);
+
+ if (file->isValid())
+ _pakfiles.push_back(file);
+ else
+ warning("couldn't load file '%s' correctly", kyraFilelist[tmp]);
+ }
+ }
+
+ Resourcemanager::~Resourcemanager() {
+ Common::List<PAKFile*>::iterator start = _pakfiles.begin();
+
+ for (;start != _pakfiles.end(); ++start) {
+ delete *start;
+ *start = 0;
+ }
+ }
+
+ uint8* Resourcemanager::fileData(const char* file, uint32* size) {
+ uint8* buffer = 0;
+
+ debug("looking for file '%s'", file);
+
+ File file_;
+
+ // test to open it in the main dir
+ if (file_.open((getPath() + file).c_str())) {
+
+ *size = file_.size();
+
+ buffer = new uint8[*size];
+ assert(buffer);
+
+ file_.read(buffer, *size);
+
+ file_.close();
+
+ } else {
+ // opens the file in a PAK File
+ Common::List<PAKFile*>::iterator start = _pakfiles.begin();
+
+ for (;start != _pakfiles.end(); ++start) {
+ *size = (*start)->getFileSize(file);
+
+ if (!*size)
+ continue;
+
+ buffer = new uint8[*size];
+ assert(buffer);
+
+ // creates a copy of the file
+ memcpy(buffer, (*start)->getFile(file), *size);
+
+ break;
+ }
+
+ }
+
+ if (!buffer || !(*size)) {
+ warning("couldn't find file '%s'", file);
+ }
+
+ return buffer;
+ }
+
+ Palette* Resourcemanager::loadPalette(const char* file) {
+ uint32 size = 0;
+ uint8* buffer = 0;
+ buffer = fileData(file, &size);
+ if (!buffer)
+ return 0;
+ return new Palette(buffer, size);
+ }
+
+ CPSImage* Resourcemanager::loadImage(const char* file) {
+ uint32 size = 0;
+ uint8* buffer = 0;
+ buffer = fileData(file, &size);
+ if (!buffer)
+ return 0;
+ return new CPSImage(buffer, size);
+ }
+
+ Font* Resourcemanager::loadFont(const char* file) {
+ uint32 size = 0;
+ uint8* buffer = 0;
+ buffer = fileData(file, &size);
+ if (!buffer)
+ return 0;
+ return new Font(buffer, size);
+ }
+
+ Movie* Resourcemanager::loadMovie(const char* file) {
+ // TODO: we have to check the Extenion to create the right movie
+ uint32 size = 0;
+ uint8* buffer = 0;
+ buffer = fileData(file, &size);
+ if (!buffer)
+ return 0;
+ return new WSAMovieV1(buffer, size);
+ }
+
+ VMContext* Resourcemanager::loadScript(const char* file) {
+ VMContext* context = new VMContext(_engine);
+ context->loadScript(file);
+ return context;
+ }
+
+ Common::String Resourcemanager::getPath(void) {
+ assert(_gameDir);
+ int32 len = strlen(_gameDir);
+
+ if(len < 1)
+ error("no valid gamedir");
+
+ // tests for an path seperator at the end
+ if (_gameDir[len - 1] == '\\') {
+ return string(_gameDir);
+ } else if (_gameDir[len - 1 ] == '/') {
+ return string(_gameDir);
+ }
+
+ // creates a path seperator at the end
+ // we are always using the path seperator from the system
+ // even if Windows shoudl accept '/'
+#ifdef WIN32
+ return string(_gameDir) + "\\";
+#else
+ return string(_gameDir) + "/";
+#endif
+ }
+
+///////////////////////////////////////////
+// Pak file manager
+ #define PAKFile_Iterate Common::List<PakChunk*>::iterator start=_files.begin();start != _files.end(); ++start
+
+ PAKFile::PAKFile(const Common::String& file) {
+ File pakfile;
+
+ if (!pakfile.open(file.c_str())) {
+ warning("PAKFile couldn't open: '%s'", file.c_str());
+ return;
+ }
+
+ uint32 filesize = pakfile.size();
+ _buffer = new uint8[filesize];
+ assert(_buffer);
+
+ pakfile.read(_buffer, filesize);
+ pakfile.close();
+
+ // works with the file
+ uint32 pos = 0, startoffset = 0, endoffset = 0;
+
+ startoffset = *(reinterpret_cast<uint32*>((_buffer + pos)));
+ pos += 4;
+
+ while (pos < filesize) {
+ PakChunk* chunk = new PakChunk;
+ assert(chunk);
+
+ // saves the name
+ chunk->_name = reinterpret_cast<const char*>(_buffer + pos);
+ pos += strlen(chunk->_name) + 1;
+ if(!chunk->_name)
+ break;
+
+ endoffset = *(reinterpret_cast<uint32*>((_buffer + pos)));
+ pos += 4;
+
+ chunk->_data = _buffer + startoffset;
+ chunk->_size = endoffset - startoffset;
+
+ startoffset = endoffset;
+
+ _files.push_back(chunk);
+ }
+ }
+
+ PAKFile::~PAKFile() {
+ delete [] _buffer;
+ _buffer = 0;
+
+ for (PAKFile_Iterate) {
+ delete *start;
+ *start = 0;
+ }
+ }
+
+ const uint8* PAKFile::getFile(const char* file) {
+ for (PAKFile_Iterate) {
+ if (!scumm_stricmp((*start)->_name, file))
+ return (*start)->_data;
+ }
+
+ return 0;
+ }
+
+ uint32 PAKFile::getFileSize(const char* file) {
+ for (PAKFile_Iterate) {
+ if (!scumm_stricmp((*start)->_name, file))
+ return (*start)->_size;
+ }
+
+ return 0;
+ }
+} // end of namespace Kyra
+
diff --git a/kyra/resource.h b/kyra/resource.h
new file mode 100644
index 0000000000..b0a73beaa5
--- /dev/null
+++ b/kyra/resource.h
@@ -0,0 +1,201 @@
+/* ScummVM - Kyrandia Interpreter
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#ifndef RESOURCE_H
+#define RESOURCE_H
+
+#include "common/stdafx.h"
+#include "common/scummsys.h"
+#include "common/str.h"
+#include "common/list.h"
+#include "common/map.h"
+
+#include "kyra.h"
+
+namespace Kyra {
+
+ // standard Package format for Kyrandia games
+ class PAKFile {
+
+ struct PakChunk {
+ const char* _name;
+ const uint8* _data;
+ uint32 _size;
+ };
+
+ public:
+
+ PAKFile(const Common::String& file);
+ ~PAKFile();
+
+ const uint8* getFile(const char* file);
+ uint32 getFileSize(const char* file);
+
+ bool isValid(void) { return (_buffer != 0); }
+
+ private:
+
+ uint8* _buffer; // the whole file
+ Common::List<PakChunk*> _files; // the entries
+
+ };
+
+ // some resource types
+ class Palette;
+ class CPSImage;
+ class Font;
+ class Movie;
+ class VMContext;
+
+ // out resource manager
+ class Resourcemanager {
+ typedef Common::String string;
+
+ public:
+
+ Resourcemanager(KyraEngine* engine, const char* gamedir);
+ virtual ~Resourcemanager();
+
+ uint8* fileData(const char* file, uint32* size);
+
+ Palette* loadPalette(const char* file);
+ CPSImage* loadImage(const char* file);
+ Font* loadFont(const char* file);
+ Movie* loadMovie(const char* file);
+ VMContext* loadScript(const char* file);
+
+ protected:
+ KyraEngine* _engine;
+
+ string getPath(void);
+ const char* _gameDir;
+ Common::List<PAKFile*> _pakfiles;
+
+ };
+
+ class Palette {
+
+ public:
+
+ Palette(uint8* data, uint32 size);
+ ~Palette() { delete [] _palette; }
+
+ uint8* getData(void) { return _palette; }
+
+ protected:
+
+ uint8* _palette;
+
+ };
+
+ class CPSImage {
+
+ public:
+
+ CPSImage(uint8* buffer, uint32 size);
+ ~CPSImage();
+
+ Palette* palette(void) { return _ownPalette; }
+ bool hasPalette(void) { return (_ownPalette != 0); }
+
+ // if col == -1 then no transparany
+ void setTransparencyColor(int16 col) { _transparency = col; }
+
+ void drawToPlane(uint8* plane, uint16 planepitch, uint16 planeheight, uint16 x, uint16 y);
+ void drawToPlane(uint8* plane, uint16 planepitch, uint16 planeheight, uint16 x, uint16 y,
+ uint16 srcx, uint16 srcy, uint16 srcwidth, uint16 srcheight);
+
+ // only for testing :)
+ uint8 getColor(uint16 x, uint16 y) { return _image[y * _width + x]; }
+
+ uint8& operator[](uint16 index) { if(index > _width * _height) return _image[0]; return _image[index]; }
+
+ protected:
+
+ struct CPSHeader {
+ uint16 _filesize;
+ uint16 _format;
+ uint16 _imagesize;
+ uint32 _pal;
+ } _cpsHeader;
+
+ Palette* _ownPalette;
+ uint8* _image;
+
+ uint16 _width, _height;
+ int16 _transparency;
+ };
+
+ class Font {
+
+ public:
+
+ Font(uint8* buffer, uint32 size);
+ ~Font();
+
+ uint32 getStringWidth(const char* string, char terminator = '\0');
+ void drawStringToPlane(const char* string,
+ uint8* plane, uint16 planewidth, uint16 planeheight,
+ uint16 x, uint16 y, uint8 color);
+
+ protected:
+
+ void drawCharToPlane(const uint8* c, uint8 color, uint8 width, uint8 height,
+ uint8* plane, uint16 planewidth, uint16 planeheight, uint16 x, uint16 y);
+ const uint8* getChar(char c, uint8* width, uint8* height, uint8* heightadd);
+ const char* getNextWord(const char* string, uint32* size);
+
+ void preRenderAllChars(uint16 offsetTableOffset);
+
+ uint8* _buffer;
+
+ uint16* _offsetTable;
+ uint8* _charWidth;
+ uint16* _charHeight;
+ uint8* _charBits;
+
+ // the chars I call 'prerendered' aren't really prerendered
+ // they are only 'decoded'
+ struct PreRenderedChar {
+ uint8* c;
+ uint8 width, height, heightadd;
+ };
+
+ Common::Map<uint8, PreRenderedChar> _preRenderedChars; // our prerendered chars :)
+
+ // INFO:
+ // _magic1 = 0x0500
+ // _magic2 = 0x000e
+ // _magic3 = 0x0014
+#pragma START_PACK_STRUCTS
+ struct FontHeader {
+ uint16 _size;
+ uint16 _magic1, _magic2, _magic3;
+ uint16 _charWidthOffset, _charBitsOffset, _charHeightOffset;
+ uint16 _version;
+ uint16 _countChars;
+ uint8 _width, _height;
+ } GCC_PACK _fontHeader;
+#pragma END_PACK_STRUCTS
+ };
+} // end of namespace Kyra
+
+#endif
diff --git a/kyra/script.cpp b/kyra/script.cpp
new file mode 100644
index 0000000000..8b5e18287a
--- /dev/null
+++ b/kyra/script.cpp
@@ -0,0 +1,506 @@
+/* ScummVM - Kyrandia Interpreter
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+#include "kyra.h"
+#include "script.h"
+#include "resource.h"
+
+#include "common/stream.h"
+
+#define COMMAND(x) { &VMContext::x, #x }
+#define OPCODE(x) { &VMContext::x, #x }
+
+namespace Kyra {
+ VMContext::VMContext(KyraEngine* engine) {
+ _engine = engine;
+
+ // now we create a list of all Command/Opcode procs and so
+ static CommandEntry commandProcs[] = {
+ // 0
+ COMMAND(c1_goToLine),
+ COMMAND(c1_setReturn),
+ COMMAND(c1_pushRetRec),
+ COMMAND(c1_push),
+ COMMAND(c1_push),
+ COMMAND(c1_pushVar),
+ COMMAND(c1_pushFrameNeg),
+ COMMAND(c1_pushFramePos),
+ COMMAND(c1_popRetRec),
+ COMMAND(c1_popVar),
+
+ // 10
+ COMMAND(c1_popFrameNeg),
+ COMMAND(c1_popFramePos),
+ COMMAND(c1_addToSP),
+ COMMAND(c1_subFromSP),
+ COMMAND(c1_execOpcode),
+ COMMAND(c1_ifNotGoTo),
+ COMMAND(c1_negate),
+ COMMAND(c1_evaluate),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 20
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 30
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 40
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 50
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 60
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 70
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 80
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 90
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 100
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 110
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 120
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 130
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 140
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 150
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 160
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 170
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 180
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 190
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 200
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 210
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 220
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 230
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 240
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+
+ // 250
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ COMMAND(c1_unknownCommand),
+ { 0, 0 }
+ };
+
+ _scriptFile = NULL;
+ _scriptFileSize = 0;
+ }
+
+ void VMContext::loadScript(const char* file) {
+ printf("a\n");
+ if (_scriptFile) {
+ delete [] _scriptFile;
+ _scriptFileSize = 0;
+ }
+
+ debug("--------------");
+
+ // loads the new file
+ _scriptFile = _engine->resManager()->fileData(file, &_scriptFileSize);
+ printf("c\n");
+
+ if (!_scriptFileSize || !_scriptFile) {
+ error("couldn't load script file '%s'", file);
+ }
+
+ Common::MemoryReadStream script(_scriptFile, _scriptFileSize);
+ memset(_chunks, 0, sizeof(ScriptChunk) * kCountChunkTypes);
+ uint8 chunkName[sizeof("EMC2ORDR") + 1];
+
+ // so lets look for our chunks :)
+ while(true) {
+ if (script.eof()) {
+ break;
+ }
+ // lets read only the first 4 chars
+ script.read(chunkName, sizeof(uint8) * 4);
+ chunkName[4] = '\0';
+ debug("chunk name(4 chars): '%s'", chunkName);
+
+ // check name of chunk
+ if (!scumm_stricmp((char*)chunkName, "FORM")) {
+ // FreeKyra swaps the size I only read it in BigEndian :)
+ _chunks[kForm]._size = script.readUint32BE();
+ debug("_chunks[kForm]._size = %d", _chunks[kForm]._size);
+ } else if (!scumm_stricmp((char*)chunkName, "TEXT")) {
+ uint32 text_size = script.readUint32BE();
+ text_size += text_size % 2 != 0 ? 1 : 0;
+
+ _chunks[kText]._data = _scriptFile + script.pos();
+ _chunks[kText]._size = READ_BE_UINT16(_chunks[kText]._data) >> 1;
+ _chunks[kText]._additional = _chunks[kText]._data + (_chunks[kText]._size << 1);
+ debug("_chunks[kText]._size = %d, real chunk size = %d", _chunks[kText]._size, text_size);
+
+ script.seek(script.pos() + text_size);
+ } else if (!scumm_stricmp((char*)chunkName, "DATA")) {
+ _chunks[kData]._size = script.readUint32BE();
+ _chunks[kData]._data = _scriptFile + script.pos();
+ debug("_chunks[kData]._size = %d", _chunks[kData]._size);
+
+ // mostly it will be the end of the file because all files should end with a 'DATA' chunk
+ script.seek(script.pos() + _chunks[kData]._size);
+ } else {
+ // read next 4 chars
+ script.read(&chunkName[4], sizeof(uint8) * 4);
+ chunkName[8] = '\0';
+ debug("chunk name(8 chars): '%s'", chunkName);
+
+ if (!scumm_stricmp((char*)chunkName, "EMC2ORDR")) {
+ _chunks[kEmc2Ordr]._size = script.readUint32BE() >> 1;
+ _chunks[kEmc2Ordr]._data = _scriptFile + script.pos();
+ debug("_chunks[kEmc2Ordr]._size = %d, real chunk size = %d", _chunks[kEmc2Ordr]._size, _chunks[kEmc2Ordr]._size * 2);
+
+ script.seek(script.pos() + _chunks[kEmc2Ordr]._size * 2);
+ } else {
+ // any unkown chunk or problems with seeking through the file
+ error("unknown chunk");
+ }
+ }
+ }
+
+ // so file loaded
+ debug("--------------");
+ }
+
+ int32 VMContext::param(int32 index) {
+ if (_stackPos - index + 1 >= 16 || _stackPos - index + 1 < 0)
+ return -0xFFFF;
+ return _stack[_stackPos - index + 1];
+ }
+
+ const char* VMContext::stringAtIndex(int32 index) {
+ if (index < 0 || (uint32)index >= _chunks[kText]._size)
+ return 0;
+
+ return (char*)(_chunks[kText]._additional + _chunks[kText]._data[index]);
+ }
+
+ bool VMContext::startScript(int32 func) {
+ if ((uint32)func >= _chunks[kEmc2Ordr]._size || func < 0) {
+ debug("script doesn't support function %d", func);
+ return false;
+ }
+
+ _instructionPos = (READ_BE_UINT16(&_chunks[kEmc2Ordr]._data[func]) << 1) + 2;
+ _stackPos = 0;
+ _tempPos = 0;
+ _delay = 0;
+ _scriptState = kScriptRunning;
+ return true;
+ }
+
+ uint32 VMContext::contScript(void) {
+ uint8* script_start = _chunks[kData]._data;
+ assert(script_start);
+
+ uint32 scriptStateAtStart = _scriptState;
+
+ // runs the script
+ while(true) {
+ if ((uint32)_instructionPos > _chunks[kData]._size) {
+ debug("_instructionPos( = %d) > _chunks[kData]._size( = %d)", _instructionPos, _chunks[kData]._size);
+ _error = true;
+ break;
+ }
+
+ _currentCommand = *(script_start + _instructionPos++);
+
+ // gets out
+ if (_currentCommand & 0x80) {
+ _argument = ((_currentCommand & 0x0F) << 8) | *(script_start + _instructionPos++);
+ _currentCommand &= 0xF0;
+ } else if (_currentCommand & 0x40) {
+ _argument = *(script_start + _instructionPos++);
+ } else if (_currentCommand & 0x20) {
+ _instructionPos++;
+
+ uint16 tmp = *(uint16*)(script_start + _instructionPos);
+ tmp &= 0xFF7F;
+
+ _argument = READ_BE_UINT16(&tmp);
+ _instructionPos += 2;
+ } else {
+ debug("unknown way of getting the command");
+ }
+
+ _currentCommand &= 0x1f;
+
+ CommandProc currentProc = _commands[_currentCommand].proc;
+ (this->*currentProc)();
+
+ if (_error) {
+ _scriptState = kScriptError;
+ break;
+ }
+
+ if (scriptStateAtStart != _scriptState) {
+ break;
+ }
+ }
+
+ return _scriptState;
+ }
+} // end of namespace Kyra
diff --git a/kyra/script.h b/kyra/script.h
new file mode 100644
index 0000000000..0100a9dd6a
--- /dev/null
+++ b/kyra/script.h
@@ -0,0 +1,155 @@
+/* ScummVM - Kyrandia Interpreter
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#ifndef VM_H
+#define VM_H
+
+namespace Kyra {
+ // TODO:
+ // find out more script functions
+ enum ScriptFunc {
+ kSetupScene = 0,
+ kClickEvent = 1, // _registers[1] and _registers[2] are mouse x, y _registers[4] is action
+ kActorEvent = 2,
+ kEnterEvent = 4,
+ kExitEvent = 5,
+ kLoadResources = 7
+ };
+
+ enum ScriptState {
+ kScriptStopped = 0,
+ kScriptRunning = 1,
+ kScriptWaiting = 2,
+ kScriptError = 3
+ };
+
+ class VMContext {
+
+ public:
+
+ VMContext(KyraEngine* engine);
+ ~VMContext() { delete [] _scriptFile; }
+
+ void loadScript(const char* file);
+
+ const char* stringAtIndex(int32 index);
+
+ // TODO: check for 'over'flow
+ void pushStack(int32 value) { _stack[_stackPos++] = value; }
+ void registerValue(int32 reg, int32 value) { _registers[reg] = value; }
+ int32 checkReg(int32 reg) { return _registers[reg]; }
+
+ uint32 state(void) { return _scriptState; }
+
+ bool startScript(int32 func);
+ uint32 contScript(void);
+
+ protected:
+ KyraEngine* _engine;
+ uint8* _scriptFile;
+ uint32 _scriptFileSize;
+
+ uint32 _scriptState;
+ uint32 _delay;
+
+ int32 _registers[32]; // registers of the interpreter
+ int32 _stack[32]; // our stack
+
+ // TODO: check for 'under'flow
+ int32 popStack(void) { return _stack[_stackPos--]; }
+ int32& topStack(void) { return _stack[_stackPos]; }
+
+ uint32 _returnValue;
+
+ int32 _instructionPos;
+ int32 _stackPos;
+ int32 _tempPos;
+
+ // used by command & opcode procs
+ uint16 _argument;
+ uint8 _currentCommand;
+ uint32 _currentOpcode;
+
+ int32 param(int32 index);
+ const char* paramString(int32 index) { return stringAtIndex(param(index)); }
+
+ bool _error; // used by all command- and opcodefuncs
+
+ enum ScriptChunkTypes {
+ kForm = 0,
+ kEmc2Ordr = 1,
+ kText = 2,
+ kData = 3,
+ kCountChunkTypes
+ };
+
+ struct ScriptChunk {
+ uint32 _size;
+ uint8* _data; // by TEXT used for count of texts, by EMC2ODRD it is used for a count of somewhat
+ uint8* _additional; // currently only used for TEXT
+ };
+
+ ScriptChunk _chunks[kCountChunkTypes];
+
+ typedef void (VMContext::*CommandProc)();
+ struct CommandEntry {
+ CommandProc proc;
+ const char* desc;
+ };
+
+ typedef void (VMContext::*OpcodeProc)();
+ struct OpcodeEntry {
+ OpcodeProc proc;
+ const char* desc;
+ };
+
+ const CommandEntry* _commands;
+ const OpcodeEntry* _opcodes;
+
+ protected:
+ // the command procs
+ void c1_goToLine(void); // 0x00
+ void c1_setReturn(void); // 0x01
+ void c1_pushRetRec(void); // 0x02
+ void c1_push(void); // 0x03 & 0x04
+ void c1_pushVar(void); // 0x05
+ void c1_pushFrameNeg(void); // 0x06
+ void c1_pushFramePos(void); // 0x07
+ void c1_popRetRec(void); // 0x08
+ void c1_popVar(void); // 0x09
+ void c1_popFrameNeg(void); // 0x0A
+ void c1_popFramePos(void); // 0x0B
+ void c1_addToSP(void); // 0x0C
+ void c1_subFromSP(void); // 0x0D
+ void c1_execOpcode(void); // 0x0E
+ void c1_ifNotGoTo(void); // 0x0F
+ void c1_negate(void); // 0x10
+ void c1_evaluate(void); // 0x11
+ void c1_unknownCommand(void);
+
+ // the opcode procs
+ void o1_0x68(void); // 0x68
+ void o1_unknownOpcode(void);
+ };
+} // end of namespace Kyra
+
+#endif
+
diff --git a/kyra/script_v1.cpp b/kyra/script_v1.cpp
new file mode 100644
index 0000000000..8b306f52e1
--- /dev/null
+++ b/kyra/script_v1.cpp
@@ -0,0 +1,220 @@
+/* ScummVM - Kyrandia Interpreter
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+
+#include "kyra.h"
+#include "script.h"
+
+namespace Kyra {
+ // Command procs
+
+ void VMContext::c1_unknownCommand(void) {
+ debug("unknown command '0x%x'.", _currentCommand);
+ debug("\targument: '0x%x'", _argument);
+
+ _error = true;
+ }
+
+ void VMContext::c1_goToLine(void) {
+ _instructionPos = _argument << 1;
+ }
+
+ void VMContext::c1_setReturn(void) {
+ _returnValue = _argument;
+ }
+
+ void VMContext::c1_pushRetRec(void) {
+ if (!_argument) {
+ pushStack(_returnValue);
+ } else {
+ int32 rec = ((int16)_tempPos << 16) | ((_instructionPos >> 1) + 1);
+ pushStack(rec);
+ _tempPos = _instructionPos;
+ }
+ }
+
+ void VMContext::c1_push(void) {
+ pushStack(_argument);
+ }
+
+ void VMContext::c1_pushVar(void) {
+ pushStack(_registers[_argument]);
+ }
+
+ void VMContext::c1_pushFrameNeg(void) {
+ pushStack(_stack[_tempPos + _argument]);
+ }
+
+ void VMContext::c1_pushFramePos(void) {
+ pushStack(_stack[_tempPos - _argument]);
+ }
+
+ void VMContext::c1_popRetRec(void) {
+ if (!_argument) {
+ _returnValue = popStack();
+ } else {
+ if (_stackPos <= 0) {
+ _scriptState = kScriptStopped;
+ }
+ int32 rec = popStack();
+
+ _tempPos = (int16)((rec & 0xFFFF0000) >> 16);
+ _instructionPos = (rec & 0x0000FFFF) * 2;
+ }
+ }
+
+ void VMContext::c1_popVar(void) {
+ _registers[_argument] = popStack();
+ }
+
+ void VMContext::c1_popFrameNeg(void) {
+ _stack[_tempPos + _argument] = popStack();
+ }
+
+ void VMContext::c1_popFramePos(void) {
+ _stack[_tempPos - _argument] = popStack();
+ }
+
+ void VMContext::c1_addToSP(void) {
+ _stackPos -= _argument;
+ }
+
+ void VMContext::c1_subFromSP(void) {
+ _stackPos += _argument;
+ }
+
+ void VMContext::c1_execOpcode(void) {
+ OpcodeProc proc = _opcodes[_argument].proc;
+ (this->*proc)();
+ }
+
+ void VMContext::c1_ifNotGoTo(void) {
+ if (!popStack()) {
+ _instructionPos = _argument << 1;
+ }
+ }
+
+ void VMContext::c1_negate(void) {
+ switch(_argument) {
+ case 0:
+ topStack() = !topStack();
+ break;
+
+ case 1:
+ topStack() = -topStack();
+ break;
+
+ case 2:
+ topStack() = ~topStack();
+ break;
+
+ default:
+ debug("unkown negate instruction %d", _argument);
+ _error = true;
+ break;
+ };
+ }
+
+ void VMContext::c1_evaluate(void) {
+ int32 x, y;
+ int32 res = false;
+
+ x = popStack();
+ y = popStack();
+
+ switch(_argument) {
+ case 0:
+ res = x && y;
+ break;
+
+ case 1:
+ res = x || y;
+ break;
+
+ case 3:
+ res = x != y;
+ break;
+
+ case 4:
+ res = x < y;
+ break;
+
+ case 5:
+ res = x <= y;
+ break;
+
+ case 6:
+ res = x > y;
+ break;
+
+ case 7:
+ res = x >= y;
+ break;
+
+ case 8:
+ res = x + y;
+ break;
+
+ case 9:
+ res = x - y;
+ break;
+
+ case 10:
+ res = x * y;
+ break;
+
+ case 11:
+ res = x / y;
+ break;
+
+ case 12:
+ res = x >> y;
+ break;
+
+ case 13:
+ res = x << y;
+ break;
+
+ case 14:
+ res = x & y;
+ break;
+
+ case 15:
+ res = x | y;
+ break;
+
+ case 16:
+ res = x % y;
+ break;
+
+ case 17:
+ res = x ^ y;
+ break;
+
+ default:
+ debug("unknown evaluate command");
+ break;
+ };
+
+ pushStack(res);
+ }
+} // end of namespace Kyra
diff --git a/kyra/wsamovie.cpp b/kyra/wsamovie.cpp
new file mode 100644
index 0000000000..5b89dccf7e
--- /dev/null
+++ b/kyra/wsamovie.cpp
@@ -0,0 +1,119 @@
+/* ScummVM - Kyrandia Interpreter
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+#include "wsamovie.h"
+#include "codecs.h"
+
+#include "common/stream.h"
+
+namespace Kyra {
+ WSAMovieV1::WSAMovieV1(uint8* data, uint32 size) {
+ if (!data) {
+ error("resource created without data");
+ }
+
+ _buffer = data;
+
+ // I like these Streams .... =)
+ Common::MemoryReadStream datastream(data, size);
+
+ datastream.read(&_wsaHeader, sizeof(_wsaHeader));
+
+ // check for version
+ if (_wsaHeader._type) {
+ error("loading a WSA version 2 with the WSA version 1 loader");
+ }
+
+ uint16 offsetAdd = 0;
+
+ // checks now for own palette
+ if (_wsaHeader._type % 2) {
+ // don't now if this will work right, because a few lines before we use
+ // _wsaHeader._type for detect the version of the WSA movie,
+ // but this code was from FreeKyra Tools so I think it will work
+
+ // if this is a packed palette we have a problem :)
+ offsetAdd = 768 /* 0x300 */;
+ }
+
+ _frameCount = _wsaHeader._numFrames;
+ _offsetTable = new uint32[_wsaHeader._numFrames + 2];
+ assert(!_offsetTable);
+
+ // loads the offset table
+ for (uint32 tmp = 0; tmp < _wsaHeader._numFrames; ++tmp) {
+ _offsetTable[tmp] = datastream.readUint32LE() + offsetAdd;
+ }
+
+ if (offsetAdd) {
+ uint8* palbuffer = new uint8[offsetAdd];
+ assert(!palbuffer);
+
+ _ownPalette = new Palette(palbuffer, offsetAdd);
+ assert(!_ownPalette);
+ }
+ }
+
+ WSAMovieV1::~WSAMovieV1() {
+ delete [] _buffer;
+ delete [] _offsetTable;
+ delete _ownPalette;
+ }
+
+ const uint8* WSAMovieV1::loadFrame(uint16 frame, uint16* width, uint16* height) {
+ if (width) *width = _wsaHeader._width;
+ if (height) *height = _wsaHeader._height;
+
+ if (frame == _prefetchedFrame) {
+ return _currentFrame;
+ } else {
+ if (!_currentFrame) {
+ _currentFrame = new uint8[_wsaHeader._width * _wsaHeader._height];
+ assert(_currentFrame);
+ }
+
+ uint8* frameData = 0;
+ uint8 image40[64000]; // I think this crash on Plam OS :)
+
+ if (frame = _prefetchedFrame + 1) {
+ frameData = _buffer + _offsetTable[frame] + (hasPalette() ? 768 : 0);
+ Compression::decode80(frameData, image40);
+ Compression::decode40(image40, _currentFrame);
+ } else {
+ memset(_currentFrame, 0, _wsaHeader._width * _wsaHeader._height);
+
+ for (uint32 i = 0; i <= frame; i++)
+ {
+ frameData = _buffer + _offsetTable[i] + (hasPalette() ? 768 : 0);
+ Compression::decode80(frameData, image40);
+ Compression::decode40(image40, _currentFrame);
+ }
+ }
+
+ _prefetchedFrame = frame;
+ return _currentFrame;
+ }
+
+ return 0;
+ }
+} // end of namespace Kyra
+
diff --git a/kyra/wsamovie.h b/kyra/wsamovie.h
new file mode 100644
index 0000000000..2f23a5c4c2
--- /dev/null
+++ b/kyra/wsamovie.h
@@ -0,0 +1,82 @@
+/* ScummVM - Kyrandia Interpreter
+ * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#ifndef MOVIES_H
+#define MOVIES_H
+
+#include "resource.h"
+
+namespace Kyra {
+
+ // a generic movie
+ class Movie {
+
+ public:
+
+ virtual ~Movie() {}
+
+ virtual const uint8* loadFrame(uint16 frame, uint16* width = 0, uint16* height = 0) = 0;
+ virtual uint16 countFrames(void) { return _frameCount; }
+
+ virtual bool hasPalette(void) { return (_ownPalette != 0); }
+ virtual Palette* palette(void) { return _ownPalette; }
+
+ protected:
+ uint16 _frameCount;
+ Palette* _ownPalette;
+ };
+
+ // movie format for Kyrandia 1
+ // there is also a new WSA Format for Kyrandia 2
+ // which i will implement in future
+ class WSAMovieV1 : public Movie {
+
+ public:
+
+ WSAMovieV1(uint8* data, uint32 size);
+ ~WSAMovieV1();
+
+ const uint8* loadFrame(uint16 frame, uint16* width, uint16* height);
+ protected:
+
+ uint8* _buffer;
+
+#pragma START_PACK_STRUCTS
+ struct WSAHeader {
+ uint16 _numFrames; // All right
+ uint16 _width; // should be right
+ uint16 _height; // should be right
+ uint8 _xPos; // could be wrong
+ uint8 _yPos; // could be wrong
+ uint16 _delta; // could be wrong
+ uint16 _type; // should be right
+ } GCC_PACK _wsaHeader;
+#pragma END_PACK_STRUCTS
+
+ uint32* _offsetTable;
+
+ uint8* _currentFrame;
+ uint16 _prefetchedFrame;
+ };
+} // end of namespace Kyra
+
+#endif
+