[Scummvm-git-logs] scummvm-tools master -> 2caf8ea37db45e542d41e57e0af8bf604e40b52f
mgerhardy
noreply at scummvm.org
Thu Jan 12 18:10:16 UTC 2023
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm-tools' repo located at https://github.com/scummvm/scummvm-tools .
Summary:
2caf8ea37d TWINE: new lba1 script decompiler
Commit: 2caf8ea37db45e542d41e57e0af8bf604e40b52f
https://github.com/scummvm/scummvm-tools/commit/2caf8ea37db45e542d41e57e0af8bf604e40b52f
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2023-01-11T19:13:33+01:00
Commit Message:
TWINE: new lba1 script decompiler
Changed paths:
A CMakeLists.txt
A engines/twine/detwine.cpp
A engines/twine/hqr.cpp
A engines/twine/hqr.h
A engines/twine/lba1.cpp
A engines/twine/lba1.h
A engines/twine/lba2.cpp
A engines/twine/lba2.h
.gitignore
Makefile
Makefile.common
common/scummsys.h
diff --git a/.gitignore b/.gitignore
index 8ab20711..ab28e83b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,7 @@
/deprince
/descumm
/desword2
+/detwine
/extract_hadesch_img
/extract_mohawk
/extract_mps
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 00000000..cd066a90
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,43 @@
+cmake_minimum_required(VERSION 3.19)
+project(scummvm-tools CXX)
+include(CheckCXXCompilerFlag)
+
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+if (WIN32)
+ add_definitions(-DWIN32)
+else()
+ add_definitions(-DPOSIX)
+endif()
+
+find_package(SDL REQUIRED)
+
+function(add_tool NAME)
+ add_executable(${NAME} ${ARGN})
+ target_include_directories(${NAME} PUBLIC .)
+ target_link_libraries(${NAME} SDL::SDL)
+endfunction()
+
+set(COMMON_SRC
+ common/file.cpp
+ common/hashmap.cpp
+ common/md5.cpp
+ common/memorypool.cpp
+ common/str.cpp
+ common/stream.cpp
+ common/util.cpp
+ sound/adpcm.cpp
+ sound/audiostream.cpp
+ sound/voc.cpp
+ sound/wave.cpp
+)
+
+set(DETWINE_SRC
+ ${COMMON_SRC}
+ engines/twine/detwine.cpp
+ engines/twine/lba1.cpp
+ engines/twine/lba2.cpp
+ engines/twine/hqr.cpp
+)
+add_tool(detwine ${DETWINE_SRC})
diff --git a/Makefile b/Makefile
index 78c4fb66..047c4042 100644
--- a/Makefile
+++ b/Makefile
@@ -108,6 +108,7 @@ endif
$(STRIP) deprince$(EXEEXT) -o $(WIN32PATH)/tools/deprince$(EXEEXT)
$(STRIP) descumm$(EXEEXT) -o $(WIN32PATH)/tools/descumm$(EXEEXT)
$(STRIP) desword2$(EXEEXT) -o $(WIN32PATH)/tools/desword2$(EXEEXT)
+ $(STRIP) detwine$(EXEEXT) -o $(WIN32PATH)/tools/detwine$(EXEEXT)
$(STRIP) extract_mohawk$(EXEEXT) -o $(WIN32PATH)/tools/extract_mohawk$(EXEEXT)
$(STRIP) gob_loadcalc$(EXEEXT) -o $(WIN32PATH)/tools/gob_loadcalc$(EXEEXT)
$(STRIP) grim_animb2txt$(EXEEXT) -o $(WIN32PATH)/tools/grim_animb2txt$(EXEEXT)
@@ -168,6 +169,7 @@ endif
$(STRIP) deprince$(EXEEXT) -o $(srcdir)/$(WIN32BUILD)/deprince$(EXEEXT)
$(STRIP) descumm$(EXEEXT) -o $(srcdir)/$(WIN32BUILD)/descumm$(EXEEXT)
$(STRIP) desword2$(EXEEXT) -o $(srcdir)/$(WIN32BUILD)/desword2$(EXEEXT)
+ $(STRIP) detwine$(EXEEXT) -o $(srcdir)/$(WIN32BUILD)/detwine$(EXEEXT)
$(STRIP) extract_hadesch$(EXEEXT) -o $(srcdir)/$(WIN32BUILD)/extract_hadesch$(EXEEXT)
$(STRIP) extract_lokalizator$(EXEEXT) -o $(srcdir)/$(WIN32BUILD)/extract_lokalizator$(EXEEXT)
$(STRIP) extract_mohawk$(EXEEXT) -o $(srcdir)/$(WIN32BUILD)/extract_mohawk$(EXEEXT)
@@ -305,6 +307,7 @@ endif
$(STRIP) deprince$(EXEEXT) -o $(AMIGAOSPATH)/deprince$(EXEEXT)
$(STRIP) descumm$(EXEEXT) -o $(AMIGAOSPATH)/descumm$(EXEEXT)
$(STRIP) desword2$(EXEEXT) -o $(AMIGAOSPATH)/desword2$(EXEEXT)
+ $(STRIP) detwine$(EXEEXT) -o $(AMIGAOSPATH)/detwine$(EXEEXT)
$(STRIP) extract_mohawk$(EXEEXT) -o $(AMIGAOSPATH)/extract_mohawk$(EXEEXT)
$(STRIP) extract_ngi$(EXEEXT) -o $(AMIGAOSPATH)/extract_ngi$(EXEEXT)
$(STRIP) gob_loadcalc$(EXEEXT) -o $(AMIGAOSPATH)/gob_loadcalc$(EXEEXT)
diff --git a/Makefile.common b/Makefile.common
index 0cd11e01..af5e53d7 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -29,6 +29,7 @@ PROGRAMS = \
deprince \
descumm \
desword2 \
+ detwine \
gob_loadcalc \
extract_gob_cdi \
extract_mohawk \
@@ -129,23 +130,6 @@ GRIM_LUA := \
decine_OBJS := engines/cine/decine.o
-degob_OBJS := \
- engines/gob/degob.o \
- engines/gob/degob_script.o \
- engines/gob/degob_script_v1.o \
- engines/gob/degob_script_v2.o \
- engines/gob/degob_script_v3.o \
- engines/gob/degob_script_v4.o \
- engines/gob/degob_script_v5.o \
- engines/gob/degob_script_v6.o \
- engines/gob/degob_script_v7.o \
- engines/gob/degob_script_bargon.o \
- engines/gob/degob_script_fascin.o \
- engines/gob/degob_script_littlered.o \
- tool.o \
- version.o \
- $(UTILS)
-
dekyra_OBJS := \
engines/kyra/dekyra.o \
engines/kyra/dekyra_v1.o \
@@ -215,6 +199,15 @@ degob_OBJS := \
version.o \
$(UTILS)
+detwine_OBJS := \
+ engines/twine/detwine.o \
+ engines/twine/hqr.o \
+ engines/twine/lba1.o \
+ engines/twine/lba2.o \
+ tool.o \
+ version.o \
+ $(UTILS)
+
gob_loadcalc_OBJS := \
engines/gob/gob_loadcalc.o
@@ -457,6 +450,7 @@ version.o: $(filter-out version.o,$(scummvm-tools-cli_OBJS))
ifdef USE_WXWIDGETS
version.o: $(filter-out version.o,$(scummvm-tools_OBJS))
endif
+version.o: $(filter-out version.o,$(detwine_OBJS))
######################################################################
diff --git a/common/scummsys.h b/common/scummsys.h
index 53c50dec..dcf7c8c6 100644
--- a/common/scummsys.h
+++ b/common/scummsys.h
@@ -209,6 +209,9 @@
typedef unsigned long int uint32;
typedef signed long int int32;
+ typedef signed long long int64;
+ typedef unsigned long long uint64;
+
#elif defined(_WIN32_WCE)
#define scumm_stricmp stricmp
@@ -267,6 +270,19 @@
#endif
#endif
+#ifndef HAVE_CONFIG_H
+ typedef unsigned char byte;
+ typedef unsigned char uint8;
+ typedef signed char int8;
+ typedef unsigned short uint16;
+ typedef signed short int16;
+ typedef unsigned int uint32;
+ typedef signed int int32;
+ typedef unsigned int uint;
+ typedef signed long long int64;
+ typedef unsigned long long uint64;
+#endif
+
// You need to set this manually if necessary
// #define SCUMM_NEED_ALIGNMENT
@@ -325,6 +341,9 @@
typedef unsigned long int uint32;
typedef signed long int int32;
+ typedef signed long long int64;
+ typedef unsigned long long uint64;
+
#elif defined(__PLAYSTATION2__)
#define scumm_stricmp strcasecmp
@@ -464,6 +483,8 @@
typedef unsigned int uint32;
typedef signed int int32;
typedef unsigned int uint;
+ typedef signed long long int64;
+ typedef unsigned long long uint64;
#endif
diff --git a/engines/twine/detwine.cpp b/engines/twine/detwine.cpp
new file mode 100644
index 00000000..c000701e
--- /dev/null
+++ b/engines/twine/detwine.cpp
@@ -0,0 +1,83 @@
+/* ScummVM Tools
+ *
+ * ScummVM Tools 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* TwinE Script disassembler */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "common/util.h"
+#include "common/memstream.h"
+#include "engines/twine/hqr.h"
+#include "engines/twine/lba1.h"
+#include "engines/twine/lba2.h"
+
+static void printHelp(const char *bin) {
+ printf("Usage: %s <variant> <index> <scene.hqr>\n\n", bin);
+ printf("The disassembled script will be written to stdout.\n\n");
+ printf("Supported variants:\n");
+ printf(" lba1 - Little Big Adventure 1\n");
+ printf(" lba2 - Little Big Adventure 2\n");
+ printf("\n");
+}
+
+static int getVariant(const char *verStr) {
+ if (!scumm_stricmp(verStr, "lba1")) {
+ return 1;
+ } else if (!scumm_stricmp(verStr, "lba2")) {
+ return 2;
+ }
+ return -1;
+}
+
+int main(int argc, char **argv) {
+ if ((argc < 3) || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
+ printHelp(argv[0]);
+ return -1;
+ }
+
+ int variant = getVariant(argv[1]);
+ if (variant == -1) {
+ printHelp(argv[0]);
+ return -1;
+ }
+
+ int index = atoi(argv[2]);
+ const char *sceneHqr = "scene.hqr";
+ if (argc >= 4) {
+ sceneHqr = argv[3];
+ }
+ const Common::Filename fn(sceneHqr);
+ uint8 *data = nullptr;
+ int size = 0;
+ if (fn.exists()) {
+ size = TwinE::HQR::getAllocEntry(&data, fn, index);
+ }
+ if (data == nullptr || size == 0) {
+ fprintf(stderr, "Failed to load index %i from %s", index, fn.getFullName().c_str());
+ return 127;
+ }
+
+ if (variant == 1) {
+ return decompileLBA1(data, size);
+ }
+ return decompileLBA2(data, size);
+}
diff --git a/engines/twine/hqr.cpp b/engines/twine/hqr.cpp
new file mode 100644
index 00000000..13b7e411
--- /dev/null
+++ b/engines/twine/hqr.cpp
@@ -0,0 +1,280 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "engines/twine/hqr.h"
+#include "common/file.h"
+#include "common/util.h"
+#include "common/substream.h"
+#include "common/memstream.h"
+
+namespace TwinE {
+
+namespace HQR {
+
+/**
+ * Decompress entry based in Yaz0r and Zink decompression code
+ * @param dst destination pointer where will be the decompressed entry
+ * @param compBuf compressed data pointer
+ * @param compSize @p compBuf buffer size
+ * @param decompsize real file size after decompression
+ * @param mode compression mode used
+ */
+static void decompressEntry(uint8 *dst, const uint8 *compBuf, uint32 compSize, int32 decompsize, int32 mode) {
+ Common::MemoryReadStream stream(compBuf, compSize);
+ do {
+ uint8 b = stream.readByte();
+ for (int32 d = 0; d < 8; d++) {
+ int32 length;
+ if (!(b & (1 << d))) {
+ const uint16 offset = stream.readUint16LE();
+ length = (offset & 0x0F) + (mode + 1);
+ const uint8 *ptr = dst - (offset >> 4) - 1;
+ for (int32 i = 0; i < length; i++) {
+ *(dst++) = *(ptr++);
+ }
+ } else {
+ length = 1;
+ *(dst++) = stream.readByte();
+ }
+ decompsize -= length;
+ if (decompsize <= 0) {
+ return;
+ }
+ }
+ } while (decompsize);
+}
+
+/**
+ * Get a HQR entry pointer
+ * @param filename HQR file name
+ * @param index entry index to extract
+ * @return entry real size
+ */
+static int voxEntrySize(const Common::Filename &filename, int32 index, int32 hiddenIndex) {
+ Common::File file;
+ file.open(filename, "r");
+ if (!file.isOpen()) {
+ warning("HQR: Could not open %s", filename.getFullPath().c_str());
+ return 0;
+ }
+
+ uint32 headerSize = file.readUint32LE();
+ if ((uint32)index >= headerSize / 4) {
+ warning("HQR: Invalid entry index");
+ return 0;
+ }
+
+ file.seek(index * 4, SEEK_SET);
+ uint32 offsetToData = file.readUint32LE();
+
+ file.seek(offsetToData, SEEK_SET);
+ uint32 realSize = file.readUint32LE();
+ uint32 compSize = file.readUint32LE();
+
+ // exist hidden entries
+ for (int32 i = 0; i < hiddenIndex; i++) {
+ file.seek(offsetToData + compSize + 10, SEEK_SET); // hidden entry
+ offsetToData = offsetToData + compSize + 10; // current hidden offset
+
+ realSize = file.readUint32LE();
+ compSize = file.readUint32LE();
+ }
+
+ return realSize;
+}
+
+int32 getEntry(uint8 *ptr, const Common::Filename &filename, int32 index) {
+ if (!ptr) {
+ return 0;
+ }
+
+ Common::File file;
+ file.open(filename, "r");
+ if (!file.isOpen()) {
+ warning("HQR: Could not open %s", filename.getFullPath().c_str());
+ return 0;
+ }
+
+ uint32 headerSize = file.readUint32LE();
+
+ if ((uint32)index >= headerSize / 4) {
+ warning("HQR: Invalid entry index");
+ return 0;
+ }
+
+ file.seek(index * 4, SEEK_SET);
+ uint32 offsetToData = file.readUint32LE();
+
+ file.seek(offsetToData, SEEK_SET);
+ uint32 realSize = file.readUint32LE();
+ uint32 compSize = file.readUint32LE();
+ uint16 mode = file.readUint16LE();
+
+ // uncompressed
+ if (mode == 0) {
+ file.read_throwsOnError(ptr, realSize);
+ }
+ // compressed: modes (1 & 2)
+ else if (mode == 1 || mode == 2) {
+ uint8 *compDataPtr = (uint8 *)malloc(compSize);
+ file.read_throwsOnError(compDataPtr, compSize);
+ decompressEntry(ptr, compDataPtr, compSize, realSize, mode);
+ free(compDataPtr);
+ }
+
+ return realSize;
+}
+
+int32 entrySize(const Common::Filename &filename, int32 index) {
+ Common::File file;
+ file.open(filename, "r");
+ if (!file.isOpen()) {
+ warning("HQR: Could not open %s", filename.getFullPath().c_str());
+ return 0;
+ }
+
+ uint32 headerSize = file.readUint32LE();
+ if ((uint32)index >= headerSize / 4) {
+ warning("HQR: Invalid entry index");
+ return 0;
+ }
+
+ file.seek(index * 4, SEEK_SET);
+ uint32 offsetToData = file.readUint32LE();
+
+ file.seek(offsetToData, SEEK_SET);
+ uint32 realSize = file.readUint32LE();
+
+ return realSize;
+}
+
+int32 numEntries(const Common::Filename &filename) {
+ Common::File file;
+ file.open(filename, "r");
+ if (!file.isOpen()) {
+ warning("HQR: Could not open %s", filename.getFullPath().c_str());
+ return 0;
+ }
+
+ uint32 headerSize = file.readUint32LE();
+ return ((int)headerSize / 4) - 1;
+}
+
+Common::SeekableReadStream *makeReadStream(const Common::Filename &filename, int index) {
+ uint8 *data = nullptr;
+ const int32 size = getAllocEntry(&data, filename, index);
+ if (size == 0) {
+ return nullptr;
+ }
+ return new Common::MemoryReadStream(data, size, DisposeAfterUse::YES);
+}
+
+int32 getAllocEntry(uint8 **ptr, const Common::Filename &filename, int32 index) {
+ if (*ptr) {
+ free(*ptr);
+ }
+ const int32 size = entrySize(filename, index);
+ if (size <= 0) {
+ *ptr = nullptr;
+ warning("HQR: failed to get entry for index %i from file: %s", index, filename.getFullPath().c_str());
+ return 0;
+ }
+ *ptr = (uint8 *)malloc(size * sizeof(uint8));
+ if (!*ptr) {
+ warning("HQR: unable to allocate entry memory");
+ return 0;
+ }
+ const int32 entrySize = getEntry(*ptr, filename, index);
+ assert(entrySize == size);
+ return entrySize;
+}
+
+int32 getVoxEntry(uint8 *ptr, const Common::Filename &filename, int32 index, int32 hiddenIndex) {
+ if (!ptr) {
+ return 0;
+ }
+ Common::File file;
+ file.open(filename, "r");
+ if (!file.isOpen()) {
+ warning("HQR: Could not open %s", filename.getFullPath().c_str());
+ return 0;
+ }
+
+ uint32 headerSize = file.readUint32LE();
+
+ if ((uint32)index >= headerSize / 4) {
+ warning("HQR: Invalid entry index");
+ return 0;
+ }
+
+ file.seek(index * 4, SEEK_SET);
+ uint32 offsetToData = file.readUint32LE();
+
+ file.seek(offsetToData, SEEK_SET);
+ uint32 realSize = file.readUint32LE();
+ uint32 compSize = file.readUint32LE();
+ uint16 mode = file.readSint16LE();
+
+ // exist hidden entries
+ for (int32 i = 0; i < hiddenIndex; i++) {
+ file.seek(offsetToData + compSize + 10, SEEK_SET); // hidden entry
+ offsetToData = offsetToData + compSize + 10; // current hidden offset
+
+ realSize = file.readUint32LE();
+ compSize = file.readUint32LE();
+ mode = file.readUint16LE();
+ }
+
+ // uncompressed
+ if (mode == 0) {
+ file.read_throwsOnError(ptr, realSize);
+ }
+ // compressed: modes (1 & 2)
+ else if (mode == 1 || mode == 2) {
+ uint8 *compDataPtr = (uint8 *)malloc(compSize);
+ file.read_throwsOnError(compDataPtr, compSize);
+ decompressEntry(ptr, compDataPtr, compSize, realSize, mode);
+ free(compDataPtr);
+ }
+
+ return realSize;
+}
+
+int32 getAllocVoxEntry(uint8 **ptr, const Common::Filename &filename, int32 index, int32 hiddenIndex) {
+ const int32 size = voxEntrySize(filename, index, hiddenIndex);
+ if (size == 0) {
+ warning("HQR: vox entry with 0 size found for index: %d", index);
+ return 0;
+ }
+
+ *ptr = (uint8 *)malloc(size * sizeof(uint8));
+ if (!*ptr) {
+ warning("HQR: unable to allocate entry memory of size %d for index: %d", size, index);
+ return 0;
+ }
+ const int32 entrySize = getVoxEntry(*ptr, filename, index, hiddenIndex);
+ assert(entrySize == size);
+ return entrySize;
+}
+
+} // namespace HQR
+
+} // namespace TwinE
diff --git a/engines/twine/hqr.h b/engines/twine/hqr.h
new file mode 100644
index 00000000..8b103402
--- /dev/null
+++ b/engines/twine/hqr.h
@@ -0,0 +1,98 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef TWINE_HQR_H
+#define TWINE_HQR_H
+
+#include "common/stream.h"
+#include "common/file.h"
+
+namespace TwinE {
+
+class TwinEEngine;
+
+/**
+ * High Quality Resource
+ *
+ * https://web.archive.org/web/20181218233826/http://lbafileinfo.kazekr.net/index.php?title=High_quality_resource
+ */
+namespace HQR {
+
+
+/**
+ * Get a HQR entry pointer
+ * @param ptr pointer to save the entry
+ * @param filename HQR file name
+ * @param index entry index to extract
+ * @return entry real size
+ */
+int32 getEntry(uint8 *ptr, const Common::Filename &filename, int32 index);
+
+/**
+ * Get a HQR entry pointer
+ * @param filename HQR file name
+ * @param index entry index to extract
+ * @return entry real size
+ */
+int32 entrySize(const Common::Filename &filename, int32 index);
+
+/**
+ * Get a HQR total number of entries
+ * @param filename HQR file name
+ * @return total number of entries
+ */
+int32 numEntries(const Common::Filename &filename);
+
+/**
+ * Get a HQR entry pointer with memory allocation
+ * @param ptr pointer to save the entry. This pointer is automatically freed and therefore must be initialized
+ * to @c nullptr on the first run.
+ * @param filename HQR file name
+ * @param index entry index to extract
+ * @return entry real size
+ */
+int32 getAllocEntry(uint8 **ptr, const Common::Filename &filename, int32 index);
+
+/**
+ * Get a HQR entry pointer
+ * @param ptr pointer to save the entry
+ * @param filename HQR file name
+ * @param index entry index to extract
+ * @return entry real size
+ */
+int32 getVoxEntry(uint8 *ptr, const Common::Filename &filename, int32 index, int32 hiddenIndex);
+/**
+ * Get a HQR entry pointer with memory allocation
+ * @param ptr pointer to save the entry. This pointer is automatically freed and therefore must be initialized
+ * to @c nullptr on the first run.
+ * @param filename HQR file name
+ * @param index entry index to extract
+ * @return entry real size
+ */
+int32 getAllocVoxEntry(uint8 **ptr, const Common::Filename &filename, int32 index, int32 hiddenIndex);
+
+Common::SeekableReadStream *makeReadStream(const Common::Filename &filename, int index);
+
+} // namespace HQR
+
+} // namespace TwinE
+
+#endif
diff --git a/engines/twine/lba1.cpp b/engines/twine/lba1.cpp
new file mode 100644
index 00000000..d48d44fe
--- /dev/null
+++ b/engines/twine/lba1.cpp
@@ -0,0 +1,1241 @@
+/* ScummVM Tools
+ *
+ * ScummVM Tools 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "engines/twine/lba1.h"
+#include <stdio.h>
+#include <string.h>
+
+#include "common/array.h"
+#include "common/util.h"
+#include "common/memstream.h"
+
+struct ScriptContext {
+ Common::MemoryReadStream stream;
+ Common::Array<int> offsets;
+ int level;
+ int comportmentId;
+ bool comportement;
+};
+
+typedef void ScriptFunc(ScriptContext &ctx);
+
+struct ScriptFunction {
+ const char *name;
+ ScriptFunc *function;
+};
+
+#define MAPFUNC(name, func) \
+ { name, func }
+
+static const int initialLevel = 2;
+static const int indentWidth = 2;
+
+static void mEND(ScriptContext &ctx) {
+ printf("%*sEND\n", ctx.level, " ");
+}
+
+static void mNOP(ScriptContext &ctx) {
+ printf("%*sNOP\n", ctx.level, " ");
+}
+
+static void mBODY(ScriptContext &ctx) {
+ printf("%*sBODY %i\n", ctx.level, " ", (int)ctx.stream.readByte());
+}
+
+static void mANIM(ScriptContext &ctx) {
+ printf("%*sANIM %i\n", ctx.level, " ", (int)ctx.stream.readByte());
+}
+
+static void mGOTO_POINT(ScriptContext &ctx) {
+ printf("%*sGOTO_POINT %i\n", ctx.level, " ", (int)ctx.stream.readByte());
+}
+
+static void mWAIT_ANIM(ScriptContext &ctx) {
+ printf("%*sWAIT_ANIM\n", ctx.level, " ");
+}
+
+static void mLOOP(ScriptContext &ctx) {
+ printf("%*sLOOP\n", ctx.level, " ");
+}
+
+static void mANGLE(ScriptContext &ctx) {
+ printf("%*sANGLE %i\n", ctx.level, " ", (int)ctx.stream.readSint16LE());
+}
+
+static void mPOS_POINT(ScriptContext &ctx) {
+ printf("%*sPOS_POINT %i\n", ctx.level, " ", (int)ctx.stream.readByte());
+}
+
+static void mLABEL(ScriptContext &ctx) {
+ ctx.level = initialLevel;
+ printf("%*sLABEL %i\n", ctx.level, " ", (int)ctx.stream.readByte());
+ ctx.level += indentWidth;
+}
+
+static void mGOTO(ScriptContext &ctx) {
+ printf("%*sGOTO_SYM_POINT %i\n", ctx.level, " ", (int)ctx.stream.readSint16LE());
+}
+
+static void mSTOP(ScriptContext &ctx) {
+ printf("%*sSTOP\n", ctx.level, " ");
+}
+
+static void mGOTO_SYM_POINT(ScriptContext &ctx) {
+ printf("%*sGOTO_SYM_POINT %i\n", ctx.level, " ", (int)ctx.stream.readByte());
+}
+
+static void mWAIT_NUM_ANIM(ScriptContext &ctx) {
+ const int32 animRepeats = ctx.stream.readByte();
+ const int32 animPos = ctx.stream.readByte();
+ printf("%*sWAIT_NUM_ANIM %i %i\n", ctx.level, " ", animRepeats, animPos);
+}
+
+static void mSAMPLE(ScriptContext &ctx) {
+ printf("%*sSAMPLE %i\n", ctx.level, " ", (int)ctx.stream.readSint16LE());
+}
+
+static void mGOTO_POINT_3D(ScriptContext &ctx) {
+ printf("%*sGOTO_POINT_3D %i\n", ctx.level, " ", (int)ctx.stream.readByte());
+}
+
+static void mSPEED(ScriptContext &ctx) {
+ printf("%*sSPEED %i\n", ctx.level, " ", (int)ctx.stream.readSint16LE());
+}
+
+static void mBACKGROUND(ScriptContext &ctx) {
+ printf("%*sBACKGROUND %i\n", ctx.level, " ", (int)ctx.stream.readByte());
+}
+
+static void mWAIT_NUM_SECOND(ScriptContext &ctx) {
+ printf("%*sWAIT_NUM_SECOND %i %i\n", ctx.level, " ", (int)ctx.stream.readByte(), ctx.stream.readSint32LE());
+}
+
+static void mNO_BODY(ScriptContext &ctx) {
+ printf("%*sNO_BODY\n", ctx.level, " ");
+}
+
+static void mBETA(ScriptContext &ctx) {
+ printf("%*sBETA %i\n", ctx.level, " ", (int)ctx.stream.readSint16LE());
+}
+
+static void mOPEN_LEFT(ScriptContext &ctx) {
+ printf("%*sOPEN_LEFT %i\n", ctx.level, " ", (int)ctx.stream.readSint16LE());
+}
+
+static void mOPEN_RIGHT(ScriptContext &ctx) {
+ printf("%*sOPEN_RIGHT %i\n", ctx.level, " ", (int)ctx.stream.readSint16LE());
+}
+
+static void mOPEN_UP(ScriptContext &ctx) {
+ printf("%*sOPEN_UP %i\n", ctx.level, " ", (int)ctx.stream.readSint16LE());
+}
+
+static void mOPEN_DOWN(ScriptContext &ctx) {
+ printf("%*sOPEN_DOWN %i\n", ctx.level, " ", (int)ctx.stream.readSint16LE());
+}
+
+static void mCLOSE(ScriptContext &ctx) {
+ printf("%*sCLOSE\n", ctx.level, " ");
+}
+
+static void mWAIT_DOOR(ScriptContext &ctx) {
+ printf("%*sWAIT_DOOR\n", ctx.level, " ");
+}
+
+static void mSAMPLE_RND(ScriptContext &ctx) {
+ printf("%*sSAMPLE_RND %i\n", ctx.level, " ", (int)ctx.stream.readSint16LE());
+}
+
+static void mSAMPLE_ALWAYS(ScriptContext &ctx) {
+ printf("%*sSAMPLE_ALWAYS %i\n", ctx.level, " ", (int)ctx.stream.readSint16LE());
+}
+
+static void mSAMPLE_STOP(ScriptContext &ctx) {
+ printf("%*sSAMPLE_STOP %i\n", ctx.level, " ", (int)ctx.stream.readSint16LE());
+}
+
+static void mPLAY_FLA(ScriptContext &ctx) {
+ int strIdx = 0;
+ char movie[64];
+ do {
+ const byte c = ctx.stream.readByte();
+ movie[strIdx++] = c;
+ if (c == '\0') {
+ break;
+ }
+ if (strIdx >= ARRAYSIZE(movie)) {
+ error("Max string size exceeded for fla name");
+ }
+ } while (true);
+
+ printf("%*sPLAY_FLA %s\n", ctx.level, " ", movie);
+}
+
+static void mREPEAT_SAMPLE(ScriptContext &ctx) {
+ printf("%*sREPEAT_SAMPLE %i\n", ctx.level, " ", (int)ctx.stream.readSint16LE());
+}
+
+static void mSIMPLE_SAMPLE(ScriptContext &ctx) {
+ printf("%*sSIMPLE_SAMPLE %i\n", ctx.level, " ", (int)ctx.stream.readSint16LE());
+}
+
+static void mFACE_HERO(ScriptContext &ctx) {
+ printf("%*sFACE_HERO %i\n", ctx.level, " ", (int)ctx.stream.readSint16LE());
+}
+
+static void mANGLE_RND(ScriptContext &ctx) {
+ const int16 val1 = ctx.stream.readSint16LE();
+ const int16 val2 = ctx.stream.readSint16LE();
+ printf("%*sANGLE_RND %i %i\n", ctx.level, " ", (int)val1, (int)val2);
+}
+
+static const ScriptFunction moveScriptFunctions[] = {
+ /*0x00*/ MAPFUNC("END", mEND),
+ /*0x01*/ MAPFUNC("NOP", mNOP),
+ /*0x02*/ MAPFUNC("BODY", mBODY),
+ /*0x03*/ MAPFUNC("ANIM", mANIM),
+ /*0x04*/ MAPFUNC("GOTO_POINT", mGOTO_POINT),
+ /*0x05*/ MAPFUNC("WAIT_ANIM", mWAIT_ANIM),
+ /*0x06*/ MAPFUNC("LOOP", mLOOP),
+ /*0x07*/ MAPFUNC("ANGLE", mANGLE),
+ /*0x08*/ MAPFUNC("POS_POINT", mPOS_POINT),
+ /*0x09*/ MAPFUNC("LABEL", mLABEL),
+ /*0x0A*/ MAPFUNC("GOTO", mGOTO),
+ /*0x0B*/ MAPFUNC("STOP", mSTOP),
+ /*0x0C*/ MAPFUNC("GOTO_SYM_POINT", mGOTO_SYM_POINT),
+ /*0x0D*/ MAPFUNC("WAIT_NUM_ANIM", mWAIT_NUM_ANIM),
+ /*0x0E*/ MAPFUNC("SAMPLE", mSAMPLE),
+ /*0x0F*/ MAPFUNC("GOTO_POINT_3D", mGOTO_POINT_3D),
+ /*0x10*/ MAPFUNC("SPEED", mSPEED),
+ /*0x11*/ MAPFUNC("BACKGROUND", mBACKGROUND),
+ /*0x12*/ MAPFUNC("WAIT_NUM_SECOND", mWAIT_NUM_SECOND),
+ /*0x13*/ MAPFUNC("NO_BODY", mNO_BODY),
+ /*0x14*/ MAPFUNC("BETA", mBETA),
+ /*0x15*/ MAPFUNC("OPEN_LEFT", mOPEN_LEFT),
+ /*0x16*/ MAPFUNC("OPEN_RIGHT", mOPEN_RIGHT),
+ /*0x17*/ MAPFUNC("OPEN_UP", mOPEN_UP),
+ /*0x18*/ MAPFUNC("OPEN_DOWN", mOPEN_DOWN),
+ /*0x19*/ MAPFUNC("CLOSE", mCLOSE),
+ /*0x1A*/ MAPFUNC("WAIT_DOOR", mWAIT_DOOR),
+ /*0x1B*/ MAPFUNC("SAMPLE_RND", mSAMPLE_RND),
+ /*0x1C*/ MAPFUNC("SAMPLE_ALWAYS", mSAMPLE_ALWAYS),
+ /*0x1D*/ MAPFUNC("SAMPLE_STOP", mSAMPLE_STOP),
+ /*0x1E*/ MAPFUNC("PLAY_FLA", mPLAY_FLA),
+ /*0x1F*/ MAPFUNC("REPEAT_SAMPLE", mREPEAT_SAMPLE),
+ /*0x20*/ MAPFUNC("SIMPLE_SAMPLE", mSIMPLE_SAMPLE),
+ /*0x21*/ MAPFUNC("FACE_HERO", mFACE_HERO),
+ /*0x22*/ MAPFUNC("ANGLE_RND", mANGLE_RND)
+};
+
+
+/** Script condition operators */
+static const char *LifeScriptOperators[] = {
+ "==",
+ ">",
+ "<",
+ ">=",
+ "<=",
+ "!="
+};
+
+/** Script condition command opcodes */
+enum LifeScriptConditions {
+ /*0x00*/ kcCOL = 0, /*<! Current actor collision with another actor. (Parameter = Actor Index) */
+ /*0x01*/ kcCOL_OBJ = 1, /*<! Actor collision with the actor passed as parameter. (Parameter = Actor Index, Parameter = Actor Index) */
+ /*0x02*/ kcDISTANCE = 2, /*<! Distance between the current actor and the actor passed as parameter. (Parameter = Actor Index, Parameter = Distance between) */
+ /*0x03*/ kcZONE = 3, /*<! Current actor tread on zone passed as parameter. (Parameter = Zone Index) */
+ /*0x04*/ kcZONE_OBJ = 4, /*<! The actor passed as parameter will tread on zone passed as parameter. (Parameter = Actor Index, Parameter = Zone Index) */
+ /*0x05*/ kcBODY = 5, /*<! Body of the current actor. (Parameter = Body Index) */
+ /*0x06*/ kcBODY_OBJ = 6, /*<! Body of the actor passed as parameter. (Parameter = Body Index) */
+ /*0x07*/ kcANIM = 7, /*<! Body Animation of the current actor. (Parameter = Animation Index) */
+ /*0x08*/ kcANIM_OBJ = 8, /*<! Body Animation of the actor passed as parameter. (Parameter = Animation Index) */
+ /*0x09*/ kcL_TRACK = 9, /*<! Current actor track. (Parameter = Track Index) */
+ /*0x0A*/ kcL_TRACK_OBJ = 10, /*<! Track of the actor passed as parameter. (Parameter = Track Index) */
+ /*0x0B*/ kcFLAG_CUBE = 11, /*<! Game Cube Flags. (Parameter = Cube Flag Index, Parameter = 0 (not set), = 1 (set))k */
+ /*0x0C*/ kcCONE_VIEW = 12, /*<! The actor passed as parameter have a "vision in circle". (Parameter = Actor Index, Parameter = Distance) */
+ /*0x0D*/ kcHIT_BY = 13, /*<! Current actor hited by the actor passed as parameter. (Parameter = Actor Index) */
+ /*0x0E*/ kcACTION = 14, /*<! Hero action behavior. (Parameter = Behaviour Index) */
+ /*0x0F*/ kcFLAG_GAME = 15, /*<! Game Flags (See further list). (Parameter = Flag Index, Parameter = 0 (not set), = 1 (set)) */
+ /*0x10*/ kcLIFE_POINT = 16, /*<! Current actor life points. (Parameter = Life points) */
+ /*0x11*/ kcLIFE_POINT_OBJ = 17, /*<! Life points of the current actor passed as parameter. (Parameter = Life points) */
+ /*0x12*/ kcNUM_LITTLE_KEYS = 18, /*<! Number of keys. (Parameter = Number of keys) */
+ /*0x13*/ kcNUM_GOLD_PIECES = 19, /*<! Coins/Gold Amount. (Parameter = Coins/Gold amount) */
+ /*0x14*/ kcBEHAVIOUR = 20, /*<! Hero behaviour. (Parameter = Behaviour Index) */
+ /*0x15*/ kcCHAPTER = 21, /*<! Story Chapters. (Parameter = Chapter Index) */
+ /*0x16*/ kcDISTANCE_3D = 22, /*<! Distance between the actor passed as parameter and the current actor. (Parameter = Actor Index, Parameter = Distance) */
+ /*0x17*/ kcMAGIC_LEVEL = 23,
+ /*0x18*/ kcMAGIC_POINTS = 24,
+ /*0x19*/ kcUSE_INVENTORY = 25, /*<! Use inventory object. (Parameter = Object Index in the inventory, Paramenter = 0 (Not in Inventory), = 1 (In the Inventory)) */
+ /*0x1A*/ kcCHOICE = 26, /*<! Menu choice. (Parameter = Text Index in the current Text Bank) */
+ /*0x1B*/ kcFUEL = 27, /*<! Amount of fuel gas the Hero have in his inventory. (Parameter = Gas amount) */
+ /*0x1C*/ kcCARRIED_BY = 28, /*<! The current is carried by the actor passed as paramenter. (Parameter = Actor Index) */
+ /*0x1D*/ kcCDROM = 29 /*<! CDROM audio tracks. (Parameter = Audio Tracks Index) */
+};
+
+static int32 processLifeConditions(ScriptContext &ctx) {
+ int32 conditionValueSize = 1;
+ int32 conditionOpcode = ctx.stream.readByte();
+ switch (conditionOpcode) {
+ case kcCOL:
+ printf("collision");
+ break;
+ case kcCOL_OBJ: {
+ int32 actorIdx = ctx.stream.readByte();
+ printf("col_obj %i", actorIdx);
+ break;
+ }
+ case kcDISTANCE: {
+ int32 actorIdx = ctx.stream.readByte();
+ printf("distance %i", actorIdx);
+ conditionValueSize = 2;
+ break;
+ }
+ case kcZONE:
+ printf("zone");
+ break;
+ case kcZONE_OBJ: {
+ int32 actorIdx = ctx.stream.readByte();
+ printf("zone_obj %i", actorIdx);
+ break;
+ }
+ case kcBODY:
+ printf("body");
+ break;
+ case kcBODY_OBJ: {
+ int32 actorIdx = ctx.stream.readByte();
+ printf("body_obj %i", actorIdx);
+ break;
+ }
+ case kcANIM:
+ printf("anim");
+ break;
+ case kcANIM_OBJ: {
+ int32 actorIdx = ctx.stream.readByte();
+ printf("anim_obj %i", actorIdx);
+ break;
+ }
+ case kcL_TRACK:
+ printf("track");
+ break;
+ case kcL_TRACK_OBJ: {
+ int32 actorIdx = ctx.stream.readByte();
+ printf("track_obj %i", actorIdx);
+ break;
+ }
+ case kcFLAG_CUBE: {
+ int32 flagIdx = ctx.stream.readByte();
+ printf("flag_cube %i", flagIdx);
+ break;
+ }
+ case kcCONE_VIEW: {
+ int32 targetActorIdx = ctx.stream.readByte();
+ printf("cone_view %i", targetActorIdx);
+ break;
+ }
+ case kcHIT_BY:
+ printf("hit_by");
+ break;
+ case kcACTION:
+ printf("action");
+ break;
+ case kcFLAG_GAME: {
+ int32 flagIdx = ctx.stream.readByte();
+ printf("flag_game %i", flagIdx);
+ break;
+ }
+ case kcLIFE_POINT:
+ printf("life_point");
+ break;
+ case kcLIFE_POINT_OBJ: {
+ int32 actorIdx = ctx.stream.readByte();
+ printf("life_point_obj %i", actorIdx);
+ break;
+ }
+ case kcNUM_LITTLE_KEYS:
+ printf("num_little_keys");
+ break;
+ case kcNUM_GOLD_PIECES:
+ printf("num_gold_pieces");
+ conditionValueSize = 2;
+ break;
+ case kcBEHAVIOUR:
+ printf("behaviour");
+ break;
+ case kcCHAPTER:
+ printf("chapter");
+ break;
+ case kcDISTANCE_3D: {
+ int32 targetActorIdx = ctx.stream.readByte();
+ printf("distance_3d %i ", targetActorIdx);
+ conditionValueSize = 2;
+ break;
+ }
+ case kcMAGIC_LEVEL:
+ printf("magic_level");
+ break;
+ case kcMAGIC_POINTS:
+ printf("magic_points");
+ break;
+ case kcUSE_INVENTORY: {
+ int32 item = ctx.stream.readByte();
+ printf("use_inventory %i", item);
+ break;
+ }
+ case kcCHOICE:
+ printf("choice");
+ conditionValueSize = 2;
+ break;
+ case kcFUEL:
+ printf("fuel");
+ break;
+ case kcCARRIED_BY:
+ printf("carried_by");
+ break;
+ case kcCDROM:
+ printf("cdrom");
+ break;
+ default:
+ error("Actor condition opcode %d", conditionOpcode);
+ break;
+ }
+
+ return conditionValueSize;
+}
+
+static void processLifeOperators(ScriptContext &ctx, int32 valueSize) {
+ const uint8 operatorCode = ctx.stream.readByte();
+ if (operatorCode >= ARRAYSIZE(LifeScriptOperators)) {
+ error("Invalid operator %i", (int)operatorCode);
+ }
+ printf(" %s ", LifeScriptOperators[operatorCode]);
+ int32 conditionValue;
+ if (valueSize == 1) {
+ conditionValue = ctx.stream.readByte();
+ } else if (valueSize == 2) {
+ conditionValue = ctx.stream.readSint16LE();
+ } else {
+ error("Unknown operator value size %d", valueSize);
+ }
+ printf("%i", conditionValue);
+}
+
+static void lEMPTY(ScriptContext &ctx) {
+ printf("%*sEMPTY\n", ctx.level, " ");
+}
+
+static void lEND(ScriptContext &ctx) {
+ printf("%*sEND\n", ctx.level, " ");
+ ctx.level -= indentWidth;
+}
+
+static void lNOP(ScriptContext &ctx) {
+ printf("%*sNOP\n", ctx.level, " ");
+}
+
+static void lOFFSET(ScriptContext &ctx) {
+ const int16 offset = ctx.stream.readSint16LE();
+ printf("%*sOFFSET %i\n", ctx.level, " ", (int)offset);
+}
+
+static void lSNIF(ScriptContext &ctx) {
+ printf("%*sSWITCH_NO_IF ", ctx.level, " ");
+ const int32 valueSize = processLifeConditions(ctx);
+ processLifeOperators(ctx, valueSize);
+ const int16 offset = ctx.stream.readSint16LE();
+ ctx.offsets.push_back(offset);
+ printf(" (offset %i)\n", offset);
+ ctx.level += indentWidth;
+}
+
+static void lNEVERIF(ScriptContext &ctx) {
+ printf("%*sNEVER_IF ", ctx.level, " ");
+ const int32 valueSize = processLifeConditions(ctx);
+ processLifeOperators(ctx, valueSize);
+ const int16 offset = ctx.stream.readSint16LE();
+ ctx.offsets.push_back(offset);
+ printf(" (offset %i)\n", offset);
+ ctx.level += indentWidth;
+}
+
+static void lOR_IF(ScriptContext &ctx) {
+ printf("%*sOR_IF ", ctx.level, " ");
+ const int32 valueSize = processLifeConditions(ctx);
+ processLifeOperators(ctx, valueSize);
+ const int16 offset = ctx.stream.readSint16LE();
+ printf(" (offset %i)\n", offset);
+}
+
+static void lNO_IF(ScriptContext &ctx) {
+ printf("%*sNO_IF\n", ctx.level, " ");
+ ctx.level += indentWidth;
+}
+
+static void lIF(ScriptContext &ctx) {
+ printf("%*sIF ", ctx.level, " ");
+ const int32 valueSize = processLifeConditions(ctx);
+ processLifeOperators(ctx, valueSize);
+ const int16 offset = ctx.stream.readSint16LE();
+ ctx.offsets.push_back(offset);
+ printf(" (offset %i)\n", offset);
+ ctx.level += indentWidth;
+}
+
+static void lSWIF(ScriptContext &ctx) {
+ printf("%*sSWITCH_IF ", ctx.level, " ");
+ const int32 valueSize = processLifeConditions(ctx);
+ processLifeOperators(ctx, valueSize);
+ const int16 offset = ctx.stream.readSint16LE();
+ ctx.offsets.push_back(offset);
+ printf(" (offset %i)\n", offset);
+ ctx.level += indentWidth;
+}
+
+static void lONEIF(ScriptContext &ctx) {
+ printf("%*sONEIF ", ctx.level, " ");
+ const int32 valueSize = processLifeConditions(ctx);
+ processLifeOperators(ctx, valueSize);
+ const int16 offset = ctx.stream.readSint16LE();
+ ctx.offsets.push_back(offset);
+ printf(" (offset %i)\n", offset);
+ ctx.level += indentWidth;
+}
+
+static void lELSE(ScriptContext &ctx) {
+ const int16 offset = ctx.stream.readSint16LE();
+ ctx.offsets.push_back(ctx.stream.pos());
+ ctx.level -= indentWidth;
+ printf("%*sELSE (offset %i)\n", ctx.level, " ", offset);
+ ctx.level += indentWidth;
+}
+
+static void lLABEL(ScriptContext &ctx) {
+ printf("%*sLABEL %i\n", ctx.level, " ", (int)ctx.stream.readByte());
+}
+
+static void lRETURN(ScriptContext &ctx) {
+ printf("%*sRETURN\n", ctx.level, " ");
+ ctx.level -= indentWidth;
+}
+
+static void lBODY(ScriptContext &ctx) {
+ const int32 bodyIdx = ctx.stream.readByte();
+ printf("%*sBODY %i\n", ctx.level, " ", (int)bodyIdx);
+}
+
+static void lBODY_OBJ(ScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const int32 otherBodyIdx = ctx.stream.readByte();
+ printf("%*sBODY_OBJ %i %i\n", ctx.level, " ", (int)otherActorIdx, (int)otherBodyIdx);
+}
+
+static void lANIM(ScriptContext &ctx) {
+ const int32 animIdx = ctx.stream.readByte();
+ printf("%*sANIM %i\n", ctx.level, " ", (int)animIdx);
+}
+
+static void lANIM_OBJ(ScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const int32 otherAnimIdx = ctx.stream.readByte();
+ printf("%*sANIM_OBJ %i %i\n", ctx.level, " ", (int)otherActorIdx, (int)otherAnimIdx);
+}
+
+static void lSET_LIFE(ScriptContext &ctx) {
+ const int16 offset = ctx.stream.readSint16LE();
+ printf("%*sSET_LIFE %i\n", ctx.level, " ", (int)offset);
+}
+
+static void lSET_LIFE_OBJ(ScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const int16 offset = ctx.stream.readSint16LE();
+ printf("%*sSET_LIFE_OBJ %i %i\n", ctx.level, " ", (int)otherActorIdx, (int)offset);
+}
+
+static void lSET_TRACK(ScriptContext &ctx) {
+ const int16 offset = ctx.stream.readSint16LE();
+ printf("%*sSET_TRACK %i\n", ctx.level, " ", (int)offset);
+}
+
+static void lSET_TRACK_OBJ(ScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const int16 offset = ctx.stream.readSint16LE();
+ printf("%*sSET_TRACK_OBJ %i %i\n", ctx.level, " ", (int)otherActorIdx, (int)offset);
+}
+
+static void lMESSAGE(ScriptContext &ctx) {
+ printf("%*sMESSAGE %i\n", ctx.level, " ", (int)ctx.stream.readSint16LE());
+}
+
+static void lFALLABLE(ScriptContext &ctx) {
+ printf("%*sFALLABLE %i\n", ctx.level, " ", (int)ctx.stream.readByte());
+}
+
+static void lSET_DIRMODE(ScriptContext &ctx) {
+ const int32 controlMode = ctx.stream.readByte();
+ if (controlMode == 2) { // kFollow
+ printf("%*sSET_DIRMODE %i %i\n", ctx.level, " ", (int)controlMode, (int)ctx.stream.readByte());
+ } else {
+ printf("%*sSET_DIRMODE %i\n", ctx.level, " ", (int)controlMode);
+ }
+}
+
+static void lSET_DIRMODE_OBJ(ScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const int32 controlMode = ctx.stream.readByte();
+
+ if (controlMode == 2) {
+ int32 followedActor = ctx.stream.readByte();
+ printf("%*sSET_DIRMODE_OBJ %i %i %i\n", ctx.level, " ", (int)otherActorIdx, (int)controlMode, (int)followedActor);
+ } else {
+ printf("%*sSET_DIRMODE_OBJ %i %i\n", ctx.level, " ", (int)otherActorIdx, (int)controlMode);
+ }
+}
+
+static void lCAM_FOLLOW(ScriptContext &ctx) {
+ printf("%*sCAM_FOLLOW %i\n", ctx.level, " ", (int)ctx.stream.readByte());
+}
+
+static void lSET_BEHAVIOUR(ScriptContext &ctx) {
+ const int32 behavior = ctx.stream.readByte();
+ printf("%*sSET_BEHAVIOUR %i\n", ctx.level, " ", (int)behavior);
+}
+
+static void lSET_FLAG_CUBE(ScriptContext &ctx) {
+ const int32 flagIdx = ctx.stream.readByte();
+ const int32 flagValue = ctx.stream.readByte();
+ printf("%*sSET_FLAG_CUBE %i %i\n", ctx.level, " ", (int)flagIdx, (int)flagValue);
+}
+
+static void lCOMPORTEMENT(ScriptContext &ctx) {
+ printf("%*sCOMPORTEMENT %i\n", ctx.level, " ", (int)ctx.stream.readByte());
+}
+
+static void lSET_COMPORTEMENT(ScriptContext &ctx) {
+ printf("%*sSET_COMPORTEMENT %i\n", ctx.level, " ", (int)ctx.stream.readSint16LE());
+}
+
+static void lSET_COMPORTEMENT_OBJ(ScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const int16 pos = ctx.stream.readSint16LE();
+ printf("%*sSET_COMPORTEMENT_OBJ %i %i\n", ctx.level, " ", (int)otherActorIdx, (int)pos);
+}
+
+static void lEND_COMPORTEMENT(ScriptContext &ctx) {
+ ctx.level -= indentWidth;
+ printf("%*sEND_COMPORTEMENT\n", ctx.level, " ");
+ ctx.comportement = false;
+}
+
+static void lSET_FLAG_GAME(ScriptContext &ctx) {
+ const uint8 flagIdx = ctx.stream.readByte();
+ const uint8 flagValue = ctx.stream.readByte();
+ printf("%*sSET_FLAG_GAME %i %i\n", ctx.level, " ", (int)flagIdx, (int)flagValue);
+}
+
+static void lKILL_OBJ(ScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ printf("%*slKILL_OBJ %i\n", ctx.level, " ", (int)otherActorIdx);
+}
+
+static void lSUICIDE(ScriptContext &ctx) {
+ printf("%*sSUICIDE\n", ctx.level, " ");
+}
+
+static void lUSE_ONE_LITTLE_KEY(ScriptContext &ctx) {
+ printf("%*sUSE_ONE_LITTLE_KEY\n", ctx.level, " ");
+}
+
+static void lGIVE_GOLD_PIECES(ScriptContext &ctx) {
+ const int16 kashes = ctx.stream.readSint16LE();
+ printf("%*sGIVE_GOLD_PIECES %i\n", ctx.level, " ", (int)kashes);
+}
+
+static void lEND_LIFE(ScriptContext &ctx) {
+ printf("%*sEND_LIFE\n", ctx.level, " ");
+}
+
+static void lSTOP_L_TRACK(ScriptContext &ctx) {
+ printf("%*sSTOP_L_TRACK\n", ctx.level, " ");
+}
+
+static void lRESTORE_L_TRACK(ScriptContext &ctx) {
+ printf("%*sRESTORE_L_TRACK\n", ctx.level, " ");
+}
+
+static void lMESSAGE_OBJ(ScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const int32 int32x = ctx.stream.readSint16LE();
+ printf("%*sMESSAGE_OBJ %i %i\n", ctx.level, " ", (int)otherActorIdx, (int)int32x);
+}
+
+static void lINC_CHAPTER(ScriptContext &ctx) {
+ printf("%*sINC_CHAPTER\n", ctx.level, " ");
+}
+
+static void lFOUND_OBJECT(ScriptContext &ctx) {
+ printf("%*sFOUND_OBJECT %i\n", ctx.level, " ", (int)ctx.stream.readByte());
+}
+
+static void lSET_DOOR_LEFT(ScriptContext &ctx) {
+ const int32 distance = ctx.stream.readSint16LE();
+ printf("%*sSET_DOOR_LEFT %i\n", ctx.level, " ", (int)distance);
+}
+
+static void lSET_DOOR_RIGHT(ScriptContext &ctx) {
+ const int32 distance = ctx.stream.readSint16LE();
+ printf("%*sSET_DOOR_RIGHT %i\n", ctx.level, " ", (int)distance);
+}
+
+static void lSET_DOOR_UP(ScriptContext &ctx) {
+ const int32 distance = ctx.stream.readSint16LE();
+ printf("%*sSET_DOOR_UP %i\n", ctx.level, " ", (int)distance);
+}
+
+static void lSET_DOOR_DOWN(ScriptContext &ctx) {
+ const int32 distance = ctx.stream.readSint16LE();
+ printf("%*sSET_DOOR_DOWN %i\n", ctx.level, " ", (int)distance);
+}
+
+static void lGIVE_BONUS(ScriptContext &ctx) {
+ const int32 flag = ctx.stream.readByte();
+ printf("%*sGIVE_BONUS %i\n", ctx.level, " ", (int)flag);
+}
+
+static void lCHANGE_CUBE(ScriptContext &ctx) {
+ const int32 sceneIdx = ctx.stream.readByte();
+ printf("%*sCHANGE_CUBE %i\n", ctx.level, " ", (int)sceneIdx);
+}
+
+static void lOBJ_COL(ScriptContext &ctx) {
+ const int32 collision = ctx.stream.readByte();
+ printf("%*sOBJ_COL %i\n", ctx.level, " ", (int)collision);
+}
+
+static void lBRICK_COL(ScriptContext &ctx) {
+ const int32 collision = ctx.stream.readByte();
+ printf("%*sBRICK_COL %i\n", ctx.level, " ", (int)collision);
+}
+
+static void lINVISIBLE(ScriptContext &ctx) {
+ printf("%*sINVISIBLE %i\n", ctx.level, " ", (int)ctx.stream.readByte());
+}
+
+static void lZOOM(ScriptContext &ctx) {
+ const int zoomScreen = ctx.stream.readByte();
+ printf("%*sZOOM %i\n", ctx.level, " ", zoomScreen);
+}
+
+static void lPOS_POINT(ScriptContext &ctx) {
+ const int32 trackIdx = ctx.stream.readByte();
+ printf("%*sPOS_POINT %i\n", ctx.level, " ", (int)trackIdx);
+}
+
+static void lSET_MAGIC_LEVEL(ScriptContext &ctx) {
+ printf("%*sSET_MAGIC_LEVEL %i\n", ctx.level, " ", (int)ctx.stream.readByte());
+}
+
+static void lSUB_MAGIC_POINT(ScriptContext &ctx) {
+ const int16 magicPoints = (int16)ctx.stream.readByte();
+ printf("%*sSET_MAGIC_POINT %i\n", ctx.level, " ", (int)magicPoints);
+}
+
+static void lSET_LIFE_POINT_OBJ(ScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const int32 lifeValue = ctx.stream.readByte();
+ printf("%*sSET_LIFE_POINT_OBJ %i %i\n", ctx.level, " ", (int)otherActorIdx, (int)lifeValue);
+}
+
+static void lSUB_LIFE_POINT_OBJ(ScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const int32 lifeValue = ctx.stream.readByte();
+ printf("%*sSUB_LIFE_POINT_OBJ %i %i\n", ctx.level, " ", (int)otherActorIdx, (int)lifeValue);
+}
+
+static void lHIT_OBJ(ScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const int32 strengthOfHit = ctx.stream.readByte();
+ printf("%*sHIT_OBJ %i %i\n", ctx.level, " ", (int)otherActorIdx, (int)strengthOfHit);
+}
+
+static void lPLAY_FLA(ScriptContext &ctx) {
+ int strIdx = 0;
+ char movie[64];
+ do {
+ const byte c = ctx.stream.readByte();
+ movie[strIdx++] = c;
+ if (c == '\0') {
+ break;
+ }
+ if (strIdx >= ARRAYSIZE(movie)) {
+ error("Max string size exceeded for fla name");
+ }
+ } while (true);
+ printf("%*sPLAY_FLA %s\n", ctx.level, " ", movie);
+}
+
+static void lPLAY_MIDI(ScriptContext &ctx) {
+ const int32 midiIdx = ctx.stream.readByte();
+ printf("%*sPLAY_MIDI %i\n", ctx.level, " ", (int)midiIdx);
+}
+
+static void lINC_CLOVER_BOX(ScriptContext &ctx) {
+ printf("%*sINC_CLOVER_BOX\n", ctx.level, " ");
+}
+
+static void lSET_USED_INVENTORY(ScriptContext &ctx) {
+ const int32 item = ctx.stream.readByte();
+ printf("%*sSET_USED_INVENTORY %i\n", ctx.level, " ", (int)item);
+}
+
+static void lADD_CHOICE(ScriptContext &ctx) {
+ const int32 choiceIdx = ctx.stream.readSint16LE();
+ printf("%*sADD_CHOICE %i\n", ctx.level, " ", (int)choiceIdx);
+}
+
+static void lASK_CHOICE(ScriptContext &ctx) {
+ const int32 choiceIdx = ctx.stream.readSint16LE();
+ printf("%*sASK_CHOICE %i\n", ctx.level, " ", (int)choiceIdx);
+}
+
+static void lBIG_MESSAGE(ScriptContext &ctx) {
+ const int32 int32x = ctx.stream.readSint16LE();
+ printf("%*sBIG_MESSAGE %i\n", ctx.level, " ", (int)int32x);
+}
+
+static void lINIT_PINGOUIN(ScriptContext &ctx) {
+ const int16 penguinActor = ctx.stream.readByte();
+ printf("%*sINIT_PINGOUIN %i\n", ctx.level, " ", (int)penguinActor);
+}
+
+static void lSET_HOLO_POS(ScriptContext &ctx) {
+ const int32 location = ctx.stream.readByte();
+ printf("%*sSET_HOLO_POS %i\n", ctx.level, " ", (int)location);
+}
+
+static void lCLR_HOLO_POS(ScriptContext &ctx) {
+ const int32 location = ctx.stream.readByte();
+ printf("%*sCLR_HOLO_POS %i\n", ctx.level, " ", (int)location);
+}
+
+static void lADD_FUEL(ScriptContext &ctx) {
+ const int16 value = ctx.stream.readByte();
+ printf("%*sADD_FUEL %i\n", ctx.level, " ", (int)value);
+}
+
+static void lSUB_FUEL(ScriptContext &ctx) {
+ const int16 value = ctx.stream.readByte();
+ printf("%*sSUB_FUEL %i\n", ctx.level, " ", (int)value);
+}
+
+static void lSET_GRM(ScriptContext &ctx) {
+ printf("%*sSET_GRM %i\n", ctx.level, " ", (int)ctx.stream.readByte());
+}
+
+static void lSAY_MESSAGE(ScriptContext &ctx) {
+ const int32 textEntry = ctx.stream.readSint16LE();
+ printf("%*sSAY_MESSAGE %i\n", ctx.level, " ", (int)textEntry);
+}
+
+static void lSAY_MESSAGE_OBJ(ScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const int32 textEntry = ctx.stream.readSint16LE();
+ printf("%*sSAY_MESSAGE_OBJ %i %i\n", ctx.level, " ", (int)otherActorIdx, (int)textEntry);
+}
+
+static void lFULL_POINT(ScriptContext &ctx) {
+ printf("%*sFULL_POINT\n", ctx.level, " ");
+}
+
+static void lBETA(ScriptContext &ctx) {
+ const int32 newAngle = ctx.stream.readSint16LE();
+ printf("%*sBETA %i\n", ctx.level, " ", (int)newAngle);
+}
+
+static void lGRM_OFF(ScriptContext &ctx) {
+ printf("%*sGRM_OFF\n", ctx.level, " ");
+}
+
+static void lFADE_PAL_RED(ScriptContext &ctx) {
+ printf("%*sFADE_PAL_RED\n", ctx.level, " ");
+}
+
+static void lFADE_ALARM_RED(ScriptContext &ctx) {
+ printf("%*sFADE_ALARM_RED\n", ctx.level, " ");
+}
+
+static void lFADE_ALARM_PAL(ScriptContext &ctx) {
+ printf("%*sFADE_ALARM_PAL\n", ctx.level, " ");
+}
+
+static void lFADE_RED_PAL(ScriptContext &ctx) {
+ printf("%*sFADE_RED_PAL\n", ctx.level, " ");
+}
+
+static void lFADE_RED_ALARM(ScriptContext &ctx) {
+ printf("%*sFADE_RED_ALARM\n", ctx.level, " ");
+}
+
+static void lFADE_PAL_ALARM(ScriptContext &ctx) {
+ printf("%*sFADE_PAL_ALARM\n", ctx.level, " ");
+}
+
+static void lEXPLODE_OBJ(ScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ printf("%*sEXPLODE_OBJ %i\n", ctx.level, " ", (int)otherActorIdx);
+}
+
+static void lBUBBLE_ON(ScriptContext &ctx) {
+ printf("%*sBUBBLE_ON\n", ctx.level, " ");
+}
+
+static void lBUBBLE_OFF(ScriptContext &ctx) {
+ printf("%*sBUBBLE_OFF\n", ctx.level, " ");
+}
+
+static void lASK_CHOICE_OBJ(ScriptContext &ctx) {
+ const int32 otherActorIdx = ctx.stream.readByte();
+ const int32 choiceIdx = ctx.stream.readSint16LE();
+ printf("%*sASK_CHOICE_OBJ %i %i\n", ctx.level, " ", (int)otherActorIdx, (int)choiceIdx);
+}
+
+static void lSET_DARK_PAL(ScriptContext &ctx) {
+ printf("%*sSET_DARK_PAL\n", ctx.level, " ");
+}
+
+static void lSET_NORMAL_PAL(ScriptContext &ctx) {
+ printf("%*sSET_NORMAL_PAL\n", ctx.level, " ");
+}
+
+static void lMESSAGE_SENDELL(ScriptContext &ctx) {
+ printf("%*sMESSAGE_SENDELL\n", ctx.level, " ");
+}
+
+static void lANIM_SET(ScriptContext &ctx) {
+ printf("%*sANIM_SET %i\n", ctx.level, " ", (int)ctx.stream.readByte());
+}
+
+static void lHOLOMAP_TRAJ(ScriptContext &ctx) {
+ printf("%*sHOLOMAP_TRAJ %i\n", ctx.level, " ", (int)ctx.stream.readByte());
+}
+
+static void lGAME_OVER(ScriptContext &ctx) {
+ printf("%*sGAME_OVER\n", ctx.level, " ");
+}
+
+static void lTHE_END(ScriptContext &ctx) {
+ printf("%*sTHE_END\n", ctx.level, " ");
+}
+
+static void lMIDI_OFF(ScriptContext &ctx) {
+ printf("%*sMIDI_OFF\n", ctx.level, " ");
+}
+
+static void lPLAY_CD_TRACK(ScriptContext &ctx) {
+ printf("%*sPLAY_CD_TRACK %i\n", ctx.level, " ", (int)ctx.stream.readByte());
+}
+
+static void lPROJ_ISO(ScriptContext &ctx) {
+ printf("%*sPROJ_ISO\n", ctx.level, " ");
+}
+
+static void lPROJ_3D(ScriptContext &ctx) {
+ printf("%*sPROJ_3D\n", ctx.level, " ");
+}
+
+static void lTEXT(ScriptContext &ctx) {
+ printf("%*sTEXT %i\n", ctx.level, " ", (int)ctx.stream.readSint16LE());
+}
+
+static void lCLEAR_TEXT(ScriptContext &ctx) {
+ printf("%*sCLEAR_TEXT\n", ctx.level, " ");
+}
+
+static void lBRUTAL_EXIT(ScriptContext &ctx) {
+ printf("%*sBRUTAL_EXIT\n", ctx.level, " ");
+}
+
+static const ScriptFunction lifeScriptFunctions[] = {
+ /*0x00*/ MAPFUNC("END", lEND),
+ /*0x01*/ MAPFUNC("NOP", lNOP),
+ /*0x02*/ MAPFUNC("SNIF", lSNIF),
+ /*0x03*/ MAPFUNC("OFFSET", lOFFSET),
+ /*0x04*/ MAPFUNC("NEVERIF", lNEVERIF),
+ /*0x05*/ MAPFUNC("", lEMPTY), // unused
+ /*0x06*/ MAPFUNC("NO_IF", lNO_IF),
+ /*0x07*/ MAPFUNC("", lEMPTY), // unused
+ /*0x08*/ MAPFUNC("", lEMPTY), // unused
+ /*0x09*/ MAPFUNC("", lEMPTY), // unused
+ /*0x0A*/ MAPFUNC("LABEL", lLABEL),
+ /*0x0B*/ MAPFUNC("RETURN", lRETURN),
+ /*0x0C*/ MAPFUNC("IF", lIF),
+ /*0x0D*/ MAPFUNC("SWIF", lSWIF),
+ /*0x0E*/ MAPFUNC("ONEIF", lONEIF),
+ /*0x0F*/ MAPFUNC("ELSE", lELSE),
+ /*0x10*/ MAPFUNC("ENDIF", lEMPTY),
+ /*0x11*/ MAPFUNC("BODY", lBODY),
+ /*0x12*/ MAPFUNC("BODY_OBJ", lBODY_OBJ),
+ /*0x13*/ MAPFUNC("ANIM", lANIM),
+ /*0x14*/ MAPFUNC("ANIM_OBJ", lANIM_OBJ),
+ /*0x15*/ MAPFUNC("SET_LIFE", lSET_LIFE),
+ /*0x16*/ MAPFUNC("SET_LIFE_OBJ", lSET_LIFE_OBJ),
+ /*0x17*/ MAPFUNC("SET_TRACK", lSET_TRACK),
+ /*0x18*/ MAPFUNC("SET_TRACK_OBJ", lSET_TRACK_OBJ),
+ /*0x19*/ MAPFUNC("MESSAGE", lMESSAGE),
+ /*0x1A*/ MAPFUNC("FALLABLE", lFALLABLE),
+ /*0x1B*/ MAPFUNC("SET_DIRMODE", lSET_DIRMODE),
+ /*0x1C*/ MAPFUNC("SET_DIRMODE_OBJ", lSET_DIRMODE_OBJ),
+ /*0x1D*/ MAPFUNC("CAM_FOLLOW", lCAM_FOLLOW),
+ /*0x1E*/ MAPFUNC("SET_BEHAVIOUR", lSET_BEHAVIOUR),
+ /*0x1F*/ MAPFUNC("SET_FLAG_CUBE", lSET_FLAG_CUBE),
+ /*0x20*/ MAPFUNC("COMPORTEMENT", lCOMPORTEMENT),
+ /*0x21*/ MAPFUNC("SET_COMPORTEMENT", lSET_COMPORTEMENT),
+ /*0x22*/ MAPFUNC("SET_COMPORTEMENT_OBJ", lSET_COMPORTEMENT_OBJ),
+ /*0x23*/ MAPFUNC("END_COMPORTEMENT", lEND_COMPORTEMENT),
+ /*0x24*/ MAPFUNC("SET_FLAG_GAME", lSET_FLAG_GAME),
+ /*0x25*/ MAPFUNC("KILL_OBJ", lKILL_OBJ),
+ /*0x26*/ MAPFUNC("SUICIDE", lSUICIDE),
+ /*0x27*/ MAPFUNC("USE_ONE_LITTLE_KEY", lUSE_ONE_LITTLE_KEY),
+ /*0x28*/ MAPFUNC("GIVE_GOLD_PIECES", lGIVE_GOLD_PIECES),
+ /*0x29*/ MAPFUNC("END_LIFE", lEND_LIFE),
+ /*0x2A*/ MAPFUNC("STOP_L_TRACK", lSTOP_L_TRACK),
+ /*0x2B*/ MAPFUNC("RESTORE_L_TRACK", lRESTORE_L_TRACK),
+ /*0x2C*/ MAPFUNC("MESSAGE_OBJ", lMESSAGE_OBJ),
+ /*0x2D*/ MAPFUNC("INC_CHAPTER", lINC_CHAPTER),
+ /*0x2E*/ MAPFUNC("FOUND_OBJECT", lFOUND_OBJECT),
+ /*0x2F*/ MAPFUNC("SET_DOOR_LEFT", lSET_DOOR_LEFT),
+ /*0x30*/ MAPFUNC("SET_DOOR_RIGHT", lSET_DOOR_RIGHT),
+ /*0x31*/ MAPFUNC("SET_DOOR_UP", lSET_DOOR_UP),
+ /*0x32*/ MAPFUNC("SET_DOOR_DOWN", lSET_DOOR_DOWN),
+ /*0x33*/ MAPFUNC("GIVE_BONUS", lGIVE_BONUS),
+ /*0x34*/ MAPFUNC("CHANGE_CUBE", lCHANGE_CUBE),
+ /*0x35*/ MAPFUNC("OBJ_COL", lOBJ_COL),
+ /*0x36*/ MAPFUNC("BRICK_COL", lBRICK_COL),
+ /*0x37*/ MAPFUNC("OR_IF", lOR_IF),
+ /*0x38*/ MAPFUNC("INVISIBLE", lINVISIBLE),
+ /*0x39*/ MAPFUNC("ZOOM", lZOOM),
+ /*0x3A*/ MAPFUNC("POS_POINT", lPOS_POINT),
+ /*0x3B*/ MAPFUNC("SET_MAGIC_LEVEL", lSET_MAGIC_LEVEL),
+ /*0x3C*/ MAPFUNC("SUB_MAGIC_POINT", lSUB_MAGIC_POINT),
+ /*0x3D*/ MAPFUNC("SET_LIFE_POINT_OBJ", lSET_LIFE_POINT_OBJ),
+ /*0x3E*/ MAPFUNC("SUB_LIFE_POINT_OBJ", lSUB_LIFE_POINT_OBJ),
+ /*0x3F*/ MAPFUNC("HIT_OBJ", lHIT_OBJ),
+ /*0x40*/ MAPFUNC("PLAY_FLA", lPLAY_FLA),
+ /*0x41*/ MAPFUNC("PLAY_MIDI", lPLAY_MIDI),
+ /*0x42*/ MAPFUNC("INC_CLOVER_BOX", lINC_CLOVER_BOX),
+ /*0x43*/ MAPFUNC("SET_USED_INVENTORY", lSET_USED_INVENTORY),
+ /*0x44*/ MAPFUNC("ADD_CHOICE", lADD_CHOICE),
+ /*0x45*/ MAPFUNC("ASK_CHOICE", lASK_CHOICE),
+ /*0x46*/ MAPFUNC("BIG_MESSAGE", lBIG_MESSAGE),
+ /*0x47*/ MAPFUNC("INIT_PINGOUIN", lINIT_PINGOUIN),
+ /*0x48*/ MAPFUNC("SET_HOLO_POS", lSET_HOLO_POS),
+ /*0x49*/ MAPFUNC("CLR_HOLO_POS", lCLR_HOLO_POS),
+ /*0x4A*/ MAPFUNC("ADD_FUEL", lADD_FUEL),
+ /*0x4B*/ MAPFUNC("SUB_FUEL", lSUB_FUEL),
+ /*0x4C*/ MAPFUNC("SET_GRM", lSET_GRM),
+ /*0x4D*/ MAPFUNC("SAY_MESSAGE", lSAY_MESSAGE),
+ /*0x4E*/ MAPFUNC("SAY_MESSAGE_OBJ", lSAY_MESSAGE_OBJ),
+ /*0x4F*/ MAPFUNC("FULL_POINT", lFULL_POINT),
+ /*0x50*/ MAPFUNC("BETA", lBETA),
+ /*0x51*/ MAPFUNC("GRM_OFF", lGRM_OFF),
+ /*0x52*/ MAPFUNC("FADE_PAL_RED", lFADE_PAL_RED),
+ /*0x53*/ MAPFUNC("FADE_ALARM_RED", lFADE_ALARM_RED),
+ /*0x54*/ MAPFUNC("FADE_ALARM_PAL", lFADE_ALARM_PAL),
+ /*0x55*/ MAPFUNC("FADE_RED_PAL", lFADE_RED_PAL),
+ /*0x56*/ MAPFUNC("FADE_RED_ALARM", lFADE_RED_ALARM),
+ /*0x57*/ MAPFUNC("FADE_PAL_ALARM", lFADE_PAL_ALARM),
+ /*0x58*/ MAPFUNC("EXPLODE_OBJ", lEXPLODE_OBJ),
+ /*0x59*/ MAPFUNC("BUBBLE_ON", lBUBBLE_ON),
+ /*0x5A*/ MAPFUNC("BUBBLE_OFF", lBUBBLE_OFF),
+ /*0x5B*/ MAPFUNC("ASK_CHOICE_OBJ", lASK_CHOICE_OBJ),
+ /*0x5C*/ MAPFUNC("SET_DARK_PAL", lSET_DARK_PAL),
+ /*0x5D*/ MAPFUNC("SET_NORMAL_PAL", lSET_NORMAL_PAL),
+ /*0x5E*/ MAPFUNC("MESSAGE_SENDELL", lMESSAGE_SENDELL),
+ /*0x5F*/ MAPFUNC("ANIM_SET", lANIM_SET),
+ /*0x60*/ MAPFUNC("HOLOMAP_TRAJ", lHOLOMAP_TRAJ),
+ /*0x61*/ MAPFUNC("GAME_OVER", lGAME_OVER),
+ /*0x62*/ MAPFUNC("THE_END", lTHE_END),
+ /*0x63*/ MAPFUNC("MIDI_OFF", lMIDI_OFF),
+ /*0x64*/ MAPFUNC("PLAY_CD_TRACK", lPLAY_CD_TRACK),
+ /*0x65*/ MAPFUNC("PROJ_ISO", lPROJ_ISO),
+ /*0x66*/ MAPFUNC("PROJ_3D", lPROJ_3D),
+ /*0x67*/ MAPFUNC("TEXT", lTEXT),
+ /*0x68*/ MAPFUNC("CLEAR_TEXT", lCLEAR_TEXT),
+ /*0x69*/ MAPFUNC("BRUTAL_EXIT", lBRUTAL_EXIT)
+};
+
+static int decompileLBA1MoveScript(int actorIdx, const uint8 *data, int16 size) {
+ Common::MemoryReadStream stream(data, size);
+ ScriptContext ctx{stream, {}, initialLevel, 0};
+
+ printf("Actor %i\n", actorIdx);
+
+ while (ctx.stream.pos() < ctx.stream.size()) {
+ const byte scriptOpcode = ctx.stream.readByte();
+ if (scriptOpcode < ARRAYSIZE(moveScriptFunctions)) {
+ moveScriptFunctions[scriptOpcode].function(ctx);
+ } else {
+ fprintf(stderr, "Actor %d with wrong offset/opcode - Offset: %d/%d (opcode: %u)", actorIdx, (int)ctx.stream.pos() - 1, (int)ctx.stream.size(), scriptOpcode);
+ return 1;
+ }
+ };
+
+ return 0;
+}
+
+static int decompileLBA1LifeScript(int actorIdx, const uint8 *data, int16 size) {
+ Common::MemoryReadStream stream(data, size);
+ ScriptContext ctx{stream, {}, initialLevel, 0, true};
+
+ printf("Actor %i\n", actorIdx);
+
+ printf("%*sCOMPORTMENT main\n", ctx.level, " ");
+ ctx.level += indentWidth;
+ while (ctx.stream.pos() < ctx.stream.size()) {
+ const byte scriptOpcode = ctx.stream.readByte();
+ if (scriptOpcode < ARRAYSIZE(lifeScriptFunctions)) {
+ if (scriptOpcode && !ctx.comportement) {
+ ++ctx.comportmentId;
+ printf("%*sCOMPORTEMENT %i\n", ctx.level, " ", ctx.comportmentId);
+ ctx.level += indentWidth;
+ ctx.comportement = true;
+ }
+ lifeScriptFunctions[scriptOpcode].function(ctx);
+ while (!ctx.offsets.empty()) {
+ if (ctx.stream.pos() == ctx.offsets.back()) {
+ ctx.level -= indentWidth;
+ printf("%*sENDIF\n", ctx.level, " ");
+ ctx.offsets.pop_back();
+ } else {
+ break;
+ }
+ }
+ } else {
+ fprintf(stderr, "Actor %d with wrong offset/opcode - Offset: %d/%d (opcode: %u)", actorIdx, (int)ctx.stream.pos() - 1, (int)ctx.stream.size(), scriptOpcode);
+ return 1;
+ }
+ };
+
+ return 0;
+}
+
+int decompileLBA1(const uint8 *data, int size) {
+ Common::MemoryReadStream stream(data, size);
+ uint8_t sceneTextBank = stream.readByte();
+ uint8_t currentGameOverScene = stream.readByte();
+ stream.skip(4);
+ int16 _alphaLight = (int16)stream.readUint16LE();
+ int16 _betaLight = (int16)stream.readUint16LE();
+
+ uint16 sampleAmbiance[4];
+ uint16 sampleRepeat[4];
+ uint16 sampleRound[4];
+
+ for (int i = 0; i < 4; ++i) {
+ sampleAmbiance[i] = stream.readUint16LE();
+ sampleRepeat[i] = stream.readUint16LE();
+ sampleRound[i] = stream.readUint16LE();
+ }
+
+ uint16 sampleMinDelay = stream.readUint16LE();
+ uint16 sampleMinDelayRnd = stream.readUint16LE();
+
+ uint8 sceneMusic = stream.readByte();
+
+ int16 sceneHeroPosx = (int16)stream.readUint16LE();
+ int16 sceneHeroPosy = (int16)stream.readUint16LE();
+ int16 sceneHeroPosz = (int16)stream.readUint16LE();
+
+ int16 moveScriptSize = (int16)stream.readUint16LE();
+ const uint8 *moveScript = data + stream.pos();
+ stream.skip(moveScriptSize);
+ decompileLBA1MoveScript(0, moveScript, moveScriptSize);
+
+ int16 lifeScriptSize = (int16)stream.readUint16LE();
+ const uint8 *lifeScript = data + stream.pos();
+ stream.skip(lifeScriptSize);
+ decompileLBA1LifeScript(0, lifeScript, lifeScriptSize);
+
+ int16 sceneNumActors = (int16)stream.readUint16LE();
+ int cnt = 1;
+ for (int32 a = 1; a < sceneNumActors; a++, cnt++) {
+ uint16 staticflags = stream.readUint16LE();
+ uint16 body = stream.readUint16LE();
+ uint8 genBody = stream.readByte();
+ uint8 genAnim = stream.readByte();
+ int16 sprite = stream.readSint16LE();
+ int16 posx = stream.readSint16LE();
+ int16 posy = stream.readSint16LE();
+ int16 posz = stream.readSint16LE();
+ uint8 strengthOfHit = stream.readByte();
+ uint16 bonusflags = stream.readUint16LE();
+ int16 beta = stream.readSint16LE();
+ int16 speed = stream.readSint16LE();
+ uint16 controlMode = stream.readUint16LE();
+ int16 cropLeft = stream.readSint16LE();
+ int16 cropTop = stream.readSint16LE();
+ int16 cropRight = stream.readSint16LE();
+ int16 cropBottom = stream.readSint16LE();
+ uint8 bonusAmount = stream.readByte();
+ uint8 talkColor = stream.readByte();
+ uint8 armor = stream.readByte();
+ uint8 lifePoints = stream.readByte();
+
+ moveScriptSize = (int16)stream.readUint16LE();
+ moveScript = data + stream.pos();
+ stream.skip(moveScriptSize);
+ decompileLBA1MoveScript(a, moveScript, moveScriptSize);
+
+ lifeScriptSize = (int16)stream.readUint16LE();
+ lifeScript = data + stream.pos();
+ stream.skip(lifeScriptSize);
+ decompileLBA1LifeScript(a, lifeScript, lifeScriptSize);
+ }
+
+ int16 sceneNumZones = stream.readSint16LE();
+ for (int16 i = 0; i < sceneNumZones; i++) {
+ int16 zoneminsx = stream.readSint16LE();
+ int16 zoneminsy = stream.readSint16LE();
+ int16 zoneminsz = stream.readSint16LE();
+
+ int16 zonemaxsx = stream.readSint16LE();
+ int16 zonemaxsy = stream.readSint16LE();
+ int16 zonemaxsz = stream.readSint16LE();
+
+ uint16 zonetype = stream.readUint16LE();
+ int16 zonenum = stream.readSint16LE();
+
+ int16 info0 = stream.readSint16LE();
+ int16 info1 = stream.readSint16LE();
+ int16 info2 = stream.readSint16LE();
+ int16 info3 = stream.readSint16LE();
+ }
+
+ uint16 sceneNumTracks = stream.readUint16LE();
+ for (uint16 i = 0; i < sceneNumTracks; i++) {
+ int16 pointx = stream.readSint16LE();
+ int16 pointy = stream.readSint16LE();
+ int16 pointz = stream.readSint16LE();
+ }
+
+ if (stream.err()) {
+ return 1;
+ }
+ return 0;
+}
diff --git a/engines/twine/lba1.h b/engines/twine/lba1.h
new file mode 100644
index 00000000..e50ef31f
--- /dev/null
+++ b/engines/twine/lba1.h
@@ -0,0 +1,29 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef TWINE_LBA1_H
+#define TWINE_LBA1_H
+
+#include "common/scummsys.h"
+
+int decompileLBA1(const uint8 *data, int size);
+
+#endif
diff --git a/engines/twine/lba2.cpp b/engines/twine/lba2.cpp
new file mode 100644
index 00000000..1b10b4b3
--- /dev/null
+++ b/engines/twine/lba2.cpp
@@ -0,0 +1,39 @@
+/* ScummVM Tools
+ *
+ * ScummVM Tools 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "engines/twine/lba2.h"
+#include "common/memstream.h"
+
+// static int decompileLBA2MoveScript(int actor, const uint8 *moveScript, int16 moveScriptSize) {
+// return 0;
+// }
+
+// static int decompileLBA2LifeScript(int actor, const uint8 *moveScript, int16 moveScriptSize) {
+// return 0;
+// }
+
+int decompileLBA2(const uint8 *data, int size) {
+ Common::MemoryReadStream stream(data, size);
+ if (stream.err()) {
+ return 1;
+ }
+ return 0;
+}
diff --git a/engines/twine/lba2.h b/engines/twine/lba2.h
new file mode 100644
index 00000000..7bf39076
--- /dev/null
+++ b/engines/twine/lba2.h
@@ -0,0 +1,29 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef TWINE_LBA2_H
+#define TWINE_LBA2_H
+
+#include "common/scummsys.h"
+
+int decompileLBA2(const uint8 *data, int size);
+
+#endif
More information about the Scummvm-git-logs
mailing list