Initial commit
This commit is contained in:
553
engines/glk/scott/c64_checksums.cpp
Normal file
553
engines/glk/scott/c64_checksums.cpp
Normal file
@@ -0,0 +1,553 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "common/str.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "glk/scott/scott.h"
|
||||
#include "glk/scott/globals.h"
|
||||
#include "glk/scott/c64_checksums.h"
|
||||
#include "glk/scott/definitions.h"
|
||||
#include "glk/scott/disk_image.h"
|
||||
#include "glk/scott/game_info.h"
|
||||
#include "glk/scott/resource.h"
|
||||
#include "glk/scott/saga_draw.h"
|
||||
#include "glk/scott/unp64/unp64_interface.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
#define MAX_LENGTH 300000
|
||||
#define MIN_LENGTH 24
|
||||
|
||||
enum FileType {
|
||||
UNKNOWN_FILE_TYPE,
|
||||
TYPE_D64,
|
||||
TYPE_T64
|
||||
};
|
||||
|
||||
struct C64Rec {
|
||||
GameIDType _id;
|
||||
size_t _length;
|
||||
uint16_t _chk;
|
||||
FileType _type;
|
||||
int _decompressIterations;
|
||||
const char *_switches;
|
||||
const char *_appendFile;
|
||||
int _parameter;
|
||||
size_t _copySource;
|
||||
size_t _copyDest;
|
||||
size_t _copySize;
|
||||
int _imgOffset;
|
||||
};
|
||||
|
||||
static C64Rec g_C64Registry[] = {
|
||||
{ BATON_C64, 0x2ab00, 0xc3fc, TYPE_D64, 0, nullptr, nullptr, 0, 0, 0, 0, 0 }, // Mysterious Adventures C64 dsk 1
|
||||
{ TIME_MACHINE_C64, 0x2ab00, 0xc3fc, TYPE_D64, 0, nullptr, nullptr, 0, 0, 0, 0, 0 },
|
||||
{ ARROW1_C64, 0x2ab00, 0xc3fc, TYPE_D64, 0, nullptr, nullptr, 0, 0, 0, 0, 0 },
|
||||
{ ARROW2_C64, 0x2ab00, 0xc3fc, TYPE_D64, 0, nullptr, nullptr, 0, 0, 0, 0, 0 },
|
||||
{ PULSAR7_C64, 0x2ab00, 0xc3fc, TYPE_D64, 0, nullptr, nullptr, 0, 0, 0, 0, 0 },
|
||||
{ CIRCUS_C64, 0x2ab00, 0xc3fc, TYPE_D64, 0, nullptr, nullptr, 0, 0, 0, 0, 0 },
|
||||
|
||||
{ FEASIBILITY_C64, 0x2ab00, 0x9eaa, TYPE_D64, 0, nullptr, nullptr, 0, 0, 0, 0, 0 }, // Mysterious Adventures C64 dsk 2
|
||||
{ AKYRZ_C64, 0x2ab00, 0x9eaa, TYPE_D64, 0, nullptr, nullptr, 0, 0, 0, 0, 0 },
|
||||
{ PERSEUS_C64, 0x2ab00, 0x9eaa, TYPE_D64, 0, nullptr, nullptr, 0, 0, 0, 0, 0 },
|
||||
{ INDIANS_C64, 0x2ab00, 0x9eaa, TYPE_D64, 0, nullptr, nullptr, 0, 0, 0, 0, 0 },
|
||||
{ WAXWORKS_C64, 0x2ab00, 0x9eaa, TYPE_D64, 0, nullptr, nullptr, 0, 0, 0, 0, 0 },
|
||||
{ BATON_C64, 0x2ab00, 0x9dca, TYPE_D64, 2, nullptr, nullptr, 0, 0, 0, 0, 0 },
|
||||
|
||||
{ ROBIN_OF_SHERWOOD_C64, 0x2ab00, 0xcf9e, TYPE_D64, 1, nullptr, nullptr, 0, 0x1802, 0xbd27, 0x2000, 0 }, // Robin Of Sherwood D64 * unknown packer
|
||||
{ ROBIN_OF_SHERWOOD_C64, 0xb2ef, 0x7c44, TYPE_T64, 1, nullptr, nullptr, 0, 0x9702, 0x9627, 0x2000, 0 }, // Robin Of Sherwood C64 (T64) * TCS Cruncher v2.0
|
||||
{ ROBIN_OF_SHERWOOD_C64, 0xb690, 0x7b61, TYPE_T64, 1, nullptr, nullptr, 0, 0x9702, 0x9627, 0x2000, 0 }, // Robin Of Sherwood C64 (T64) alt * TCS Cruncher v2.0
|
||||
{ ROBIN_OF_SHERWOOD_C64, 0x8db6, 0x7853, TYPE_T64, 1, nullptr, nullptr, 0, 0xd7fb, 0xbd20, 0x2000, 0 }, // Robin Of Sherwood T64 alt 2 * PUCrunch
|
||||
|
||||
{ GREMLINS_C64, 0xdd94, 0x25a8, TYPE_T64, 1, nullptr, nullptr, 0, 0, 0, 0, 0 }, // Gremlins C64 (T64) version * Action Replay v4.x
|
||||
{ GREMLINS_C64, 0x2ab00, 0xc402, TYPE_D64, 0, nullptr, "G1", -0x8D, 0, 0, 0, 0 }, // Gremlins C64 (D64) version
|
||||
{ GREMLINS_C64, 0x2ab00, 0x3ccf, TYPE_D64, 0, nullptr, "G1", -0x8D, 0, 0, 0, 0 }, // Gremlins C64 (D64) version 2
|
||||
{ GREMLINS_C64, 0x2ab00, 0xabf8, TYPE_D64, 2, "-e0x1255",nullptr, 2, 0, 0, 0, 0 }, // Gremlins C64 (D64) version alt * ByteBoiler, Exomizer
|
||||
{ GREMLINS_C64, 0x2ab00, 0xa265, TYPE_D64, 2, "-e0x1255",nullptr, 2, 0, 0, 0, 0 }, // Gremlins C64 (D64) version alt 2 * ByteBoiler, Exomizer
|
||||
{ GREMLINS_GERMAN_C64, 0xc003, 0x558c, TYPE_T64, 1, nullptr, nullptr, 0, 0xd801, 0xc6c0, 0x1f00, 0 }, // German Gremlins C64 (T64) version * TBC Multicompactor v2.x
|
||||
{ GREMLINS_GERMAN_C64, 0x2ab00, 0x6729, TYPE_D64, 2, nullptr, nullptr, 0, 0xdc02, 0xcac1, 0x1f00, 0 }, // German Gremlins C64 (D64) version * Exomizer
|
||||
|
||||
{ SEAS_OF_BLOOD_C64, 0xa209, 0xf115, TYPE_T64, 6, "-e0x1000", nullptr, 3, 0xd802, 0xb07c, 0x2000, 0 }, // Seas of Blood C64 (T64) MasterCompressor / Relax -> ECA
|
||||
// Compacker -> Unknown -> MasterCompressor / Relax -> ECA
|
||||
// Compacker -> CCS Packer
|
||||
{ SEAS_OF_BLOOD_C64, 0x2ab00, 0x5c1d, TYPE_D64, 1, nullptr, nullptr, 0, 0xd802, 0xb07c, 0x2000, 0 }, // Seas of Blood C64 (D64) CCS Packer
|
||||
{ SEAS_OF_BLOOD_C64, 0x2ab00, 0xe308, TYPE_D64, 1, nullptr, nullptr, 0, 0xd802, 0xb07c, 0x2000, 0 }, // Seas of Blood C64 (D64) alt CCS Packer
|
||||
|
||||
{ CLAYMORGUE_C64, 0x6ff7, 0xe4ed, TYPE_T64, 3, nullptr, nullptr, 0, 0x855, 0x7352, 0x20, 0 }, // Sorcerer Of Claymorgue Castle C64 (T64), MasterCompressor / Relax
|
||||
// -> ECA Compacker -> MegaByte Cruncher v1.x Missing 17 pictures
|
||||
{ CLAYMORGUE_C64, 0x912f, 0xa69f, TYPE_T64, 1, nullptr, nullptr, 0, 0x855, 0x7352, 0x20, 0 }, // Sorcerer Of Claymorgue Castle C64 (T64) alt, MegaByte Cruncher
|
||||
// v1.x Missing 17 pictures
|
||||
{ CLAYMORGUE_C64, 0xc0dd, 0x3701, TYPE_T64, 1, nullptr, nullptr, 0, 0, 0, 0, -0x7fe },// Sorcerer Of Claymorgue Castle C64 (T64) alt 2, Trilogic Expert
|
||||
// v2.7
|
||||
{ CLAYMORGUE_C64, 0xbc5f, 0x492c, TYPE_T64, 1, nullptr, nullptr, 0, 0x855, 0x7352, 0x20, 0 }, // Sorcerer Of Claymorgue Castle C64 (T64) alt 3, , Section8 Packer
|
||||
{ CLAYMORGUE_C64, 0x2ab00, 0xfd67, TYPE_D64, 1, nullptr, nullptr, 0, 0x855, 0x7352, 0x20, 0 }, // Sorcerer Of Claymorgue Castle C64 (D64), Section8 Packer
|
||||
|
||||
{ ADVENTURELAND_C64, 0x6a10, 0x1910, TYPE_T64, 1, nullptr, nullptr, 0, 0, 0, 0, 0 }, // Adventureland C64 (T64) CruelCrunch v2.2
|
||||
{ ADVENTURELAND_C64, 0x6a10, 0x1b10, TYPE_T64, 1, nullptr, nullptr, 0, 0, 0, 0, 0 }, // Adventureland C64 (T64) alt CruelCrunch v2.2
|
||||
{ ADVENTURELAND_C64, 0x2ab00, 0x6638, TYPE_D64, 1, nullptr, nullptr, 0, 0, 0, 0, 0 }, // Adventureland C64 (D64) CruelCrunch v2.2
|
||||
{ ADVENTURELAND_C64, 0x2adab, 0x751f, TYPE_D64, 0, nullptr, nullptr, 0, 0, 0, 0, 0 }, // Adventureland C64 (D64) alt
|
||||
{ ADVENTURELAND_C64, 0x2adab, 0x64a4, TYPE_D64, 0, nullptr, "SAG1PIC", -0xa53, 0, 0, 0, 0x65af }, // Adventureland C64 (D64) alt 2
|
||||
|
||||
{ SAVAGE_ISLAND_C64, 0x2ab00, 0x8801, TYPE_D64, 1, "-f86 -d0x1793", "SAVAGEISLAND1+", 1, 0, 0, 0, 0 }, // Savage Island part 1 C64 (D64)
|
||||
{ SAVAGE_ISLAND2_C64, 0x2ab00, 0x8801, TYPE_D64, 1, "-f86 -d0x178b", "SAVAGEISLAND2+", 1, 0, 0, 0, 0 }, // Savage Island part 2 C64 (D64)
|
||||
{ SAVAGE_ISLAND_C64, 0x2ab00, 0xc361, TYPE_D64, 1, "-f86 -d0x1793", "SAVAGE ISLAND P1", 1, 0, 0, 0, 0 }, // Savage Island part 1 C64 (D64) alt
|
||||
{ SAVAGE_ISLAND2_C64, 0x2ab00, 0xc361, TYPE_D64, 1, nullptr, "SAVAGE ISLAND P2", 0, 0, 0, 0, 0 }, // Savage Island part 2 C64 (D64) alt
|
||||
|
||||
{ HULK_C64, 0x2ab00, 0xcdd8, TYPE_D64, 0, nullptr, nullptr, 0, 0x1806, 0xb801, 0x307, 0 }, // Questprobe 1 - The Hulk C64 (D64)
|
||||
{ SPIDERMAN_C64, 0x2ab00, 0xde56, TYPE_D64, 0, nullptr, nullptr, 0, 0x1801, 0xa801, 0x2000, 0 }, // Spiderman C64 (D64)
|
||||
{ SPIDERMAN_C64, 0x08e72, 0xb2f4, TYPE_T64, 3, nullptr, nullptr, 0, 0, 0, 0, 0 }, // Spiderman C64 (T64) MasterCompressor / Relax -> ECA Compacker -> Section8 Packer
|
||||
|
||||
{ BATON_C64, 0x5170, 0xb240, TYPE_T64, 2, nullptr, nullptr, 0, 0, 0, 0, 0 }, // The Golden Baton C64, T64
|
||||
{ BATON_C64, 0x2ab00, 0xbfbf, TYPE_D64, 2, nullptr, nullptr, 0, 0, 0, 0, 0 }, // Mysterious Adventures C64 dsk 1 alt
|
||||
{ FEASIBILITY_C64, 0x2ab00, 0x9c18, TYPE_D64, 2, nullptr, nullptr, 0, 0, 0, 0, 0 }, // Mysterious Adventures C64 dsk 2 alt
|
||||
{ TIME_MACHINE_C64, 0x5032, 0x5635, TYPE_T64, 1, nullptr, nullptr, 0, 0, 0, 0, 0 }, // The Time Machine C64
|
||||
{ ARROW1_C64, 0x5b46, 0x92db, TYPE_T64, 1, nullptr, nullptr, 0, 0, 0, 0, 0 }, // Arrow of Death part 1 C64
|
||||
{ ARROW2_C64, 0x5fe2, 0xe14f, TYPE_T64, 1, nullptr, nullptr, 0, 0, 0, 0, 0 }, // Arrow of Death part 2 C64
|
||||
{ PULSAR7_C64, 0x46bf, 0x1679, TYPE_T64, 1, nullptr, nullptr, 0, 0, 0, 0, 0 }, // Escape from Pulsar 7 C64
|
||||
{ CIRCUS_C64, 0x4269, 0xa449, TYPE_T64, 2, nullptr, nullptr, 0, 0, 0, 0, 0 }, // Circus C64
|
||||
{ FEASIBILITY_C64, 0x5a7b, 0x0f48, TYPE_T64, 1, nullptr, nullptr, 0, 0, 0, 0, 0 }, // Feasibility Experiment C64
|
||||
{ AKYRZ_C64, 0x2ab00, 0x6cca, TYPE_D64, 0, nullptr, nullptr, 0, 0, 0, 0, 0 }, // The Wizard of Akyrz C64
|
||||
{ AKYRZ_C64, 0x4be1, 0x5a00, TYPE_T64, 1, nullptr, nullptr, 0, 0, 0, 0, 0 }, // The Wizard of Akyrz C64, T64
|
||||
{ PERSEUS_C64, 0x502b, 0x913b, TYPE_T64, 1, nullptr, nullptr, 0, 0, 0, 0, 0 }, // Perseus and Andromeda C64
|
||||
{ INDIANS_C64, 0x4f9f, 0xe6c8, TYPE_T64, 1, nullptr, nullptr, 0, 0, 0, 0, 0 }, // Ten Little Indians C64
|
||||
{ WAXWORKS_C64, 0x4a11, 0xa37a, TYPE_T64, 1, nullptr, nullptr, 0, 0, 0, 0, 0 }, // Waxworks C64
|
||||
|
||||
{ SUPERGRAN_C64, 0x726f, 0x0901, TYPE_T64, 1, nullptr, nullptr, 0, 0xd802, 0xc623, 0x1f00, 0 }, // Super Gran C64 (T64) PUCrunch Generic Hack
|
||||
|
||||
{ UNKNOWN_GAME, 0, 0, UNKNOWN_FILE_TYPE, 0, nullptr, nullptr, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
int decrunchC64(uint8_t **sf, size_t *extent, C64Rec entry);
|
||||
|
||||
uint8_t *getLargestFile(uint8_t *data, int length, int *newlength) {
|
||||
uint8_t *file = nullptr;
|
||||
*newlength = 0;
|
||||
DiskImage *d64 = diCreateFromData(data, length);
|
||||
if (d64) {
|
||||
RawDirEntry *largest = findLargestFileEntry(d64);
|
||||
if (largest) {
|
||||
ImageFile *c64file = diOpen(d64, largest->_rawname, largest->_type, "rb");
|
||||
if (c64file) {
|
||||
uint8_t *largeFile = new uint8_t[0xffff];
|
||||
*newlength = diRead(c64file, largeFile, 0xffff);
|
||||
file = new uint8_t[*newlength];
|
||||
memcpy(file, largeFile, *newlength);
|
||||
}
|
||||
}
|
||||
//di_free_image(d64);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
uint8_t *getFileNamed(uint8_t* data, int length, int* newLength, const char* name) {
|
||||
uint8_t *file = nullptr;
|
||||
*newLength = 0;
|
||||
DiskImage *d64 = diCreateFromData(data, length);
|
||||
byte rawname[100];
|
||||
diRawnameFromName(rawname, name);
|
||||
if (d64) {
|
||||
ImageFile *c64file = diOpen(d64, rawname, 0xC2, "rb");
|
||||
if (c64file) {
|
||||
uint8_t *buf = new uint8_t[0xffff];
|
||||
*newLength = diRead(c64file, buf, 0xffff);
|
||||
file = new uint8_t[*newLength];
|
||||
memcpy(file, buf, *newLength);
|
||||
delete[] buf;
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
int savageIslandMenu(uint8_t **sf, size_t *extent, int recIndex) {
|
||||
g_scott->output("This disk image contains two games. Select one.\n\n"
|
||||
"1. Savage Island part I\n"
|
||||
"2. Savage Island part II");
|
||||
|
||||
g_scott->glk_request_char_event(_G(_bottomWindow));
|
||||
|
||||
event_t ev;
|
||||
int result = 0;
|
||||
do {
|
||||
g_scott->glk_select(&ev);
|
||||
if (ev.type == evtype_CharInput) {
|
||||
if (ev.val1 == '1' || ev.val1 == '2') {
|
||||
result = ev.val1 - '0';
|
||||
} else {
|
||||
g_scott->glk_request_char_event(_G(_bottomWindow));
|
||||
}
|
||||
}
|
||||
|
||||
if (g_vm->shouldQuit())
|
||||
return 0;
|
||||
} while (result == 0);
|
||||
|
||||
g_scott->glk_window_clear(_G(_bottomWindow));
|
||||
|
||||
recIndex += result - 1;
|
||||
|
||||
C64Rec rec = g_C64Registry[recIndex];
|
||||
int length;
|
||||
uint8_t *file = getFileNamed(*sf, *extent, &length, rec._appendFile);
|
||||
|
||||
if (file != nullptr) {
|
||||
if (rec._chk == 0xc361) {
|
||||
if (rec._switches != nullptr) {
|
||||
_G(_saveIslandAppendix1) = getFileNamed(*sf, *extent, &_G(_saveIslandAppendix1Length), "SI1PC1");
|
||||
_G(_saveIslandAppendix2) = getFileNamed(*sf, *extent, &_G(_saveIslandAppendix2Length), "SI1PC2");
|
||||
} else {
|
||||
_G(_saveIslandAppendix1) = getFileNamed(*sf, *extent, &_G(_saveIslandAppendix1Length), "SI2PIC");
|
||||
}
|
||||
}
|
||||
delete[] *sf;
|
||||
*sf = file;
|
||||
*extent = length;
|
||||
if (_G(_saveIslandAppendix1Length) > 2)
|
||||
_G(_saveIslandAppendix1Length) -= 2;
|
||||
if (_G(_saveIslandAppendix2Length) > 2)
|
||||
_G(_saveIslandAppendix2Length) -= 2;
|
||||
return decrunchC64(sf, extent, rec);
|
||||
} else {
|
||||
error("savageIslandMenu: Failed loading file %s\n", rec._appendFile);
|
||||
}
|
||||
}
|
||||
|
||||
void appendSIfiles(uint8_t **sf, size_t *extent) {
|
||||
//int totalLength = *extent + _G(_saveIslandAppendix1Length) + _G(_saveIslandAppendix2Length);
|
||||
|
||||
uint8_t *megabuf = new uint8_t[0xFFFF];
|
||||
memcpy(megabuf, *sf, *extent);
|
||||
delete[] *sf;
|
||||
int offset = 0x6202;
|
||||
|
||||
if (_G(_saveIslandAppendix1)) {
|
||||
memcpy(megabuf + offset, _G(_saveIslandAppendix1) + 2, _G(_saveIslandAppendix1Length));
|
||||
delete[] _G(_saveIslandAppendix1);
|
||||
}
|
||||
if (_G(_saveIslandAppendix2)) {
|
||||
memcpy(megabuf + offset + _G(_saveIslandAppendix1Length), _G(_saveIslandAppendix2) + 2, _G(_saveIslandAppendix2Length));
|
||||
delete[] _G(_saveIslandAppendix2);
|
||||
}
|
||||
*extent = offset + _G(_saveIslandAppendix1Length) + _G(_saveIslandAppendix2Length);
|
||||
*sf = new uint8_t[*extent];
|
||||
memcpy(*sf, megabuf, *extent);
|
||||
delete[] megabuf;
|
||||
}
|
||||
|
||||
int mysteriousMenu(uint8_t **sf, size_t *extent, int recindex) {
|
||||
recindex = 0;
|
||||
|
||||
g_scott->output("This disk image contains six games. Select one.\n\n"
|
||||
"1. The Golden Baton\n"
|
||||
"2. The Time Machine\n"
|
||||
"3. Arrow of Death part 1\n"
|
||||
"4. Arrow of Death part 2\n"
|
||||
"5. Escape from Pulsar 7\n"
|
||||
"6. Circus");
|
||||
|
||||
g_scott->glk_request_char_event(_G(_bottomWindow));
|
||||
|
||||
event_t ev;
|
||||
int result = 0;
|
||||
do {
|
||||
g_scott->glk_select(&ev);
|
||||
if (ev.type == evtype_CharInput) {
|
||||
if (ev.val1 >= '1' && ev.val1 <= '6') {
|
||||
result = ev.val1 - '0';
|
||||
} else {
|
||||
g_scott->glk_request_char_event(_G(_bottomWindow));
|
||||
}
|
||||
}
|
||||
|
||||
if (g_vm->shouldQuit())
|
||||
return 0;
|
||||
} while (result == 0);
|
||||
|
||||
g_scott->glk_window_clear(_G(_bottomWindow));
|
||||
|
||||
const char *filename = nullptr;
|
||||
switch (result) {
|
||||
case 1:
|
||||
filename = "BATON";
|
||||
break;
|
||||
case 2:
|
||||
filename = "TIME MACHINE";
|
||||
break;
|
||||
case 3:
|
||||
filename = "ARROW I";
|
||||
break;
|
||||
case 4:
|
||||
filename = "ARROW II";
|
||||
break;
|
||||
case 5:
|
||||
filename = "PULSAR 7";
|
||||
break;
|
||||
case 6:
|
||||
filename = "CIRCUS";
|
||||
break;
|
||||
default:
|
||||
error("mysteriousMenu: Unknown Game");
|
||||
}
|
||||
|
||||
int length;
|
||||
uint8_t *file = getFileNamed(*sf, *extent, &length, filename);
|
||||
|
||||
if (file != nullptr) {
|
||||
delete[] *sf;
|
||||
*sf = file;
|
||||
*extent = length;
|
||||
C64Rec rec = g_C64Registry[recindex - 1 + result];
|
||||
return decrunchC64(sf, extent, rec);
|
||||
} else {
|
||||
error("mysteriousMenu: Failed loading file %s", filename);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int mysteriousMenu2(uint8_t **sf, size_t *extent, int recindex) {
|
||||
recindex = 6;
|
||||
|
||||
g_scott->output("This disk image contains five games. Select one.\n\n"
|
||||
"1. Feasibility Experiment\n"
|
||||
"2. The Wizard of Akyrz\n"
|
||||
"3. Perseus and Andromeda\n"
|
||||
"4. Ten Little Indians\n"
|
||||
"5. Waxworks");
|
||||
|
||||
g_scott->glk_request_char_event(_G(_bottomWindow));
|
||||
|
||||
event_t ev;
|
||||
int result = 0;
|
||||
do {
|
||||
g_scott->glk_select(&ev);
|
||||
if (ev.type == evtype_CharInput) {
|
||||
if (ev.val1 >= '1' && ev.val1 <= '5') {
|
||||
result = ev.val1 - '0';
|
||||
} else {
|
||||
g_scott->glk_request_char_event(_G(_bottomWindow));
|
||||
}
|
||||
}
|
||||
|
||||
if (g_vm->shouldQuit())
|
||||
return 0;
|
||||
} while (result == 0);
|
||||
|
||||
g_scott->glk_window_clear(_G(_bottomWindow));
|
||||
|
||||
const char *filename = nullptr;
|
||||
switch (result) {
|
||||
case 1:
|
||||
filename = "EXPERIMENT";
|
||||
break;
|
||||
case 2:
|
||||
filename = "WIZARD OF AKYRZ";
|
||||
break;
|
||||
case 3:
|
||||
filename = "PERSEUS";
|
||||
break;
|
||||
case 4:
|
||||
filename = "INDIANS";
|
||||
break;
|
||||
case 5:
|
||||
filename = "WAXWORKS";
|
||||
break;
|
||||
default:
|
||||
error("mysteriousMenu2: Unknown Game");
|
||||
}
|
||||
|
||||
int length;
|
||||
uint8_t *file = getFileNamed(*sf, *extent, &length, filename);
|
||||
|
||||
if (file != nullptr) {
|
||||
delete[] *sf;
|
||||
*sf = file;
|
||||
*extent = length;
|
||||
C64Rec rec = g_C64Registry[recindex - 1 + result];
|
||||
return decrunchC64(sf, extent, rec);
|
||||
} else {
|
||||
error("mysteriousMenu2: Failed loading file %s", filename);
|
||||
}
|
||||
}
|
||||
|
||||
int detectC64(uint8_t **sf, size_t *extent) {
|
||||
if (*extent > MAX_LENGTH || *extent < MIN_LENGTH)
|
||||
return 0;
|
||||
|
||||
Common::String md5 = g_vm->getGameMD5();
|
||||
int index = _G(_md5Index)[md5];
|
||||
if (g_C64Registry[index]._id == SAVAGE_ISLAND_C64) {
|
||||
return savageIslandMenu(sf, extent, index);
|
||||
} else if (g_C64Registry[index]._id == BATON_C64 && index == 0) {
|
||||
return mysteriousMenu(sf, extent, index);
|
||||
} else if (g_C64Registry[index]._id == FEASIBILITY_C64 && index == 6) {
|
||||
return mysteriousMenu2(sf, extent, index);
|
||||
}
|
||||
if (g_C64Registry[index]._type == TYPE_D64) {
|
||||
int newlength;
|
||||
uint8_t *largest_file = getLargestFile(*sf, *extent, &newlength);
|
||||
uint8_t *appendix = nullptr;
|
||||
int appendixlen = 0;
|
||||
|
||||
if (g_C64Registry[index]._appendFile != nullptr) {
|
||||
appendix = getFileNamed(*sf, *extent, &appendixlen, g_C64Registry[index]._appendFile);
|
||||
if (appendix == nullptr)
|
||||
error("detectC64(): Appending file failed");
|
||||
appendixlen -= 2;
|
||||
}
|
||||
|
||||
uint8_t *megabuf = new uint8_t[newlength + appendixlen];
|
||||
memcpy(megabuf, largest_file, newlength);
|
||||
if (appendix != nullptr) {
|
||||
memcpy(megabuf + newlength + g_C64Registry[index]._parameter, appendix + 2, appendixlen);
|
||||
newlength += appendixlen;
|
||||
}
|
||||
delete[] appendix;
|
||||
|
||||
if (largest_file) {
|
||||
*sf = megabuf;
|
||||
*extent = newlength;
|
||||
}
|
||||
delete[] largest_file;
|
||||
|
||||
} else if (g_C64Registry[index]._type == TYPE_T64) {
|
||||
uint8_t *file_records = *sf + 64;
|
||||
int number_of_records = READ_LE_UINT16(&(*sf)[36]);
|
||||
int offset = READ_LE_UINT16(&file_records[8]);
|
||||
int start_addr = READ_LE_UINT16(&file_records[2]);
|
||||
int end_addr = READ_LE_UINT16(&file_records[4]);
|
||||
int size;
|
||||
if (number_of_records == 1)
|
||||
size = *extent - offset;
|
||||
else
|
||||
size = end_addr - start_addr;
|
||||
uint8_t *first_file = new uint8_t[size + 2];
|
||||
memcpy(first_file + 2, *sf + offset, size);
|
||||
memcpy(first_file, file_records + 2, 2);
|
||||
*sf = first_file;
|
||||
*extent = size + 2;
|
||||
}
|
||||
return decrunchC64(sf, extent, g_C64Registry[index]);
|
||||
}
|
||||
|
||||
size_t copyData(size_t dest, size_t source, uint8_t** data, size_t dataSize, size_t bytesToMove) {
|
||||
if (source > dataSize || *data == nullptr)
|
||||
return 0;
|
||||
|
||||
size_t newSize = MAX(dest + bytesToMove, dataSize);
|
||||
uint8_t *megaBuf = new uint8_t[newSize];
|
||||
memcpy(megaBuf, *data, dataSize);
|
||||
memcpy(megaBuf + dest, *data + source, bytesToMove);
|
||||
delete[] *data;
|
||||
*data = megaBuf;
|
||||
return newSize;
|
||||
}
|
||||
|
||||
int decrunchC64(uint8_t **sf, size_t *extent, C64Rec record) {
|
||||
uint8_t *uncompressed = nullptr;
|
||||
_G(_fileLength) = *extent;
|
||||
|
||||
size_t decompressedLength = *extent;
|
||||
|
||||
uncompressed = new uint8_t[0xffff];
|
||||
|
||||
size_t result = 0;
|
||||
|
||||
for (int i = 1; i <= record._decompressIterations; i++) {
|
||||
/* We only send switches on the iteration specified by parameter */
|
||||
if (i == record._parameter && record._switches != nullptr) {
|
||||
result = unp64(_G(_entireFile), _G(_fileLength), uncompressed, &decompressedLength, record._switches);
|
||||
} else
|
||||
result = unp64(_G(_entireFile), _G(_fileLength), uncompressed, &decompressedLength, nullptr);
|
||||
if (result) {
|
||||
if (_G(_entireFile) != nullptr)
|
||||
delete[] _G(_entireFile);
|
||||
_G(_entireFile) = new uint8_t[decompressedLength];
|
||||
memcpy(_G(_entireFile), uncompressed, decompressedLength);
|
||||
_G(_fileLength) = decompressedLength;
|
||||
} else {
|
||||
delete[] uncompressed;
|
||||
uncompressed = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (uncompressed != nullptr)
|
||||
delete[] uncompressed;
|
||||
|
||||
for (int i = 0; i < NUMGAMES; i++) {
|
||||
if (_G(_games)[i]._gameID == record._id) {
|
||||
_G(_game) = &_G(_games)[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_G(_game)->_title == nullptr) {
|
||||
error("decrunchC64: Game not found");
|
||||
}
|
||||
|
||||
int offset;
|
||||
|
||||
DictionaryType dictype = getId(&offset);
|
||||
if (dictype != _G(_game)->_dictionary) {
|
||||
error("decrunchC64: Wrong game?");
|
||||
}
|
||||
|
||||
if (!tryLoading(*_G(_game), offset, 0)) {
|
||||
error("decrunchC64: Game could not be read");
|
||||
}
|
||||
|
||||
if (_G(_saveIslandAppendix1) != nullptr) {
|
||||
appendSIfiles(sf, extent);
|
||||
}
|
||||
|
||||
if (record._copySource != 0) {
|
||||
result = copyData(record._copyDest, record._copySource, sf, *extent, record._copySize);
|
||||
if (result) {
|
||||
*extent = result;
|
||||
}
|
||||
}
|
||||
|
||||
if (CURRENT_GAME == CLAYMORGUE_C64 && record._copySource == 0x855) {
|
||||
result = copyData(0x1531a, 0x2002, sf, *extent, 0x2000);
|
||||
if (result) {
|
||||
*extent = result;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(_G(_game)->_subType & MYSTERIOUS))
|
||||
sagaSetup(record._imgOffset);
|
||||
|
||||
return CURRENT_GAME;
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
46
engines/glk/scott/c64_checksums.h
Normal file
46
engines/glk/scott/c64_checksums.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_C64CHECKSUMS_H
|
||||
#define GLK_SCOTT_C64CHECKSUMS_H
|
||||
|
||||
#include "glk/scott/types.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
int detectC64(uint8_t **sf, size_t *extent);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
872
engines/glk/scott/command_parser.cpp
Normal file
872
engines/glk/scott/command_parser.cpp
Normal file
@@ -0,0 +1,872 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "common/str.h"
|
||||
#include "glk/scott/scott.h"
|
||||
#include "glk/scott/globals.h"
|
||||
#include "glk/scott/command_parser.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
#define MAX_WORDLENGTH 128
|
||||
#define MAX_WORDS 128
|
||||
#define MAX_BUFFER 128
|
||||
|
||||
void freeStrings() {
|
||||
if (_G(_firstErrorMessage) != nullptr) {
|
||||
delete[] _G(_firstErrorMessage);
|
||||
_G(_firstErrorMessage) = nullptr;
|
||||
}
|
||||
if (_G(_wordsInInput) == 0) {
|
||||
if (_G(_unicodeWords) != nullptr || _G(_charWords) != nullptr) {
|
||||
g_scott->fatal("ERROR! Wordcount 0 but word arrays not empty!\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < _G(_wordsInInput); i++) {
|
||||
if (_G(_unicodeWords)[i] != nullptr)
|
||||
delete _G(_unicodeWords)[i];
|
||||
if (_G(_charWords)[i] != nullptr)
|
||||
delete _G(_charWords)[i];
|
||||
}
|
||||
|
||||
delete _G(_unicodeWords);
|
||||
_G(_unicodeWords) = nullptr;
|
||||
delete _G(_charWords);
|
||||
_G(_charWords) = nullptr;
|
||||
_G(_wordsInInput) = 0;
|
||||
}
|
||||
|
||||
void createErrorMessage(const char *fchar, glui32 *second, const char *tchar) {
|
||||
if (_G(_firstErrorMessage) != nullptr)
|
||||
return;
|
||||
glui32 *first = toUnicode(fchar);
|
||||
glui32 *third = toUnicode(tchar);
|
||||
glui32 buffer[MAX_BUFFER];
|
||||
int i, j = 0, k = 0;
|
||||
for (i = 0; first[i] != 0 && i < MAX_BUFFER; i++)
|
||||
buffer[i] = first[i];
|
||||
if (second != nullptr) {
|
||||
for (j = 0; second[j] != 0 && i + j < MAX_BUFFER; j++)
|
||||
buffer[i + j] = second[j];
|
||||
}
|
||||
if (third != nullptr) {
|
||||
for (k = 0; third[k] != 0 && i + j + k < MAX_BUFFER; k++)
|
||||
buffer[i + j + k] = third[k];
|
||||
delete[] third;
|
||||
}
|
||||
int length = i + j + k;
|
||||
_G(_firstErrorMessage) = new glui32[(length + 1) * 4];
|
||||
memcpy(_G(_firstErrorMessage), buffer, length * 4);
|
||||
_G(_firstErrorMessage)[length] = 0;
|
||||
delete[] first;
|
||||
}
|
||||
|
||||
void printPendingError(void) {
|
||||
if (_G(_firstErrorMessage)) {
|
||||
g_scott->glk_put_string_stream_uni(g_scott->glk_window_get_stream(_G(_bottomWindow)), _G(_firstErrorMessage));
|
||||
delete[] _G(_firstErrorMessage);
|
||||
_G(_firstErrorMessage) = nullptr;
|
||||
_G(_stopTime) = 1;
|
||||
}
|
||||
}
|
||||
|
||||
char **LineInput(void) {
|
||||
event_t ev;
|
||||
glui32 unibuf[512];
|
||||
|
||||
do {
|
||||
g_scott->display(_G(_bottomWindow), "\n%s", _G(_sys)[WHAT_NOW].c_str());
|
||||
g_scott->glk_request_line_event_uni(_G(_bottomWindow), unibuf, (glui32)511, 0);
|
||||
|
||||
while (ev.type != evtype_Quit) {
|
||||
g_scott->glk_select(&ev);
|
||||
if (ev.type == evtype_Quit)
|
||||
return nullptr;
|
||||
|
||||
if (ev.type == evtype_LineInput)
|
||||
break;
|
||||
else
|
||||
g_scott->updates(ev);
|
||||
}
|
||||
|
||||
unibuf[ev.val1] = 0;
|
||||
|
||||
if (_G(_transcript)) {
|
||||
g_scott->glk_put_string_stream_uni(_G(_transcript), unibuf);
|
||||
g_scott->glk_put_char_stream_uni(_G(_transcript), 10);
|
||||
}
|
||||
|
||||
_G(_charWords) = splitIntoWords(unibuf, ev.val1);
|
||||
|
||||
if (_G(_wordsInInput) == 0 || _G(_charWords) == nullptr)
|
||||
g_scott->output(_G(_sys)[HUH]);
|
||||
else {
|
||||
return _G(_charWords);
|
||||
}
|
||||
|
||||
} while (_G(_wordsInInput) == 0 || _G(_charWords) == nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int matchYMCA(glui32 *string, int length, int index) {
|
||||
const char *ymca = "y.m.c.a.";
|
||||
int i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (i + index > length || string[index + i] != static_cast<unsigned int>(ymca[i]))
|
||||
return i;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
char **splitIntoWords(glui32 *string, int length) {
|
||||
if (length < 1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
g_scott->glk_buffer_to_lower_case_uni(string, 256, length);
|
||||
g_scott->glk_buffer_canon_normalize_uni(string, 256, length);
|
||||
|
||||
int startpos[MAX_WORDS];
|
||||
int wordlength[MAX_WORDS];
|
||||
|
||||
int words_found = 0;
|
||||
int word_index = 0;
|
||||
int foundspace = 0;
|
||||
int foundcomma = 0;
|
||||
startpos[0] = 0;
|
||||
wordlength[0] = 0;
|
||||
int lastwasspace = 1;
|
||||
for (int i = 0; string[i] != 0 && i < length && word_index < MAX_WORDS; i++) {
|
||||
foundspace = 0;
|
||||
switch (string[i]) {
|
||||
case 'y': {
|
||||
int ymca = matchYMCA(string, length, i);
|
||||
if (ymca > 3) {
|
||||
/* Start a new word */
|
||||
startpos[words_found] = i;
|
||||
wordlength[words_found] = ymca;
|
||||
words_found++;
|
||||
wordlength[words_found] = 0;
|
||||
i += ymca;
|
||||
if (i < length)
|
||||
foundspace = 1;
|
||||
lastwasspace = 0;
|
||||
}
|
||||
} break;
|
||||
/* Unicode space and tab variants */
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '!':
|
||||
case '?':
|
||||
case '\"':
|
||||
case 0x83: // ¿
|
||||
case 0x80: // ¡
|
||||
case 0xa0: // non-breaking space
|
||||
case 0x2000: // en quad
|
||||
case 0x2001: // em quad
|
||||
case 0x2003: // em
|
||||
case 0x2004: // three-per-em
|
||||
case 0x2005: // four-per-em
|
||||
case 0x2006: // six-per-em
|
||||
case 0x2007: // figure space
|
||||
case 0x2009: // thin space
|
||||
case 0x200A: // hair space
|
||||
case 0x202f: // narrow no-break space
|
||||
case 0x205f: // medium mathematical space
|
||||
case 0x3000: // ideographic space
|
||||
foundspace = 1;
|
||||
break;
|
||||
case '.':
|
||||
case ',':
|
||||
foundcomma = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!foundspace) {
|
||||
if (lastwasspace || foundcomma) {
|
||||
/* Start a new word */
|
||||
startpos[words_found] = i;
|
||||
words_found++;
|
||||
wordlength[words_found] = 0;
|
||||
}
|
||||
wordlength[words_found - 1]++;
|
||||
lastwasspace = 0;
|
||||
} else {
|
||||
/* Check if the last character of previous word was a period or comma */
|
||||
lastwasspace = 1;
|
||||
foundcomma = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (words_found == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
wordlength[words_found]--; /* Don't count final newline character */
|
||||
|
||||
/* Now we've created two arrays, one for starting positions
|
||||
and one for word length. Now we convert these into an array of strings */
|
||||
glui32 **words = new glui32 *[words_found];
|
||||
char **words8 = new char *[words_found];
|
||||
|
||||
for (int i = 0; i < words_found; i++) {
|
||||
words[i] = new glui32[(wordlength[i] + 1) * 4];
|
||||
memcpy(words[i], string + startpos[i], wordlength[i] * 4);
|
||||
words[i][wordlength[i]] = 0;
|
||||
words8[i] = fromUnicode(words[i], wordlength[i]);
|
||||
}
|
||||
_G(_unicodeWords) = words;
|
||||
_G(_wordsInInput) = words_found;
|
||||
|
||||
return words8;
|
||||
}
|
||||
|
||||
int findVerb(const char *string, Common::StringArray *list) {
|
||||
*list = _G(_verbs);
|
||||
int verb = whichWord(string, *list, _G(_gameHeader)->_wordLength);
|
||||
if (verb) {
|
||||
return verb;
|
||||
}
|
||||
*list = _G(_directions);
|
||||
verb = whichWord(string, *list, _G(_gameHeader)->_wordLength);
|
||||
if (verb) {
|
||||
if (verb == 13)
|
||||
verb = 4;
|
||||
if (verb > 6)
|
||||
verb -= 6;
|
||||
return verb;
|
||||
}
|
||||
*list = _G(_abbreviations);
|
||||
verb = whichWord(string, *list, _G(_gameHeader)->_wordLength);
|
||||
if (verb) {
|
||||
verb = whichWord(_G(_abbreviationsKey)[verb].c_str(), _G(_verbs), _G(_gameHeader)->_wordLength);
|
||||
if (verb) {
|
||||
list = &_G(_verbs);
|
||||
return verb;
|
||||
}
|
||||
}
|
||||
|
||||
int stringlength = strlen(string);
|
||||
|
||||
*list = _G(_skipList);
|
||||
verb = whichWord(string, *list, stringlength);
|
||||
if (verb) {
|
||||
return 0;
|
||||
}
|
||||
*list = _G(_nouns);
|
||||
verb = whichWord(string, *list, _G(_gameHeader)->_wordLength);
|
||||
if (verb) {
|
||||
return verb;
|
||||
}
|
||||
|
||||
*list = _G(_extraCommands);
|
||||
verb = whichWord(string, *list, stringlength);
|
||||
if (verb) {
|
||||
verb = _G(_extraCommandsKey)[verb];
|
||||
return verb + _G(_gameHeader)->_numWords;
|
||||
}
|
||||
|
||||
*list = _G(_extraNouns);
|
||||
verb = whichWord(string, *list, stringlength);
|
||||
if (verb) {
|
||||
verb = _G(_extraNounsKey)[verb];
|
||||
return verb + _G(_gameHeader)->_numWords;
|
||||
}
|
||||
|
||||
*list = _G(_delimiterList);
|
||||
verb = whichWord(string, *list, stringlength);
|
||||
if (!verb)
|
||||
*list = Common::StringArray();
|
||||
return verb;
|
||||
}
|
||||
|
||||
int findExtraneousWords(int *index, int noun) {
|
||||
/* Looking for extraneous words that should invalidate the command */
|
||||
int originalIndex = *index;
|
||||
if (*index >= _G(_wordsInInput)) {
|
||||
return 0;
|
||||
}
|
||||
Common::StringArray list;
|
||||
int verb = 0;
|
||||
int stringlength = strlen(_G(_charWords)[*index]);
|
||||
|
||||
list = _G(_skipList);
|
||||
do {
|
||||
verb = whichWord(_G(_charWords)[*index], _G(_skipList), stringlength);
|
||||
if (verb)
|
||||
*index = *index + 1;
|
||||
} while (verb && *index < _G(_wordsInInput));
|
||||
|
||||
if (*index >= _G(_wordsInInput))
|
||||
return 0;
|
||||
|
||||
verb = findVerb(_G(_charWords)[*index], &list);
|
||||
|
||||
if (list == _G(_delimiterList)) {
|
||||
if (*index > originalIndex)
|
||||
*index = *index - 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (list == _G(_nouns) && noun) {
|
||||
if (g_scott->mapSynonym(noun) == g_scott->mapSynonym(verb)) {
|
||||
*index = *index + 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (list.empty()) {
|
||||
if (*index >= _G(_wordsInInput))
|
||||
*index = _G(_wordsInInput) - 1;
|
||||
createErrorMessage(_G(_sys)[I_DONT_KNOW_WHAT_A].c_str(), _G(_unicodeWords)[*index], _G(_sys)[IS].c_str());
|
||||
} else {
|
||||
createErrorMessage(_G(_sys)[I_DONT_UNDERSTAND].c_str(), nullptr, nullptr);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
Command *commandFromStrings(int index, Command *previous);
|
||||
|
||||
Command *createCommandStruct(int verb, int noun, int verbIndex, int nounIndex, Command *previous) {
|
||||
Command *command = new Command;
|
||||
command->_verb = verb;
|
||||
command->_noun = noun;
|
||||
command->_allFlag = 0;
|
||||
command->_item = 0;
|
||||
command->_previous = previous;
|
||||
command->_verbWordIndex = verbIndex;
|
||||
if (noun && nounIndex > 0) {
|
||||
command->_nounWordIndex = nounIndex - 1;
|
||||
} else {
|
||||
command->_nounWordIndex = 0;
|
||||
}
|
||||
command->_next = commandFromStrings(nounIndex, command);
|
||||
return command;
|
||||
}
|
||||
|
||||
int findNoun(const char *string, Common::StringArray *list) {
|
||||
*list = _G(_nouns);
|
||||
int noun = whichWord(string, *list, _G(_gameHeader)->_wordLength);
|
||||
if (noun) {
|
||||
return noun;
|
||||
}
|
||||
|
||||
*list = _G(_directions);
|
||||
noun = whichWord(string, *list, _G(_gameHeader)->_wordLength);
|
||||
if (noun) {
|
||||
if (noun > 6)
|
||||
noun -= 6;
|
||||
*list = _G(_nouns);
|
||||
return noun;
|
||||
}
|
||||
|
||||
int stringLength = strlen(string);
|
||||
|
||||
*list = _G(_extraNouns);
|
||||
|
||||
noun = whichWord(string, *list, stringLength);
|
||||
if (noun) {
|
||||
noun = _G(_extraNounsKey)[noun];
|
||||
return noun + _G(_gameHeader)->_numWords;
|
||||
}
|
||||
|
||||
*list = _G(_skipList);
|
||||
noun = whichWord(string, *list, stringLength);
|
||||
if (noun) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*list = _G(_verbs);
|
||||
noun = whichWord(string, *list, _G(_gameHeader)->_wordLength);
|
||||
if (noun) {
|
||||
return noun;
|
||||
}
|
||||
|
||||
*list = _G(_delimiterList);
|
||||
noun = whichWord(string, *list, stringLength);
|
||||
|
||||
if (!noun)
|
||||
*list = Common::StringArray();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Command *commandFromStrings(int index, Command *previous) {
|
||||
if (index < 0 || index >= _G(_wordsInInput)) {
|
||||
return nullptr;
|
||||
}
|
||||
Common::StringArray list;
|
||||
int verb = 0;
|
||||
int i = index;
|
||||
|
||||
do {
|
||||
/* Checking if it is a verb */
|
||||
verb = findVerb(_G(_charWords)[i++], &list);
|
||||
} while ((list == _G(_skipList) || list == _G(_delimiterList)) && i < _G(_wordsInInput));
|
||||
|
||||
int verbindex = i - 1;
|
||||
|
||||
if (list == _G(_directions)) {
|
||||
/* It is a direction */
|
||||
if (verb == 0 || findExtraneousWords(&i, 0) != 0)
|
||||
return nullptr;
|
||||
return createCommandStruct(GO, verb, 0, i, previous);
|
||||
}
|
||||
|
||||
int found_noun_at_verb_position = 0;
|
||||
int lastverb = 0;
|
||||
|
||||
if (list == _G(_nouns) || list == _G(_extraNouns)) {
|
||||
/* It is a noun */
|
||||
/* If we find no verb, we try copying the verb from the previous command */
|
||||
if (previous) {
|
||||
lastverb = previous->_verb;
|
||||
}
|
||||
/* Unless the game is German, where we allow the noun to come before the
|
||||
* verb */
|
||||
if (CURRENT_GAME != GREMLINS_GERMAN && CURRENT_GAME != GREMLINS_GERMAN_C64) {
|
||||
if (!previous) {
|
||||
createErrorMessage(_G(_sys)[I_DONT_KNOW_HOW_TO].c_str(), _G(_unicodeWords)[i - 1], _G(_sys)[SOMETHING].c_str());
|
||||
return nullptr;
|
||||
} else {
|
||||
verbindex = previous->_verbWordIndex;
|
||||
}
|
||||
if (findExtraneousWords(&i, verb) != 0)
|
||||
return nullptr;
|
||||
|
||||
return createCommandStruct(lastverb, verb, verbindex, i, previous);
|
||||
} else {
|
||||
found_noun_at_verb_position = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (list.empty() || list == _G(_skipList)) {
|
||||
createErrorMessage(_G(_sys)[I_DONT_KNOW_HOW_TO].c_str(), _G(_unicodeWords)[i - 1], _G(_sys)[SOMETHING].c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (i == _G(_wordsInInput)) {
|
||||
if (lastverb) {
|
||||
return createCommandStruct(lastverb, verb, previous->_verbWordIndex, i, previous);
|
||||
} else if (found_noun_at_verb_position) {
|
||||
createErrorMessage(_G(_sys)[I_DONT_KNOW_HOW_TO].c_str(), _G(_unicodeWords)[i - 1], _G(_sys)[SOMETHING].c_str());
|
||||
return nullptr;
|
||||
} else {
|
||||
return createCommandStruct(verb, 0, i - 1, i, previous);
|
||||
}
|
||||
}
|
||||
|
||||
int noun = 0;
|
||||
|
||||
do {
|
||||
/* Check if it is a noun */
|
||||
noun = findNoun(_G(_charWords)[i++], &list);
|
||||
} while (list == _G(_skipList) && i < _G(_wordsInInput));
|
||||
|
||||
if (list == _G(_nouns) || list == _G(_extraNouns)) {
|
||||
/* It is a noun */
|
||||
|
||||
/* Check if it is an ALL followed by EXCEPT */
|
||||
int except = 0;
|
||||
if (list == _G(_extraNouns) && i < _G(_wordsInInput) && noun - _G(_gameHeader)->_numWords == ALL) {
|
||||
int stringlength = strlen(_G(_charWords)[i]);
|
||||
except = whichWord(_G(_charWords)[i], _G(_extraCommands), stringlength);
|
||||
}
|
||||
if (_G(_extraCommandsKey)[except] != EXCEPT && findExtraneousWords(&i, noun) != 0)
|
||||
return nullptr;
|
||||
if (found_noun_at_verb_position) {
|
||||
int realverb = whichWord(_G(_charWords)[i - 1], _G(_verbs), _G(_gameHeader)->_wordLength);
|
||||
if (realverb) {
|
||||
noun = verb;
|
||||
verb = realverb;
|
||||
} else if (lastverb) {
|
||||
noun = verb;
|
||||
verb = lastverb;
|
||||
}
|
||||
}
|
||||
return createCommandStruct(verb, noun, verbindex, i, previous);
|
||||
}
|
||||
|
||||
if (list == _G(_delimiterList)) {
|
||||
/* It is a delimiter */
|
||||
return createCommandStruct(verb, 0, verbindex, i, previous);
|
||||
}
|
||||
|
||||
if (list == _G(_verbs) && found_noun_at_verb_position) {
|
||||
/* It is a verb */
|
||||
/* Check if it is an ALL followed by EXCEPT */
|
||||
int except = 0;
|
||||
if (i < _G(_wordsInInput) && verb - _G(_gameHeader)->_numWords == ALL) {
|
||||
int stringlength = strlen(_G(_charWords)[i]);
|
||||
except = whichWord(_G(_charWords)[i], _G(_extraCommands), stringlength);
|
||||
}
|
||||
if (_G(_extraCommandsKey)[except] != EXCEPT && findExtraneousWords(&i, 0) != 0)
|
||||
return nullptr;
|
||||
return createCommandStruct(noun, verb, i - 1, i, previous);
|
||||
}
|
||||
|
||||
createErrorMessage(_G(_sys)[I_DONT_KNOW_WHAT_A].c_str(), _G(_unicodeWords)[i - 1], _G(_sys)[IS].c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int createAllCommands(Command *command) {
|
||||
|
||||
Common::Array<int> exceptions(_G(_gameHeader)->_numItems);
|
||||
int exceptioncount = 0;
|
||||
|
||||
int location = CARRIED;
|
||||
if (command->_verb == TAKE)
|
||||
location = MY_LOC;
|
||||
|
||||
Command *next = command->_next;
|
||||
/* Check if the ALL command is followed by EXCEPT */
|
||||
/* and if it is, build an array of items to be excepted */
|
||||
while (next && next->_verb == _G(_gameHeader)->_numWords + EXCEPT) {
|
||||
for (int i = 0; i <= _G(_gameHeader)->_numItems; i++) {
|
||||
if (!_G(_items)[i]._autoGet.empty() && scumm_strnicmp(_G(_items)[i]._autoGet.c_str(), _G(_charWords)[next->_nounWordIndex], _G(_gameHeader)->_wordLength) == 0) {
|
||||
exceptions[exceptioncount++] = i;
|
||||
}
|
||||
}
|
||||
/* Remove the EXCEPT command from the linked list of commands */
|
||||
next = next->_next;
|
||||
delete command->_next;
|
||||
command->_next = next;
|
||||
}
|
||||
|
||||
Command *c = command;
|
||||
int found = 0;
|
||||
for (int i = 0; i < _G(_gameHeader)->_numItems; i++) {
|
||||
if (!_G(_items)[i]._autoGet.empty() && _G(_items)[i]._autoGet[0] != '*' && _G(_items)[i]._location == location) {
|
||||
int exception = 0;
|
||||
for (int j = 0; j < exceptioncount; j++) {
|
||||
if (exceptions[j] == i) {
|
||||
exception = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!exception) {
|
||||
if (found) {
|
||||
c->_next = new Command;
|
||||
c->_next->_previous = c;
|
||||
c = c->_next;
|
||||
}
|
||||
found = 1;
|
||||
c->_verb = command->_verb;
|
||||
c->_noun = whichWord(_G(_items)[i]._autoGet.c_str(), _G(_nouns), _G(_gameHeader)->_wordLength);
|
||||
c->_item = i;
|
||||
c->_next = nullptr;
|
||||
c->_nounWordIndex = 0;
|
||||
c->_allFlag = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found == 0) {
|
||||
if (command->_verb == TAKE)
|
||||
createErrorMessage(_G(_sys)[NOTHING_HERE_TO_TAKE].c_str(), nullptr, nullptr);
|
||||
else
|
||||
createErrorMessage(_G(_sys)[YOU_HAVE_NOTHING].c_str(), nullptr, nullptr);
|
||||
return 0;
|
||||
} else {
|
||||
c->_next = next;
|
||||
c->_allFlag = 1 | LASTALL;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int getInput(int *vb, int *no) {
|
||||
if (_G(_currentCommand) && _G(_currentCommand)->_next) {
|
||||
_G(_currentCommand) = _G(_currentCommand)->_next;
|
||||
} else {
|
||||
printPendingError();
|
||||
if (_G(_currentCommand))
|
||||
freeCommands();
|
||||
_G(_charWords) = LineInput();
|
||||
|
||||
if (_G(_wordsInInput) == 0 || _G(_charWords) == nullptr)
|
||||
return 0;
|
||||
|
||||
_G(_currentCommand) = commandFromStrings(0, nullptr);
|
||||
}
|
||||
|
||||
if (_G(_currentCommand) == nullptr) {
|
||||
printPendingError();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We use NumWords + verb for our extra commands */
|
||||
/* such as UNDO and TRANSCRIPT */
|
||||
if (_G(_currentCommand)->_verb > _G(_gameHeader)->_numWords) {
|
||||
if (!g_scott->performExtraCommand(0)) {
|
||||
createErrorMessage(_G(_sys)[I_DONT_UNDERSTAND].c_str(), nullptr, nullptr);
|
||||
}
|
||||
return 1;
|
||||
/* And NumWords + noun for our extra nouns */
|
||||
/* such as ALL */
|
||||
} else if (_G(_currentCommand)->_noun > _G(_gameHeader->_numWords)) {
|
||||
_G(_currentCommand)->_noun -= _G(_gameHeader)->_numWords;
|
||||
if (_G(_currentCommand)->_noun == ALL) {
|
||||
if (_G(_currentCommand)->_verb != TAKE && _G(_currentCommand)->_verb != DROP) {
|
||||
createErrorMessage(_G(_sys)[CANT_USE_ALL].c_str(), nullptr, nullptr);
|
||||
return 1;
|
||||
}
|
||||
if (!createAllCommands(_G(_currentCommand)))
|
||||
return 1;
|
||||
} else if (_G(_currentCommand)->_noun == IT) {
|
||||
_G(_currentCommand)->_noun = _G(_lastNoun);
|
||||
}
|
||||
}
|
||||
|
||||
*vb = _G(_currentCommand)->_verb;
|
||||
*no = _G(_currentCommand)->_noun;
|
||||
|
||||
if (*no > 6) {
|
||||
_G(_lastNoun) = *no;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void freeCommands() {
|
||||
while (_G(_currentCommand) && _G(_currentCommand)->_previous)
|
||||
_G(_currentCommand) = _G(_currentCommand)->_previous;
|
||||
while (_G(_currentCommand)) {
|
||||
Command *temp = _G(_currentCommand);
|
||||
_G(_currentCommand) = _G(_currentCommand)->_next;
|
||||
delete temp;
|
||||
}
|
||||
_G(_currentCommand) = nullptr;
|
||||
freeStrings();
|
||||
if (_G(_firstErrorMessage))
|
||||
delete[] _G(_firstErrorMessage);
|
||||
_G(_firstErrorMessage) = nullptr;
|
||||
}
|
||||
|
||||
glui32 *toUnicode(const char *string) {
|
||||
if (string == nullptr)
|
||||
return nullptr;
|
||||
glui32 unicode[2048];
|
||||
int i;
|
||||
int dest = 0;
|
||||
for (i = 0; string[i] != 0 && i < 2047; i++) {
|
||||
char c = string[i];
|
||||
if (c == '\n')
|
||||
c = 10;
|
||||
glui32 unichar = (glui32)c;
|
||||
if (_G(_game) && (CURRENT_GAME == GREMLINS_GERMAN || CURRENT_GAME == GREMLINS_GERMAN_C64)) {
|
||||
const char d = string[i + 1];
|
||||
if (c == 'u' && d == 'e') { // ü
|
||||
if (!(i > 2 && string[i - 1] == 'e')) {
|
||||
unichar = 0xfc;
|
||||
i++;
|
||||
}
|
||||
} else if (c == 'o' && d == 'e') {
|
||||
unichar = 0xf6; // ö
|
||||
i++;
|
||||
} else if (c == 'a' && d == 'e') {
|
||||
unichar = 0xe4; // ä
|
||||
i++;
|
||||
} else if (c == 's' && d == 's') {
|
||||
if (string[i + 2] != 'c' && string[i - 2] != 'W' && !(string[i - 1] == 'a' && string[i - 2] == 'l') && string[i + 2] != '-' && string[i - 2] != 'b') {
|
||||
unichar = 0xdf; // ß
|
||||
i++;
|
||||
}
|
||||
} else if (c == 'U' && d == 'E') {
|
||||
unichar = 0xdc; // Ü
|
||||
i++;
|
||||
}
|
||||
if (c == '\"') {
|
||||
unichar = 0x2019; // ’
|
||||
}
|
||||
} else if (_G(_game) && CURRENT_GAME == GREMLINS_SPANISH) {
|
||||
switch (c) {
|
||||
case '\x83':
|
||||
unichar = 0xbf; // ¿
|
||||
break;
|
||||
case '\x80':
|
||||
unichar = 0xa1; // ¡
|
||||
break;
|
||||
case '\x82':
|
||||
unichar = 0xfc; // ü
|
||||
break;
|
||||
case '{':
|
||||
unichar = 0xe1; // á
|
||||
break;
|
||||
case '}':
|
||||
unichar = 0xed; // í
|
||||
break;
|
||||
case '|':
|
||||
unichar = 0xf3; // ó
|
||||
break;
|
||||
case '~':
|
||||
unichar = 0xf1; // ñ
|
||||
break;
|
||||
case '\x84':
|
||||
unichar = 0xe9; // é
|
||||
break;
|
||||
case '\x85':
|
||||
unichar = 0xfa; // ú
|
||||
break;
|
||||
}
|
||||
} else if (_G(_game) && CURRENT_GAME == TI994A) {
|
||||
switch (c) {
|
||||
case '@':
|
||||
unicode[dest++] = 0xa9;
|
||||
unichar = ' ';
|
||||
break;
|
||||
case '}':
|
||||
unichar = 0xfc;
|
||||
break;
|
||||
case 12:
|
||||
unichar = 0xf6;
|
||||
break;
|
||||
case '{':
|
||||
unichar = 0xe4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
unicode[dest++] = unichar;
|
||||
}
|
||||
unicode[dest] = 0;
|
||||
glui32 *result = new glui32[(dest + 1) * 4];
|
||||
memcpy(result, unicode, (dest + 1) * 4);
|
||||
return result;
|
||||
}
|
||||
|
||||
char *fromUnicode(glui32 *unicodeString, int origLength) {
|
||||
int sourcepos = 0;
|
||||
int destpos = 0;
|
||||
|
||||
char dest[MAX_WORDLENGTH];
|
||||
glui32 unichar = unicodeString[sourcepos];
|
||||
while (unichar != 0 && destpos < MAX_WORDLENGTH && sourcepos < origLength) {
|
||||
switch (unichar) {
|
||||
case '.':
|
||||
if (origLength == 1) {
|
||||
dest[destpos++] = 'a';
|
||||
dest[destpos++] = 'n';
|
||||
dest[destpos++] = 'd';
|
||||
} else {
|
||||
dest[destpos] = (char)unichar;
|
||||
}
|
||||
break;
|
||||
case 0xf6: // ö
|
||||
dest[destpos++] = 'o';
|
||||
dest[destpos] = 'e';
|
||||
break;
|
||||
case 0xe4: // ä
|
||||
dest[destpos++] = 'a';
|
||||
dest[destpos] = 'e';
|
||||
break;
|
||||
case 0xfc: // ü
|
||||
dest[destpos] = 'u';
|
||||
if (CURRENT_GAME == GREMLINS_GERMAN || CURRENT_GAME == GREMLINS_GERMAN_C64) {
|
||||
destpos++;
|
||||
dest[destpos] = 'e';
|
||||
}
|
||||
break;
|
||||
case 0xdf: // ß
|
||||
dest[destpos++] = 's';
|
||||
dest[destpos] = 's';
|
||||
break;
|
||||
case 0xed: // í
|
||||
dest[destpos] = 'i';
|
||||
break;
|
||||
case 0xe1: // á
|
||||
dest[destpos] = 'a';
|
||||
break;
|
||||
case 0xf3: // ó
|
||||
dest[destpos] = 'o';
|
||||
break;
|
||||
case 0xf1: // ñ
|
||||
dest[destpos] = 'n';
|
||||
break;
|
||||
case 0xe9: // é
|
||||
dest[destpos] = 'e';
|
||||
break;
|
||||
default:
|
||||
dest[destpos] = (char)unichar;
|
||||
break;
|
||||
}
|
||||
sourcepos++;
|
||||
destpos++;
|
||||
unichar = unicodeString[sourcepos];
|
||||
}
|
||||
if (destpos == 0)
|
||||
return nullptr;
|
||||
char *result = new char[destpos + 1];
|
||||
memcpy(result, dest, destpos);
|
||||
|
||||
result[destpos] = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
int recheckForExtraCommand() {
|
||||
const char *verbWord = _G(_charWords)[_G(_currentCommand)->_verbWordIndex];
|
||||
|
||||
int extraVerb = whichWord(verbWord, _G(_extraCommands), _G(_gameHeader)->_wordLength);
|
||||
if (!extraVerb) {
|
||||
return 0;
|
||||
}
|
||||
int ExtraNoun = 0;
|
||||
if (_G(_currentCommand)->_noun) {
|
||||
const char *nounWord = _G(_charWords)[_G(_currentCommand)->_nounWordIndex];
|
||||
ExtraNoun = whichWord(nounWord, _G(_extraNouns), strlen(nounWord));
|
||||
}
|
||||
_G(_currentCommand)->_verb = _G(_extraCommandsKey)[extraVerb];
|
||||
if (ExtraNoun)
|
||||
_G(_currentCommand)->_noun = _G(_extraNounsKey)[ExtraNoun];
|
||||
|
||||
return g_scott->performExtraCommand(1);
|
||||
}
|
||||
|
||||
int whichWord(const char *word, Common::StringArray list, int wordLength) {
|
||||
int n = 1;
|
||||
unsigned int ne = 1;
|
||||
const char *tp;
|
||||
while (ne < list.size()) {
|
||||
tp = list[ne].c_str();
|
||||
if (*tp == '*')
|
||||
tp++;
|
||||
else
|
||||
n = ne;
|
||||
if (scumm_strnicmp(word, tp, wordLength) == 0)
|
||||
return (n);
|
||||
ne++;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
89
engines/glk/scott/command_parser.h
Normal file
89
engines/glk/scott/command_parser.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_PARSER_H
|
||||
#define GLK_SCOTT_PARSER_H
|
||||
|
||||
#include "common/str-array.h"
|
||||
#include "glk/glk_types.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
#define NUMBER_OF_DIRECTIONS 14
|
||||
#define NUMBER_OF_SKIPPABLE_WORDS 18
|
||||
#define NUMBER_OF_DELIMITERS 5
|
||||
#define NUMBER_OF_EXTRA_COMMANDS 20
|
||||
#define NUMBER_OF_EXTRA_NOUNS 16
|
||||
|
||||
struct Command {
|
||||
int _verb;
|
||||
int _noun;
|
||||
int _item;
|
||||
int _verbWordIndex;
|
||||
int _nounWordIndex;
|
||||
int _allFlag;
|
||||
struct Command *_previous;
|
||||
struct Command *_next;
|
||||
};
|
||||
|
||||
enum ExtraCommand : int {
|
||||
NO_COMMAND,
|
||||
RESTART,
|
||||
SAVE,
|
||||
RESTORE,
|
||||
SCRIPT,
|
||||
ON,
|
||||
OFF,
|
||||
UNDO,
|
||||
RAM,
|
||||
RAMSAVE,
|
||||
RAMLOAD,
|
||||
GAME,
|
||||
COMMAND,
|
||||
ALL,
|
||||
IT,
|
||||
EXCEPT
|
||||
};
|
||||
|
||||
char **splitIntoWords(glui32 *string, int length);
|
||||
int getInput(int *vb, int *no);
|
||||
void freeCommands();
|
||||
glui32 *toUnicode(const char *string);
|
||||
char *fromUnicode(glui32 *unicodeString, int origLength);
|
||||
int recheckForExtraCommand();
|
||||
int whichWord(const char *word, Common::StringArray list, int wordLength);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
123
engines/glk/scott/decompress_text.cpp
Normal file
123
engines/glk/scott/decompress_text.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "common/str.h"
|
||||
#include "glk/scott/decompress_text.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
int rotateLeftWithCarry(uint8_t *byte, int lastCarry) {
|
||||
int carry = ((*byte & 0x80) > 0);
|
||||
*byte = *byte << 1;
|
||||
if (lastCarry)
|
||||
*byte = *byte | 0x01;
|
||||
return carry;
|
||||
}
|
||||
|
||||
int decompressOne(uint8_t *bytes) {
|
||||
uint8_t result = 0;
|
||||
int carry;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
carry = 0;
|
||||
for (int j = 0; j < 5; j++) {
|
||||
carry = rotateLeftWithCarry(bytes + 4 - j, carry);
|
||||
}
|
||||
rotateLeftWithCarry(&result, carry);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
char *decompressText(uint8_t *source, int stringIndex) {
|
||||
// Lookup table
|
||||
const char *alphabet = " abcdefghijklmnopqrstuvwxyz'\x01,.\x00";
|
||||
//Common::String alphabet = " abcdefghijklmnopqrstuvwxyz'\x01,.\x00";
|
||||
|
||||
int pos, c, uppercase, i, j;
|
||||
uint8_t decompressed[256];
|
||||
uint8_t buffer[5];
|
||||
int idx = 0;
|
||||
|
||||
// Find the start of the compressed message
|
||||
for (i = 0; i < stringIndex; i++) {
|
||||
pos = *source;
|
||||
pos = pos & 0x7F;
|
||||
source += pos;
|
||||
};
|
||||
|
||||
uppercase = ((*source & 0x40) == 0); // Test bit 6
|
||||
|
||||
source++;
|
||||
do {
|
||||
// Get five compressed bytes
|
||||
for (i = 0; i < 5; i++) {
|
||||
buffer[i] = *source++;
|
||||
}
|
||||
for (j = 0; j < 8; j++) {
|
||||
// Decompress one character:
|
||||
int next = decompressOne(buffer);
|
||||
|
||||
c = alphabet[next];
|
||||
|
||||
if (c == 0x01) {
|
||||
uppercase = 1;
|
||||
c = ' ';
|
||||
}
|
||||
|
||||
if (c >= 'a' && uppercase) {
|
||||
c = toupper(c);
|
||||
uppercase = 0;
|
||||
}
|
||||
decompressed[idx++] = c;
|
||||
|
||||
if (idx > 255)
|
||||
return nullptr;
|
||||
|
||||
if (idx == 255)
|
||||
c = 0; // We've gone too far, return
|
||||
|
||||
if (c == 0) {
|
||||
char *result = new char[idx];
|
||||
memcpy(result, decompressed, idx);
|
||||
return result;
|
||||
} else if (c == '.' || c == ',') {
|
||||
if (c == '.')
|
||||
uppercase = 1;
|
||||
decompressed[idx++] = ' ';
|
||||
}
|
||||
}
|
||||
} while (idx < 0xff); // Chosen arbitrarily, might be too small
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
46
engines/glk/scott/decompress_text.h
Normal file
46
engines/glk/scott/decompress_text.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_DECOMPRESSTEXT_H
|
||||
#define GLK_SCOTT_DECOMPRESSTEXT_H
|
||||
|
||||
#include "glk/scott/types.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
char *decompressText(uint8_t *source, int stringIndex);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
915
engines/glk/scott/decompress_z80.cpp
Normal file
915
engines/glk/scott/decompress_z80.cpp
Normal file
@@ -0,0 +1,915 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "common/algorithm.h"
|
||||
#include "common/array.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "glk/scott/decompress_z80.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
/* Sizes of some of the arrays in the snap structure */
|
||||
const int SNAPSHOT_RAM_PAGES = 16;
|
||||
//const int SNAPSHOT_SLT_PAGES = 256;
|
||||
//const int SNAPSHOT_ZXATASP_PAGES = 32;
|
||||
//const int SNAPSHOT_ZXCF_PAGES = 64;
|
||||
//const int SNAPSHOT_DOCK_EXROM_PAGES = 8;
|
||||
//const int SNAPSHOT_JOYSTICKS = 7;
|
||||
//const int SNAPSHOT_DIVIDE_PAGES = 4;
|
||||
|
||||
void *libspectrumReallocN(void *ptr, size_t nmemb, size_t size) {
|
||||
if (nmemb > SIZE_MAX / size)
|
||||
error("libspectrumReallocN: Can't reallocate to required size");
|
||||
|
||||
return realloc(ptr, nmemb * size);
|
||||
}
|
||||
/* Ensure there is room for `requested' characters after the current
|
||||
position `ptr' in `buffer'. If not, renew() and update the
|
||||
pointers as necessary */
|
||||
void libspectrumMakeRoom(uint8_t **dest, size_t requested, uint8_t **ptr,
|
||||
size_t *allocated) {
|
||||
size_t current_length = 0;
|
||||
|
||||
if (*allocated == 0) {
|
||||
|
||||
(*allocated) = requested;
|
||||
*dest = new uint8_t[requested];
|
||||
|
||||
} else {
|
||||
current_length = *ptr - *dest;
|
||||
|
||||
/* If there's already enough room here, just return */
|
||||
if (current_length + requested <= (*allocated))
|
||||
return;
|
||||
|
||||
/* Make the new size the maximum of the new needed size and the
|
||||
old allocated size * 2 */
|
||||
(*allocated) = current_length + requested > 2 * (*allocated)
|
||||
? current_length + requested
|
||||
: 2 * (*allocated);
|
||||
|
||||
*dest = static_cast<uint8_t *>(libspectrumReallocN(*dest, *allocated, sizeof(uint8_t)));
|
||||
}
|
||||
|
||||
/* Update the secondary pointer to the block */
|
||||
*ptr = *dest + current_length;
|
||||
}
|
||||
|
||||
struct LibspectrumSnap {
|
||||
LibspectrumSnap() : pages(SNAPSHOT_RAM_PAGES) {}
|
||||
|
||||
/* Which machine are we using here? */
|
||||
int machine;
|
||||
|
||||
/* Registers and the like */
|
||||
uint16_t pc;
|
||||
|
||||
Common::Array<uint8_t *> pages;
|
||||
};
|
||||
|
||||
/* Error handling */
|
||||
|
||||
/* The various errors which can occur */
|
||||
enum LibspectrumError {
|
||||
|
||||
LIBSPECTRUM_ERROR_NONE = 0,
|
||||
|
||||
LIBSPECTRUM_ERROR_WARNING,
|
||||
LIBSPECTRUM_ERROR_MEMORY,
|
||||
LIBSPECTRUM_ERROR_UNKNOWN,
|
||||
LIBSPECTRUM_ERROR_CORRUPT,
|
||||
LIBSPECTRUM_ERROR_SIGNATURE,
|
||||
LIBSPECTRUM_ERROR_SLT, /* .slt data found at end of a .z80 file */
|
||||
LIBSPECTRUM_ERROR_INVALID, /* Invalid parameter supplied */
|
||||
|
||||
LIBSPECTRUM_ERROR_LOGIC = -1,
|
||||
};
|
||||
|
||||
enum LibspectrumMachine {
|
||||
|
||||
LIBSPECTRUM_MACHINE_48,
|
||||
LIBSPECTRUM_MACHINE_TC2048,
|
||||
LIBSPECTRUM_MACHINE_128,
|
||||
LIBSPECTRUM_MACHINE_PLUS2,
|
||||
LIBSPECTRUM_MACHINE_PENT,
|
||||
LIBSPECTRUM_MACHINE_PLUS2A,
|
||||
LIBSPECTRUM_MACHINE_PLUS3,
|
||||
|
||||
/* Used by libspectrum_tape_guess_hardware if we can't work out what
|
||||
hardware should be used */
|
||||
LIBSPECTRUM_MACHINE_UNKNOWN,
|
||||
|
||||
LIBSPECTRUM_MACHINE_16,
|
||||
LIBSPECTRUM_MACHINE_TC2068,
|
||||
|
||||
LIBSPECTRUM_MACHINE_SCORP,
|
||||
LIBSPECTRUM_MACHINE_PLUS3E,
|
||||
LIBSPECTRUM_MACHINE_SE,
|
||||
|
||||
LIBSPECTRUM_MACHINE_TS2068,
|
||||
LIBSPECTRUM_MACHINE_PENT512,
|
||||
LIBSPECTRUM_MACHINE_PENT1024,
|
||||
LIBSPECTRUM_MACHINE_48_NTSC,
|
||||
|
||||
LIBSPECTRUM_MACHINE_128E,
|
||||
|
||||
};
|
||||
|
||||
enum LibspectrumMachineCapability {
|
||||
LIBSPECTRUM_MACHINE_CAPABILITY_128_MEMORY = (1u << 0),
|
||||
LIBSPECTRUM_MACHINE_CAPABILITY_PLUS3_MEMORY = (1u << 1),
|
||||
LIBSPECTRUM_MACHINE_CAPABILITY_TIMEX_MEMORY = (1u << 2),
|
||||
LIBSPECTRUM_MACHINE_CAPABILITY_SCORP_MEMORY = (1u << 3),
|
||||
LIBSPECTRUM_MACHINE_CAPABILITY_SE_MEMORY = (1u << 4),
|
||||
LIBSPECTRUM_MACHINE_CAPABILITY_PENT512_MEMORY = (1u << 5),
|
||||
LIBSPECTRUM_MACHINE_CAPABILITY_PENT1024_MEMORY = (1u << 6),
|
||||
};
|
||||
|
||||
/* Given a machine type, what features does it have? */
|
||||
int libspectrumMachineCapabilities(LibspectrumMachine type) {
|
||||
int capabilities = 0;
|
||||
|
||||
/* 128K Spectrum-style 0x7ffd memory paging */
|
||||
switch (type) {
|
||||
case LIBSPECTRUM_MACHINE_128:
|
||||
case LIBSPECTRUM_MACHINE_PLUS2:
|
||||
case LIBSPECTRUM_MACHINE_PLUS2A:
|
||||
case LIBSPECTRUM_MACHINE_PLUS3:
|
||||
case LIBSPECTRUM_MACHINE_PLUS3E:
|
||||
case LIBSPECTRUM_MACHINE_128E:
|
||||
case LIBSPECTRUM_MACHINE_PENT:
|
||||
case LIBSPECTRUM_MACHINE_PENT512:
|
||||
case LIBSPECTRUM_MACHINE_PENT1024:
|
||||
case LIBSPECTRUM_MACHINE_SCORP:
|
||||
/* FIXME: SE needs to have this capability to be considered a 128k machine
|
||||
*/
|
||||
case LIBSPECTRUM_MACHINE_SE:
|
||||
capabilities |= LIBSPECTRUM_MACHINE_CAPABILITY_128_MEMORY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* +3 Spectrum-style 0x1ffd memory paging */
|
||||
switch (type) {
|
||||
case LIBSPECTRUM_MACHINE_PLUS2A:
|
||||
case LIBSPECTRUM_MACHINE_PLUS3:
|
||||
case LIBSPECTRUM_MACHINE_PLUS3E:
|
||||
case LIBSPECTRUM_MACHINE_128E:
|
||||
capabilities |= LIBSPECTRUM_MACHINE_CAPABILITY_PLUS3_MEMORY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* T[CS]20[46]8-style 0x00fd memory paging */
|
||||
switch (type) {
|
||||
case LIBSPECTRUM_MACHINE_TC2048:
|
||||
case LIBSPECTRUM_MACHINE_TC2068:
|
||||
case LIBSPECTRUM_MACHINE_TS2068:
|
||||
capabilities |= LIBSPECTRUM_MACHINE_CAPABILITY_TIMEX_MEMORY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Scorpion-style 0x1ffd memory paging */
|
||||
switch (type) {
|
||||
case LIBSPECTRUM_MACHINE_SCORP:
|
||||
capabilities |= LIBSPECTRUM_MACHINE_CAPABILITY_SCORP_MEMORY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* SE-style 0x7ffd and 0x00fd memory paging */
|
||||
switch (type) {
|
||||
case LIBSPECTRUM_MACHINE_SE:
|
||||
capabilities |= LIBSPECTRUM_MACHINE_CAPABILITY_SE_MEMORY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Pentagon 512-style memory paging */
|
||||
switch (type) {
|
||||
case LIBSPECTRUM_MACHINE_PENT512:
|
||||
case LIBSPECTRUM_MACHINE_PENT1024:
|
||||
capabilities |= LIBSPECTRUM_MACHINE_CAPABILITY_PENT512_MEMORY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Pentagon 1024-style memory paging */
|
||||
switch (type) {
|
||||
case LIBSPECTRUM_MACHINE_PENT1024:
|
||||
capabilities |= LIBSPECTRUM_MACHINE_CAPABILITY_PENT1024_MEMORY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
/* Length of the basic .z80 headers */
|
||||
static const int LIBSPECTRUM_Z80_HEADER_LENGTH = 30;
|
||||
|
||||
/* Length of the v2 extensions */
|
||||
#define LIBSPECTRUM_Z80_V2_LENGTH 23
|
||||
|
||||
/* Length of the v3 extensions */
|
||||
#define LIBSPECTRUM_Z80_V3_LENGTH 54
|
||||
|
||||
/* Length of xzx's extensions */
|
||||
#define LIBSPECTRUM_Z80_V3X_LENGTH 55
|
||||
|
||||
/* The constants used for each machine type */
|
||||
enum {
|
||||
|
||||
/* v2 constants */
|
||||
Z80_MACHINE_48_V2 = 0,
|
||||
Z80_MACHINE_48_IF1_V2 = 1,
|
||||
Z80_MACHINE_48_SAMRAM_V2 = 2,
|
||||
Z80_MACHINE_128_V2 = 3,
|
||||
Z80_MACHINE_128_IF1_V2 = 4,
|
||||
|
||||
/* v3 constants */
|
||||
Z80_MACHINE_48 = 0,
|
||||
Z80_MACHINE_48_IF1 = 1,
|
||||
Z80_MACHINE_48_SAMRAM = 2,
|
||||
Z80_MACHINE_48_MGT = 3,
|
||||
Z80_MACHINE_128 = 4,
|
||||
Z80_MACHINE_128_IF1 = 5,
|
||||
Z80_MACHINE_128_MGT = 6,
|
||||
|
||||
/* Extensions */
|
||||
Z80_MACHINE_PLUS3 = 7,
|
||||
Z80_MACHINE_PLUS3_XZX_ERROR = 8,
|
||||
Z80_MACHINE_PENTAGON = 9,
|
||||
Z80_MACHINE_SCORPION = 10,
|
||||
Z80_MACHINE_PLUS2 = 12,
|
||||
Z80_MACHINE_PLUS2A = 13,
|
||||
Z80_MACHINE_TC2048 = 14,
|
||||
Z80_MACHINE_TC2068 = 15,
|
||||
Z80_MACHINE_TS2068 = 128,
|
||||
|
||||
/* The first extension ID; anything here or greater applies to both
|
||||
v2 and v3 files */
|
||||
Z80_MACHINE_FIRST_EXTENSION = Z80_MACHINE_PLUS3,
|
||||
};
|
||||
|
||||
static LibspectrumError readHeader(const uint8_t *buffer, LibspectrumSnap *snap, const uint8_t **data, int *version, int *compressed);
|
||||
|
||||
static LibspectrumError getMachineType(LibspectrumSnap *snap, uint8_t type, uint8_t mgt_type, int version);
|
||||
|
||||
static LibspectrumError getMachineTypeV2(LibspectrumSnap *snap, uint8_t type);
|
||||
|
||||
static LibspectrumError getMachineTypeV3(LibspectrumSnap *snap, uint8_t type, uint8_t mgt_type);
|
||||
|
||||
static LibspectrumError getMachineTypeExtension(LibspectrumSnap *snap, uint8_t type);
|
||||
|
||||
static LibspectrumError readBlocks(const uint8_t *buffer, size_t buffer_length, LibspectrumSnap *snap, int version, int compressed);
|
||||
|
||||
static LibspectrumError readBlock(const uint8_t *buffer, LibspectrumSnap *snap, const uint8_t **next_block, const uint8_t *end, int version, int compressed);
|
||||
|
||||
static LibspectrumError readV1Block(const uint8_t *buffer, int is_compressed, uint8_t **uncompressed, const uint8_t **next_block, const uint8_t *end);
|
||||
|
||||
static LibspectrumError readV2Block(const uint8_t *buffer, uint8_t **block, size_t *length, int *page, const uint8_t **next_block, const uint8_t *end);
|
||||
|
||||
static void uncompressBlock(uint8_t **dest, size_t *dest_length, const uint8_t *src, size_t src_length);
|
||||
|
||||
void libspectrumSnapSetMachine(LibspectrumSnap *snap, int val) {
|
||||
snap->machine = val;
|
||||
}
|
||||
|
||||
uint8_t *libspectrumSnapPages(LibspectrumSnap *snap, int page) {
|
||||
return snap->pages[page];
|
||||
}
|
||||
|
||||
void libspectrumSnapSetPages(LibspectrumSnap *snap, int page, uint8_t *buf) {
|
||||
snap->pages[page] = buf;
|
||||
}
|
||||
|
||||
void libspectrumPrintError(LibspectrumError error) {
|
||||
switch (error) {
|
||||
case LIBSPECTRUM_ERROR_WARNING:
|
||||
warning("warning");
|
||||
break;
|
||||
case LIBSPECTRUM_ERROR_MEMORY:
|
||||
warning("memory error");
|
||||
break;
|
||||
case LIBSPECTRUM_ERROR_UNKNOWN:
|
||||
warning("unknown error");
|
||||
break;
|
||||
case LIBSPECTRUM_ERROR_CORRUPT:
|
||||
warning("corruption error");
|
||||
break;
|
||||
case LIBSPECTRUM_ERROR_SIGNATURE:
|
||||
warning("signature error");
|
||||
break;
|
||||
case LIBSPECTRUM_ERROR_SLT:
|
||||
warning("SLT data in Z80 error");
|
||||
break;
|
||||
case LIBSPECTRUM_ERROR_INVALID:
|
||||
warning("invalid parameter error");
|
||||
break;
|
||||
case LIBSPECTRUM_ERROR_LOGIC:
|
||||
warning("logic error");
|
||||
break;
|
||||
default:
|
||||
warning("unhandled error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int libspectrumSnapMachine(LibspectrumSnap *snap) {
|
||||
return snap->machine;
|
||||
}
|
||||
|
||||
/* Read an LSB dword from buffer */
|
||||
uint32_t libspectrumReadDword(const uint8_t **buffer) {
|
||||
uint32_t value;
|
||||
|
||||
value = (*buffer)[0] + (*buffer)[1] * 0x100 + (*buffer)[2] * 0x10000 + (*buffer)[3] * 0x1000000;
|
||||
|
||||
(*buffer) += 4;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static LibspectrumError getMachineTypeExtension(LibspectrumSnap *snap, uint8_t type) {
|
||||
switch (type) {
|
||||
case Z80_MACHINE_PLUS3:
|
||||
case Z80_MACHINE_PLUS3_XZX_ERROR:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_PLUS3);
|
||||
break;
|
||||
case Z80_MACHINE_PENTAGON:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_PENT);
|
||||
break;
|
||||
case Z80_MACHINE_SCORPION:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_SCORP);
|
||||
break;
|
||||
case Z80_MACHINE_PLUS2:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_PLUS2);
|
||||
break;
|
||||
case Z80_MACHINE_PLUS2A:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_PLUS2A);
|
||||
break;
|
||||
case Z80_MACHINE_TC2048:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_TC2048);
|
||||
break;
|
||||
case Z80_MACHINE_TC2068:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_TC2068);
|
||||
break;
|
||||
case Z80_MACHINE_TS2068:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_TS2068);
|
||||
break;
|
||||
default:
|
||||
libspectrumPrintError(LIBSPECTRUM_ERROR_UNKNOWN);
|
||||
warning("%s:get_machine_type: unknown extension machine type %d", __FILE__, type);
|
||||
return LIBSPECTRUM_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return LIBSPECTRUM_ERROR_NONE;
|
||||
}
|
||||
|
||||
LibspectrumError internalZ80Read(LibspectrumSnap *snap, const uint8_t *buffer, size_t buffer_length);
|
||||
|
||||
uint8_t *decompressZ80(uint8_t *raw_data, size_t length) {
|
||||
LibspectrumSnap *snap = new LibspectrumSnap;
|
||||
for (int i = 0; i < SNAPSHOT_RAM_PAGES; i++)
|
||||
libspectrumSnapSetPages(snap, i, nullptr);
|
||||
|
||||
if (internalZ80Read(snap, raw_data, length) != LIBSPECTRUM_ERROR_NONE) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint8_t *uncompressed = new uint8_t[0xC000];
|
||||
if (uncompressed == nullptr)
|
||||
return nullptr;
|
||||
Common::copy(snap->pages[5], snap->pages[5] + 0x4000, uncompressed);
|
||||
Common::copy(snap->pages[2], snap->pages[2] + 0x4000, uncompressed + 0x4000);
|
||||
Common::copy(snap->pages[0], snap->pages[0] + 0x4000, uncompressed + 0x8000);
|
||||
|
||||
for (int i = 0; i < SNAPSHOT_RAM_PAGES; i++)
|
||||
if (snap->pages[i] != nullptr)
|
||||
delete snap->pages[i];
|
||||
delete snap;
|
||||
|
||||
return uncompressed;
|
||||
}
|
||||
|
||||
LibspectrumError internalZ80Read(LibspectrumSnap *snap, const uint8_t *buffer, size_t buffer_length) {
|
||||
LibspectrumError error;
|
||||
const uint8_t *data;
|
||||
int version, compressed = 1;
|
||||
|
||||
error = readHeader(buffer, snap, &data, &version, &compressed);
|
||||
if (error != LIBSPECTRUM_ERROR_NONE)
|
||||
return error;
|
||||
|
||||
error = readBlocks(data, buffer_length - (data - buffer), snap, version,
|
||||
compressed);
|
||||
if (error != LIBSPECTRUM_ERROR_NONE)
|
||||
return error;
|
||||
|
||||
return LIBSPECTRUM_ERROR_NONE;
|
||||
}
|
||||
|
||||
static LibspectrumError readHeader(const uint8_t *buffer, LibspectrumSnap *snap, const uint8_t **data, int *version, int *compressed) {
|
||||
const uint8_t *header = buffer;
|
||||
LibspectrumError error;
|
||||
|
||||
uint8_t header_6 = header[6];
|
||||
uint8_t header_7 = header[7] * 0x100;
|
||||
snap->pc = header_6 + header_7;
|
||||
|
||||
if (snap->pc == 0) { /* PC == 0x0000 => v2 or greater */
|
||||
|
||||
size_t extra_length;
|
||||
const uint8_t *extra_header;
|
||||
|
||||
extra_length = header[LIBSPECTRUM_Z80_HEADER_LENGTH] + header[LIBSPECTRUM_Z80_HEADER_LENGTH + 1] * 0x100;
|
||||
|
||||
switch (extra_length) {
|
||||
case LIBSPECTRUM_Z80_V2_LENGTH:
|
||||
*version = 2;
|
||||
break;
|
||||
case LIBSPECTRUM_Z80_V3_LENGTH:
|
||||
case LIBSPECTRUM_Z80_V3X_LENGTH:
|
||||
*version = 3;
|
||||
break;
|
||||
default:
|
||||
libspectrumPrintError(LIBSPECTRUM_ERROR_UNKNOWN);
|
||||
warning("libspectrumReadZ80Header: unknown header length %d", (int)extra_length);
|
||||
return LIBSPECTRUM_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
extra_header = buffer + LIBSPECTRUM_Z80_HEADER_LENGTH + 2;
|
||||
|
||||
snap->pc = extra_header[0] + extra_header[1] * 0x100;
|
||||
|
||||
error = getMachineType(snap, extra_header[2], extra_header[51], *version);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (extra_header[5] & 0x80) {
|
||||
|
||||
switch (libspectrumSnapMachine(snap)) {
|
||||
case LIBSPECTRUM_MACHINE_48:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_16);
|
||||
break;
|
||||
case LIBSPECTRUM_MACHINE_128:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_PLUS2);
|
||||
break;
|
||||
case LIBSPECTRUM_MACHINE_PLUS3:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_PLUS2A);
|
||||
break;
|
||||
default:
|
||||
break; /* Do nothing */
|
||||
}
|
||||
}
|
||||
|
||||
(*data) = buffer + LIBSPECTRUM_Z80_HEADER_LENGTH + 2 + extra_length;
|
||||
|
||||
} else { /* v1 .z80 file */
|
||||
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_48);
|
||||
*version = 1;
|
||||
|
||||
/* Need to flag this for later */
|
||||
*compressed = (header[12] & 0x20) ? 1 : 0;
|
||||
|
||||
(*data) = buffer + LIBSPECTRUM_Z80_HEADER_LENGTH;
|
||||
}
|
||||
|
||||
return LIBSPECTRUM_ERROR_NONE;
|
||||
}
|
||||
|
||||
static LibspectrumError getMachineType(LibspectrumSnap *snap, uint8_t type, uint8_t mgt_type, int version) {
|
||||
LibspectrumError error;
|
||||
|
||||
if (type < Z80_MACHINE_FIRST_EXTENSION) {
|
||||
switch (version) {
|
||||
case 2:
|
||||
error = getMachineTypeV2(snap, type);
|
||||
if (error)
|
||||
return error;
|
||||
break;
|
||||
case 3:
|
||||
error = getMachineTypeV3(snap, type, mgt_type);
|
||||
if (error)
|
||||
return error;
|
||||
break;
|
||||
default:
|
||||
libspectrumPrintError(LIBSPECTRUM_ERROR_LOGIC);
|
||||
warning("%s:getMachineType: unknown version %d", __FILE__, version);
|
||||
return LIBSPECTRUM_ERROR_LOGIC;
|
||||
}
|
||||
|
||||
} else {
|
||||
error = getMachineTypeExtension(snap, type);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
return LIBSPECTRUM_ERROR_NONE;
|
||||
}
|
||||
|
||||
static LibspectrumError getMachineTypeV2(LibspectrumSnap *snap, uint8_t type) {
|
||||
switch (type) {
|
||||
case Z80_MACHINE_48_V2:
|
||||
case Z80_MACHINE_48_SAMRAM_V2:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_48);
|
||||
break;
|
||||
case Z80_MACHINE_48_IF1_V2:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_48);
|
||||
break;
|
||||
case Z80_MACHINE_128_V2:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_128);
|
||||
break;
|
||||
case Z80_MACHINE_128_IF1_V2:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_128);
|
||||
break;
|
||||
default:
|
||||
libspectrumPrintError(LIBSPECTRUM_ERROR_UNKNOWN);
|
||||
warning("%s: getMachineType: unknown v2 machine type %d", __FILE__, type);
|
||||
return LIBSPECTRUM_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return LIBSPECTRUM_ERROR_NONE;
|
||||
}
|
||||
|
||||
static LibspectrumError getMachineTypeV3(LibspectrumSnap *snap, uint8_t type, uint8_t mgt_type) {
|
||||
switch (type) {
|
||||
case Z80_MACHINE_48:
|
||||
case Z80_MACHINE_48_SAMRAM:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_48);
|
||||
break;
|
||||
case Z80_MACHINE_48_IF1:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_48);
|
||||
break;
|
||||
case Z80_MACHINE_48_MGT:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_48);
|
||||
break;
|
||||
case Z80_MACHINE_128:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_128);
|
||||
break;
|
||||
case Z80_MACHINE_128_MGT:
|
||||
libspectrumSnapSetMachine(snap, LIBSPECTRUM_MACHINE_128);
|
||||
break;
|
||||
default:
|
||||
libspectrumPrintError(LIBSPECTRUM_ERROR_UNKNOWN);
|
||||
warning("%s:getMachineType: unknown v3 machine type %d", __FILE__, type);
|
||||
return LIBSPECTRUM_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return LIBSPECTRUM_ERROR_NONE;
|
||||
}
|
||||
|
||||
/* Given a 48K memory dump `data', place it into the
|
||||
appropriate bits of `snap' for a 48K machine */
|
||||
LibspectrumError libspectrumSplitTo48kPages(LibspectrumSnap *snap, const uint8_t *data) {
|
||||
uint8_t *buffer[3];
|
||||
size_t i;
|
||||
|
||||
/* If any of the three pages are already occupied, barf */
|
||||
if (libspectrumSnapPages(snap, 5) || libspectrumSnapPages(snap, 2) || libspectrumSnapPages(snap, 0)) {
|
||||
libspectrumPrintError(LIBSPECTRUM_ERROR_LOGIC);
|
||||
warning("libspectrumSplitTo48kPages: RAM page already in use");
|
||||
return LIBSPECTRUM_ERROR_LOGIC;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
buffer[i] = new uint8_t[0x4000];
|
||||
}
|
||||
|
||||
libspectrumSnapSetPages(snap, 5, buffer[0]);
|
||||
libspectrumSnapSetPages(snap, 2, buffer[1]);
|
||||
libspectrumSnapSetPages(snap, 0, buffer[2]);
|
||||
|
||||
/* Finally, do the copies... */
|
||||
Common::copy(&data[0x0000], &data[0x0000] + 0x4000, libspectrumSnapPages(snap, 5));
|
||||
Common::copy(&data[0x4000], &data[0x4000] + 0x4000, libspectrumSnapPages(snap, 2));
|
||||
Common::copy(&data[0x8000], &data[0x8000] + 0x4000, libspectrumSnapPages(snap, 0));
|
||||
|
||||
return LIBSPECTRUM_ERROR_NONE;
|
||||
}
|
||||
|
||||
static LibspectrumError readBlocks(const uint8_t *buffer, size_t buffer_length, LibspectrumSnap *snap, int version, int compressed) {
|
||||
const uint8_t *end, *next_block;
|
||||
|
||||
end = buffer + buffer_length;
|
||||
next_block = buffer;
|
||||
|
||||
while (next_block < end) {
|
||||
LibspectrumError error;
|
||||
error = readBlock(next_block, snap, &next_block, end, version, compressed);
|
||||
if (error != LIBSPECTRUM_ERROR_NONE)
|
||||
return error;
|
||||
}
|
||||
|
||||
return LIBSPECTRUM_ERROR_NONE;
|
||||
}
|
||||
|
||||
static LibspectrumError readBlock(const uint8_t *buffer, LibspectrumSnap *snap, const uint8_t **next_block, const uint8_t *end, int version, int compressed) {
|
||||
LibspectrumError error;
|
||||
uint8_t *uncompressed;
|
||||
|
||||
int capabilities = libspectrumMachineCapabilities(static_cast<LibspectrumMachine>(libspectrumSnapMachine(snap)));
|
||||
|
||||
if (version == 1) {
|
||||
error = readV1Block(buffer, compressed, &uncompressed, next_block, end);
|
||||
if (error != LIBSPECTRUM_ERROR_NONE)
|
||||
return error;
|
||||
|
||||
libspectrumSplitTo48kPages(snap, uncompressed);
|
||||
|
||||
delete[] uncompressed;
|
||||
|
||||
} else {
|
||||
|
||||
size_t length;
|
||||
int page;
|
||||
|
||||
error = readV2Block(buffer, &uncompressed, &length, &page, next_block, end);
|
||||
if (error != LIBSPECTRUM_ERROR_NONE)
|
||||
return error;
|
||||
|
||||
if (page <= 0 || page > 18) {
|
||||
libspectrumPrintError(LIBSPECTRUM_ERROR_UNKNOWN);
|
||||
warning("readBlock: unknown page %d", page);
|
||||
delete[] uncompressed;
|
||||
return LIBSPECTRUM_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
/* If it's a ROM page, just throw it away */
|
||||
if (page < 3) {
|
||||
delete[] uncompressed;
|
||||
return LIBSPECTRUM_ERROR_NONE;
|
||||
}
|
||||
|
||||
/* Page 11 is the Multiface ROM unless we're emulating something
|
||||
Scorpion-like */
|
||||
if (page == 11 && !(capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_SCORP_MEMORY)) {
|
||||
delete[] uncompressed;
|
||||
return LIBSPECTRUM_ERROR_NONE;
|
||||
}
|
||||
|
||||
/* Deal with 48K snaps -- first, throw away page 3, as it's a ROM.
|
||||
Then remap the numbers slightly */
|
||||
if (!(capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_128_MEMORY)) {
|
||||
switch (page) {
|
||||
case 3:
|
||||
delete[] uncompressed;
|
||||
return LIBSPECTRUM_ERROR_NONE;
|
||||
case 4:
|
||||
page = 5;
|
||||
break;
|
||||
case 5:
|
||||
page = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now map onto RAM page numbers */
|
||||
page -= 3;
|
||||
|
||||
if (libspectrumSnapPages(snap, page) == nullptr) {
|
||||
libspectrumSnapSetPages(snap, page, uncompressed);
|
||||
} else {
|
||||
delete[] uncompressed;
|
||||
libspectrumPrintError(LIBSPECTRUM_ERROR_UNKNOWN);
|
||||
warning("readBlock: page %d duplicated", page);
|
||||
return LIBSPECTRUM_ERROR_CORRUPT;
|
||||
}
|
||||
}
|
||||
|
||||
return LIBSPECTRUM_ERROR_NONE;
|
||||
}
|
||||
|
||||
static LibspectrumError readV1Block(const uint8_t *buffer, int is_compressed, uint8_t **uncompressed, const uint8_t **next_block, const uint8_t *end) {
|
||||
if (is_compressed) {
|
||||
const uint8_t *ptr;
|
||||
int state;
|
||||
size_t uncompressed_length = 0;
|
||||
|
||||
state = 0;
|
||||
ptr = buffer;
|
||||
|
||||
while (state != 4) {
|
||||
if (ptr == end) {
|
||||
libspectrumPrintError(LIBSPECTRUM_ERROR_CORRUPT);
|
||||
warning("readV1Block: end marker not found");
|
||||
return LIBSPECTRUM_ERROR_CORRUPT;
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
switch (*ptr++) {
|
||||
case 0x00:
|
||||
state = 1;
|
||||
break;
|
||||
default:
|
||||
state = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
switch (*ptr++) {
|
||||
case 0x00:
|
||||
state = 1;
|
||||
break;
|
||||
case 0xed:
|
||||
state = 2;
|
||||
break;
|
||||
default:
|
||||
state = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch (*ptr++) {
|
||||
case 0x00:
|
||||
state = 1;
|
||||
break;
|
||||
case 0xed:
|
||||
state = 3;
|
||||
break;
|
||||
default:
|
||||
state = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
switch (*ptr++) {
|
||||
case 0x00:
|
||||
state = 4;
|
||||
break;
|
||||
default:
|
||||
state = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
libspectrumPrintError(LIBSPECTRUM_ERROR_LOGIC);
|
||||
warning("readV1Block: unknown state %d", state);
|
||||
return LIBSPECTRUM_ERROR_LOGIC;
|
||||
}
|
||||
}
|
||||
|
||||
/* Length passed here is reduced by 4 to remove the end marker */
|
||||
uncompressBlock(uncompressed, &uncompressed_length, buffer, (ptr - buffer - 4));
|
||||
|
||||
/* Uncompressed data must be exactly 48Kb long */
|
||||
if (uncompressed_length != 0xc000) {
|
||||
delete *uncompressed;
|
||||
libspectrumPrintError(LIBSPECTRUM_ERROR_CORRUPT);
|
||||
warning("readV1Block: data does not uncompress to 48Kb");
|
||||
return LIBSPECTRUM_ERROR_CORRUPT;
|
||||
}
|
||||
|
||||
*next_block = ptr;
|
||||
|
||||
} else { /* Snap isn't compressed */
|
||||
/* Check we've got enough bytes to read */
|
||||
if (end - *next_block < 0xc000) {
|
||||
libspectrumPrintError(LIBSPECTRUM_ERROR_CORRUPT);
|
||||
warning("readV1Block: not enough data in buffer");
|
||||
return LIBSPECTRUM_ERROR_CORRUPT;
|
||||
}
|
||||
|
||||
*uncompressed = new uint8_t[0xC000];
|
||||
Common::copy(buffer, buffer + 0xC000, *uncompressed);
|
||||
*next_block = buffer + 0xc000;
|
||||
}
|
||||
|
||||
return LIBSPECTRUM_ERROR_NONE;
|
||||
}
|
||||
|
||||
/* The signature used to designate the .slt extensions */
|
||||
static uint8_t slt_signature[] = "\0\0\0SLT";
|
||||
static size_t slt_signature_length = 6;
|
||||
|
||||
static LibspectrumError readV2Block(const uint8_t *buffer, uint8_t **block, size_t *length, int *page, const uint8_t **next_block, const uint8_t *end) {
|
||||
size_t length2;
|
||||
length2 = buffer[0] + buffer[1] * 0x100;
|
||||
(*page) = buffer[2];
|
||||
|
||||
if (length2 == 0 && *page == 0) {
|
||||
if (buffer + 8 < end && !memcmp(buffer, slt_signature, slt_signature_length)) {
|
||||
/* Ah, we have what looks like SLT data... */
|
||||
*next_block = buffer + 6;
|
||||
return LIBSPECTRUM_ERROR_SLT;
|
||||
}
|
||||
}
|
||||
|
||||
/* A length of 0xffff => 16384 bytes of uncompressed data */
|
||||
if (length2 != 0xffff) {
|
||||
/* Check we're not going to run over the end of the buffer */
|
||||
if (buffer + 3 + length2 > end) {
|
||||
libspectrumPrintError(LIBSPECTRUM_ERROR_CORRUPT);
|
||||
warning("readV2Block: not enough data in buffer");
|
||||
return LIBSPECTRUM_ERROR_CORRUPT;
|
||||
}
|
||||
|
||||
*length = 0;
|
||||
uncompressBlock(block, length, buffer + 3, length2);
|
||||
*next_block = buffer + 3 + length2;
|
||||
|
||||
} else { /* Uncompressed block */
|
||||
/* Check we're not going to run over the end of the buffer */
|
||||
if (buffer + 3 + 0x4000 > end) {
|
||||
libspectrumPrintError(LIBSPECTRUM_ERROR_CORRUPT);
|
||||
warning("readV2Block: not enough data in buffer");
|
||||
return LIBSPECTRUM_ERROR_CORRUPT;
|
||||
}
|
||||
|
||||
*block = new uint8_t[0x4000];
|
||||
Common::copy(buffer + 3, buffer + 3 + 0x4000, *block);
|
||||
|
||||
*length = 0x4000;
|
||||
*next_block = buffer + 3 + 0x4000;
|
||||
}
|
||||
|
||||
return LIBSPECTRUM_ERROR_NONE;
|
||||
}
|
||||
|
||||
static void uncompressBlock(uint8_t **dest, size_t *dest_length, const uint8_t *src, size_t src_length) {
|
||||
const uint8_t *in_ptr;
|
||||
uint8_t *out_ptr;
|
||||
|
||||
/* Allocate memory for dest if requested */
|
||||
if (*dest_length == 0) {
|
||||
*dest_length = src_length / 2;
|
||||
*dest = new uint8_t[*dest_length];
|
||||
}
|
||||
|
||||
in_ptr = src;
|
||||
out_ptr = *dest;
|
||||
|
||||
while (in_ptr < src + src_length) {
|
||||
/* If we're pointing at the last byte, just copy it across and exit */
|
||||
if (in_ptr == src + src_length - 1) {
|
||||
libspectrumMakeRoom(dest, 1, &out_ptr, dest_length);
|
||||
*out_ptr++ = *in_ptr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we're pointing at two successive 0xed bytes, that's a run. If not, just copy the byte across */
|
||||
if (*in_ptr == 0xed && *(in_ptr + 1) == 0xed) {
|
||||
size_t run_length;
|
||||
uint8_t repeated;
|
||||
|
||||
in_ptr += 2;
|
||||
run_length = *in_ptr++;
|
||||
repeated = *in_ptr++;
|
||||
|
||||
libspectrumMakeRoom(dest, run_length, &out_ptr, dest_length);
|
||||
|
||||
while (run_length--) {
|
||||
*out_ptr++ = repeated;
|
||||
}
|
||||
} else {
|
||||
libspectrumMakeRoom(dest, 1, &out_ptr, dest_length);
|
||||
*out_ptr++ = *in_ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
*dest_length = out_ptr - *dest;
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
47
engines/glk/scott/decompress_z80.h
Normal file
47
engines/glk/scott/decompress_z80.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_DECOMPRESSZ80_H
|
||||
#define GLK_SCOTT_DECOMPRESSZ80_H
|
||||
|
||||
#include "glk/scott/types.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
// Will return nullptr on error or 0xc000 (49152) bytes of uncompressed raw data on success
|
||||
uint8_t *decompressZ80(uint8_t *rawData, size_t length);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
89
engines/glk/scott/definitions.cpp
Normal file
89
engines/glk/scott/definitions.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "glk/scott/definitions.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
GameInfo::GameInfo() {}
|
||||
|
||||
GameInfo::GameInfo(
|
||||
const char *title,
|
||||
GameIDType gameID,
|
||||
GameType type,
|
||||
Subtype subType,
|
||||
DictionaryType dictionary,
|
||||
int numberOfItems,
|
||||
int numberOfActions,
|
||||
int numberOfWords,
|
||||
int numberOfRooms,
|
||||
int maxCarried,
|
||||
int wordLength,
|
||||
int numberOfMessages,
|
||||
int numberOfVerbs,
|
||||
int numberOfNouns,
|
||||
int startOfHeader,
|
||||
HeaderType headerStyle,
|
||||
int startOfRoomImageList,
|
||||
int startOfItemFlags,
|
||||
int startOfItemImageList,
|
||||
int startOfActions,
|
||||
ActionTableType actionsStyle,
|
||||
int startOfDictionary,
|
||||
int startOfRoomDescriptions,
|
||||
int startOfRoomConnections,
|
||||
int startOfMessages,
|
||||
int startOfItemDescriptions,
|
||||
int startOfItemLocations,
|
||||
int startOfSystemMessages,
|
||||
int startOfDirections,
|
||||
int startOfCharacters,
|
||||
int startOfImageData,
|
||||
int imageAddressOffset,
|
||||
int numberOfPictures,
|
||||
PaletteType palette,
|
||||
int pictureFormatVersion,
|
||||
int startOfIntroText)
|
||||
: _title(title), _gameID(gameID), _type(type), _subType(subType), _dictionary(dictionary), _numberOfItems(numberOfItems),
|
||||
_numberOfActions(numberOfActions), _numberOfWords(numberOfWords), _numberOfRooms(numberOfRooms), _maxCarried(maxCarried),
|
||||
_wordLength(wordLength), _numberOfMessages(numberOfMessages), _numberOfVerbs(numberOfVerbs), _numberOfNouns(numberOfNouns),
|
||||
_startOfHeader(startOfHeader), _headerStyle(headerStyle), _startOfRoomImageList(startOfRoomImageList),
|
||||
_startOfItemFlags(startOfItemFlags), _startOfItemImageList(startOfItemImageList), _startOfActions(startOfActions),
|
||||
_actionsStyle(actionsStyle), _startOfDictionary(startOfDictionary), _startOfRoomDescriptions(startOfRoomDescriptions),
|
||||
_startOfRoomConnections(startOfRoomConnections), _startOfMessages(startOfMessages), _startOfItemDescriptions(startOfItemDescriptions),
|
||||
_startOfItemLocations(startOfItemLocations), _startOfSystemMessages(startOfSystemMessages), _startOfDirections(startOfDirections),
|
||||
_startOfCharacters(startOfCharacters), _startOfImageData(startOfImageData), _imageAddressOffset(imageAddressOffset),
|
||||
_numberOfPictures(numberOfPictures), _palette(palette), _pictureFormatVersion(pictureFormatVersion), _startOfIntroText(startOfIntroText) {}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
320
engines/glk/scott/definitions.h
Normal file
320
engines/glk/scott/definitions.h
Normal file
@@ -0,0 +1,320 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_DEFINITIONS_H
|
||||
#define GLK_SCOTT_DEFINITIONS_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
const int FOLLOWS = 0xFFFF;
|
||||
|
||||
const int GO = 1;
|
||||
const int TAKE = 10;
|
||||
const int DROP = 18;
|
||||
|
||||
const int LASTALL = 128;
|
||||
|
||||
enum GameIDType {
|
||||
UNKNOWN_GAME,
|
||||
SCOTTFREE,
|
||||
TI994A,
|
||||
PIRATE,
|
||||
VOODOO,
|
||||
STRANGE,
|
||||
BANZAI,
|
||||
BATON,
|
||||
BATON_C64,
|
||||
TIME_MACHINE,
|
||||
TIME_MACHINE_C64,
|
||||
ARROW1,
|
||||
ARROW1_C64,
|
||||
ARROW2,
|
||||
ARROW2_C64,
|
||||
PULSAR7,
|
||||
PULSAR7_C64,
|
||||
CIRCUS,
|
||||
CIRCUS_C64,
|
||||
FEASIBILITY,
|
||||
FEASIBILITY_C64,
|
||||
AKYRZ,
|
||||
AKYRZ_C64,
|
||||
PERSEUS,
|
||||
PERSEUS_C64,
|
||||
PERSEUS_ITALIAN,
|
||||
INDIANS,
|
||||
INDIANS_C64,
|
||||
WAXWORKS,
|
||||
WAXWORKS_C64,
|
||||
HULK,
|
||||
HULK_C64,
|
||||
ADVENTURELAND,
|
||||
ADVENTURELAND_C64,
|
||||
SECRET_MISSION,
|
||||
SECRET_MISSION_C64,
|
||||
CLAYMORGUE,
|
||||
CLAYMORGUE_C64,
|
||||
SPIDERMAN,
|
||||
SPIDERMAN_C64,
|
||||
SAVAGE_ISLAND,
|
||||
SAVAGE_ISLAND_C64,
|
||||
SAVAGE_ISLAND2,
|
||||
SAVAGE_ISLAND2_C64,
|
||||
GREMLINS,
|
||||
GREMLINS_ALT,
|
||||
GREMLINS_C64,
|
||||
GREMLINS_GERMAN,
|
||||
GREMLINS_GERMAN_C64,
|
||||
GREMLINS_SPANISH,
|
||||
SUPERGRAN,
|
||||
SUPERGRAN_C64,
|
||||
ROBIN_OF_SHERWOOD,
|
||||
ROBIN_OF_SHERWOOD_C64,
|
||||
SEAS_OF_BLOOD,
|
||||
SEAS_OF_BLOOD_C64,
|
||||
NUMGAMES
|
||||
};
|
||||
|
||||
enum ExplicitResultType {
|
||||
ER_NO_RESULT,
|
||||
ER_SUCCESS = 0,
|
||||
ER_RAN_ALL_LINES_NO_MATCH = -1,
|
||||
ER_RAN_ALL_LINES = -2
|
||||
};
|
||||
|
||||
enum ActionResultType {
|
||||
ACT_SUCCESS = 0,
|
||||
ACT_FAILURE = 1,
|
||||
ACT_CONTINUE,
|
||||
ACT_GAMEOVER
|
||||
};
|
||||
|
||||
enum SysMessageType {
|
||||
NORTH,
|
||||
SOUTH,
|
||||
EAST,
|
||||
WEST,
|
||||
UP,
|
||||
DOWN,
|
||||
PLAY_AGAIN,
|
||||
IVE_STORED,
|
||||
TREASURES,
|
||||
ON_A_SCALE_THAT_RATES,
|
||||
DROPPED,
|
||||
TAKEN,
|
||||
OK,
|
||||
YOUVE_SOLVED_IT,
|
||||
I_DONT_UNDERSTAND,
|
||||
YOU_CANT_DO_THAT_YET,
|
||||
HUH,
|
||||
DIRECTION,
|
||||
YOU_HAVENT_GOT_IT,
|
||||
YOU_HAVE_IT,
|
||||
YOU_DONT_SEE_IT,
|
||||
THATS_BEYOND_MY_POWER,
|
||||
DANGEROUS_TO_MOVE_IN_DARK,
|
||||
YOU_FELL_AND_BROKE_YOUR_NECK,
|
||||
YOU_CANT_GO_THAT_WAY,
|
||||
I_DONT_KNOW_HOW_TO,
|
||||
SOMETHING,
|
||||
I_DONT_KNOW_WHAT_A,
|
||||
IS,
|
||||
TOO_DARK_TO_SEE,
|
||||
YOU_ARE,
|
||||
YOU_SEE,
|
||||
EXITS,
|
||||
INVENTORY,
|
||||
NOTHING,
|
||||
WHAT_NOW,
|
||||
HIT_ENTER,
|
||||
LIGHT_HAS_RUN_OUT,
|
||||
LIGHT_RUNS_OUT_IN,
|
||||
TURNS,
|
||||
YOURE_CARRYING_TOO_MUCH,
|
||||
IM_DEAD,
|
||||
RESUME_A_SAVED_GAME,
|
||||
NONE,
|
||||
NOTHING_HERE_TO_TAKE,
|
||||
YOU_HAVE_NOTHING,
|
||||
LIGHT_GROWING_DIM,
|
||||
EXITS_DELIMITER,
|
||||
MESSAGE_DELIMITER,
|
||||
ITEM_DELIMITER,
|
||||
WHAT,
|
||||
YES,
|
||||
NO,
|
||||
ANSWER_YES_OR_NO,
|
||||
ARE_YOU_SURE,
|
||||
MOVE_UNDONE,
|
||||
CANT_UNDO_ON_FIRST_TURN,
|
||||
NO_UNDO_STATES,
|
||||
SAVED,
|
||||
CANT_USE_ALL,
|
||||
TRANSCRIPT_OFF,
|
||||
TRANSCRIPT_ON,
|
||||
NO_TRANSCRIPT,
|
||||
TRANSCRIPT_ALREADY,
|
||||
FAILED_TRANSCRIPT,
|
||||
TRANSCRIPT_START,
|
||||
TRANSCRIPT_END,
|
||||
BAD_DATA,
|
||||
STATE_SAVED,
|
||||
STATE_RESTORED,
|
||||
NO_SAVED_STATE,
|
||||
LAST_SYSTEM_MESSAGE
|
||||
};
|
||||
|
||||
const SysMessageType MAX_SYSMESS = LAST_SYSTEM_MESSAGE;
|
||||
|
||||
enum DictionaryType {
|
||||
NOT_A_GAME,
|
||||
FOUR_LETTER_UNCOMPRESSED,
|
||||
THREE_LETTER_UNCOMPRESSED,
|
||||
FIVE_LETTER_UNCOMPRESSED,
|
||||
FOUR_LETTER_COMPRESSED,
|
||||
FIVE_LETTER_COMPRESSED,
|
||||
GERMAN,
|
||||
SPANISH,
|
||||
ITALIAN
|
||||
};
|
||||
|
||||
enum GameType {
|
||||
NO_TYPE,
|
||||
GREMLINS_VARIANT,
|
||||
SHERWOOD_VARIANT,
|
||||
SAVAGE_ISLAND_VARIANT,
|
||||
SECRET_MISSION_VARIANT,
|
||||
SEAS_OF_BLOOD_VARIANT,
|
||||
OLD_STYLE,
|
||||
};
|
||||
|
||||
enum Subtype {
|
||||
ENGLISH = 0x1,
|
||||
MYSTERIOUS = 0x2,
|
||||
LOCALIZED = 0x4,
|
||||
C64 = 0x8
|
||||
};
|
||||
|
||||
enum PaletteType {
|
||||
NO_PALETTE,
|
||||
ZX,
|
||||
ZXOPT,
|
||||
C64A,
|
||||
C64B,
|
||||
VGA
|
||||
};
|
||||
|
||||
enum HeaderType {
|
||||
NO_HEADER,
|
||||
EARLY,
|
||||
LATE,
|
||||
HULK_HEADER,
|
||||
GREMLINS_C64_HEADER,
|
||||
ROBIN_C64_HEADER,
|
||||
SUPERGRAN_C64_HEADER,
|
||||
SEAS_OF_BLOOD_C64_HEADER,
|
||||
MYSTERIOUS_C64_HEADER,
|
||||
ARROW_OF_DEATH_PT_2_C64_HEADER,
|
||||
INDIANS_C64_HEADER
|
||||
};
|
||||
|
||||
enum ActionTableType {
|
||||
UNKNOWN_ACTIONS_TYPE,
|
||||
COMPRESSED,
|
||||
UNCOMPRESSED,
|
||||
HULK_ACTIONS
|
||||
};
|
||||
|
||||
struct GameInfo {
|
||||
GameInfo();
|
||||
GameInfo(const char *title, GameIDType gameID, GameType type, Subtype subType, DictionaryType dictionary,
|
||||
int numberOfItems, int numberOfActions, int numberOfWords, int numberOfRooms, int maxCarried,
|
||||
int wordLength, int numberOfMessages, int numberOfVerbs, int numberOfNouns, int startOfHeader,
|
||||
HeaderType headerStyle, int startOfRoomImageList, int startOfItemFlags, int startOfItemImageList,
|
||||
int startOfActions, ActionTableType actionsStyle, int startOfDictionary, int startOfRoomDescriptions,
|
||||
int startOfRoomConnections, int startOfMessages, int startOfItemDescriptions, int startOfItemLocations,
|
||||
int startOfSystemMessages, int startOfDirections, int startOfCharacters, int startOfImageData,
|
||||
int imageAddressOffset, int numberOfPictures, PaletteType palette, int pictureFormatVersion,
|
||||
int startOfIntroText);
|
||||
const char *_title;
|
||||
|
||||
GameIDType _gameID = UNKNOWN_GAME;
|
||||
GameType _type = NO_TYPE;
|
||||
Subtype _subType = ENGLISH;
|
||||
DictionaryType _dictionary = NOT_A_GAME;
|
||||
|
||||
int _numberOfItems = 0;
|
||||
int _numberOfActions = 0;
|
||||
int _numberOfWords = 0;
|
||||
int _numberOfRooms = 0;
|
||||
int _maxCarried = 0;
|
||||
int _wordLength = 0;
|
||||
int _numberOfMessages = 0;
|
||||
|
||||
int _numberOfVerbs = 0;
|
||||
int _numberOfNouns = 0;
|
||||
|
||||
int _startOfHeader = 0;
|
||||
HeaderType _headerStyle = NO_HEADER;
|
||||
|
||||
int _startOfRoomImageList = 0;
|
||||
int _startOfItemFlags = 0;
|
||||
int _startOfItemImageList = 0;
|
||||
|
||||
int _startOfActions = 0;
|
||||
ActionTableType _actionsStyle = UNKNOWN_ACTIONS_TYPE;
|
||||
int _startOfDictionary = 0;
|
||||
int _startOfRoomDescriptions = 0;
|
||||
int _startOfRoomConnections = 0;
|
||||
int _startOfMessages = 0;
|
||||
int _startOfItemDescriptions = 0;
|
||||
int _startOfItemLocations = 0;
|
||||
|
||||
int _startOfSystemMessages = 0;
|
||||
int _startOfDirections = 0;
|
||||
|
||||
int _startOfCharacters = 0;
|
||||
int _startOfImageData = 0;
|
||||
int _imageAddressOffset = 0; /* This is the difference between the value given by
|
||||
the image data lookup table and a usable file
|
||||
offset */
|
||||
int _numberOfPictures = 0;
|
||||
PaletteType _palette = NO_PALETTE;
|
||||
int _pictureFormatVersion = 0;
|
||||
int _startOfIntroText = 0;
|
||||
};
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
#endif /* definitions_h */
|
||||
127
engines/glk/scott/detection.cpp
Normal file
127
engines/glk/scott/detection.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "common/file.h"
|
||||
#include "common/md5.h"
|
||||
#include "engines/game.h"
|
||||
#include "glk/blorb.h"
|
||||
#include "glk/scott/detection.h"
|
||||
#include "glk/scott/detection_tables.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void ScottMetaEngine::getSupportedGames(PlainGameList &games) {
|
||||
for (const PlainGameDescriptor *pd = SCOTT_GAME_LIST; pd->gameId; ++pd)
|
||||
games.push_back(*pd);
|
||||
}
|
||||
|
||||
const GlkDetectionEntry* ScottMetaEngine::getDetectionEntries() {
|
||||
return SCOTT_GAMES;
|
||||
}
|
||||
|
||||
GameDescriptor ScottMetaEngine::findGame(const char *gameId) {
|
||||
for (const PlainGameDescriptor *pd = SCOTT_GAME_LIST; pd->gameId; ++pd) {
|
||||
if (!strcmp(gameId, pd->gameId))
|
||||
return *pd;
|
||||
}
|
||||
|
||||
return GameDescriptor::empty();
|
||||
}
|
||||
|
||||
bool ScottMetaEngine::detectGames(const Common::FSList &fslist, DetectedGames &gameList) {
|
||||
const char *const EXTENSIONS[] = {".z80", ".saga", ".dat", ".D64", ".T64", "fiad", nullptr};
|
||||
|
||||
// Loop through the files of the folder
|
||||
for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
|
||||
// Check for a recognised filename
|
||||
if (file->isDirectory())
|
||||
continue;
|
||||
|
||||
Common::String filename = file->getName();
|
||||
bool hasExt = Blorb::hasBlorbExt(filename), isBlorb = false;
|
||||
for (const char *const *ext = &EXTENSIONS[0]; *ext && !hasExt; ++ext)
|
||||
hasExt = filename.hasSuffixIgnoreCase(*ext);
|
||||
if (!hasExt)
|
||||
continue;
|
||||
|
||||
Common::File gameFile;
|
||||
if (!gameFile.open(*file))
|
||||
continue;
|
||||
Common::String md5;
|
||||
if (filename.hasSuffixIgnoreCase(".D64"))
|
||||
md5 = Common::computeStreamMD5AsString(gameFile);
|
||||
else
|
||||
md5 = Common::computeStreamMD5AsString(gameFile, 5000);
|
||||
|
||||
size_t filesize = (size_t)gameFile.size();
|
||||
gameFile.seek(0);
|
||||
isBlorb = Blorb::isBlorb(gameFile, ID_SAAI);
|
||||
gameFile.close();
|
||||
|
||||
if (!isBlorb && Blorb::hasBlorbExt(filename))
|
||||
continue;
|
||||
|
||||
// Scan through the Scott game list for a match
|
||||
const GlkDetectionEntry *p = SCOTT_GAMES;
|
||||
while (p->_md5 && (p->_filesize != filesize || md5 != p->_md5))
|
||||
++p;
|
||||
|
||||
if (!p->_gameId) {
|
||||
|
||||
// ignore possible variants for common extensions to prevent flooding in mass-add
|
||||
if (!isBlorb && (filename.hasSuffixIgnoreCase(".z80") || filename.hasSuffixIgnoreCase(".dat") ||
|
||||
filename.hasSuffixIgnoreCase(".d64") || filename.hasSuffixIgnoreCase(".t64")))
|
||||
continue;
|
||||
|
||||
const PlainGameDescriptor &desc = SCOTT_GAME_LIST[0];
|
||||
gameList.push_back(GlkDetectedGame(desc.gameId, desc.description, filename, md5, filesize));
|
||||
} else {
|
||||
// Found a match
|
||||
PlainGameDescriptor gameDesc = findGame(p->_gameId);
|
||||
gameList.push_back(GlkDetectedGame(p->_gameId, gameDesc.description, filename, p->_language, p->_platform));
|
||||
}
|
||||
}
|
||||
|
||||
return !gameList.empty();
|
||||
}
|
||||
|
||||
void ScottMetaEngine::detectClashes(Common::StringMap &map) {
|
||||
for (const PlainGameDescriptor *pd = SCOTT_GAME_LIST; pd->gameId; ++pd) {
|
||||
if (map.contains(pd->gameId))
|
||||
error("ScottMetaEngine::detectClashes: Duplicate game Id found - %s", pd->gameId);
|
||||
map[pd->gameId] = "";
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
75
engines/glk/scott/detection.h
Normal file
75
engines/glk/scott/detection.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_DETECTION_H
|
||||
#define GLK_SCOTT_DETECTION_H
|
||||
|
||||
#include "common/fs.h"
|
||||
#include "common/hash-str.h"
|
||||
#include "engines/game.h"
|
||||
#include "glk/detection.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
class ScottMetaEngine {
|
||||
public:
|
||||
/**
|
||||
* Get a list of supported games
|
||||
*/
|
||||
static void getSupportedGames(PlainGameList &games);
|
||||
|
||||
/**
|
||||
* Get the detection entries
|
||||
*/
|
||||
static const GlkDetectionEntry* getDetectionEntries();
|
||||
|
||||
/**
|
||||
* Returns a game description for the given game Id, if it's supported
|
||||
*/
|
||||
static GameDescriptor findGame(const char *gameId);
|
||||
|
||||
/**
|
||||
* Detect supported games
|
||||
*/
|
||||
static bool detectGames(const Common::FSList &fslist, DetectedGames &gameList);
|
||||
|
||||
/**
|
||||
* Check for game Id clashes with other sub-engines
|
||||
*/
|
||||
static void detectClashes(Common::StringMap &map);
|
||||
};
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
291
engines/glk/scott/detection_tables.h
Normal file
291
engines/glk/scott/detection_tables.h
Normal file
@@ -0,0 +1,291 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
|
||||
#include "common/language.h"
|
||||
#include "engines/game.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
const PlainGameDescriptor SCOTT_GAME_LIST[] = {
|
||||
{ "scottadams", "Scott Adams IF Game" },
|
||||
|
||||
// Scott Adams games
|
||||
{ "adventureland", "Adventureland" },
|
||||
{ "pirateadventure", "Pirate Adventure" },
|
||||
{ "missionimpossible", "Mission Impossible" },
|
||||
{ "voodoocastle", "Voodoo Castle" },
|
||||
{ "thecount", "The Count" },
|
||||
{ "strangeodyssey", "Strange Odyssey" },
|
||||
{ "mysteryfunhouse", "Mystery Fun House" },
|
||||
{ "pyramidofdoom", "Pyramid Of Doom" },
|
||||
{ "ghosttown_sa", "Ghost Town (by Scott Adams)" },
|
||||
{ "savageisland", "Savage Island" },
|
||||
{ "savageisland1", "Savage Island, Part 1" },
|
||||
{ "savageisland2", "Savage Island, Part 2" },
|
||||
{ "goldenvoyage", "The Golden Voyage" },
|
||||
{ "claymorguesorcerer", "Sorcerer of Claymorgue Castle" },
|
||||
{ "pirateisle", "Return to Pirate Isle" },
|
||||
{ "buckaroobanzai", "Buckaroo Banzai" },
|
||||
{ "marveladventure", "Marvel Adventure #1" },
|
||||
{ "marveladventure2", "Marvel Adventure #2" },
|
||||
{ "scottsampler", "Adventure International's Mini-Adventure Sampler" },
|
||||
{ "robinofsherwood", "Robin Of Sherwood" },
|
||||
|
||||
// 11 Mysterious Adventures by Brian Howarth
|
||||
{ "goldenbaton", "Mysterious Adventures 1: The Golden Baton" },
|
||||
{ "timemachine", "Mysterious Adventures 2: The Time Machine" },
|
||||
{ "arrowofdeath1", "Mysterious Adventures 3: Arrow of Death Part 1" },
|
||||
{ "arrowofdeath2", "Mysterious Adventures 4: Arrow of Death Part 2" },
|
||||
{ "pulsar7", "Mysterious Adventures 5: Escape from Pulsar 7" },
|
||||
{ "circus", "Mysterious Adventures 6: Circus" },
|
||||
{ "feasibility", "Mysterious Adventures 7: Feasibility Experiment" },
|
||||
{ "akyrz", "Mysterious Adventures 8: The Wizard of Akyrz" },
|
||||
{ "perseus", "Mysterious Adventures 9: Perseus and Andromeda" },
|
||||
{ "10indians", "Mysterious Adventures 10: Ten Little Indians" },
|
||||
{ "waxworks11", "Mysterious Adventures 11: Waxworks" },
|
||||
{ "mysadv1", "11 Mysterious Adventures - Disk 1" },
|
||||
{ "mysadv2", "11 Mysterious Adventures - Disk 2" },
|
||||
|
||||
// Home Brew TI99 Games
|
||||
{ "advocadoadv", "The Great Advocado Adventure" },
|
||||
{ "matildadilemma", "Matilda's Dilemma" },
|
||||
{ "escapecannibal", "Escape from Cannibal Island" },
|
||||
{ "captkiddmystery", "Mystery of Captain Kidd" },
|
||||
{ "advscott", "Adventure, Colossal Cave (adaptation)" },
|
||||
{ "advscottmaster", "Adventure, Colossal Cave (adaptation) - Masters Game" },
|
||||
{ "computorama", "Computorama" },
|
||||
{ "escapealcatraz", "Escape from Alcatraz" },
|
||||
{ "gerryplace", "Gerry's Place" },
|
||||
{ "grayelftomb", "Tomb of the Gray Elf" },
|
||||
{ "knightiron", "Knight Ironheart" },
|
||||
{ "moonadv", "Moon Adventure" },
|
||||
{ "nessy", "Nessy" },
|
||||
{ "travelling", "Travelling" },
|
||||
|
||||
// Other Games
|
||||
{ "desert", "Desert Adventure" },
|
||||
{ "jamesbondadv", "James Bond Adventure" },
|
||||
{ "burglarsadv", "Burglar's Adventure" },
|
||||
{ "underseaconquest", "Undersea Conquest part 1" },
|
||||
{ "gammaworld", "Gamma World" },
|
||||
{ "marooned_kw", "Marooned (by Kim Watt)" },
|
||||
{ "minersadv", "Miner's Adventure" },
|
||||
{ "romulanadv", "Romulan Adventure" },
|
||||
{ "topsecretadv", "Top Secret Adventure" },
|
||||
{ "gremlins", "Gremlins" },
|
||||
{ "seasofblood", "Seas Of Blood" },
|
||||
{ "supergran", "Super Gran" },
|
||||
{ "ghostking", "Ghost King" },
|
||||
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
const GlkDetectionEntry SCOTT_GAMES[] = {
|
||||
// PC game versions
|
||||
DT_ENTRY0("adventureland", "7c6f495d757a54e73d259efc718d8024", 15896),
|
||||
DT_ENTRY0("pirateadventure", "ea535fa7684508410151b4561de1f323", 16325),
|
||||
DT_ENTRY0("missionimpossible", "379c77a9a483886366b3b5c425e56410", 15275),
|
||||
DT_ENTRY0("voodoocastle", "a530a6857d1092eaa177eee575c94c71", 15852),
|
||||
DT_ENTRY0("thecount", "5ebb4ade985670bb2eac54f8fa202214", 17476),
|
||||
DT_ENTRY0("strangeodyssey", "c57bb6df04dc77a2b232bc5bcab6e417", 17489),
|
||||
DT_ENTRY0("mysteryfunhouse", "ce2931ac3d5cbc270a5cb7be9e614f6e", 17165),
|
||||
DT_ENTRY0("pyramidofdoom", "4e6127fad6b5d75eccd3f3b101f8c9c8", 17673),
|
||||
DT_ENTRY0("ghosttown_sa", "2c08327ab06d5490bd9e367ddaeca627", 17831),
|
||||
DT_ENTRY0("savageisland1", "8feb77f11d32e9567ce2fc7d435eaf44", 19533),
|
||||
DT_ENTRY0("savageisland2", "20c40a349f7a214ac515fb1d63c30a87", 18367),
|
||||
DT_ENTRY0("goldenvoyage", "e2a8f956ab215012d1495550c4c11ee8", 18513),
|
||||
DT_ENTRY0("claymorguesorcerer","f986d7e1ee074f65b6c1d00461c9b3c3", 19232),
|
||||
DT_ENTRY0("pirateisle", "6d98f422cc986d959a3c74351785aea3", 19013),
|
||||
DT_ENTRY0("buckaroobanzai", "ee2c7139d58423c5e25dd918fcb48383", 17989),
|
||||
DT_ENTRY0("marveladventure", "aadcc04e6b37eb9d30a58b5bc775842e", 18876),
|
||||
DT_ENTRY0("marveladventure2", "f7e772643a24eaf94cfb2d48e3949ec1", 18643),
|
||||
DT_ENTRY0("scottsampler", "d569a769f304dc02b3062d97458ddd01", 13854),
|
||||
|
||||
// PDA game versions
|
||||
DT_ENTRY0("adventureland", "ae541fc1085da2f7d561b72ed20a6bc1", 18003),
|
||||
DT_ENTRY0("pirateadventure", "cbd47ab4fcfe00231ffd71d52378d410", 18482),
|
||||
DT_ENTRY0("missionimpossible", "9251ab2c64e63559d8a6e9e6246760a5", 17227),
|
||||
DT_ENTRY0("voodoocastle", "be849c5747c7fc3b201984afb4403b8e", 18140),
|
||||
DT_ENTRY0("thecount", "85b75b6079b5ee572b5259b29a0e5d21", 19999),
|
||||
DT_ENTRY0("strangeodyssey", "c423cae841ac1927b5b2e503607b21bc", 20115),
|
||||
DT_ENTRY0("mysteryfunhouse", "326b98b991d401605074e64d474ce566", 19700),
|
||||
DT_ENTRY0("pyramidofdoom", "8ef9010399f055da9adb15ce7745a11c", 20320),
|
||||
DT_ENTRY0("ghosttown", "fcdcca8b2acf76ba2d0006cefa3630a1", 20687),
|
||||
DT_ENTRY0("savageisland1", "c8aaa80f07c40fa8e4b17432644919dc", 22669),
|
||||
DT_ENTRY0("savageisland2", "2add0f28d9b236c866890cdf8d86ee60", 21169),
|
||||
DT_ENTRY0("goldenvoyage", "675126bd0477e8ed9230ad3db5afc45f", 21401),
|
||||
DT_ENTRY0("claymorguesorcerer","0ef0def798d895ed766041fa99dd28a0", 22346),
|
||||
DT_ENTRY0("pirateisle", "0bf1bcc649422798332a38c88588fdff", 22087),
|
||||
DT_ENTRY0("buckaroobanzai", "a0a5423967287dae9cbeb9abe8324479", 21038),
|
||||
|
||||
// 11 Mysterious Adventures
|
||||
DT_ENTRY0("goldenbaton", "2ebf7b1dd515aff34b99b40f27af00e3", 13373),
|
||||
DT_ENTRY0("timemachine", "a10cde2063bb56694000013b32dc0798", 13742),
|
||||
DT_ENTRY0("arrowofdeath1", "6f7040fe091eeb9ebdc2fd7533b94ceb", 13412),
|
||||
DT_ENTRY0("arrowofdeath2", "c5758034b83b06258e46091a80abebde", 15554),
|
||||
DT_ENTRY0("pulsar7", "7597704b423c1ca2bea3a48263b5f4dc", 17777),
|
||||
DT_ENTRY0("circus", "93a7947e2edb7c45036446168b427546", 13621),
|
||||
DT_ENTRY0("feasibility", "c8f423a79ad0e508f43ba4ce91f1e573", 13441),
|
||||
DT_ENTRY0("akyrz", "645c089d6d66324472d939993793eb57", 16803),
|
||||
DT_ENTRY0("perseus", "2f5bb15b461fbdc000243acabd324c67", 15080),
|
||||
DT_ENTRY0("10indians", "3bb85fd505b4d42bd1767c1a76347e2f", 14215),
|
||||
DT_ENTRY0("waxworks11", "af134c32cc0d50329d6e7335639ded88", 16068),
|
||||
DT_ENTRY0("goldenbaton", "028303fd062c39b59b28982cde75f085", 53374),
|
||||
DT_ENTRY0("timemachine", "b2ff405412d92b06373d9a5efbb048d4", 54062),
|
||||
DT_ENTRY0("arrowofdeath1", "f11f85802eff8aed9e212aef7f26ede1", 68150),
|
||||
DT_ENTRY0("arrowofdeath2", "8f2609b1270248c93cdf254435f9d410", 77544),
|
||||
DT_ENTRY0("pulsar7", "72e14dbfca7ced5c0aadf019b47b4024", 55516),
|
||||
DT_ENTRY0("circus", "64d44e66c4f5353150f8fbaceaa99800", 48624),
|
||||
DT_ENTRY0("feasibility", "2d717aa4f0eba77b77e259f81f92fc37", 78456),
|
||||
DT_ENTRY0("akyrz", "3467e09eb247c474ae7e8a8d503968d0", 65008),
|
||||
DT_ENTRY0("perseus", "4d8389c0ea3425bd4d92492538f63b19", 56914),
|
||||
DT_ENTRY0("10indians", "72e91da7590138b78d370a3cb1448f3c", 64660),
|
||||
DT_ENTRY0("waxworks11", "4d4ee8aa1f24e1745ab1aa017590dcff", 54556),
|
||||
|
||||
// Other games
|
||||
DT_ENTRY0("desert", "c43e19228bae08eab74bc080e17bbe16", 12287),
|
||||
DT_ENTRY0("jamesbondadv", "5c59396a2db040148a5d86beb37b2bb9", 12405),
|
||||
DT_ENTRY0("burglarsadv", "0072d8afcd30aa1577350dcfad269e47", 11541),
|
||||
DT_ENTRY0("underseaconquest", "d57705f8f17f0b6044a575accf9cbfd1", 5616),
|
||||
DT_ENTRY0("gammaworld", "b980c44e8a49aa9d71e92f6b6bf1d136", 11531),
|
||||
DT_ENTRY0("marooned_kw", "a1ac54630a0583c19269901ec10cd0b1", 12576),
|
||||
DT_ENTRY0("minersadv", "0000d9da5a13701601fb3e7399daa128", 11898),
|
||||
DT_ENTRY0("romulanadv", "d97b5cb5ed66eb276ef9f1c1bae0b8dd", 13959),
|
||||
DT_ENTRY0("topsecretadv", "effb411e74dfe3a8d69b57b9bc3a2cef", 15575),
|
||||
DT_ENTRY0("ghostking", "28d433d9f5d2de99dac460c5e1dfa9c5", 14206),
|
||||
|
||||
// ZX Spectrum games
|
||||
DT_ENTRYP1("marveladventure", "ZXSpectrum", "0eec511d3cde815c73e5464ab0cdbef9", 40727, Common::kPlatformZX),
|
||||
|
||||
// 11 Mysterious Adventures
|
||||
DT_ENTRYP1("goldenbaton", "ZXSpectrum", "cb7dadc9d5f8bce453b9139265e4dd7d", 32060, Common::kPlatformZX),
|
||||
DT_ENTRYP1("timemachine", "ZXSpectrum", "b22d1f4d46c99ff4443d541d3fe424c1", 30928, Common::kPlatformZX),
|
||||
DT_ENTRYP1("arrowofdeath1", "ZXSpectrum", "3a5c3f4079c1c0347f03420db8ad4596", 34105, Common::kPlatformZX),
|
||||
DT_ENTRYP1("arrowofdeath2", "ZXSpectrum", "d3f8943c4f5f71ce00139065055a72ee", 38043, Common::kPlatformZX),
|
||||
DT_ENTRYP1("pulsar7", "ZXSpectrum", "441edd90fc7f9ff39a5eebe035a974e9", 29961, Common::kPlatformZX),
|
||||
DT_ENTRYP1("circus", "ZXSpectrum", "ed99306a2fb23bf6579068a4d74034ee", 27746, Common::kPlatformZX),
|
||||
DT_ENTRYP1("feasibility", "ZXSpectrum", "5e381e83f15d77e3542be4a4cffc8e25", 37395, Common::kPlatformZX),
|
||||
DT_ENTRYP1("akyrz", "ZXSpectrum", "b0f8676817475753f1edd7f1eeea31fb", 33753, Common::kPlatformZX),
|
||||
DT_ENTRYP1("perseus", "ZXSpectrum", "84d5fbb16a37e495abf09d191fd8b1a2", 31504, Common::kPlatformZX),
|
||||
DT_ENTRYP1("10indians", "ZXSpectrum", "afde056c152de79ea20453c42a2d08af", 31664, Common::kPlatformZX),
|
||||
DT_ENTRYP1("waxworks11", "ZXSpectrum", "6c6fbbbb50032463a6ea71c6750ea1f5", 32662, Common::kPlatformZX),
|
||||
|
||||
// C64 Games
|
||||
DT_ENTRYP1("robinofsherwood", "C64", "10109d9776b9372f9c768b53a664b113", 174848, Common::kPlatformC64),
|
||||
DT_ENTRYP1("robinofsherwood", "C64", "552c95ec15d750cbfa02c1f11dcbca1e", 36278, Common::kPlatformC64),
|
||||
DT_ENTRYP1("robinofsherwood", "C64", "4262f85382d1bc3b8924a1929511a558", 45807, Common::kPlatformC64),
|
||||
DT_ENTRYP1("robinofsherwood", "C64", "bf3a4d72cff5ef97bebce6b12c756df2", 46736, Common::kPlatformC64),
|
||||
DT_ENTRYP1("gremlins", "C64", "33c920f7ba150dfa1a832d510eebd8fe", 174848, Common::kPlatformC64),
|
||||
DT_ENTRYP1("gremlins", "C64", "947e35037cf02269ac013857925137ce", 174848, Common::kPlatformC64),
|
||||
DT_ENTRYP1("gremlins", "C64", "95b2582a89c59961d5b709c9b32e4131", 174848, Common::kPlatformC64),
|
||||
DT_ENTRYP1("gremlins", "C64", "644c366956202d41df0ea1c4303c5895", 174848, Common::kPlatformC64),
|
||||
DT_ENTRYP1("gremlins", "C64", "108063b2a16a199794f2ecf52ce26377", 56724, Common::kPlatformC64),
|
||||
DT_ENTRYLP1("gremlins", Common::DE_DEU, "C64", "c60977950ff22ae57483f073345b8373", 174848, Common::kPlatformC64),
|
||||
DT_ENTRYLP1("gremlins", Common::DE_DEU, "C64", "e5d743d8727c8aca011a737bbb5ad818", 49155, Common::kPlatformC64),
|
||||
DT_ENTRYP1("seasofblood", "C64", "267c3fe2bb150365de0358f07b5df15c", 174848, Common::kPlatformC64),
|
||||
DT_ENTRYP1("seasofblood", "C64", "0300c2d21289157539bbd03ab4e366ee", 174848, Common::kPlatformC64),
|
||||
DT_ENTRYP1("seasofblood", "C64", "46280fb1d701a41492b8434467c31029", 41481, Common::kPlatformC64),
|
||||
DT_ENTRYP1("marveladventure", "C64", "d80e133dd396565f773052cb317e8222", 174848, Common::kPlatformC64),
|
||||
DT_ENTRYP1("marveladventure2", "C64", "5d0ea85ca1f260ca718a6bbb6da4cdb9", 174848, Common::kPlatformC64),
|
||||
DT_ENTRYP1("marveladventure2", "C64", "3d88539a6dd7e6e179bb61041125cc0f", 36466, Common::kPlatformC64),
|
||||
DT_ENTRYP1("supergran", "C64", "36a5b1b2afb38902933856b3446d760e", 29295, Common::kPlatformC64),
|
||||
|
||||
|
||||
// Scott Adams
|
||||
DT_ENTRYP1("adventureland", "C64", "05cf6c64ecde5288ae2e46099bfd19a3", 27152, Common::kPlatformC64),
|
||||
DT_ENTRYP1("adventureland", "C64", "5af919881417920ec6a3961b4577f587", 27152, Common::kPlatformC64),
|
||||
DT_ENTRYP1("adventureland", "C64", "ccd3e3c805134b4fc36ad92e1cae623f", 174848, Common::kPlatformC64),
|
||||
DT_ENTRYP1("adventureland", "C64", "547036c586bfcd53e741ecfad74e3001", 175531, Common::kPlatformC64),
|
||||
DT_ENTRYP1("adventureland", "C64", "6c3de0b0ef39fad9d63e788de8cd972c", 175531, Common::kPlatformC64),
|
||||
DT_ENTRYP1("claymorguesorcerer", "C64", "a1db488c49ad221fa0dc79591cb5a3db", 28663, Common::kPlatformC64),
|
||||
DT_ENTRYP1("claymorguesorcerer", "C64", "1ebaf9a378355246aa7ed2623bb27fab", 49373, Common::kPlatformC64),
|
||||
DT_ENTRYP1("claymorguesorcerer", "C64", "dde67117a432420ef05f8d665fbbbe10", 37167, Common::kPlatformC64),
|
||||
DT_ENTRYP1("claymorguesorcerer", "C64", "8d2af429e53df1c4da0d21bdc9de6826", 48223, Common::kPlatformC64),
|
||||
DT_ENTRYP1("claymorguesorcerer", "C64", "64fcee173adecc0f03c595e25d4def04", 174848, Common::kPlatformC64),
|
||||
DT_ENTRYP1("savageisland", "C64", "414d459ceb211230356ad823475866b3", 174848, Common::kPlatformC64),
|
||||
DT_ENTRYP1("savageisland", "C64", "f0087b1f42ea9a0656462bf339278b08", 174848, Common::kPlatformC64),
|
||||
|
||||
// 11 Mysterious Adventures
|
||||
DT_ENTRYP1("mysadv1", "C64", "b4d8fc4eabed4f2400717303561ad0fa", 174848, Common::kPlatformC64),
|
||||
DT_ENTRYP1("mysadv2", "C64", "3ce5ea1a0473244bf469fd3c51f1dc48", 174848, Common::kPlatformC64),
|
||||
DT_ENTRYP1("goldenbaton", "C64", "f2711fe0376442f6f320da1b73b5b1a3", 20848, Common::kPlatformC64),
|
||||
DT_ENTRYP1("goldenbaton", "C64", "ed22cb234af638e7d9f570b937f9fc52", 174848, Common::kPlatformC64),
|
||||
DT_ENTRYP1("timemachine", "C64", "cc8e94d3fb665d5d23b728e9c1f262ba", 20530, Common::kPlatformC64),
|
||||
DT_ENTRYP1("arrowofdeath1", "C64", "da044c4c57dc194002ba47f5b2921411", 23366, Common::kPlatformC64),
|
||||
DT_ENTRYP1("arrowofdeath2", "C64", "3d40cb011167e7ae9f6695cdd1f4a1bf", 24546, Common::kPlatformC64),
|
||||
DT_ENTRYP1("pulsar7", "C64", "db68753e4c4c536693edca2f58747044", 18111, Common::kPlatformC64),
|
||||
DT_ENTRYP1("circus", "C64", "4f732cb27e2a0bb484443a7dd1974ccf", 17001, Common::kPlatformC64),
|
||||
DT_ENTRYP1("feasibility", "C64", "6c7ed2fd5f0247a55beb266344967662", 23163, Common::kPlatformC64),
|
||||
DT_ENTRYP1("akyrz", "C64", "94e4b070e45204b12d1655091c56045d", 19425, Common::kPlatformC64),
|
||||
DT_ENTRYP1("akyrz", "C64", "c423ad31ab3f6b45f0215c2e7fc3eb7e", 174848, Common::kPlatformC64),
|
||||
DT_ENTRYP1("perseus", "C64", "96a1ccb3212808eee03e74cdc1f0d1a4", 20523, Common::kPlatformC64),
|
||||
DT_ENTRYP1("10indians", "C64", "79ee3669ccfff7338dfc1810228005dc", 20383, Common::kPlatformC64),
|
||||
DT_ENTRYP1("waxworks11", "C64", "facc11aa8b51e88a807236b765203eb0", 18961, Common::kPlatformC64),
|
||||
|
||||
// TI99 Games
|
||||
// Scott Adams
|
||||
DT_ENTRYP1("adventureland", "TI99/4A", "c677576bd33a0fe0ff95a9d5c0e3b3ba", 10774, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("pirateadventure", "TI99/4A", "6f293ad8fcce6b0adf56e98fdfe3eaf4", 10488, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("missionimpossible", "TI99/4A", "ac977babc6d7cce815b05be42deeec55", 10562, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("voodoocastle", "TI99/4A", "ff8383afe5addf2f302975b0085b5d5e", 10424, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("thecount", "TI99/4A", "c75701c886bc476e1cbb5321ebd594b2", 10326, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("strangeodyssey", "TI99/4A", "46dbc05fc0177cfee1e9ccd3ec4a9a4c", 10170, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("mysteryfunhouse", "TI99/4A", "9f236bd084f5d1fabb7f9591b6ad1c44", 10594, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("pyramidofdoom", "TI99/4A", "2912111425d87af5b156f95e5766206d", 10242, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("ghosttown", "TI99/4A", "34feb31e2265fd8721d2192443595a8c", 10170, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("savageisland1", "TI99/4A", "a59c7841037fce63cf54899e8f562f25", 10170, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("savageisland2", "TI99/4A", "b40ec602d4c4c442b910b4f109929562", 12616, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("goldenvoyage", "TI99/4A", "ce4a136b4c2f3d56ce0341d830760bb5", 10346, Common::kPlatformTI994),
|
||||
|
||||
// Home Brew
|
||||
DT_ENTRYP1("advocadoadv", "TI99/4A", "80d6b91ea10c26c8139c4fa39dbd8161", 12416, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("matildadilemma", "TI99/4A", "d540575c23434b5ff424513820158a84", 13440, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("escapecannibal", "TI99/4A", "3d0f7d76a81c1fd5c0f2bb52c6dda37e", 12672, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("captkiddmystery", "TI99/4A", "2ec292ced102259f10bd4089f3d31d27", 11136, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("advscott", "TI99/4A", "01bbf82b4047294322e63a7622bb9803", 13440, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("advscottmaster", "TI99/4A", "229b84804d3b74af2fc52e18f6241f36", 10880, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("computorama", "TI99/4A", "c5e9a015d59c584cd48bffde3f394ff8", 5147, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("escapealcatraz", "TI99/4A", "1a01336ce0799f67403d50192a99d63f", 9600, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("gerryplace", "TI99/4A", "36f427bd810e60554ef6ff3b91851816", 9600, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("grayelftomb", "TI99/4A", "b88a4644652589ff6633c400f4943305", 10112, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("knightiron", "TI99/4A", "c97aac994799840b634a501599ec5059", 13305, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("moonadv", "TI99/4A", "40af101895149d397bef50dfdf3cedbd", 9600, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("nessy", "TI99/4A", "49d3b3402c49f947577a14f8588f0dcd", 11392, Common::kPlatformTI994),
|
||||
DT_ENTRYP1("travelling", "TI99/4A", "1f2624be91a256901e555f4d49b09f85", 11648, Common::kPlatformTI994),
|
||||
|
||||
DT_END_MARKER
|
||||
};
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
811
engines/glk/scott/disk_image.cpp
Normal file
811
engines/glk/scott/disk_image.cpp
Normal file
@@ -0,0 +1,811 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* https://paradroid.automac.se/diskimage/
|
||||
* Copyright (c) 2003-2006, Per Olofsson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer. Redistributions in
|
||||
* binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/str.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "glk/scott/disk_image.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
/* dos errors as used by the DOS internally (and as saves in the error info) */
|
||||
struct DosError {
|
||||
signed int _number; /* dos error number */
|
||||
signed int _errnum; /* reported error number */
|
||||
const char *_string; /* description */
|
||||
};
|
||||
|
||||
DosError g_dosError[] = {
|
||||
/* non-errors */
|
||||
{0x01, 0, "ok"},
|
||||
/* errors */
|
||||
{0x02, 20, "Header descriptor byte not found (Seek)"},
|
||||
/* { 0x02, 20, "Header block not found (Seek)" }, */
|
||||
{0x03, 21, "No SYNC sequence found (Seek)"},
|
||||
{0x04, 22, "Data descriptor byte not found (Read)"},
|
||||
{0x05, 23, "Checksum error in data block (Read)"},
|
||||
{0x06, 24, "Write verify (Write)"},
|
||||
{0x07, 25, "Write verify error (Write)"},
|
||||
{0x08, 26, "Write protect on (Write)"},
|
||||
{0x09, 27, "Checksum error in header block (Seek)"},
|
||||
{0x0A, 28, "Write error (Write)"},
|
||||
{0x0B, 29, "Disk sector ID mismatch (Seek)"},
|
||||
{0x0F, 74, "Drive Not Ready (Read)"},
|
||||
{-1, -1, nullptr}
|
||||
};
|
||||
|
||||
int setStatus(DiskImage *di, int status, int track, int sector) {
|
||||
di->_status = status;
|
||||
di->_statusts._track = track;
|
||||
di->_statusts._sector = sector;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* check if given track/sector is within valid range */
|
||||
int diTsIsValid(ImageType type, TrackSector ts) {
|
||||
if ((ts._track < 1) || (ts._track > diTracks(type))) {
|
||||
return 0; /* track out of range */
|
||||
}
|
||||
if (ts._sector > (diSectorsPerTrack(type, ts._track) - 1)) {
|
||||
return 0; /* sector out of range */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int matchPattern(byte *rawPattern, byte *rawname) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; ++i) {
|
||||
if (rawPattern[i] == '*') {
|
||||
return 1;
|
||||
}
|
||||
if (rawname[i] == 0xa0) {
|
||||
if (rawPattern[i] == 0xa0) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (rawPattern[i] == '?' || rawPattern[i] == rawname[i]) {
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* return a pointer to the next block in the chain */
|
||||
TrackSector nextTsInChain(DiskImage *di, TrackSector ts) {
|
||||
byte *p;
|
||||
TrackSector newTs;
|
||||
|
||||
p = diGetTsAddr(di, ts);
|
||||
newTs._track = p[0];
|
||||
newTs._sector = p[1];
|
||||
|
||||
return newTs;
|
||||
}
|
||||
|
||||
RawDirEntry *findFileEntry(DiskImage *di, byte *rawPattern, int type) {
|
||||
byte *buffer;
|
||||
TrackSector ts;
|
||||
RawDirEntry *rde;
|
||||
int offset;
|
||||
|
||||
ts = diGetDirTs(di);
|
||||
|
||||
while (ts._track) {
|
||||
buffer = diGetTsAddr(di, ts);
|
||||
for (offset = 0; offset < 256; offset += 32) {
|
||||
rde = (RawDirEntry *)(buffer + offset);
|
||||
if (matchPattern(rawPattern, rde->_rawname)) {
|
||||
return rde;
|
||||
}
|
||||
}
|
||||
/* todo: add sanity checking */
|
||||
ts = nextTsInChain(di, ts);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* allocate next available directory block */
|
||||
TrackSector allocNextDirTs(DiskImage *di) {
|
||||
byte *p;
|
||||
int spt;
|
||||
TrackSector ts, lastTs;
|
||||
|
||||
if (diTrackBlocksFree(di, di->_bam._track)) {
|
||||
lastTs._track = di->_bam._track;
|
||||
lastTs._sector = 0;
|
||||
if ((di->_type == D64) || (di->_type == D71)) {
|
||||
ts._track = 18;
|
||||
ts._sector = 1;
|
||||
} else {
|
||||
ts = nextTsInChain(di, lastTs);
|
||||
}
|
||||
while (ts._track) {
|
||||
lastTs = ts;
|
||||
ts = nextTsInChain(di, ts);
|
||||
}
|
||||
ts._track = lastTs._track;
|
||||
ts._sector = lastTs._sector + 3;
|
||||
spt = diSectorsPerTrack(di->_type, ts._track);
|
||||
for (;; ts._sector = (ts._sector + 1) % spt) {
|
||||
if (diIsTsFree(di, ts)) {
|
||||
diAllocTs(di, ts);
|
||||
p = diGetTsAddr(di, lastTs);
|
||||
p[0] = ts._track;
|
||||
p[1] = ts._sector;
|
||||
p = diGetTsAddr(di, ts);
|
||||
memset(p, 0, 256);
|
||||
p[1] = 0xff;
|
||||
di->_modified = 1;
|
||||
return ts;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ts._track = 0;
|
||||
ts._sector = 0;
|
||||
return ts;
|
||||
}
|
||||
}
|
||||
|
||||
RawDirEntry *allocFileEntry(DiskImage *di, byte *rawName, int type) {
|
||||
byte *buffer;
|
||||
TrackSector ts;
|
||||
RawDirEntry *rde;
|
||||
int offset;
|
||||
|
||||
/* check if file already exists */
|
||||
ts = nextTsInChain(di, di->_bam);
|
||||
while (ts._track) {
|
||||
buffer = diGetTsAddr(di, ts);
|
||||
for (offset = 0; offset < 256; offset += 32) {
|
||||
rde = (RawDirEntry *)(buffer + offset);
|
||||
if (rde->_type) {
|
||||
if (scumm_strnicmp((char *)rawName, (char *)rde->_rawname, 16) == 0) {
|
||||
setStatus(di, 63, 0, 0);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
ts = nextTsInChain(di, ts);
|
||||
}
|
||||
|
||||
/* allocate empty slot */
|
||||
ts = nextTsInChain(di, di->_bam);
|
||||
while (ts._track) {
|
||||
buffer = diGetTsAddr(di, ts);
|
||||
for (offset = 0; offset < 256; offset += 32) {
|
||||
rde = (RawDirEntry *)(buffer + offset);
|
||||
if (rde->_type == 0) {
|
||||
memset((byte *)rde + 2, 0, 30);
|
||||
memcpy(rde->_rawname, rawName, 16);
|
||||
rde->_type = type;
|
||||
di->_modified = 1;
|
||||
return rde;
|
||||
}
|
||||
}
|
||||
ts = nextTsInChain(di, ts);
|
||||
}
|
||||
|
||||
/* allocate new dir block */
|
||||
ts = allocNextDirTs(di);
|
||||
if (ts._track) {
|
||||
rde = (RawDirEntry *)diGetTsAddr(di, ts);
|
||||
memset((byte *)rde + 2, 0, 30);
|
||||
memcpy(rde->_rawname, rawName, 16);
|
||||
rde->_type = type;
|
||||
di->_modified = 1;
|
||||
return rde;
|
||||
} else {
|
||||
setStatus(di, 72, 0, 0);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ImageFile *diOpen(DiskImage *di, byte *rawname, byte type, const char *mode) {
|
||||
ImageFile *imgFile;
|
||||
RawDirEntry *rde;
|
||||
byte *p;
|
||||
|
||||
setStatus(di, 255, 0, 0);
|
||||
|
||||
if (scumm_stricmp("rb", mode) == 0) {
|
||||
|
||||
if ((imgFile = new ImageFile) == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
memset(imgFile->_visited, 0, sizeof(imgFile->_visited));
|
||||
|
||||
if (scumm_stricmp("$", (char *)rawname) == 0) {
|
||||
imgFile->_mode = 'r';
|
||||
|
||||
imgFile->_ts = di->_dir;
|
||||
|
||||
p = diGetTsAddr(di, di->_dir);
|
||||
imgFile->_buffer = p + 2;
|
||||
|
||||
imgFile->_nextts = diGetDirTs(di);
|
||||
|
||||
imgFile->_buflen = 254;
|
||||
|
||||
if (!diTsIsValid(di->_type, imgFile->_nextts)) {
|
||||
setStatus(di, 66, imgFile->_nextts._track, imgFile->_nextts._sector);
|
||||
delete imgFile;
|
||||
return nullptr;
|
||||
}
|
||||
rde = nullptr;
|
||||
|
||||
} else {
|
||||
if ((rde = findFileEntry(di, rawname, type)) == nullptr) {
|
||||
setStatus(di, 62, 0, 0);
|
||||
delete imgFile;
|
||||
return nullptr;
|
||||
}
|
||||
imgFile->_mode = 'r';
|
||||
imgFile->_ts = rde->_startts;
|
||||
|
||||
if (!diTsIsValid(di->_type, imgFile->_ts)) {
|
||||
setStatus(di, 66, imgFile->_ts._track, imgFile->_ts._sector);
|
||||
delete imgFile;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
p = diGetTsAddr(di, rde->_startts);
|
||||
imgFile->_buffer = p + 2;
|
||||
imgFile->_nextts._track = p[0];
|
||||
imgFile->_nextts._sector = p[1];
|
||||
|
||||
if (imgFile->_nextts._track == 0) {
|
||||
if (imgFile->_nextts._sector != 0) {
|
||||
imgFile->_buflen = imgFile->_nextts._sector - 1;
|
||||
} else {
|
||||
imgFile->_buflen = 254;
|
||||
}
|
||||
} else {
|
||||
if (!diTsIsValid(di->_type, imgFile->_nextts)) {
|
||||
setStatus(di, 66, imgFile->_nextts._track, imgFile->_nextts._sector);
|
||||
delete imgFile;
|
||||
return nullptr;
|
||||
}
|
||||
imgFile->_buflen = 254;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (strcmp("wb", mode) == 0) {
|
||||
|
||||
if ((rde = allocFileEntry(di, rawname, type)) == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if ((imgFile = new ImageFile) == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
imgFile->_mode = 'w';
|
||||
imgFile->_ts._track = 0;
|
||||
imgFile->_ts._sector = 0;
|
||||
if ((imgFile->_buffer = new byte[254]) == nullptr) {
|
||||
delete imgFile;
|
||||
return nullptr;
|
||||
}
|
||||
imgFile->_buflen = 254;
|
||||
di->_modified = 1;
|
||||
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
imgFile->_diskimage = di;
|
||||
imgFile->_rawdirentry = rde;
|
||||
imgFile->_position = 0;
|
||||
imgFile->_bufptr = 0;
|
||||
|
||||
++(di->_openfiles);
|
||||
setStatus(di, 0, 0, 0);
|
||||
return imgFile;
|
||||
}
|
||||
|
||||
int diRead(ImageFile *imgFile, byte *buffer, int len) {
|
||||
byte *p;
|
||||
int bytesLeft;
|
||||
int counter = 0;
|
||||
int err;
|
||||
|
||||
while (len) {
|
||||
bytesLeft = imgFile->_buflen - imgFile->_bufptr;
|
||||
|
||||
err = diGetTsErr(imgFile->_diskimage, imgFile->_ts);
|
||||
if (err) {
|
||||
setStatus(imgFile->_diskimage, err, imgFile->_ts._track, imgFile->_ts._sector);
|
||||
return counter;
|
||||
}
|
||||
|
||||
if (bytesLeft == 0) {
|
||||
if (imgFile->_nextts._track == 0) {
|
||||
return counter;
|
||||
}
|
||||
if (((imgFile->_diskimage->_type == D64) || (imgFile->_diskimage->_type == D71)) && imgFile->_ts._track == 18 && imgFile->_ts._sector == 0) {
|
||||
imgFile->_ts._track = 18;
|
||||
imgFile->_ts._sector = 1;
|
||||
} else {
|
||||
imgFile->_ts = nextTsInChain(imgFile->_diskimage, imgFile->_ts);
|
||||
}
|
||||
if (imgFile->_ts._track == 0) {
|
||||
return counter;
|
||||
}
|
||||
|
||||
/* check for cyclic files */
|
||||
if (imgFile->_visited[imgFile->_ts._track][imgFile->_ts._sector]) {
|
||||
/* return 52, file too long error */
|
||||
setStatus(imgFile->_diskimage, 52, imgFile->_ts._track, imgFile->_ts._sector);
|
||||
} else {
|
||||
imgFile->_visited[imgFile->_ts._track][imgFile->_ts._sector] = 1;
|
||||
}
|
||||
|
||||
err = diGetTsErr(imgFile->_diskimage, imgFile->_ts);
|
||||
if (err) {
|
||||
setStatus(imgFile->_diskimage, err, imgFile->_ts._track, imgFile->_ts._sector);
|
||||
return counter;
|
||||
}
|
||||
|
||||
p = diGetTsAddr(imgFile->_diskimage, imgFile->_ts);
|
||||
imgFile->_buffer = p + 2;
|
||||
imgFile->_nextts._track = p[0];
|
||||
imgFile->_nextts._sector = p[1];
|
||||
|
||||
if (imgFile->_nextts._track == 0) {
|
||||
if (imgFile->_nextts._sector == 0) {
|
||||
/* fixme, something is wrong if this happens, should be a proper error */
|
||||
imgFile->_buflen = 0;
|
||||
setStatus(imgFile->_diskimage, -1, imgFile->_ts._track, imgFile->_ts._sector);
|
||||
} else {
|
||||
imgFile->_buflen = imgFile->_nextts._sector - 1;
|
||||
}
|
||||
} else {
|
||||
if (!diTsIsValid(imgFile->_diskimage->_type, imgFile->_nextts)) {
|
||||
setStatus(imgFile->_diskimage, 66, imgFile->_nextts._track, imgFile->_nextts._sector);
|
||||
return counter;
|
||||
}
|
||||
imgFile->_buflen = 254;
|
||||
}
|
||||
imgFile->_bufptr = 0;
|
||||
} else {
|
||||
if (len >= bytesLeft) {
|
||||
while (bytesLeft) {
|
||||
*buffer++ = imgFile->_buffer[imgFile->_bufptr++];
|
||||
--len;
|
||||
--bytesLeft;
|
||||
++counter;
|
||||
++(imgFile->_position);
|
||||
}
|
||||
} else {
|
||||
while (len) {
|
||||
*buffer++ = imgFile->_buffer[imgFile->_bufptr++];
|
||||
--len;
|
||||
--bytesLeft;
|
||||
++counter;
|
||||
++(imgFile->_position);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
// get a pointer to block data
|
||||
byte *diGetTsAddr(DiskImage *di, TrackSector ts) {
|
||||
return di->_image + diGetBlockNum(di->_type, ts) * 256;
|
||||
}
|
||||
|
||||
/* get error info for a sector */
|
||||
int getTsDosErr(DiskImage *di, TrackSector ts) {
|
||||
// return 1;
|
||||
if (di->_errinfo == nullptr) {
|
||||
return 1; /* return OK if image has no error info */
|
||||
}
|
||||
|
||||
return di->_errinfo[diGetBlockNum(di->_type, ts)];
|
||||
}
|
||||
|
||||
int diGetTsErr(DiskImage *di, TrackSector ts) {
|
||||
int errnum;
|
||||
DosError *err = g_dosError;
|
||||
|
||||
errnum = getTsDosErr(di, ts);
|
||||
while (err->_number >= 0) {
|
||||
if (errnum == err->_number) {
|
||||
return err->_errnum;
|
||||
}
|
||||
++err;
|
||||
}
|
||||
return -1; /* unknown error */
|
||||
}
|
||||
|
||||
/* return disk geometry for track */
|
||||
int diSectorsPerTrack(ImageType type, int track) {
|
||||
switch (type) {
|
||||
case D71:
|
||||
if (track > 35) {
|
||||
track -= 35;
|
||||
}
|
||||
/* fall through */
|
||||
case D64:
|
||||
if (track < 18) {
|
||||
return 21;
|
||||
} else if (track < 25) {
|
||||
return 19;
|
||||
} else if (track < 31) {
|
||||
return 18;
|
||||
} else {
|
||||
return 17;
|
||||
}
|
||||
break;
|
||||
case D81:
|
||||
return 40;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return number of tracks for image type */
|
||||
int diTracks(ImageType type) {
|
||||
switch (type) {
|
||||
case D64:
|
||||
return 35;
|
||||
break;
|
||||
case D71:
|
||||
return 70;
|
||||
break;
|
||||
case D81:
|
||||
return 80;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int diGetBlockNum(ImageType type, TrackSector ts) {
|
||||
int block;
|
||||
|
||||
/* assertion, should never happen (indicates bad error handling elsewhere) */
|
||||
if (!diTsIsValid(type, ts)) {
|
||||
error("diGetBlockNum: internal error, track/sector out of range");
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case D64:
|
||||
if (ts._track < 18) {
|
||||
block = (ts._track - 1) * 21;
|
||||
} else if (ts._track < 25) {
|
||||
block = (ts._track - 18) * 19 + 17 * 21;
|
||||
} else if (ts._track < 31) {
|
||||
block = (ts._track - 25) * 18 + 17 * 21 + 7 * 19;
|
||||
} else {
|
||||
block = (ts._track - 31) * 17 + 17 * 21 + 7 * 19 + 6 * 18;
|
||||
}
|
||||
return block + ts._sector;
|
||||
break;
|
||||
case D71:
|
||||
if (ts._track > 35) {
|
||||
block = 683;
|
||||
ts._track -= 35;
|
||||
} else {
|
||||
block = 0;
|
||||
}
|
||||
if (ts._track < 18) {
|
||||
block += (ts._track - 1) * 21;
|
||||
} else if (ts._track < 25) {
|
||||
block += (ts._track - 18) * 19 + 17 * 21;
|
||||
} else if (ts._track < 31) {
|
||||
block += (ts._track - 25) * 18 + 17 * 21 + 7 * 19;
|
||||
} else {
|
||||
block += (ts._track - 31) * 17 + 17 * 21 + 7 * 19 + 6 * 18;
|
||||
}
|
||||
return block + ts._sector;
|
||||
break;
|
||||
case D81:
|
||||
return (ts._track - 1) * 40 + ts._sector;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return t/s of first directory sector */
|
||||
TrackSector diGetDirTs(DiskImage *di) {
|
||||
TrackSector newTs;
|
||||
byte *p;
|
||||
|
||||
p = diGetTsAddr(di, di->_dir);
|
||||
if ((di->_type == D64) || (di->_type == D71)) {
|
||||
newTs._track = 18; /* 1541/71 ignores bam t/s link */
|
||||
newTs._sector = 1;
|
||||
} else {
|
||||
newTs._track = p[0];
|
||||
newTs._sector = p[1];
|
||||
}
|
||||
|
||||
return newTs;
|
||||
}
|
||||
|
||||
/* return number of free blocks in track */
|
||||
int diTrackBlocksFree(DiskImage *di, int track) {
|
||||
byte *bam;
|
||||
|
||||
switch (di->_type) {
|
||||
default:
|
||||
case D64:
|
||||
bam = diGetTsAddr(di, di->_bam);
|
||||
break;
|
||||
case D71:
|
||||
bam = diGetTsAddr(di, di->_bam);
|
||||
if (track >= 36) {
|
||||
return bam[track + 185];
|
||||
}
|
||||
break;
|
||||
case D81:
|
||||
if (track <= 40) {
|
||||
bam = diGetTsAddr(di, di->_bam);
|
||||
} else {
|
||||
bam = diGetTsAddr(di, di->_bam2);
|
||||
track -= 40;
|
||||
}
|
||||
return bam[track * 6 + 10];
|
||||
break;
|
||||
}
|
||||
return bam[track * 4];
|
||||
}
|
||||
|
||||
/* check if track, sector is free in BAM */
|
||||
int diIsTsFree(DiskImage *di, TrackSector ts) {
|
||||
byte mask;
|
||||
byte *bam;
|
||||
|
||||
switch (di->_type) {
|
||||
case D64:
|
||||
bam = diGetTsAddr(di, di->_bam);
|
||||
if (bam[ts._track * 4]) {
|
||||
mask = 1 << (ts._sector & 7);
|
||||
return bam[ts._track * 4 + ts._sector / 8 + 1] & mask ? 1 : 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case D71:
|
||||
mask = 1 << (ts._sector & 7);
|
||||
if (ts._track < 36) {
|
||||
bam = diGetTsAddr(di, di->_bam);
|
||||
return bam[ts._track * 4 + ts._sector / 8 + 1] & mask ? 1 : 0;
|
||||
} else {
|
||||
bam = diGetTsAddr(di, di->_bam2);
|
||||
return bam[(ts._track - 35) * 3 + ts._sector / 8 - 3] & mask ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
case D81:
|
||||
mask = 1 << (ts._sector & 7);
|
||||
if (ts._track < 41) {
|
||||
bam = diGetTsAddr(di, di->_bam);
|
||||
} else {
|
||||
bam = diGetTsAddr(di, di->_bam2);
|
||||
ts._track -= 40;
|
||||
}
|
||||
return bam[ts._track * 6 + ts._sector / 8 + 11] & mask ? 1 : 0;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* allocate track, sector in BAM */
|
||||
void diAllocTs(DiskImage *di, TrackSector ts) {
|
||||
byte mask;
|
||||
byte *bam;
|
||||
|
||||
di->_modified = 1;
|
||||
switch (di->_type) {
|
||||
case D64:
|
||||
bam = diGetTsAddr(di, di->_bam);
|
||||
bam[ts._track * 4] -= 1;
|
||||
mask = 1 << (ts._sector & 7);
|
||||
bam[ts._track * 4 + ts._sector / 8 + 1] &= ~mask;
|
||||
break;
|
||||
case D71:
|
||||
mask = 1 << (ts._sector & 7);
|
||||
if (ts._track < 36) {
|
||||
bam = diGetTsAddr(di, di->_bam);
|
||||
bam[ts._track * 4] -= 1;
|
||||
bam[ts._track * 4 + ts._sector / 8 + 1] &= ~mask;
|
||||
} else {
|
||||
bam = diGetTsAddr(di, di->_bam);
|
||||
bam[ts._track + 185] -= 1;
|
||||
bam = diGetTsAddr(di, di->_bam2);
|
||||
bam[(ts._track - 35) * 3 + ts._sector / 8 - 3] &= ~mask;
|
||||
}
|
||||
break;
|
||||
case D81:
|
||||
if (ts._track < 41) {
|
||||
bam = diGetTsAddr(di, di->_bam);
|
||||
} else {
|
||||
bam = diGetTsAddr(di, di->_bam2);
|
||||
ts._track -= 40;
|
||||
}
|
||||
bam[ts._track * 6 + 10] -= 1;
|
||||
mask = 1 << (ts._sector & 7);
|
||||
bam[ts._track * 6 + ts._sector / 8 + 11] &= ~mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* convert to rawname */
|
||||
int diRawnameFromName(byte *rawname, const char *name) {
|
||||
int i;
|
||||
|
||||
memset(rawname, 0xa0, 16);
|
||||
for (i = 0; i < 16 && name[i]; ++i)
|
||||
rawname[i] = name[i];
|
||||
return i;
|
||||
}
|
||||
|
||||
/* count number of free blocks */
|
||||
int blocksFree(DiskImage *di) {
|
||||
int blocks = 0;
|
||||
|
||||
for (int track = 1; track <= diTracks(di->_type); ++track) {
|
||||
if (track != di->_dir._track) {
|
||||
blocks += diTrackBlocksFree(di, track);
|
||||
}
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
|
||||
/* return write interleave */
|
||||
int interleave(ImageType type) {
|
||||
switch (type) {
|
||||
case D64:
|
||||
return 10;
|
||||
break;
|
||||
case D71:
|
||||
return 6;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RawDirEntry *findLargestFileEntry(DiskImage *di) {
|
||||
byte *buffer;
|
||||
TrackSector ts;
|
||||
RawDirEntry *rde, *largest = nullptr;
|
||||
int offset, largestSize = 0;
|
||||
|
||||
ts = diGetDirTs(di);
|
||||
|
||||
while (ts._track) {
|
||||
buffer = diGetTsAddr(di, ts);
|
||||
for (offset = 0; offset < 256; offset += 32) {
|
||||
rde = (RawDirEntry *)(buffer + offset);
|
||||
int size = rde->_sizelo + rde->_sizehi * 0x100;
|
||||
if (size > largestSize) {
|
||||
largest = rde;
|
||||
largestSize = size;
|
||||
}
|
||||
}
|
||||
/* todo: add sanity checking */
|
||||
ts = nextTsInChain(di, ts);
|
||||
}
|
||||
return largest;
|
||||
}
|
||||
|
||||
DiskImage *diCreateFromData(uint8_t *data, int length) {
|
||||
DiskImage *di;
|
||||
|
||||
if (data == nullptr)
|
||||
return nullptr;
|
||||
|
||||
if ((di = new DiskImage) == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
di->_size = length;
|
||||
di->_image = data;
|
||||
|
||||
di->_errinfo = nullptr;
|
||||
|
||||
/* check image type */
|
||||
switch (length) {
|
||||
case D64ERRSIZE: /* D64 with error info */
|
||||
// di->_errinfo = &(di->_error_);
|
||||
// fallthrough
|
||||
case D64SIZE: /* standard D64 */
|
||||
di->_type = D64;
|
||||
di->_bam._track = 18;
|
||||
di->_bam._sector = 0;
|
||||
di->_dir = di->_bam;
|
||||
break;
|
||||
|
||||
case D71ERRSIZE: /* D71 with error info */
|
||||
di->_errinfo = &(di->_image[D71SIZE]);
|
||||
// fallthrough
|
||||
case D71SIZE:
|
||||
di->_type = D71;
|
||||
di->_bam._track = 18;
|
||||
di->_bam._sector = 0;
|
||||
di->_bam2._track = 53;
|
||||
di->_bam2._sector = 0;
|
||||
di->_dir = di->_bam;
|
||||
break;
|
||||
|
||||
case D81ERRSIZE: /* D81 with error info */
|
||||
di->_errinfo = &(di->_image[D81SIZE]);
|
||||
// fallthrough
|
||||
case D81SIZE:
|
||||
di->_type = D81;
|
||||
di->_bam._track = 40;
|
||||
di->_bam._sector = 1;
|
||||
di->_bam2._track = 40;
|
||||
di->_bam2._sector = 2;
|
||||
di->_dir._track = 40;
|
||||
di->_dir._sector = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
delete di;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
di->_filename = nullptr;
|
||||
di->_openfiles = 0;
|
||||
di->_blocksfree = blocksFree(di);
|
||||
di->_modified = 0;
|
||||
di->_interleave = interleave(di->_type);
|
||||
setStatus(di, 254, 0, 0);
|
||||
return di;
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
144
engines/glk/scott/disk_image.h
Normal file
144
engines/glk/scott/disk_image.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* https://paradroid.automac.se/diskimage/
|
||||
* Copyright (c) 2003-2006, Per Olofsson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer. Redistributions in
|
||||
* binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_DISKIMAGE_H
|
||||
#define GLK_SCOTT_DISKIMAGE_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "glk/scott/types.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
// constants for the supported disk formats
|
||||
#define MAXTRACKS 80
|
||||
#define MAXSECTORS 40
|
||||
#define D64SIZE 174848
|
||||
#define D64ERRSIZE 175531
|
||||
#define D71SIZE 349696
|
||||
#define D71ERRSIZE 351062
|
||||
#define D81SIZE 819200
|
||||
#define D81ERRSIZE 822400
|
||||
|
||||
enum ImageType {
|
||||
D64 = 1,
|
||||
D71,
|
||||
D81
|
||||
};
|
||||
|
||||
struct TrackSector {
|
||||
byte _track;
|
||||
byte _sector;
|
||||
};
|
||||
|
||||
struct DiskImage {
|
||||
char *_filename;
|
||||
int _size;
|
||||
ImageType _type;
|
||||
byte *_image;
|
||||
byte *_errinfo;
|
||||
TrackSector _bam;
|
||||
TrackSector _bam2;
|
||||
TrackSector _dir;
|
||||
int _openfiles;
|
||||
int _blocksfree;
|
||||
int _modified;
|
||||
int _status;
|
||||
int _interleave;
|
||||
TrackSector _statusts;
|
||||
};
|
||||
|
||||
struct RawDirEntry {
|
||||
TrackSector _nextts;
|
||||
byte _type;
|
||||
TrackSector _startts;
|
||||
byte _rawname[16];
|
||||
TrackSector _relsidets;
|
||||
byte _relrecsize;
|
||||
byte _unused[4];
|
||||
TrackSector _replacetemp;
|
||||
byte _sizelo;
|
||||
byte _sizehi;
|
||||
};
|
||||
|
||||
struct ImageFile {
|
||||
DiskImage *_diskimage;
|
||||
RawDirEntry *_rawdirentry;
|
||||
char _mode;
|
||||
int _position;
|
||||
TrackSector _ts;
|
||||
TrackSector _nextts;
|
||||
byte *_buffer;
|
||||
int _bufptr;
|
||||
int _buflen;
|
||||
byte _visited[MAXTRACKS][MAXSECTORS];
|
||||
};
|
||||
|
||||
ImageFile *diOpen(DiskImage *di, byte *rawname, byte type, const char *mode);
|
||||
int diRead(ImageFile *imgfile, byte *buffer, int len);
|
||||
|
||||
byte *diGetTsAddr(DiskImage *di, TrackSector ts);
|
||||
int diGetTsErr(DiskImage *di, TrackSector ts);
|
||||
|
||||
int diSectorsPerTrack(ImageType type, int track);
|
||||
int diTracks(ImageType type);
|
||||
int diGetBlockNum(ImageType type, TrackSector ts);
|
||||
|
||||
TrackSector diGetDirTs(DiskImage *di);
|
||||
int diTrackBlocksFree(DiskImage *di, int track);
|
||||
int diIsTsFree(DiskImage *di, TrackSector ts);
|
||||
void diAllocTs(DiskImage *di, TrackSector ts);
|
||||
|
||||
int diRawnameFromName(byte *rawname, const char *name);
|
||||
|
||||
RawDirEntry *findLargestFileEntry(DiskImage *di);
|
||||
DiskImage *diCreateFromData(uint8_t *data, int length);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
282
engines/glk/scott/game_info.cpp
Normal file
282
engines/glk/scott/game_info.cpp
Normal file
@@ -0,0 +1,282 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/str.h"
|
||||
#include "common/str-array.h"
|
||||
#include "glk/scott/definitions.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
/* This is supposed to be the original ScottFree system
|
||||
messages in second person, as far as possible */
|
||||
const char *g_sysDict[] = {
|
||||
"North",
|
||||
"South",
|
||||
"East",
|
||||
"West",
|
||||
"Up",
|
||||
"Down",
|
||||
"The game is now over. Play again?",
|
||||
"You have stored",
|
||||
"treasures. ",
|
||||
"On a scale of 0 to 100 that rates",
|
||||
"O.K.",
|
||||
"O.K.",
|
||||
"O.K. ",
|
||||
"Well done.\n",
|
||||
"I don't understand ",
|
||||
"You can't do that yet. ",
|
||||
"Huh ? ",
|
||||
"Give me a direction too. ",
|
||||
"You haven't got it. ",
|
||||
"You have it. ",
|
||||
"You don't see it. ",
|
||||
"It is beyond your power to do that. ",
|
||||
"\nDangerous to move in the dark! ",
|
||||
"You fell down and broke your neck. ",
|
||||
"You can't go in that direction. ",
|
||||
"I don't know how to \"",
|
||||
"\" something. ",
|
||||
"I don't know what a \"",
|
||||
"\" is. ",
|
||||
"You can't see. It is too dark!\n",
|
||||
"You are in a ",
|
||||
"\nYou can also see: ",
|
||||
"Obvious exits: ",
|
||||
"You are carrying:\n",
|
||||
"Nothing.\n",
|
||||
"Tell me what to do ? ",
|
||||
"<HIT ENTER>",
|
||||
"Light has run out. ",
|
||||
"Light runs out in",
|
||||
"turns! ",
|
||||
"You are carrying too much. \n",
|
||||
"You're dead. ",
|
||||
"Resume a saved game? ",
|
||||
"None",
|
||||
"There's nothing here to take. ",
|
||||
"You carry nothing. ",
|
||||
"Your light is growing dim. ",
|
||||
", ",
|
||||
"\n",
|
||||
" - ",
|
||||
"What ?",
|
||||
"yes",
|
||||
"no",
|
||||
"Answer yes or no.\n",
|
||||
"Are you sure? ",
|
||||
"Move undone. ",
|
||||
"Can't undo on first turn. ",
|
||||
"No more undo states stored. ",
|
||||
"Saved. ",
|
||||
"You can't use ALL with that verb. ",
|
||||
"Transcript is now off.\n",
|
||||
"Transcript is now on.\n",
|
||||
"No transcript is currently running.\n",
|
||||
"A transcript is already running.\n",
|
||||
"Failed to create transcript file. ",
|
||||
"Start of transcript\n\n",
|
||||
"\n\nEnd of transcript\n",
|
||||
"BAD DATA! Invalid save file.\n",
|
||||
"State saved.\n",
|
||||
"State restored.\n",
|
||||
"No saved state exists.\n"
|
||||
};
|
||||
|
||||
/* These are supposed to be the original ScottFree system
|
||||
messages in first person, as far as possible */
|
||||
const char *g_sysDictIAm[] = {
|
||||
"North",
|
||||
"South",
|
||||
"East",
|
||||
"West",
|
||||
"Up",
|
||||
"Down",
|
||||
"The game is now over. Play again?",
|
||||
"You have stored",
|
||||
"treasures. ",
|
||||
"On a scale of 0 to 100 that rates",
|
||||
"O.K.",
|
||||
"O.K.",
|
||||
"O.K. ",
|
||||
"Well done.\n",
|
||||
"I don't understand ",
|
||||
"I can't do that yet. ",
|
||||
"Huh ? ",
|
||||
"Give me a direction too.",
|
||||
"I'm not carrying it. ",
|
||||
"I already have it. ",
|
||||
"I don't see it here. ",
|
||||
"It is beyond my power to do that. ",
|
||||
"Dangerous to move in the dark! ",
|
||||
"\nI fell and broke my neck.",
|
||||
"I can't go in that direction. ",
|
||||
"I don't know how to \"",
|
||||
"\" something. ",
|
||||
"I don't know what a \"",
|
||||
"\" is. ",
|
||||
"I can't see. It is too dark!\n",
|
||||
"I'm in a ",
|
||||
"\nI can also see: ",
|
||||
"Obvious exits: ",
|
||||
"I'm carrying: \n",
|
||||
"Nothing.\n",
|
||||
"Tell me what to do ? ",
|
||||
"<HIT ENTER>",
|
||||
"Light has run out. ",
|
||||
"Light runs out in",
|
||||
"turns! ",
|
||||
"I've too much to carry. \n",
|
||||
"I'm dead. ",
|
||||
"Resume a saved game? ",
|
||||
"None",
|
||||
"There's nothing here to take. ",
|
||||
"I have nothing to drop. ",
|
||||
"My light is growing dim. ",
|
||||
nullptr
|
||||
};
|
||||
|
||||
/* These are supposed to be the original TI-99/4A system
|
||||
messages in first person, as far as possible */
|
||||
const char *g_sysDictTI994A[] = {
|
||||
"North",
|
||||
"South",
|
||||
"East",
|
||||
"West",
|
||||
"Up",
|
||||
"Down",
|
||||
"This adventure is over. Play again?",
|
||||
"You have stored",
|
||||
"treasures. ",
|
||||
"On a scale of 0 to 100 that rates",
|
||||
"OK. ",
|
||||
"OK. ",
|
||||
"OK. ",
|
||||
"Well done.\n",
|
||||
"I don't understand the command. ",
|
||||
"I can't do that yet. ",
|
||||
"Huh? ",
|
||||
"Give me a direction too.",
|
||||
"I'm not carrying it. ",
|
||||
"I already have it. ",
|
||||
"I don't see it here. ",
|
||||
"It is beyond my power to do that. ",
|
||||
"Dangerous to move in the dark!\n",
|
||||
"\nI fell down and broke my neck.",
|
||||
"I can't go in that direction. ",
|
||||
"I don't know how to \"",
|
||||
"\" something. ",
|
||||
"I don't know what a \"",
|
||||
"\" is. ",
|
||||
"I can't see. It is too dark!\n",
|
||||
"I am in a ",
|
||||
"\nVisible items are : ",
|
||||
"Obvious exits : ",
|
||||
"I am carrying : ",
|
||||
"Nothing. ",
|
||||
"What shall I do? ",
|
||||
"<HIT ENTER>",
|
||||
"Light went out! ",
|
||||
"Light runs out in",
|
||||
"turns! ",
|
||||
"I am carrying too much.\n",
|
||||
"I'm dead... ",
|
||||
"Resume a saved game? ",
|
||||
"None",
|
||||
"There's nothing here to take. ",
|
||||
"I have nothing to drop. ",
|
||||
"Light is growing dim ",
|
||||
", ",
|
||||
" ",
|
||||
", ",
|
||||
nullptr,
|
||||
};
|
||||
|
||||
const char *g_sysDictZX[] = {
|
||||
"NORTH",
|
||||
"SOUTH",
|
||||
"EAST",
|
||||
"WEST",
|
||||
"UP",
|
||||
"DOWN",
|
||||
"The Adventure is over. Want to try this Adventure again? ",
|
||||
"I've stored",
|
||||
"Treasures. ",
|
||||
"On a scale of 0 to 100 that rates",
|
||||
"Dropped.",
|
||||
"Taken.",
|
||||
"O.K. ",
|
||||
"FANTASTIC! You've solved it ALL! \n",
|
||||
"I must be stupid, but I just don't understand what you mean ",
|
||||
"I can't do that...yet! ",
|
||||
"Huh? ",
|
||||
"I need a direction too. ",
|
||||
"I'm not carrying it. ",
|
||||
"I already have it. ",
|
||||
"I don't see it here. ",
|
||||
"It's beyond my Power to do that. ",
|
||||
"It's dangerous to move in the dark! ",
|
||||
"\nI fell and broke my neck! I'm DEAD! ",
|
||||
"I can't go in that direction. ",
|
||||
"I don't know how to \"",
|
||||
"\" something. ",
|
||||
"I don't know what a \"",
|
||||
"\" is. ",
|
||||
"It's too dark to see!\n",
|
||||
"I am in a ",
|
||||
". Visible items:\n",
|
||||
"Exits: ",
|
||||
"I'm carrying the following: ",
|
||||
"Nothing at all. ",
|
||||
"---TELL ME WHAT TO DO ? ",
|
||||
"<HIT ENTER> ",
|
||||
"Light has run out. ",
|
||||
"Light runs out in",
|
||||
"turns! ",
|
||||
"I'm carrying too much! Try: TAKE INVENTORY. ",
|
||||
"I'm DEAD!! ",
|
||||
"Restore a previously saved game ? ",
|
||||
"None",
|
||||
"There's nothing here to take. ",
|
||||
"I have nothing to drop. ",
|
||||
"My light is growing dim. ",
|
||||
" ",
|
||||
" ",
|
||||
". ",
|
||||
"What ? ",
|
||||
nullptr
|
||||
};
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
50
engines/glk/scott/game_info.h
Normal file
50
engines/glk/scott/game_info.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_GAMEINFO_H
|
||||
#define GLK_SCOTT_GAMEINFO_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "glk/scott/definitions.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
extern const char *g_sysDict[];
|
||||
extern const char *g_sysDictIAm[];
|
||||
extern const char *g_sysDictZX[];
|
||||
extern const char *g_sysDictTI994A[];
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
366
engines/glk/scott/game_specific.cpp
Normal file
366
engines/glk/scott/game_specific.cpp
Normal file
@@ -0,0 +1,366 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "common/str.h"
|
||||
#include "glk/scott/scott.h"
|
||||
#include "glk/scott/globals.h"
|
||||
#include "glk/scott/game_specific.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void mysterious64Sysmess() {
|
||||
SysMessageType messageKey[] = {
|
||||
NORTH,
|
||||
SOUTH,
|
||||
EAST,
|
||||
WEST,
|
||||
UP,
|
||||
DOWN,
|
||||
EXITS,
|
||||
YOU_SEE,
|
||||
YOU_ARE,
|
||||
TOO_DARK_TO_SEE,
|
||||
LIGHT_HAS_RUN_OUT,
|
||||
LIGHT_RUNS_OUT_IN,
|
||||
TURNS,
|
||||
I_DONT_KNOW_HOW_TO,
|
||||
SOMETHING,
|
||||
I_DONT_KNOW_WHAT_A,
|
||||
IS,
|
||||
YOU_CANT_GO_THAT_WAY,
|
||||
OK,
|
||||
WHAT_NOW,
|
||||
HUH,
|
||||
YOU_HAVENT_GOT_IT,
|
||||
INVENTORY,
|
||||
YOU_DONT_SEE_IT,
|
||||
THATS_BEYOND_MY_POWER,
|
||||
DANGEROUS_TO_MOVE_IN_DARK,
|
||||
DIRECTION,
|
||||
YOU_FELL_AND_BROKE_YOUR_NECK,
|
||||
YOURE_CARRYING_TOO_MUCH,
|
||||
IM_DEAD,
|
||||
PLAY_AGAIN,
|
||||
RESUME_A_SAVED_GAME,
|
||||
IVE_STORED,
|
||||
TREASURES,
|
||||
ON_A_SCALE_THAT_RATES,
|
||||
YOU_CANT_DO_THAT_YET,
|
||||
I_DONT_UNDERSTAND,
|
||||
NOTHING,
|
||||
YOUVE_SOLVED_IT,
|
||||
YOUVE_SOLVED_IT};
|
||||
|
||||
for (int i = 0; i < 40; i++) {
|
||||
_G(_sys)[messageKey[i]] = _G(_systemMessages)[i];
|
||||
}
|
||||
|
||||
_G(_sys)[ITEM_DELIMITER] = " - ";
|
||||
_G(_sys)[MESSAGE_DELIMITER] = "\n";
|
||||
|
||||
_G(_sys)[YOU_SEE] = "\nThings I can see:\n";
|
||||
|
||||
_G(_sys)[I_DONT_KNOW_HOW_TO] = "\"";
|
||||
_G(_sys)[PLAY_AGAIN] = "The game is over, thanks for playing\nWant to play again ? ";
|
||||
|
||||
char *dictword = nullptr;
|
||||
for (int i = 1; i <= 6; i++) {
|
||||
dictword = new char[_G(_gameHeader)->_wordLength];
|
||||
Common::strlcpy(dictword, _G(_sys)[i - 1].c_str(), _G(_gameHeader)->_wordLength);
|
||||
_G(_nouns)[i] = dictword;
|
||||
}
|
||||
|
||||
_G(_nouns)[0] = "ANY\0";
|
||||
|
||||
switch (CURRENT_GAME) {
|
||||
case BATON_C64:
|
||||
_G(_nouns)[79] = "CAST\0";
|
||||
_G(_verbs)[79] = ".\0";
|
||||
_G(_gameHeader)->_numWords = 79;
|
||||
break;
|
||||
case TIME_MACHINE_C64:
|
||||
_G(_verbs)[86] = ".\0";
|
||||
break;
|
||||
case ARROW1_C64:
|
||||
_G(_nouns)[82] = ".\0";
|
||||
break;
|
||||
case ARROW2_C64:
|
||||
_G(_verbs)[80] = ".\0";
|
||||
break;
|
||||
case PULSAR7_C64:
|
||||
_G(_nouns)[102] = ".\0";
|
||||
break;
|
||||
case CIRCUS_C64:
|
||||
_G(_nouns)[96] = ".\0";
|
||||
break;
|
||||
case FEASIBILITY_C64:
|
||||
_G(_nouns)[80] = ".\0";
|
||||
break;
|
||||
case PERSEUS_C64:
|
||||
_G(_nouns)[82] = ".\0";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void claymorgue64Sysmess() {
|
||||
SysMessageType messagekey[] = {
|
||||
NORTH,
|
||||
SOUTH,
|
||||
EAST,
|
||||
WEST,
|
||||
UP,
|
||||
DOWN,
|
||||
EXITS,
|
||||
YOU_SEE,
|
||||
YOU_ARE,
|
||||
TOO_DARK_TO_SEE,
|
||||
LIGHT_HAS_RUN_OUT,
|
||||
LIGHT_RUNS_OUT_IN,
|
||||
TURNS,
|
||||
I_DONT_KNOW_HOW_TO,
|
||||
SOMETHING,
|
||||
I_DONT_KNOW_WHAT_A,
|
||||
IS,
|
||||
YOU_CANT_GO_THAT_WAY,
|
||||
OK,
|
||||
WHAT_NOW,
|
||||
HUH,
|
||||
YOU_HAVE_IT,
|
||||
YOU_HAVENT_GOT_IT,
|
||||
INVENTORY,
|
||||
YOU_DONT_SEE_IT,
|
||||
THATS_BEYOND_MY_POWER,
|
||||
DANGEROUS_TO_MOVE_IN_DARK,
|
||||
DIRECTION,
|
||||
YOU_FELL_AND_BROKE_YOUR_NECK,
|
||||
YOURE_CARRYING_TOO_MUCH,
|
||||
IM_DEAD,
|
||||
PLAY_AGAIN,
|
||||
RESUME_A_SAVED_GAME,
|
||||
IVE_STORED,
|
||||
TREASURES,
|
||||
ON_A_SCALE_THAT_RATES,
|
||||
YOU_CANT_DO_THAT_YET,
|
||||
I_DONT_UNDERSTAND,
|
||||
NOTHING,
|
||||
YOUVE_SOLVED_IT};
|
||||
|
||||
for (int i = 0; i < 40; i++) {
|
||||
_G(_sys)[messagekey[i]] = _G(_systemMessages)[i];
|
||||
}
|
||||
|
||||
_G(_sys)[I_DONT_KNOW_HOW_TO] = "I don't know how to \"";
|
||||
_G(_sys)[SOMETHING] = "\" something. ";
|
||||
}
|
||||
|
||||
void adventurelandAction(int p) {
|
||||
int image = 0;
|
||||
switch (p) {
|
||||
case 1:
|
||||
image = 36;
|
||||
break;
|
||||
case 2:
|
||||
image = 34;
|
||||
break;
|
||||
case 3:
|
||||
image = 33;
|
||||
break;
|
||||
case 4:
|
||||
image = 35;
|
||||
break;
|
||||
default:
|
||||
error("Adventureland: Unsupported action parameter %d", p);
|
||||
return;
|
||||
}
|
||||
g_scott->drawImage(image);
|
||||
g_scott->output("\n");
|
||||
g_scott->output(_G(_sys)[HIT_ENTER]);
|
||||
g_scott->hitEnter();
|
||||
return;
|
||||
}
|
||||
|
||||
void adventurelandDarkness() {
|
||||
if ((_G(_rooms)[MY_LOC]._image & 128) == 128)
|
||||
_G(_bitFlags) |= 1 << DARKBIT;
|
||||
else
|
||||
_G(_bitFlags) &= ~(1 << DARKBIT);
|
||||
}
|
||||
|
||||
void adventureland64Sysmess() {
|
||||
SysMessageType messagekey[] = {
|
||||
NORTH,
|
||||
SOUTH,
|
||||
EAST,
|
||||
WEST,
|
||||
UP,
|
||||
DOWN,
|
||||
EXITS,
|
||||
YOU_SEE,
|
||||
YOU_ARE,
|
||||
TOO_DARK_TO_SEE,
|
||||
LIGHT_HAS_RUN_OUT,
|
||||
LIGHT_RUNS_OUT_IN,
|
||||
TURNS,
|
||||
I_DONT_KNOW_HOW_TO,
|
||||
SOMETHING,
|
||||
I_DONT_KNOW_WHAT_A,
|
||||
IS,
|
||||
YOU_CANT_GO_THAT_WAY,
|
||||
OK,
|
||||
WHAT_NOW,
|
||||
HUH,
|
||||
YOU_HAVENT_GOT_IT,
|
||||
INVENTORY,
|
||||
YOU_DONT_SEE_IT,
|
||||
THATS_BEYOND_MY_POWER,
|
||||
DANGEROUS_TO_MOVE_IN_DARK,
|
||||
DIRECTION,
|
||||
YOU_FELL_AND_BROKE_YOUR_NECK,
|
||||
YOURE_CARRYING_TOO_MUCH,
|
||||
IM_DEAD,
|
||||
PLAY_AGAIN,
|
||||
RESUME_A_SAVED_GAME,
|
||||
IVE_STORED,
|
||||
TREASURES,
|
||||
ON_A_SCALE_THAT_RATES,
|
||||
YOU_CANT_DO_THAT_YET,
|
||||
I_DONT_UNDERSTAND,
|
||||
NOTHING,
|
||||
YOUVE_SOLVED_IT};
|
||||
|
||||
for (int i = 0; i < 39; i++) {
|
||||
_G(_sys)[messagekey[i]] = _G(_systemMessages)[i];
|
||||
}
|
||||
|
||||
_G(_sys)[I_DONT_KNOW_HOW_TO] = "I don't know how to \"";
|
||||
_G(_sys)[SOMETHING] = "\" something. ";
|
||||
}
|
||||
|
||||
void spiderman64Sysmess() {
|
||||
SysMessageType messagekey[] = {
|
||||
NORTH,
|
||||
SOUTH,
|
||||
EAST,
|
||||
WEST,
|
||||
UP,
|
||||
DOWN,
|
||||
EXITS,
|
||||
YOU_SEE,
|
||||
YOU_ARE,
|
||||
TOO_DARK_TO_SEE,
|
||||
LIGHT_HAS_RUN_OUT,
|
||||
LIGHT_RUNS_OUT_IN,
|
||||
TURNS,
|
||||
I_DONT_KNOW_HOW_TO,
|
||||
SOMETHING,
|
||||
I_DONT_KNOW_WHAT_A,
|
||||
IS,
|
||||
YOU_CANT_GO_THAT_WAY,
|
||||
OK,
|
||||
WHAT_NOW,
|
||||
HUH,
|
||||
YOU_HAVE_IT,
|
||||
YOU_HAVENT_GOT_IT,
|
||||
INVENTORY,
|
||||
YOU_DONT_SEE_IT,
|
||||
THATS_BEYOND_MY_POWER,
|
||||
DANGEROUS_TO_MOVE_IN_DARK,
|
||||
DIRECTION,
|
||||
YOU_FELL_AND_BROKE_YOUR_NECK,
|
||||
YOURE_CARRYING_TOO_MUCH,
|
||||
IM_DEAD,
|
||||
DROPPED,
|
||||
TAKEN,
|
||||
PLAY_AGAIN,
|
||||
RESUME_A_SAVED_GAME,
|
||||
IVE_STORED,
|
||||
TREASURES,
|
||||
ON_A_SCALE_THAT_RATES,
|
||||
YOU_CANT_DO_THAT_YET,
|
||||
I_DONT_UNDERSTAND,
|
||||
NOTHING,
|
||||
YOUVE_SOLVED_IT};
|
||||
|
||||
for (int i = 0; i < 42; i++) {
|
||||
_G(_sys)[messagekey[i]] = _G(_systemMessages)[i];
|
||||
}
|
||||
|
||||
_G(_sys)[I_DONT_KNOW_HOW_TO] = "I don't know how to \"";
|
||||
_G(_sys)[SOMETHING] = "\" something. ";
|
||||
}
|
||||
|
||||
void supergran64Sysmess(void) {
|
||||
SysMessageType messagekey[] = {
|
||||
NORTH,
|
||||
SOUTH,
|
||||
EAST,
|
||||
WEST,
|
||||
UP,
|
||||
DOWN,
|
||||
EXITS,
|
||||
YOU_SEE,
|
||||
YOU_ARE,
|
||||
I_DONT_KNOW_WHAT_A,
|
||||
IS,
|
||||
YOU_CANT_GO_THAT_WAY,
|
||||
OK,
|
||||
WHAT_NOW,
|
||||
HUH,
|
||||
YOU_HAVE_IT,
|
||||
TAKEN,
|
||||
DROPPED,
|
||||
YOU_HAVENT_GOT_IT,
|
||||
INVENTORY,
|
||||
YOU_DONT_SEE_IT,
|
||||
THATS_BEYOND_MY_POWER,
|
||||
DIRECTION,
|
||||
YOURE_CARRYING_TOO_MUCH,
|
||||
IM_DEAD,
|
||||
PLAY_AGAIN,
|
||||
RESUME_A_SAVED_GAME,
|
||||
YOU_CANT_DO_THAT_YET,
|
||||
I_DONT_UNDERSTAND,
|
||||
NOTHING};
|
||||
|
||||
for (int i = 0; i < 30; i++) {
|
||||
_G(_sys)[messagekey[i]] = _G(_systemMessages)[i];
|
||||
}
|
||||
|
||||
_G(_sys)[I_DONT_KNOW_WHAT_A] = "\"";
|
||||
_G(_sys)[IS] = "\" is a word I don't know. ";
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
50
engines/glk/scott/game_specific.h
Normal file
50
engines/glk/scott/game_specific.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_GAMESPECIFIC_H
|
||||
#define GLK_SCOTT_GAMESPECIFIC_H
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void mysterious64Sysmess();
|
||||
void claymorgue64Sysmess();
|
||||
void adventurelandAction(int p);
|
||||
void adventurelandDarkness();
|
||||
void adventureland64Sysmess();
|
||||
void spiderman64Sysmess();
|
||||
void supergran64Sysmess(void);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
1994
engines/glk/scott/games.h
Normal file
1994
engines/glk/scott/games.h
Normal file
File diff suppressed because it is too large
Load Diff
162
engines/glk/scott/globals.cpp
Normal file
162
engines/glk/scott/globals.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "common/algorithm.h"
|
||||
#include "glk/scott/scott.h"
|
||||
#include "glk/scott/command_parser.h"
|
||||
#include "glk/scott/line_drawing.h"
|
||||
#include "glk/scott/saga_draw.h"
|
||||
#include "glk/scott/globals.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
Globals *g_globals;
|
||||
|
||||
Globals::Globals() : _sys(MAX_SYSMESS), _directions(NUMBER_OF_DIRECTIONS), _extraNouns(NUMBER_OF_EXTRA_NOUNS),
|
||||
_skipList(NUMBER_OF_SKIPPABLE_WORDS), _delimiterList(NUMBER_OF_DELIMITERS), _systemMessages(60),
|
||||
_vectorState(NO_VECTOR_IMAGE) {
|
||||
|
||||
g_globals = this;
|
||||
|
||||
_gameHeader = new Header;
|
||||
|
||||
_englishDirections = {nullptr, "north", "south", "east", "west", "up", "down", "n", "s", "e", "w", "u", "d", " "};
|
||||
|
||||
_extraCommands = {nullptr, "restart", "save", "restore", "load", "transcript", "script", "oops", "undo", "ram",
|
||||
"ramload", "ramrestore", "ramsave", "except", "but", " ", " ", " ", " ", " "};
|
||||
|
||||
_extraCommandsKey = {NO_COMMAND, RESTART, SAVE, RESTORE, RESTORE, SCRIPT, SCRIPT, UNDO, UNDO, RAM,
|
||||
RAMLOAD, RAMLOAD, RAMSAVE, EXCEPT, EXCEPT, RESTORE, RESTORE, SCRIPT, UNDO, RESTART};
|
||||
|
||||
_englishExtraNouns = {nullptr, "game", "story", "on", "off", "load", "restore", "save", "move",
|
||||
"command", "turn", "all", "everything", "it", " ", " "};
|
||||
|
||||
_extraNounsKey = {NO_COMMAND, GAME, GAME, ON, OFF, RAMLOAD, RAMLOAD, RAMSAVE, COMMAND, COMMAND, COMMAND,
|
||||
ALL, ALL, IT, ON, OFF};
|
||||
|
||||
_abbreviations = {nullptr, "i", "l", "x", "z", "q"};
|
||||
|
||||
_abbreviationsKey = {nullptr, "inventory", "look", "examine", "wait", "quit"};
|
||||
|
||||
_englishSkipList = {nullptr, "at", "to", "in", "into", "the", "a", "an", "my", "quickly",
|
||||
"carefully", "quietly", "slowly", "violently", "fast", "hard", "now", "room"};
|
||||
|
||||
_englishDelimiterList = {nullptr, ",", "and", "then", " "};
|
||||
|
||||
_spanishDirections = {nullptr, "norte", "sur", "este", "oeste", "arriba", "abajo", "n", "s", "e", "o", "u", "d", "w"};
|
||||
|
||||
_germanDirections = {nullptr, "norden", "sueden", "osten", "westen", "oben", "unten", "n", "s", "o", "w", "u", "d", " "};
|
||||
|
||||
_germanExtraCommands = {nullptr, "restart", "save", "restore", "load", "transcript", "script", "oops", "undo", "ram", "ramload", "ramrestore", "ramsave",
|
||||
"ausser", "bis", "laden", "wiederherstellen", "transkript", "rueckgaengig", "neustarten"};
|
||||
|
||||
_spanishExtraCommands = {nullptr, "restart", "save", "restore", "load", "transcript", "script", "oops", "undo", "ram", "ramload", "ramrestore", "ramsave",
|
||||
"excepto", "menos", "reanuda", "cargar", "transcripcion", "deshacer", "reinicia"};
|
||||
|
||||
_germanExtraNouns = {nullptr, "spiel", "story", "on", "off", "wiederherstellen", "laden", "speichern", "move", "verschieben", "runde",
|
||||
"alle", "alles", "es", "einschalten", "ausschalten"};
|
||||
|
||||
_spanishExtraNouns = {nullptr, "juego", "story", "on", "off", "cargar", "reanuda", "conserva", "move", "command", "jugada", "toda", "todo", "eso", "activar", "desactivar"};
|
||||
|
||||
_germanSkipList = {nullptr, "nach", "die", "der", "das", "im", "mein", "meine", "an", "auf", "den", "lassen", "lass", "fallen", " ", " ", " ", " "};
|
||||
|
||||
_germanDelimiterList = {nullptr, ",", "und", "dann", "and"};
|
||||
|
||||
Common::fill(&_counters[0], &_counters[16], 0);
|
||||
Common::fill(&_roomSaved[0], &_roomSaved[16], 0);
|
||||
|
||||
_md5Index.setVal("cb7dadc9d5f8bce453b9139265e4dd7d", 0); // goldenbaton
|
||||
_md5Index.setVal("b22d1f4d46c99ff4443d541d3fe424c1", 2); // timemachine
|
||||
_md5Index.setVal("3a5c3f4079c1c0347f03420db8ad4596", 4); // arrowofdeath1
|
||||
_md5Index.setVal("d3f8943c4f5f71ce00139065055a72ee", 6); // arrowofdeath2
|
||||
_md5Index.setVal("441edd90fc7f9ff39a5eebe035a974e9", 8); // pulsar7
|
||||
_md5Index.setVal("ed99306a2fb23bf6579068a4d74034ee", 10); // circus
|
||||
_md5Index.setVal("5e381e83f15d77e3542be4a4cffc8e25", 12); // feasibility
|
||||
_md5Index.setVal("b0f8676817475753f1edd7f1eeea31fb", 14); // akyrz
|
||||
_md5Index.setVal("84d5fbb16a37e495abf09d191fd8b1a2", 16); // perseus
|
||||
_md5Index.setVal("afde056c152de79ea20453c42a2d08af", 18); // 10indians
|
||||
_md5Index.setVal("6c6fbbbb50032463a6ea71c6750ea1f5", 20); // waxworks11
|
||||
_md5Index.setVal("0eec511d3cde815c73e5464ab0cdbef9" ,22); // marveladventure
|
||||
_md5Index.setVal("b4d8fc4eabed4f2400717303561ad0fa", 0); // misadv1
|
||||
_md5Index.setVal("3ce5ea1a0473244bf469fd3c51f1dc48", 6); // midadv2
|
||||
_md5Index.setVal("10109d9776b9372f9c768b53a664b113", 12); // robin of sherwood
|
||||
_md5Index.setVal("4262f85382d1bc3b8924a1929511a558", 13); // robin of sherwood
|
||||
_md5Index.setVal("bf3a4d72cff5ef97bebce6b12c756df2", 14); // robin of sherwood
|
||||
_md5Index.setVal("552c95ec15d750cbfa02c1f11dcbca1e", 15); // robin of sherwood
|
||||
_md5Index.setVal("108063b2a16a199794f2ecf52ce26377", 16); // gremlins
|
||||
_md5Index.setVal("947e35037cf02269ac013857925137ce", 17); // gremlins
|
||||
_md5Index.setVal("95b2582a89c59961d5b709c9b32e4131", 18); // gremlins
|
||||
_md5Index.setVal("33c920f7ba150dfa1a832d510eebd8fe", 19); // gremlins
|
||||
_md5Index.setVal("644c366956202d41df0ea1c4303c5895", 20); // gremlins
|
||||
_md5Index.setVal("e5d743d8727c8aca011a737bbb5ad818", 21); // gremlins
|
||||
_md5Index.setVal("c60977950ff22ae57483f073345b8373", 22); // gremlins
|
||||
_md5Index.setVal("46280fb1d701a41492b8434467c31029", 23); // seas of blood
|
||||
_md5Index.setVal("267c3fe2bb150365de0358f07b5df15c", 24); // seas of blood
|
||||
_md5Index.setVal("0300c2d21289157539bbd03ab4e366ee", 25); // seas of blood
|
||||
_md5Index.setVal("a1db488c49ad221fa0dc79591cb5a3db", 26); // sorcerer of claymorgue castle
|
||||
_md5Index.setVal("dde67117a432420ef05f8d665fbbbe10", 27); // sorcerer of claymorgue castle
|
||||
_md5Index.setVal("1ebaf9a378355246aa7ed2623bb27fab", 28); // sorcerer of claymorgue castle
|
||||
_md5Index.setVal("8d2af429e53df1c4da0d21bdc9de6826", 29); // sorcerer of claymorgue castle
|
||||
_md5Index.setVal("64fcee173adecc0f03c595e25d4def04", 30); // sorcerer of claymorgue castle
|
||||
_md5Index.setVal("05cf6c64ecde5288ae2e46099bfd19a3", 31); // adventureland
|
||||
_md5Index.setVal("5af919881417920ec6a3961b4577f587", 32); // adventureland
|
||||
_md5Index.setVal("ccd3e3c805134b4fc36ad92e1cae623f", 33); // adventureland
|
||||
_md5Index.setVal("6c3de0b0ef39fad9d63e788de8cd972c", 34); // adventureland
|
||||
_md5Index.setVal("547036c586bfcd53e741ecfad74e3001", 35); // adventureland
|
||||
_md5Index.setVal("f0087b1f42ea9a0656462bf339278b08", 36); // savage island
|
||||
_md5Index.setVal("414d459ceb211230356ad823475866b3", 38); // savage island
|
||||
_md5Index.setVal("d80e133dd396565f773052cb317e8222", 40); // questprobe hulk
|
||||
_md5Index.setVal("5d0ea85ca1f260ca718a6bbb6da4cdb9", 41); // questprobe spiderman
|
||||
_md5Index.setVal("3d88539a6dd7e6e179bb61041125cc0f", 42); // questprobe spiderman
|
||||
_md5Index.setVal("f2711fe0376442f6f320da1b73b5b1a3", 43); // golden baton
|
||||
_md5Index.setVal("ed22cb234af638e7d9f570b937f9fc52", 11); // golden baton
|
||||
_md5Index.setVal("cc8e94d3fb665d5d23b728e9c1f262ba", 46); // time machine
|
||||
_md5Index.setVal("da044c4c57dc194002ba47f5b2921411", 47); // arrow of death 1
|
||||
_md5Index.setVal("3d40cb011167e7ae9f6695cdd1f4a1bf", 48); // arrow of death 2
|
||||
_md5Index.setVal("db68753e4c4c536693edca2f58747044", 49); // pulsar 7
|
||||
_md5Index.setVal("4f732cb27e2a0bb484443a7dd1974ccf", 50); // circus
|
||||
_md5Index.setVal("6c7ed2fd5f0247a55beb266344967662", 51); // feasibility
|
||||
_md5Index.setVal("94e4b070e45204b12d1655091c56045d", 53); // akyrz
|
||||
_md5Index.setVal("c423ad31ab3f6b45f0215c2e7fc3eb7e", 52); // akyrz
|
||||
_md5Index.setVal("96a1ccb3212808eee03e74cdc1f0d1a4", 54); // perseus
|
||||
_md5Index.setVal("79ee3669ccfff7338dfc1810228005dc", 55); // 10 indians
|
||||
_md5Index.setVal("facc11aa8b51e88a807236b765203eb0", 56); // waxworks11
|
||||
_md5Index.setVal("36a5b1b2afb38902933856b3446d760e", 57); // super gran
|
||||
}
|
||||
|
||||
Globals::~Globals() {
|
||||
delete _gameHeader;
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
236
engines/glk/scott/globals.h
Normal file
236
engines/glk/scott/globals.h
Normal file
@@ -0,0 +1,236 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_GLOBALS_H
|
||||
#define GLK_SCOTT_GLOBALS_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/str.h"
|
||||
#include "common/str-array.h"
|
||||
#include "common/hashmap.h"
|
||||
#include "glk/glk_types.h"
|
||||
#include "glk/windows.h"
|
||||
#include "glk/scott/definitions.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/unp64/unp64.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
struct Command;
|
||||
enum ExtraCommand : int;
|
||||
struct LineImage;
|
||||
enum VectorStateType : int;
|
||||
|
||||
struct PixelToDraw;
|
||||
struct Image;
|
||||
|
||||
typedef uint8_t RGB[3];
|
||||
typedef RGB PALETTE[16];
|
||||
|
||||
struct Header;
|
||||
struct Item;
|
||||
struct Room;
|
||||
struct Action;
|
||||
|
||||
struct SavedState;
|
||||
|
||||
class Globals {
|
||||
public:
|
||||
// scott
|
||||
Header *_gameHeader;
|
||||
Common::Array<Item> _items;
|
||||
Common::Array<Room> _rooms;
|
||||
Common::StringArray _verbs;
|
||||
Common::StringArray _nouns;
|
||||
Common::StringArray _messages;
|
||||
Common::Array<Action> _actions;
|
||||
Common::StringArray _sys;
|
||||
Common::StringArray _systemMessages;
|
||||
winid_t _graphics = nullptr;
|
||||
uint8_t *_entireFile = nullptr;
|
||||
size_t _fileLength = 0;
|
||||
strid_t _roomDescriptionStream = nullptr;
|
||||
int _fileBaselineOffset = 0;
|
||||
int _header[24];
|
||||
int _lightRefill = 0;
|
||||
winid_t _bottomWindow = nullptr, _topWindow = nullptr;
|
||||
Command *_currentCommand = nullptr;
|
||||
int _justStarted = 1;
|
||||
int _shouldRestart = 0;
|
||||
int _stopTime = 0;
|
||||
strid_t _transcript = nullptr;
|
||||
int _counters[16]; ///< Range unknown
|
||||
int _currentCounter = 0;
|
||||
int _savedRoom = 0;
|
||||
int _roomSaved[16]; ///< Range unknown
|
||||
uint32 _bitFlags = 0; ///< Might be >32 flags - I haven't seen >32 yet
|
||||
int _autoInventory = 0;
|
||||
int _animationFlag = 0;
|
||||
uint8_t _enemyTable[126];
|
||||
const char *_battleMessages[33];
|
||||
int _options = 0; ///< Option flags set
|
||||
Common::String _titleScreen;
|
||||
int _shouldLookInTranscript = 0;
|
||||
|
||||
// sagadraw
|
||||
int _drawToBuffer = 0;
|
||||
uint8_t _sprite[256][8];
|
||||
uint8_t _screenchars[768][8];
|
||||
uint8_t _buffer[384][9];
|
||||
Common::Array<Image> _images;
|
||||
int _pixelSize = 0;
|
||||
int _xOffset = 0;
|
||||
PALETTE _pal;
|
||||
int _whiteColour = 15;
|
||||
int _blueColour = 9;
|
||||
glui32 _diceColour = 0xFF0000;
|
||||
int32_t _errorCount = 0;
|
||||
PaletteType _palChosen = NO_PALETTE;
|
||||
size_t _hulkCoordinates = 0x26DB;
|
||||
size_t _hulkItemImageOffsets = 0x2798;
|
||||
size_t _hulkLookImageOffsets = 0x27BC;
|
||||
size_t _hulkSpecialImageOffsets = 0x276E;
|
||||
size_t _hulkImageOffset = 0x441B;
|
||||
|
||||
// line_drawing
|
||||
Common::Array<LineImage> _lineImages;
|
||||
VectorStateType _vectorState;
|
||||
PixelToDraw **_pixelsToDraw = nullptr;
|
||||
int _totalDrawInstructions = 0;
|
||||
int _currentDrawInstruction = 0;
|
||||
int _vectorImageShown = -1;
|
||||
uint8_t *_pictureBitmap = nullptr;
|
||||
int _lineColour = 15;
|
||||
int _bgColour = 0;
|
||||
int _scottGraphicsWidth = 255;
|
||||
int _scottGraphicsHeight = 94;
|
||||
|
||||
// connect
|
||||
int _gliSlowDraw = 0;
|
||||
|
||||
// parser
|
||||
int _lastNoun = 0;
|
||||
glui32 *_firstErrorMessage = nullptr;
|
||||
glui32 **_unicodeWords = nullptr;
|
||||
char **_charWords = nullptr;
|
||||
int _wordsInInput = 0;
|
||||
Common::StringArray _directions;
|
||||
Common::StringArray _englishDirections;
|
||||
Common::StringArray _skipList;
|
||||
Common::StringArray _englishSkipList;
|
||||
Common::StringArray _delimiterList;
|
||||
Common::StringArray _englishDelimiterList;
|
||||
Common::StringArray _extraCommands;
|
||||
Common::StringArray _extraNouns;
|
||||
Common::StringArray _englishExtraNouns;
|
||||
Common::Array<ExtraCommand> _extraNounsKey;
|
||||
Common::Array<ExtraCommand> _extraCommandsKey;
|
||||
Common::StringArray _abbreviations;
|
||||
Common::StringArray _abbreviationsKey;
|
||||
Common::StringArray _spanishDirections;
|
||||
Common::StringArray _germanDirections;
|
||||
Common::StringArray _germanExtraCommands;
|
||||
Common::StringArray _spanishExtraCommands;
|
||||
Common::StringArray _germanExtraNouns;
|
||||
Common::StringArray _spanishExtraNouns;
|
||||
Common::StringArray _germanSkipList;
|
||||
Common::StringArray _germanDelimiterList;
|
||||
|
||||
// restore state
|
||||
int _justUndid = 0;
|
||||
SavedState *_initialState = nullptr;
|
||||
SavedState *_ramSave = nullptr;
|
||||
SavedState *_lastUndo = nullptr;
|
||||
SavedState *_oldestUndo = nullptr;
|
||||
int _numberOfUndos = 0;
|
||||
|
||||
const GameInfo *_game;
|
||||
GameInfo _fallbackGame;
|
||||
// Include game list
|
||||
#include "glk/scott/games.h"
|
||||
|
||||
// detect game
|
||||
Common::HashMap<Common::String, int> _md5Index;
|
||||
|
||||
// unp64
|
||||
UnpStr _unp;
|
||||
int _parsePar = 1;
|
||||
int _iter = 0;
|
||||
|
||||
// 6502 emu
|
||||
int _byted011[2] = {0, 0};
|
||||
int _retfire = 0xff;
|
||||
int _retspace = 0xff;
|
||||
|
||||
// robin of sherwood]
|
||||
uint8_t *_forestImages = nullptr;
|
||||
|
||||
// seas of blood
|
||||
winid_t _leftDiceWin = nullptr;
|
||||
winid_t _rightDiceWin = nullptr;
|
||||
winid_t _battleRight = nullptr;
|
||||
uint _backgroundColour = 0;
|
||||
uint8_t *_bloodImageData = nullptr;
|
||||
glui32 _dicePixelSize = 0;
|
||||
glui32 _diceXOffset = 0;
|
||||
glui32 _diceYOffset = 0;
|
||||
int _shouldDrawObjectImages = 0;
|
||||
|
||||
// savage island
|
||||
uint8_t *_saveIslandAppendix1 = nullptr;
|
||||
int _saveIslandAppendix1Length = 0;
|
||||
uint8_t *_saveIslandAppendix2 = nullptr;
|
||||
int _saveIslandAppendix2Length = 0;
|
||||
|
||||
// load TI994A
|
||||
int _maxMessages = 0;
|
||||
int _maxItemDescr = 0;
|
||||
size_t _ti99ImplicitExtent = 0;
|
||||
size_t _ti99ExplicitExtent = 0;
|
||||
uint8_t *_ti99ImplicitActions = nullptr;
|
||||
uint8_t *_ti99ExplicitActions = nullptr;
|
||||
uint8_t **_verbActionOffsets = nullptr;
|
||||
|
||||
public:
|
||||
Globals();
|
||||
~Globals();
|
||||
};
|
||||
|
||||
extern Globals *g_globals;
|
||||
|
||||
#define _G(FIELD) (g_globals->FIELD)
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
335
engines/glk/scott/gremlins.cpp
Normal file
335
engines/glk/scott/gremlins.cpp
Normal file
@@ -0,0 +1,335 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "glk/scott/scott.h"
|
||||
#include "glk/scott/command_parser.h"
|
||||
#include "glk/scott/saga_draw.h"
|
||||
#include "glk/scott/globals.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
#define GREMLINS_ANIMATION_RATE 670
|
||||
|
||||
void updateGremlinsAnimations(void) {
|
||||
if (_G(_rooms)[MY_LOC]._image == 255) {
|
||||
g_scott->glk_request_timer_events(0);
|
||||
return;
|
||||
}
|
||||
g_scott->openGraphicsWindow();
|
||||
if (_G(_graphics) == nullptr) {
|
||||
g_scott->glk_request_timer_events(0);
|
||||
return;
|
||||
}
|
||||
|
||||
int timer_delay = GREMLINS_ANIMATION_RATE;
|
||||
switch (MY_LOC) {
|
||||
case 1: /* Bedroom */
|
||||
if (_G(_items)[50]._location == 1) /* Gremlin throwing darts */
|
||||
{
|
||||
if (_G(_animationFlag)) {
|
||||
g_scott->drawImage(60); /* Gremlin throwing dart frame 1 */
|
||||
} else {
|
||||
g_scott->drawImage(59); /* Gremlin throwing dart frame 2 */
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 17: /* Dotty's Tavern */
|
||||
if (_G(_items)[82]._location == 17) /* Gang of GREMLINS */
|
||||
{
|
||||
if (_G(_animationFlag)) {
|
||||
g_scott->drawImage(49); /* Gremlin hanging from curtains frame 1 */
|
||||
g_scott->drawImage(51); /* Gremlin ear frame 1 */
|
||||
g_scott->drawImage(54); /* Gremlin's mouth frame 1 */
|
||||
} else {
|
||||
g_scott->drawImage(50); /* Gremlin hanging from curtains frame 2 */
|
||||
g_scott->drawImage(52); /* Gremlin ear frame 2 */
|
||||
g_scott->drawImage(53); /* Gremlin's mouth frame 2 */
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 16: /* Behind a Bar */
|
||||
if (_G(_items)[82]._location == 16) /* Gang of GREMLINS */
|
||||
{
|
||||
if (_G(_animationFlag)) {
|
||||
g_scott->drawImage(57); /* Flasher gremlin frame 1 */
|
||||
g_scott->drawImage(24); /* Gremlin tongue frame 1 */
|
||||
if (CURRENT_GAME == GREMLINS_GERMAN)
|
||||
g_scott->drawImage(46); /* Gremlin ear frame 1 */
|
||||
else
|
||||
g_scott->drawImage(73); /* Gremlin ear frame 1 */
|
||||
} else {
|
||||
g_scott->drawImage(58); /* Flasher gremlin frame 2 */
|
||||
|
||||
if (CURRENT_GAME == GREMLINS_GERMAN) {
|
||||
g_scott->drawImage(33); /* Gremlin tongue frame 2 */
|
||||
g_scott->drawImage(23); /* Gremlin ear frame 2 */
|
||||
} else {
|
||||
g_scott->drawImage(72); /* Gremlin tongue frame 2 */
|
||||
if (CURRENT_GAME == GREMLINS_SPANISH)
|
||||
g_scott->drawImage(23); /* Gremlin ear frame 2 */
|
||||
else
|
||||
g_scott->drawImage(74); /* Gremlin ear frame 2 */
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 19: /* Square */
|
||||
if (_G(_items)[82]._location == 19) /* Gang of GREMLINS */
|
||||
{
|
||||
if (_G(_animationFlag)) {
|
||||
g_scott->drawImage(55); /* Silhouette of Gremlins frame 1 */
|
||||
} else {
|
||||
g_scott->drawImage(71); /* Silhouette of Gremlins frame 1 */
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 6: /* on a road */
|
||||
if (_G(_items)[82]._location == 6) /* Gang of GREMLINS */
|
||||
{
|
||||
if (_G(_animationFlag)) {
|
||||
if ((_G(_game)->_subType & (LOCALIZED | C64)) == LOCALIZED) {
|
||||
g_scott->drawImage(25); /* Silhouette 2 of Gremlins */
|
||||
} else {
|
||||
g_scott->drawImage(75); /* Silhouette 2 of Gremlins */
|
||||
}
|
||||
} else {
|
||||
g_scott->drawImage(48); /* Silhouette 2 of Gremlins flipped */
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3: /* Kitchen */
|
||||
if (_G(_counters)[2] == 2) /* Blender is on */
|
||||
{
|
||||
if (_G(_animationFlag)) {
|
||||
g_scott->drawImage(56); /* Blended Gremlin */
|
||||
} else {
|
||||
g_scott->drawImage(12); /* Blended Gremlin flipped */
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
timer_delay = 0;
|
||||
break;
|
||||
}
|
||||
_G(_animationFlag) = (_G(_animationFlag) == 0);
|
||||
g_scott->glk_request_timer_events(timer_delay);
|
||||
}
|
||||
|
||||
void gremlinsLook(void) {
|
||||
if (_G(_rooms)[MY_LOC]._image != 255) {
|
||||
if (MY_LOC == 17 && _G(_items)[82]._location == 17)
|
||||
g_scott->drawImage(45); /* Bar full of Gremlins */
|
||||
else
|
||||
g_scott->drawImage(_G(_rooms)[MY_LOC]._image);
|
||||
_G(_animationFlag) = 0;
|
||||
updateGremlinsAnimations();
|
||||
}
|
||||
/* Ladder image at the top of the department store */
|
||||
if (MY_LOC == 34 && _G(_items)[53]._location == MY_LOC) {
|
||||
g_scott->drawImage(42);
|
||||
} else if (MY_LOC == 10 && _G(_items)[15]._location == 0) {
|
||||
if (_G(_items)[99]._location == MY_LOC && CURRENT_GAME == GREMLINS_GERMAN_C64)
|
||||
g_scott->drawImage(90); /* Dazed Stripe */
|
||||
g_scott->drawImage(82); /* Empty pool with puddle */
|
||||
/* Draw puddle on top of Stripe */
|
||||
/* Doesn't look great, but better than the other way round */
|
||||
}
|
||||
}
|
||||
|
||||
void fillInGermanSystemMessages() {
|
||||
_G(_sys)[I_DONT_KNOW_HOW_TO] = "Ich weiss nicht, wie man etwas \"";
|
||||
_G(_sys)[SOMETHING] = "\" macht. ";
|
||||
_G(_sys)[I_DONT_KNOW_WHAT_A] = "\"";
|
||||
_G(_sys)[IS] = "\" kenne ich nicht. ";
|
||||
_G(_sys)[YES] = "Ja";
|
||||
_G(_sys)[NO] = "Nein";
|
||||
_G(_sys)[ANSWER_YES_OR_NO] = "Antworte Ja oder Nein.\n";
|
||||
_G(_sys)[I_DONT_UNDERSTAND] = "Ich verstehe nicht. ";
|
||||
_G(_sys)[ARE_YOU_SURE] = "Sind Sie sicher? ";
|
||||
_G(_sys)[NOTHING_HERE_TO_TAKE] = "Hier gibt es nichts zu nehmen. ";
|
||||
_G(_sys)[YOU_HAVE_NOTHING] = "Ich traege nichts. ";
|
||||
_G(_sys)[MOVE_UNDONE] = "Verschieben rueckgaengig gemacht. ";
|
||||
_G(_sys)[CANT_UNDO_ON_FIRST_TURN] = "Sie koennen die erste Runde nicht rueckgaengig machen. ";
|
||||
_G(_sys)[NO_UNDO_STATES] = "Keine rueckgaengig-Zustaende mehr gespeichert. ";
|
||||
_G(_sys)[SAVED] = "Spiel gespeichert. ";
|
||||
_G(_sys)[CANT_USE_ALL] = "Sie koennen ALLES nicht mit diesem Verb verwenden. ";
|
||||
_G(_sys)[TRANSCRIPT_ON] = "Das Transkript ist jetzt eingeschaltet. ";
|
||||
_G(_sys)[TRANSCRIPT_OFF] = "Das Transkript ist jetzt deaktiviert. ";
|
||||
_G(_sys)[NO_TRANSCRIPT] = "Es wird kein Transkript ausgefuehrt. ";
|
||||
_G(_sys)[TRANSCRIPT_ALREADY] = "Eine Transkript laeuft bereits. ";
|
||||
_G(_sys)[FAILED_TRANSCRIPT] = "Transkriptdatei konnte nicht erstellt werden. ";
|
||||
_G(_sys)[TRANSCRIPT_START] = "Beginn einer Transkript.\n\n";
|
||||
_G(_sys)[TRANSCRIPT_END] = "\n\nEnde eniner Transkript.\n";
|
||||
_G(_sys)[BAD_DATA] = "SCHLECHTE DATEN! Ungueltige Speicherdatei.\n";
|
||||
_G(_sys)[STATE_SAVED] = "Zustand speichern.\n";
|
||||
_G(_sys)[NO_SAVED_STATE] = "Es ist kein gespeicherter Zustand vorhanden.\n";
|
||||
_G(_sys)[STATE_RESTORED] = "Zustand wiederhergestellt.\n";
|
||||
|
||||
_G(_sys)[YOU_ARE] = "Ich bin ";
|
||||
_G(_sys)[WHAT] = _G(_sys)[HUH];
|
||||
|
||||
for (int i = 0; i < NUMBER_OF_DIRECTIONS; i++)
|
||||
_G(_directions)[i] = _G(_germanDirections)[i];
|
||||
for (int i = 0; i < NUMBER_OF_SKIPPABLE_WORDS; i++)
|
||||
_G(_skipList)[i] = _G(_germanSkipList)[i];
|
||||
for (int i = 0; i < NUMBER_OF_DELIMITERS; i++)
|
||||
_G(_delimiterList)[i] = _G(_germanDelimiterList)[i];
|
||||
for (int i = 0; i < NUMBER_OF_EXTRA_COMMANDS; i++)
|
||||
_G(_extraCommands)[i] = _G(_germanExtraCommands)[i];
|
||||
for (int i = 0; i < NUMBER_OF_EXTRA_NOUNS; i++)
|
||||
_G(_extraNouns)[i] = _G(_germanExtraNouns)[i];
|
||||
}
|
||||
|
||||
void loadExtraGermanGremlinsc64Data() {
|
||||
_G(_verbs)[0] = "AUTO\0";
|
||||
_G(_nouns)[0] = "ANY\0";
|
||||
_G(_nouns)[28] = "*Y.M.C\0";
|
||||
|
||||
// These are broken in some versions
|
||||
_G(_actions)[0]._condition[0] = 1005;
|
||||
_G(_actions)[6]._vocab = 100;
|
||||
|
||||
_G(_gameHeader)->_numActions = 236;
|
||||
|
||||
SysMessageType messagekey[] = {
|
||||
NORTH,
|
||||
SOUTH,
|
||||
EAST,
|
||||
WEST,
|
||||
UP,
|
||||
DOWN,
|
||||
EXITS,
|
||||
YOU_SEE,
|
||||
YOU_ARE,
|
||||
YOU_CANT_GO_THAT_WAY,
|
||||
OK,
|
||||
WHAT_NOW,
|
||||
HUH,
|
||||
YOU_HAVE_IT,
|
||||
TAKEN,
|
||||
DROPPED,
|
||||
YOU_HAVENT_GOT_IT,
|
||||
INVENTORY,
|
||||
YOU_DONT_SEE_IT,
|
||||
THATS_BEYOND_MY_POWER,
|
||||
DIRECTION,
|
||||
YOURE_CARRYING_TOO_MUCH,
|
||||
IM_DEAD,
|
||||
RESUME_A_SAVED_GAME,
|
||||
PLAY_AGAIN,
|
||||
YOU_CANT_DO_THAT_YET,
|
||||
I_DONT_UNDERSTAND,
|
||||
NOTHING};
|
||||
|
||||
for (int i = 0; i < 28; i++) {
|
||||
_G(_sys)[messagekey[i]] = _G(_systemMessages)[i];
|
||||
}
|
||||
|
||||
_G(_sys)[HIT_ENTER] = _G(_systemMessages)[30];
|
||||
|
||||
fillInGermanSystemMessages();
|
||||
|
||||
_G(_items)[99]._image = 255;
|
||||
}
|
||||
|
||||
void loadExtraGermanGremlinsData() {
|
||||
_G(_verbs)[0] = "AUTO\0";
|
||||
_G(_nouns)[0] = "ANY\0";
|
||||
_G(_nouns)[28] = "*Y.M.C\0";
|
||||
|
||||
_G(_messages)[90] = "Ehe ich etwas anderes mache, much aich erst alles andere fallenlassen. ";
|
||||
fillInGermanSystemMessages();
|
||||
}
|
||||
|
||||
void loadExtraSpanishGremlinsData() {
|
||||
_G(_verbs)[0] = "AUTO\0";
|
||||
_G(_nouns)[0] = "ANY\0";
|
||||
|
||||
for (int i = YOU_ARE; i <= HIT_ENTER; i++)
|
||||
_G(_sys)[i] = _G(_systemMessages)[15 - YOU_ARE + i];
|
||||
for (int i = I_DONT_UNDERSTAND; i <= THATS_BEYOND_MY_POWER; i++)
|
||||
_G(_sys)[i] = _G(_systemMessages)[6 - I_DONT_UNDERSTAND + i];
|
||||
|
||||
for (int i = DROPPED; i <= OK; i++)
|
||||
_G(_sys)[i] = _G(_systemMessages)[2 - DROPPED + i];
|
||||
_G(_sys)[PLAY_AGAIN] = _G(_systemMessages)[5];
|
||||
_G(_sys)[YOURE_CARRYING_TOO_MUCH] = _G(_systemMessages)[22];
|
||||
_G(_sys)[IM_DEAD] = _G(_systemMessages)[23];
|
||||
_G(_sys)[YOU_CANT_GO_THAT_WAY] = _G(_systemMessages)[14];
|
||||
_G(_sys)[WHAT] = _G(_sys)[HUH];
|
||||
_G(_sys)[YES] = "s}";
|
||||
_G(_sys)[NO] = "no";
|
||||
_G(_sys)[ANSWER_YES_OR_NO] = "Contesta s} o no.\n";
|
||||
_G(_sys)[I_DONT_KNOW_WHAT_A] = "No s\x84 qu\x84 es un \"";
|
||||
_G(_sys)[IS] = "\". ";
|
||||
_G(_sys)[I_DONT_KNOW_HOW_TO] = "No s\x84 c|mo \"";
|
||||
_G(_sys)[SOMETHING] = "\" algo. ";
|
||||
|
||||
_G(_sys)[ARE_YOU_SURE] = "\x83\x45stas segura? ";
|
||||
_G(_sys)[NOTHING_HERE_TO_TAKE] = "No hay nada aqu} para tomar. ";
|
||||
_G(_sys)[YOU_HAVE_NOTHING] = "No llevo nada. ";
|
||||
_G(_sys)[MOVE_UNDONE] = "Deshacer. ";
|
||||
_G(_sys)[CANT_UNDO_ON_FIRST_TURN] = "No se puede deshacer en el primer turno. ";
|
||||
_G(_sys)[NO_UNDO_STATES] = "No hay m{s estados de deshacer disponibles. ";
|
||||
_G(_sys)[SAVED] = "Juego guardado. ";
|
||||
_G(_sys)[CANT_USE_ALL] = "No puedes usar TODO con este verbo. ";
|
||||
_G(_sys)[TRANSCRIPT_ON] = "Transcripci|n en. ";
|
||||
_G(_sys)[TRANSCRIPT_OFF] = "Transcripci|n desactivada. ";
|
||||
_G(_sys)[NO_TRANSCRIPT] = "No se est{ ejecutando ninguna transcripci|n. ";
|
||||
_G(_sys)[TRANSCRIPT_ALREADY] = "Ya se est{ ejecutando una transcripci|n. ";
|
||||
_G(_sys)[FAILED_TRANSCRIPT] = "No se pudo crear el archivo de transcripci|n. ";
|
||||
_G(_sys)[TRANSCRIPT_START] = "Comienzo de una transcripci|n.\n\n";
|
||||
_G(_sys)[TRANSCRIPT_END] = "\n\nFin de una transcripci|n.\n";
|
||||
_G(_sys)[BAD_DATA] = "\x80MALOS DATOS! Guardar archivo no v{lido.\n";
|
||||
_G(_sys)[STATE_SAVED] = "Estado guardado.\n";
|
||||
_G(_sys)[NO_SAVED_STATE] = "No existe ning\x85n estado guardado.\n";
|
||||
_G(_sys)[STATE_RESTORED] = "Estado restaurado.\n";
|
||||
|
||||
for (int i = 0; i < NUMBER_OF_DIRECTIONS; i++)
|
||||
_G(_directions)[i] = _G(_spanishDirections)[i];
|
||||
for (int i = 0; i < NUMBER_OF_EXTRA_NOUNS; i++)
|
||||
_G(_extraNouns)[i] = _G(_spanishExtraNouns)[i];
|
||||
for (int i = 0; i < NUMBER_OF_EXTRA_COMMANDS; i++)
|
||||
_G(_extraCommands)[i] = _G(_spanishExtraCommands)[i];
|
||||
}
|
||||
|
||||
void gremlinsAction(int parameter) {
|
||||
g_scott->drawImage(68); /* Mogwai */
|
||||
g_scott->display(_G(_bottomWindow), "\n%s\n", _G(_sys)[HIT_ENTER].c_str());
|
||||
g_scott->hitEnter();
|
||||
g_scott->look();
|
||||
}
|
||||
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
50
engines/glk/scott/gremlins.h
Normal file
50
engines/glk/scott/gremlins.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_GREMLINS_H
|
||||
#define GLK_SCOTT_GREMLINS_H
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void updateGremlinsAnimations();
|
||||
void gremlinsLook();
|
||||
void gremlinsAction(int p);
|
||||
void loadExtraGermanGremlinsData();
|
||||
void loadExtraSpanishGremlinsData();
|
||||
void loadExtraGermanGremlinsc64Data();
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
|
||||
431
engines/glk/scott/hulk.cpp
Normal file
431
engines/glk/scott/hulk.cpp
Normal file
@@ -0,0 +1,431 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "glk/scott/scott.h"
|
||||
#include "glk/scott/definitions.h"
|
||||
#include "glk/scott/resource.h"
|
||||
#include "glk/scott/globals.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/hulk.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void hulkShowImageOnExamine(int noun) {
|
||||
int image = 0;
|
||||
switch (noun) {
|
||||
case 55: // Dome
|
||||
if (_G(_items)[11]._location == MY_LOC)
|
||||
image = 28;
|
||||
break;
|
||||
case 108: // Natter energy egg
|
||||
if (_G(_items)[17]._location == MY_LOC || _G(_items)[17]._location == CARRIED)
|
||||
image = 30;
|
||||
break;
|
||||
case 124: // Bio-Gem
|
||||
case 41:
|
||||
if (_G(_items)[18]._location == MY_LOC || _G(_items)[18]._location == CARRIED)
|
||||
image = 29;
|
||||
break;
|
||||
case 21: // Killer Bees
|
||||
if (_G(_items)[24]._location == MY_LOC)
|
||||
image = 31;
|
||||
break;
|
||||
case 83: // Iron ring
|
||||
if (_G(_items)[33]._location == MY_LOC)
|
||||
image = 32;
|
||||
break;
|
||||
case 121: // Cage
|
||||
if (_G(_items)[47]._location == MY_LOC)
|
||||
image = 33;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (image) {
|
||||
g_scott->drawImage(image);
|
||||
g_scott->output(_G(_sys)[HIT_ENTER]);
|
||||
g_scott->hitEnter();
|
||||
}
|
||||
}
|
||||
|
||||
void hulkLook() {
|
||||
g_scott->drawImage(_G(_rooms)[MY_LOC]._image);
|
||||
for (int ct = 0; ct <= _G(_gameHeader)->_numItems; ct++) {
|
||||
int image = _G(_items)[ct]._image;
|
||||
if (_G(_items)[ct]._location == MY_LOC && image != 255) {
|
||||
/* Don't draw bio gem in fuzzy area */
|
||||
if ((ct == 18 && MY_LOC != 15) ||
|
||||
/* Don't draw Dr. Strange until outlet is plugged */
|
||||
(ct == 26 && _G(_items)[28]._location != MY_LOC))
|
||||
continue;
|
||||
g_scott->drawImage(image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawHulkImage(int p) {
|
||||
int image = 0;
|
||||
switch (p) {
|
||||
case 85:
|
||||
image = 34;
|
||||
break;
|
||||
case 86:
|
||||
image = 35;
|
||||
break;
|
||||
case 83:
|
||||
image = 36;
|
||||
break;
|
||||
case 84:
|
||||
image = 37;
|
||||
break;
|
||||
case 87:
|
||||
image = 38;
|
||||
break;
|
||||
case 88:
|
||||
image = 39;
|
||||
break;
|
||||
case 89:
|
||||
image = 40;
|
||||
break;
|
||||
case 82:
|
||||
image = 41;
|
||||
break;
|
||||
case 81:
|
||||
image = 42;
|
||||
break;
|
||||
default:
|
||||
|
||||
error("drawHulkImage: Unhandled image number %d", p);
|
||||
break;
|
||||
}
|
||||
|
||||
if (image != 0) {
|
||||
g_scott->drawImage(image);
|
||||
g_scott->output(_G(_sys)[HIT_ENTER]);
|
||||
g_scott->hitEnter();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *readHulkDictionary(GameInfo info, uint8_t **pointer) {
|
||||
uint8_t *ptr = *pointer;
|
||||
char *dictword = new char[info._wordLength + 2];
|
||||
char c = 0;
|
||||
int wordnum = 0;
|
||||
int charindex = 0;
|
||||
|
||||
int nv = info._numberOfVerbs;
|
||||
int nn = info._numberOfNouns;
|
||||
|
||||
for (int i = 0; i < nn - nv; i++)
|
||||
_G(_verbs)[nv + i] = ".\0";
|
||||
|
||||
for (int i = 0; i < nv - nn; i++)
|
||||
_G(_nouns)[nn + i] = ".\0";
|
||||
|
||||
do {
|
||||
for (int i = 0; i < info._wordLength; i++) {
|
||||
c = *(ptr++);
|
||||
if (c == 0) {
|
||||
if (charindex == 0) {
|
||||
c = *(ptr++);
|
||||
}
|
||||
}
|
||||
dictword[charindex] = c;
|
||||
if (c == '*')
|
||||
i--;
|
||||
charindex++;
|
||||
|
||||
dictword[charindex] = 0;
|
||||
}
|
||||
|
||||
if (wordnum < nn) {
|
||||
_G(_nouns)[wordnum] = Common::String(dictword, charindex + 1);
|
||||
} else {
|
||||
_G(_verbs)[wordnum - nn] = Common::String(dictword, charindex + 1);
|
||||
}
|
||||
wordnum++;
|
||||
|
||||
if (c != 0 && !isascii(c))
|
||||
return ptr;
|
||||
|
||||
charindex = 0;
|
||||
} while (wordnum <= nv + nn);
|
||||
|
||||
delete[] dictword;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int tryLoadingHulk(GameInfo info, int dictStart) {
|
||||
int ni, na, nw, nr, mc, pr, tr, wl, lt, mn, trm;
|
||||
int ct;
|
||||
|
||||
Action *ap;
|
||||
Room *rp;
|
||||
Item *ip;
|
||||
|
||||
/* Load the header */
|
||||
uint8_t *ptr = _G(_entireFile);
|
||||
|
||||
_G(_fileBaselineOffset) = dictStart - info._startOfDictionary - 645;
|
||||
|
||||
int offset = info._startOfHeader + _G(_fileBaselineOffset);
|
||||
ptr = seekToPos(_G(_entireFile), offset);
|
||||
|
||||
if (ptr == 0)
|
||||
return 0;
|
||||
|
||||
readHeader(ptr);
|
||||
|
||||
parseHeader(_G(_header), info._headerStyle, &ni, &na, &nw, &nr, &mc, &pr, &tr, &wl, <, &mn, &trm);
|
||||
|
||||
_G(_gameHeader)->_numItems = ni;
|
||||
_G(_items).resize(ni + 1);
|
||||
_G(_gameHeader)->_numActions = na;
|
||||
_G(_actions).resize(na + 1);
|
||||
_G(_gameHeader)->_numWords = nw;
|
||||
_G(_gameHeader)->_wordLength = wl;
|
||||
_G(_verbs).resize(nw + 1);
|
||||
_G(_nouns).resize(nw + 1);
|
||||
_G(_gameHeader)->_numRooms = nr;
|
||||
_G(_rooms).resize(nr + 1);
|
||||
_G(_gameHeader)->_maxCarry = mc;
|
||||
_G(_gameHeader)->_playerRoom = pr;
|
||||
_G(_gameHeader)->_treasures = tr;
|
||||
_G(_gameHeader)->_lightTime = lt;
|
||||
_G(_lightRefill) = lt;
|
||||
_G(_gameHeader)->_numMessages = mn;
|
||||
_G(_messages).resize(mn + 1);
|
||||
_G(_gameHeader)->_treasureRoom = trm;
|
||||
|
||||
if (_G(_header)[0] != info._wordLength || _G(_header)[1] != info._numberOfWords || _G(_header)[2] != info._numberOfActions || _G(_header)[3] != info._numberOfItems || _G(_header)[4] != info._numberOfMessages || _G(_header)[5] != info._numberOfRooms || _G(_header)[6] != info._maxCarried) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma mark Dictionary
|
||||
|
||||
if (seekIfNeeded(info._startOfDictionary, &offset, &ptr) == 0)
|
||||
return 0;
|
||||
|
||||
readHulkDictionary(info, &ptr);
|
||||
|
||||
#pragma mark Rooms
|
||||
|
||||
if (seekIfNeeded(info._startOfRoomDescriptions, &offset, &ptr) == 0)
|
||||
return 0;
|
||||
|
||||
ct = 0;
|
||||
|
||||
uint8_t string_length = 0;
|
||||
do {
|
||||
rp = &_G(_rooms)[ct];
|
||||
string_length = *(ptr++);
|
||||
if (string_length == 0) {
|
||||
rp->_text = ".\0";
|
||||
} else {
|
||||
for (int i = 0; i < string_length; i++) {
|
||||
rp->_text += *(ptr++);
|
||||
}
|
||||
}
|
||||
ct++;
|
||||
} while (ct < nr + 1);
|
||||
|
||||
#pragma mark Messages
|
||||
|
||||
ct = 0;
|
||||
const char *string;
|
||||
|
||||
do {
|
||||
string_length = *(ptr++);
|
||||
if (string_length == 0) {
|
||||
string = ".\0";
|
||||
_G(_messages)[ct] = string;
|
||||
} else {
|
||||
char *s = new char[string_length + 1];
|
||||
for (int i = 0; i < string_length; i++) {
|
||||
s[i] = *(ptr++);
|
||||
}
|
||||
s[string_length] = 0;
|
||||
_G(_messages)[ct] = s;
|
||||
}
|
||||
ct++;
|
||||
} while (ct < mn + 1);
|
||||
|
||||
#pragma mark Items
|
||||
|
||||
if (seekIfNeeded(info._startOfItemDescriptions, &offset, &ptr) == 0)
|
||||
return 0;
|
||||
|
||||
ct = 0;
|
||||
|
||||
do {
|
||||
ip = &_G(_items)[ct];
|
||||
string_length = *(ptr++);
|
||||
if (string_length == 0) {
|
||||
ip->_text = ".\0";
|
||||
} else {
|
||||
for (int i = 0; i < string_length; i++) {
|
||||
ip->_text += *(ptr++);
|
||||
}
|
||||
const char *p = strchr(ip->_text.c_str(), '/');
|
||||
if (p) {
|
||||
ip->_autoGet = Common::String(p);
|
||||
|
||||
/* Some games use // to mean no auto get/drop word! */
|
||||
if (!(ip->_autoGet == "//") && !(ip->_autoGet == "/*")) {
|
||||
ip->_text = Common::String(ip->_text.c_str(), p);
|
||||
ip->_autoGet.deleteChar(0);
|
||||
|
||||
const char *t = strchr(ip->_autoGet.c_str(), '/');
|
||||
if (t) {
|
||||
ip->_autoGet = Common::String(ip->_autoGet.c_str(), t);
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ct++;
|
||||
} while (ct < ni + 1);
|
||||
|
||||
#pragma mark Room connections
|
||||
|
||||
if (seekIfNeeded(info._startOfRoomConnections, &offset, &ptr) == 0)
|
||||
return 0;
|
||||
|
||||
/* The room connections are ordered by direction, not room, so all the North
|
||||
* connections for all the rooms come first, then the South connections, and
|
||||
* so on. */
|
||||
for (int j = 0; j < 6; j++) {
|
||||
ct = 0;
|
||||
|
||||
while (ct < nr + 1) {
|
||||
rp = &_G(_rooms)[ct];
|
||||
rp->_exits[j] = *(ptr++);
|
||||
ptr++;
|
||||
ct++;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark item locations
|
||||
|
||||
if (seekIfNeeded(info._startOfItemLocations, &offset, &ptr) == 0)
|
||||
return 0;
|
||||
|
||||
ct = 0;
|
||||
while (ct < ni + 1) {
|
||||
ip = &_G(_items)[ct];
|
||||
ip->_location = *(ptr++);
|
||||
ip->_location += *(ptr++) * 0x100;
|
||||
ip->_initialLoc = ip->_location;
|
||||
ct++;
|
||||
}
|
||||
|
||||
#pragma mark room images
|
||||
|
||||
if (seekIfNeeded(info._startOfRoomImageList, &offset, &ptr) == 0)
|
||||
return 0;
|
||||
|
||||
for (ct = 0; ct <= _G(_gameHeader)->_numRooms; ct++) {
|
||||
rp = &_G(_rooms)[ct];
|
||||
rp->_image = *(ptr++);
|
||||
}
|
||||
|
||||
#pragma mark item images
|
||||
|
||||
if (seekIfNeeded(info._startOfItemImageList, &offset, &ptr) == 0)
|
||||
return 0;
|
||||
|
||||
for (ct = 0; ct <= _G(_gameHeader)->_numItems; ct++) {
|
||||
ip = &_G(_items)[ct];
|
||||
ip->_image = 255;
|
||||
}
|
||||
|
||||
int index, image = 10;
|
||||
|
||||
for (index = (*ptr++); index != 255; index = (*ptr++)) {
|
||||
_G(_items)[index]._image = image++;
|
||||
}
|
||||
|
||||
#pragma mark item flags
|
||||
|
||||
/* Hulk does not seem to use item flags */
|
||||
|
||||
#pragma mark Actions
|
||||
|
||||
if (seekIfNeeded(info._startOfActions, &offset, &ptr) == 0)
|
||||
return 0;
|
||||
|
||||
ct = 0;
|
||||
|
||||
int verb, noun, value, value2, plus;
|
||||
while (ct < na + 1) {
|
||||
ap = &_G(_actions)[ct];
|
||||
plus = na + 1;
|
||||
verb = _G(_entireFile)[offset + ct];
|
||||
noun = _G(_entireFile)[offset + ct + plus];
|
||||
|
||||
ap->_vocab = verb * 150 + noun;
|
||||
|
||||
for (int j = 0; j < 2; j++) {
|
||||
plus += na + 1;
|
||||
value = _G(_entireFile)[offset + ct + plus];
|
||||
plus += na + 1;
|
||||
value2 = _G(_entireFile)[offset + ct + plus];
|
||||
ap->_action[j] = 150 * value + value2;
|
||||
}
|
||||
|
||||
int offset2 = offset + 0x624;
|
||||
plus = 0;
|
||||
|
||||
for (int j = 0; j < 5; j++) {
|
||||
value = _G(_entireFile)[offset2 + ct * 2 + plus];
|
||||
value2 = _G(_entireFile)[offset2 + ct * 2 + plus + 1];
|
||||
ap->_condition[j] = value + value2 * 0x100;
|
||||
plus += (na + 1) * 2;
|
||||
}
|
||||
ct++;
|
||||
}
|
||||
|
||||
if (CURRENT_GAME == HULK_C64) {
|
||||
_G(_hulkCoordinates) = 0x22cd;
|
||||
_G(_hulkItemImageOffsets) = 0x2731;
|
||||
_G(_hulkLookImageOffsets) = 0x2761;
|
||||
_G(_hulkSpecialImageOffsets) = 0x2781;
|
||||
_G(_hulkImageOffset) = static_cast<size_t>(-0x7ff);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
49
engines/glk/scott/hulk.h
Normal file
49
engines/glk/scott/hulk.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_HULK_H
|
||||
#define GLK_SCOTT_HULK_H
|
||||
|
||||
struct GameInfo;
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void hulkShowImageOnExamine(int noun);
|
||||
void hulkLook();
|
||||
void drawHulkImage(int p);
|
||||
int tryLoadingHulk(GameInfo info, int dictStart);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
119
engines/glk/scott/layout_text.cpp
Normal file
119
engines/glk/scott/layout_text.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "common/util.h"
|
||||
#include "glk/scott/layout_text.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
int findBreak(const char *buf, int pos, int columns) {
|
||||
int diff = 0;
|
||||
|
||||
while (diff < columns && !Common::isSpace((unsigned char)buf[pos])) {
|
||||
pos--;
|
||||
diff++;
|
||||
}
|
||||
|
||||
if (diff >= columns || diff < 1) /* Found no space */ {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
/* Breaks a null-terminated string up by inserting newlines, moving words
|
||||
down to the next line when reaching the end of the line */
|
||||
char *lineBreakText(char *source, int columns, int *rows, int *length) {
|
||||
columns -= 1;
|
||||
|
||||
char *result = nullptr;
|
||||
char buf[768];
|
||||
int col = 0;
|
||||
int row = 0;
|
||||
int sourcepos = 0;
|
||||
int destpos = 0;
|
||||
int diff = 0;
|
||||
*rows = 0;
|
||||
while (source[sourcepos] != '\0') {
|
||||
while (col < columns && source[sourcepos] != '\0') {
|
||||
if (source[sourcepos] == 10 || source[sourcepos] == 13) {
|
||||
/* Found a line break. */
|
||||
/* Any spaces before a line break may cause trouble, */
|
||||
/* so we delete them */
|
||||
while (destpos && buf[destpos - 1] == ' ') {
|
||||
destpos--;
|
||||
}
|
||||
col = 0;
|
||||
row++;
|
||||
} else {
|
||||
col++;
|
||||
}
|
||||
|
||||
buf[destpos++] = source[sourcepos++];
|
||||
|
||||
if (source[sourcepos] == 10 || source[sourcepos] == 13)
|
||||
col--;
|
||||
}
|
||||
|
||||
/* We have reached the end of a line */
|
||||
row++;
|
||||
col = 0;
|
||||
|
||||
if (source[sourcepos] == '\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
diff = findBreak(source, sourcepos, columns);
|
||||
if (diff > -1) { /* We found a suitable break */
|
||||
sourcepos = sourcepos - diff;
|
||||
destpos = destpos - diff;
|
||||
buf[destpos++] = '\n';
|
||||
|
||||
if (Common::isSpace((unsigned char)source[sourcepos])) {
|
||||
sourcepos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
*rows = row;
|
||||
*length = 0;
|
||||
result = new char[destpos + 1];
|
||||
if (result == nullptr)
|
||||
return nullptr;
|
||||
memcpy(result, buf, destpos);
|
||||
result[destpos] = '\0';
|
||||
*length = destpos;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
45
engines/glk/scott/layout_text.h
Normal file
45
engines/glk/scott/layout_text.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_LAYOUTTEXT_H
|
||||
#define GLK_SCOTT_LAYOUTTEXT_H
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
/* Breaks a null-terminated string up by inserting newlines,*/
|
||||
/* moving words down to the next line when reaching the end of the line */
|
||||
char *lineBreakText(char *source, int columns, int *rows, int *length);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
#endif
|
||||
246
engines/glk/scott/line_drawing.cpp
Normal file
246
engines/glk/scott/line_drawing.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "glk/scott/scott.h"
|
||||
#include "glk/scott/globals.h"
|
||||
#include "glk/scott/ring_buffer.h"
|
||||
#include "glk/scott/saga_draw.h"
|
||||
#include "glk/scott/line_drawing.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void scottLinegraphicsPlotClip(int x, int y, int colour) {
|
||||
/*
|
||||
* Clip the plot if the value is outside the context. Otherwise, plot the
|
||||
* pixel as colour1 if it is currently colour2.
|
||||
*/
|
||||
if (x >= 0 && x <= _G(_scottGraphicsWidth) && y >= 0 && y < _G(_scottGraphicsHeight)) {
|
||||
_G(_pictureBitmap)[y * 255 + x] = colour;
|
||||
PixelToDraw *toDraw = new PixelToDraw;
|
||||
toDraw->_x = x;
|
||||
toDraw->_y = y;
|
||||
toDraw->_colour = colour;
|
||||
_G(_pixelsToDraw)[_G(_totalDrawInstructions)++] = toDraw;
|
||||
}
|
||||
}
|
||||
|
||||
void scottLinegraphicsDrawLine(int x1, int y1, int x2, int y2, int colour) {
|
||||
int x, y, dx, dy, incx, incy, balance;
|
||||
|
||||
/* Normalize the line into deltas and increments. */
|
||||
if (x2 >= x1) {
|
||||
dx = x2 - x1;
|
||||
incx = 1;
|
||||
} else {
|
||||
dx = x1 - x2;
|
||||
incx = -1;
|
||||
}
|
||||
|
||||
if (y2 >= y1) {
|
||||
dy = y2 - y1;
|
||||
incy = 1;
|
||||
} else {
|
||||
dy = y1 - y2;
|
||||
incy = -1;
|
||||
}
|
||||
|
||||
/* Start at x1,y1. */
|
||||
x = x1;
|
||||
y = y1;
|
||||
|
||||
/* Decide on a direction to progress in. */
|
||||
if (dx >= dy) {
|
||||
dy <<= 1;
|
||||
balance = dy - dx;
|
||||
dx <<= 1;
|
||||
|
||||
/* Loop until we reach the end point of the line. */
|
||||
while (x != x2) {
|
||||
scottLinegraphicsPlotClip(x, y, colour);
|
||||
if (balance >= 0) {
|
||||
y += incy;
|
||||
balance -= dx;
|
||||
}
|
||||
balance += dy;
|
||||
x += incx;
|
||||
}
|
||||
scottLinegraphicsPlotClip(x, y, colour);
|
||||
} else {
|
||||
dx <<= 1;
|
||||
balance = dx - dy;
|
||||
dy <<= 1;
|
||||
|
||||
/* Loop until we reach the end point of the line. */
|
||||
while (y != y2) {
|
||||
scottLinegraphicsPlotClip(x, y, colour);
|
||||
if (balance >= 0) {
|
||||
x += incx;
|
||||
balance -= dy;
|
||||
}
|
||||
balance += dx;
|
||||
y += incy;
|
||||
}
|
||||
scottLinegraphicsPlotClip(x, y, colour);
|
||||
}
|
||||
}
|
||||
|
||||
void freePixels() {
|
||||
for (int i = 0; i < _G(_totalDrawInstructions); i++)
|
||||
if (_G(_pixelsToDraw)[i] != nullptr)
|
||||
delete _G(_pixelsToDraw)[i];
|
||||
delete[] _G(_pixelsToDraw);
|
||||
}
|
||||
|
||||
int linegraphicsGetPixel(int x, int y) {
|
||||
return _G(_pictureBitmap)[y * 255 + x];
|
||||
}
|
||||
|
||||
void diamondFill(int x, int y, int colour) {
|
||||
uint8_t buffer[2048];
|
||||
cbuf_handle_t ringbuf = circularBufInit(buffer, 2048);
|
||||
circularBufPut(ringbuf, x, y);
|
||||
while (!circularBufEmpty(ringbuf)) {
|
||||
circularBufGet(ringbuf, &x, &y);
|
||||
if (x >= 0 && x < _G(_scottGraphicsWidth) && y >= 0 &&
|
||||
y < _G(_scottGraphicsHeight) &&
|
||||
linegraphicsGetPixel(x, y) == _G(_bgColour)) {
|
||||
scottLinegraphicsPlotClip(x, y, colour);
|
||||
circularBufPut(ringbuf, x, y + 1);
|
||||
circularBufPut(ringbuf, x, y - 1);
|
||||
circularBufPut(ringbuf, x + 1, y);
|
||||
circularBufPut(ringbuf, x - 1, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawVectorPicture(int image) {
|
||||
if (image < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_G(_vectorImageShown) == image) {
|
||||
if (_G(_vectorState) == SHOWING_VECTOR_IMAGE) {
|
||||
return;
|
||||
} else {
|
||||
if (_G(_gliSlowDraw))
|
||||
g_scott->glk_request_timer_events(20);
|
||||
drawSomeVectorPixels(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
g_scott->glk_request_timer_events(0);
|
||||
_G(_vectorImageShown) = image;
|
||||
if (_G(_pixelsToDraw) != nullptr)
|
||||
freePixels();
|
||||
_G(_pixelsToDraw) = new PixelToDraw *[255 * 97];
|
||||
_G(_totalDrawInstructions) = 0;
|
||||
_G(_currentDrawInstruction) = 0;
|
||||
|
||||
if (_G(_palChosen) == NO_PALETTE) {
|
||||
_G(_palChosen) = _G(_game)->_palette;
|
||||
definePalette();
|
||||
}
|
||||
_G(_pictureBitmap) = new uint8_t[255 * 97];
|
||||
_G(_bgColour) = _G(_lineImages)[image]._bgColour;
|
||||
memset(_G(_pictureBitmap), _G(_bgColour), 255 * 97);
|
||||
if (_G(_bgColour) == 0)
|
||||
_G(_lineColour) = 7;
|
||||
else
|
||||
_G(_lineColour) = 0;
|
||||
int x = 0, y = 0, y2 = 0;
|
||||
int arg1, arg2, arg3;
|
||||
uint8_t *p = _G(_lineImages)[image]._data;
|
||||
uint8_t opcode = 0;
|
||||
while (((p < _G(_lineImages)[image]._data) || static_cast<size_t>(p - _G(_lineImages)[image]._data) < _G(_lineImages)[image]._size) && opcode != 0xff) {
|
||||
if (p > _G(_entireFile) + _G(_fileLength)) {
|
||||
error("drawVectorPicture: Out of range! Opcode: %x. Image: %d. LineImages[%d].size: %llu", opcode, image, image, _G(_lineImages)[image]._size);
|
||||
break;
|
||||
}
|
||||
opcode = *(p++);
|
||||
switch (opcode) {
|
||||
case 0xc0:
|
||||
y = 190 - *(p++);
|
||||
x = *(p++);
|
||||
break;
|
||||
case 0xc1:
|
||||
arg1 = *(p++);
|
||||
arg2 = *(p++);
|
||||
arg3 = *(p++);
|
||||
diamondFill(arg3, 190 - arg2, arg1);
|
||||
break;
|
||||
case 0xff:
|
||||
break;
|
||||
default:
|
||||
arg1 = *(p++);
|
||||
y2 = 190 - opcode;
|
||||
scottLinegraphicsDrawLine(x, y, arg1, y2, _G(_lineColour));
|
||||
x = arg1;
|
||||
y = y2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_G(_pictureBitmap) != nullptr) {
|
||||
delete[] _G(_pictureBitmap);
|
||||
_G(_pictureBitmap) = nullptr;
|
||||
}
|
||||
if (_G(_gliSlowDraw))
|
||||
g_scott->glk_request_timer_events(20);
|
||||
else
|
||||
drawSomeVectorPixels(1);
|
||||
}
|
||||
|
||||
void drawSomeVectorPixels(int fromStart) {
|
||||
_G(_vectorState) = DRAWING_VECTOR_IMAGE;
|
||||
int i = _G(_currentDrawInstruction);
|
||||
if (fromStart)
|
||||
i = 0;
|
||||
if (i == 0)
|
||||
rectFill(0, 0, _G(_scottGraphicsWidth), _G(_scottGraphicsHeight), remap(_G(_bgColour)));
|
||||
for (; i < _G(_totalDrawInstructions) && (!_G(_gliSlowDraw) || i < _G(_currentDrawInstruction) + 50); i++) {
|
||||
PixelToDraw toDraw = *_G(_pixelsToDraw)[i];
|
||||
putPixel(toDraw._x, toDraw._y, remap(toDraw._colour));
|
||||
}
|
||||
_G(_currentDrawInstruction) = i;
|
||||
if (_G(_currentDrawInstruction) >= _G(_totalDrawInstructions)) {
|
||||
g_scott->glk_request_timer_events(0);
|
||||
_G(_vectorState) = SHOWING_VECTOR_IMAGE;
|
||||
}
|
||||
}
|
||||
|
||||
int drawingVector() {
|
||||
return (_G(_totalDrawInstructions) > _G(_currentDrawInstruction));
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
67
engines/glk/scott/line_drawing.h
Normal file
67
engines/glk/scott/line_drawing.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_LINEDRAWING_H
|
||||
#define GLK_SCOTT_LINEDRAWING_H
|
||||
|
||||
#include "glk/scott/types.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
struct LineImage {
|
||||
uint8_t *_data;
|
||||
int _bgColour;
|
||||
size_t _size;
|
||||
};
|
||||
|
||||
struct PixelToDraw {
|
||||
uint8_t _x = 0;
|
||||
uint8_t _y = 0;
|
||||
uint8_t _colour = 0;
|
||||
};
|
||||
|
||||
void drawVectorPicture(int image);
|
||||
void drawSomeVectorPixels(int fromStart);
|
||||
int drawingVector();
|
||||
void freePixels();
|
||||
|
||||
enum VectorStateType : int {
|
||||
NO_VECTOR_IMAGE,
|
||||
DRAWING_VECTOR_IMAGE,
|
||||
SHOWING_VECTOR_IMAGE
|
||||
};
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
266
engines/glk/scott/load_game.cpp
Normal file
266
engines/glk/scott/load_game.cpp
Normal file
@@ -0,0 +1,266 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "common/str.h"
|
||||
#include "glk/scott/scott.h"
|
||||
#include "glk/scott/globals.h"
|
||||
#include "glk/scott/command_parser.h"
|
||||
#include "glk/scott/decompress_text.h"
|
||||
#include "glk/scott/decompress_z80.h"
|
||||
#include "glk/scott/detection.h"
|
||||
#include "glk/scott/detection_tables.h"
|
||||
#include "glk/scott/game_info.h"
|
||||
#include "glk/scott/hulk.h"
|
||||
#include "glk/scott/line_drawing.h"
|
||||
#include "glk/scott/saga_draw.h"
|
||||
#include "glk/scott/c64_checksums.h"
|
||||
#include "glk/scott/game_specific.h"
|
||||
#include "glk/scott/resource.h"
|
||||
#include "glk/scott/load_game.h"
|
||||
#include "glk/scott/robin_of_sherwood.h"
|
||||
#include "glk/scott/gremlins.h"
|
||||
#include "glk/scott/seas_of_blood.h"
|
||||
#include "glk/scott/load_ti99_4a.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void loadZXSpectrum(Common::SeekableReadStream *f, Common::String md5) {
|
||||
_G(_entireFile) = new uint8_t[_G(_fileLength)];
|
||||
size_t result = f->read(_G(_entireFile), _G(_fileLength));
|
||||
if (result != _G(_fileLength))
|
||||
g_scott->fatal("File empty or read error!");
|
||||
|
||||
uint8_t *uncompressed = decompressZ80(_G(_entireFile), _G(_fileLength));
|
||||
if (uncompressed != nullptr) {
|
||||
delete[] _G(_entireFile);
|
||||
_G(_entireFile) = uncompressed;
|
||||
_G(_fileLength) = 0xc000;
|
||||
}
|
||||
|
||||
int offset;
|
||||
DictionaryType dict_type = getId(&offset);
|
||||
if (dict_type == NOT_A_GAME)
|
||||
return;
|
||||
|
||||
int index = _G(_md5Index)[md5];
|
||||
if (tryLoading(_G(_games)[index], offset, 0)) {
|
||||
_G(_game) = &_G(_games)[index];
|
||||
}
|
||||
}
|
||||
|
||||
void loadC64(Common::SeekableReadStream* f, Common::String md5) {
|
||||
_G(_entireFile) = new uint8_t[_G(_fileLength)];
|
||||
size_t result = f->read(_G(_entireFile), _G(_fileLength));
|
||||
if (result != _G(_fileLength))
|
||||
g_scott->fatal("File empty or read error!");
|
||||
|
||||
_G(_fallbackGame)._gameID = static_cast<GameIDType>(detectC64(&_G(_entireFile), &_G(_fileLength)));
|
||||
}
|
||||
|
||||
void loadTI994A(Common::SeekableReadStream *f) {
|
||||
_G(_entireFile) = new uint8_t[_G(_fileLength)];
|
||||
size_t result = f->read(_G(_entireFile), _G(_fileLength));
|
||||
if (result != _G(_fileLength))
|
||||
g_scott->fatal("File empty or read error!");
|
||||
|
||||
_G(_fallbackGame)._gameID = detectTI994A(f, &_G(_entireFile), &_G(_fileLength));
|
||||
}
|
||||
|
||||
void loadGameFile(Common::SeekableReadStream *f) {
|
||||
|
||||
for (int i = 0; i < NUMBER_OF_DIRECTIONS; i++)
|
||||
_G(_directions)[i] = _G(_englishDirections)[i];
|
||||
for (int i = 0; i < NUMBER_OF_SKIPPABLE_WORDS; i++)
|
||||
_G(_skipList)[i] = _G(_englishSkipList)[i];
|
||||
for (int i = 0; i < NUMBER_OF_DELIMITERS; i++)
|
||||
_G(_delimiterList)[i] = _G(_englishDelimiterList)[i];
|
||||
for (int i = 0; i < NUMBER_OF_EXTRA_NOUNS; i++)
|
||||
_G(_extraNouns)[i] = _G(_englishExtraNouns)[i];
|
||||
|
||||
_G(_fileLength) = f->size();
|
||||
|
||||
_G(_game) = &_G(_fallbackGame);
|
||||
|
||||
Common::String md5 = g_vm->getGameMD5();
|
||||
const GlkDetectionEntry *p = SCOTT_GAMES;
|
||||
|
||||
while (p->_md5) {
|
||||
if (md5.equalsC(p->_md5)) {
|
||||
if (!scumm_stricmp(p->_extra, "")) {
|
||||
_G(_fallbackGame)._gameID = SCOTTFREE;
|
||||
break;
|
||||
} else if (!scumm_stricmp(p->_extra, "ZXSpectrum")) {
|
||||
loadZXSpectrum(f, md5);
|
||||
break;
|
||||
} else if (!scumm_stricmp(p->_extra, "C64")) {
|
||||
loadC64(f, md5);
|
||||
break;
|
||||
} else {
|
||||
loadTI994A(f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
++p;
|
||||
}
|
||||
|
||||
if (CURRENT_GAME == SCOTTFREE || CURRENT_GAME == TI994A)
|
||||
return;
|
||||
|
||||
/* Copy ZX Spectrum style system messages as base */
|
||||
for (int i = 6; i < MAX_SYSMESS && g_sysDictZX[i] != nullptr; i++) {
|
||||
_G(_sys)[i] = g_sysDictZX[i];
|
||||
}
|
||||
|
||||
switch (CURRENT_GAME) {
|
||||
case ROBIN_OF_SHERWOOD:
|
||||
loadExtraSherwoodData();
|
||||
break;
|
||||
case ROBIN_OF_SHERWOOD_C64:
|
||||
loadExtraSherwoodData64();
|
||||
break;
|
||||
case SEAS_OF_BLOOD:
|
||||
loadExtraSeasOfBloodData();
|
||||
break;
|
||||
case SEAS_OF_BLOOD_C64:
|
||||
loadExtraSeasOfBlood64Data();
|
||||
break;
|
||||
case CLAYMORGUE:
|
||||
for (int i = OK; i <= RESUME_A_SAVED_GAME; i++)
|
||||
_G(_sys)[i] = _G(_systemMessages)[6 - OK + i];
|
||||
for (int i = PLAY_AGAIN; i <= ON_A_SCALE_THAT_RATES; i++)
|
||||
_G(_sys)[i] = _G(_systemMessages)[2 - PLAY_AGAIN + i];
|
||||
break;
|
||||
case ADVENTURELAND:
|
||||
for (int i = PLAY_AGAIN; i <= ON_A_SCALE_THAT_RATES; i++)
|
||||
_G(_sys)[i] = _G(_systemMessages)[2 - PLAY_AGAIN + i];
|
||||
for (int i = OK; i <= YOU_HAVENT_GOT_IT; i++)
|
||||
_G(_sys)[i] = _G(_systemMessages)[6 - OK + i];
|
||||
for (int i = YOU_DONT_SEE_IT; i <= RESUME_A_SAVED_GAME; i++)
|
||||
_G(_sys)[i] = _G(_systemMessages)[13 - YOU_DONT_SEE_IT + i];
|
||||
break;
|
||||
case ADVENTURELAND_C64:
|
||||
adventureland64Sysmess();
|
||||
break;
|
||||
case CLAYMORGUE_C64:
|
||||
claymorgue64Sysmess();
|
||||
break;
|
||||
case GREMLINS_GERMAN_C64:
|
||||
loadExtraGermanGremlinsc64Data();
|
||||
break;
|
||||
case SPIDERMAN_C64:
|
||||
spiderman64Sysmess();
|
||||
break;
|
||||
case SUPERGRAN_C64:
|
||||
supergran64Sysmess();
|
||||
break;
|
||||
case SAVAGE_ISLAND_C64:
|
||||
_G(_items)[20]._image = 13;
|
||||
// fallthrough
|
||||
case SAVAGE_ISLAND2_C64:
|
||||
_G(_sys)[IM_DEAD] = "I'm DEAD!! ";
|
||||
if (CURRENT_GAME == SAVAGE_ISLAND2_C64)
|
||||
_G(_rooms)[30]._image = 20;
|
||||
break;
|
||||
case SAVAGE_ISLAND:
|
||||
_G(_items)[20]._image = 13;
|
||||
// fallthrough
|
||||
case SAVAGE_ISLAND2:
|
||||
MY_LOC = 30; /* Both parts of Savage Island begin in room 30 */
|
||||
// fallthrough
|
||||
case GREMLINS_GERMAN:
|
||||
case GREMLINS:
|
||||
case SUPERGRAN:
|
||||
for (int i = DROPPED; i <= OK; i++)
|
||||
_G(_sys)[i] = _G(_systemMessages)[2 - DROPPED + i];
|
||||
for (int i = I_DONT_UNDERSTAND; i <= THATS_BEYOND_MY_POWER; i++)
|
||||
_G(_sys)[i] = _G(_systemMessages)[6 - I_DONT_UNDERSTAND + i];
|
||||
for (int i = YOU_ARE; i <= HIT_ENTER; i++)
|
||||
_G(_sys)[i] = _G(_systemMessages)[17 - YOU_ARE + i];
|
||||
_G(_sys)[PLAY_AGAIN] = _G(_systemMessages)[5];
|
||||
_G(_sys)[YOURE_CARRYING_TOO_MUCH] = _G(_systemMessages)[24];
|
||||
_G(_sys)[IM_DEAD] = _G(_systemMessages)[25];
|
||||
_G(_sys)[YOU_CANT_GO_THAT_WAY] = _G(_systemMessages)[14];
|
||||
break;
|
||||
case GREMLINS_SPANISH:
|
||||
loadExtraSpanishGremlinsData();
|
||||
break;
|
||||
case HULK_C64:
|
||||
case HULK:
|
||||
for (int i = 0; i < 6; i++) {
|
||||
_G(_sys)[i] = g_sysDictZX[i];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!(_G(_game)->_subType & C64)) {
|
||||
if (_G(_game)->_subType & MYSTERIOUS) {
|
||||
for (int i = PLAY_AGAIN; i <= YOU_HAVENT_GOT_IT; i++)
|
||||
_G(_sys)[i] = _G(_systemMessages)[2 - PLAY_AGAIN + i];
|
||||
for (int i = YOU_DONT_SEE_IT; i <= WHAT_NOW; i++)
|
||||
_G(_sys)[i] = _G(_systemMessages)[15 - YOU_DONT_SEE_IT + i];
|
||||
for (int i = LIGHT_HAS_RUN_OUT; i <= RESUME_A_SAVED_GAME; i++)
|
||||
_G(_sys)[i] = _G(_systemMessages)[31 - LIGHT_HAS_RUN_OUT + i];
|
||||
_G(_sys)[ITEM_DELIMITER] = " - ";
|
||||
_G(_sys)[MESSAGE_DELIMITER] = "\n";
|
||||
_G(_sys)[YOU_SEE] = "\nThings I can see:\n";
|
||||
break;
|
||||
} else {
|
||||
for (int i = PLAY_AGAIN; i <= RESUME_A_SAVED_GAME; i++)
|
||||
_G(_sys)[i] = _G(_systemMessages)[2 - PLAY_AGAIN + i];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (CURRENT_GAME) {
|
||||
case GREMLINS_GERMAN:
|
||||
loadExtraGermanGremlinsData();
|
||||
break;
|
||||
case GREMLINS_GERMAN_C64:
|
||||
loadExtraGermanGremlinsc64Data();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((_G(_game)->_subType & (C64 | MYSTERIOUS)) == (MYSTERIOUS | C64)) {
|
||||
mysterious64Sysmess();
|
||||
}
|
||||
|
||||
/* If it is a C64 or a Mysterious Adventures game, we have setup the graphics already */
|
||||
if (!(_G(_game)->_subType & (C64 | MYSTERIOUS)) && _G(_game)->_numberOfPictures > 0) {
|
||||
sagaSetup(0);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
48
engines/glk/scott/load_game.h
Normal file
48
engines/glk/scott/load_game.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_DETECTGAME_H
|
||||
#define GLK_SCOTT_DETECTGAME_H
|
||||
|
||||
#include "common/stream.h"
|
||||
#include "glk/scott/definitions.h"
|
||||
#include "glk/scott/types.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void loadGameFile(Common::SeekableReadStream *f);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
529
engines/glk/scott/load_ti99_4a.cpp
Normal file
529
engines/glk/scott/load_ti99_4a.cpp
Normal file
@@ -0,0 +1,529 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "glk/scott/scott.h"
|
||||
#include "glk/scott/globals.h"
|
||||
#include "glk/scott/resource.h"
|
||||
#include "glk/scott/game_info.h"
|
||||
#include "glk/scott/load_ti99_4a.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
struct DataHeader {
|
||||
uint8_t _numObjects; /* number of objects */
|
||||
uint8_t _numVerbs; /* number of verbs */
|
||||
uint8_t _numNouns; /* number of nouns */
|
||||
uint8_t _redRoom; /* the red room (dead room) */
|
||||
uint8_t _maxItemsCarried; /* max number of items can be carried */
|
||||
uint8_t _beginLocn; /* room to start in */
|
||||
uint8_t _numTreasures; /* number of treasures */
|
||||
uint8_t _cmdLength; /* number of letters in commands */
|
||||
uint16_t _lightTurns; /* max number of turns light lasts */
|
||||
uint8_t _treasureLocn; /* location of where to store treasures */
|
||||
uint8_t _strange; /* !?! not known. */
|
||||
|
||||
uint16_t _pObjTable; /* pointer to object table */
|
||||
uint16_t _pOrigItems; /* pointer to original items */
|
||||
uint16_t _pObjLink; /* pointer to link table from noun to object */
|
||||
uint16_t _pObjDescr; /* pointer to object descriptions */
|
||||
uint16_t _pMessage; /* pointer to message pointers */
|
||||
uint16_t _pRoomExit; /* pointer to room exits table */
|
||||
uint16_t _pRoomDescr; /* pointer to room descr table */
|
||||
|
||||
uint16_t _pNounTable; /* pointer to noun table */
|
||||
uint16_t _pVerbTable; /* pointer to verb table */
|
||||
|
||||
uint16_t _pExplicit; /* pointer to explicit action table */
|
||||
uint16_t _pImplicit; /* pointer to implicit actions */
|
||||
};
|
||||
|
||||
uint16_t fixAddress(uint16_t ina) {
|
||||
return (ina - 0x380 + _G(_fileBaselineOffset));
|
||||
}
|
||||
|
||||
uint16_t fixWord(uint16_t word) {
|
||||
return (((word & 0xFF) << 8) | ((word >> 8) & 0xFF));
|
||||
}
|
||||
|
||||
uint16_t getWord(uint8_t *mem) {
|
||||
uint16_t x = *(uint16_t *)mem;
|
||||
return fixWord(x);
|
||||
}
|
||||
|
||||
void getMaxTI99Messages(DataHeader dh) {
|
||||
uint8_t *msg;
|
||||
uint16_t msg1;
|
||||
|
||||
msg = _G(_entireFile) + fixAddress(fixWord(dh._pMessage));
|
||||
msg1 = fixAddress(getWord(msg));
|
||||
_G(_maxMessages) = (msg1 - fixAddress(fixWord(dh._pMessage))) / 2;
|
||||
}
|
||||
|
||||
void getMaxTI99Items(DataHeader dh) {
|
||||
uint8_t *msg;
|
||||
uint16_t msg1;
|
||||
|
||||
msg = _G(_entireFile) + fixAddress(fixWord(dh._pObjDescr));
|
||||
msg1 = fixAddress(getWord(msg));
|
||||
_G(_maxItemDescr) = (msg1 - fixAddress(fixWord(dh._pObjDescr))) / 2;
|
||||
}
|
||||
|
||||
uint8_t *getTI994AWord(uint8_t* string, uint8_t** result, size_t* length) {
|
||||
uint8_t *msg;
|
||||
|
||||
msg = string;
|
||||
*length = msg[0];
|
||||
if (*length == 0 || *length > 100) {
|
||||
*length = 0;
|
||||
*result = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
msg++;
|
||||
*result = new uint8_t[*length];
|
||||
memcpy(*result, msg, *length);
|
||||
|
||||
msg += *length;
|
||||
|
||||
return (msg);
|
||||
}
|
||||
|
||||
char *getTI994AString(uint16_t table, int tableOffset) {
|
||||
uint8_t *msgx, *msgy, *nextword;
|
||||
char *result;
|
||||
uint16_t msg1, msg2;
|
||||
uint8_t buffer[1024];
|
||||
size_t length, totalLength = 0;
|
||||
|
||||
uint8_t *game = _G(_entireFile);
|
||||
|
||||
msgx = game + fixAddress(fixWord(table));
|
||||
|
||||
msgx += tableOffset * 2;
|
||||
msg1 = fixAddress(getWord((uint8_t *)msgx));
|
||||
msg2 = fixAddress(getWord((uint8_t *)msgx + 2));
|
||||
|
||||
msgy = game + msg2;
|
||||
msgx = game + msg1;
|
||||
|
||||
while (msgx < msgy) {
|
||||
msgx = getTI994AWord(msgx, &nextword, &length);
|
||||
if (length == 0 || nextword == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (length > 100) {
|
||||
delete[] nextword;
|
||||
return nullptr;
|
||||
}
|
||||
memcpy(buffer + totalLength, nextword, length);
|
||||
delete[] nextword;
|
||||
totalLength += length;
|
||||
if (totalLength > 1000)
|
||||
break;
|
||||
if (msgx < msgy)
|
||||
buffer[totalLength++] = ' ';
|
||||
}
|
||||
if (totalLength == 0)
|
||||
return nullptr;
|
||||
totalLength++;
|
||||
result = new char[totalLength];
|
||||
memcpy(result, buffer, totalLength);
|
||||
result[totalLength - 1] = '\0';
|
||||
return result;
|
||||
}
|
||||
|
||||
void loadTI994ADict(int vorn, uint16_t table, int numWords, Common::StringArray &dict) {
|
||||
uint16_t *wtable;
|
||||
int i;
|
||||
int wordLen;
|
||||
char *w1;
|
||||
char *w2;
|
||||
|
||||
/* table is either verb or noun table */
|
||||
wtable = (uint16_t *)(_G(_entireFile) + fixAddress(fixWord(table)));
|
||||
|
||||
for (i = 0; i <= numWords; i++) {
|
||||
do {
|
||||
w1 = (char *)_G(_entireFile) + fixAddress(getWord((uint8_t *)wtable + (i * 2)));
|
||||
w2 = (char *)_G(_entireFile) + fixAddress(getWord((uint8_t *)wtable + ((1 + i) * 2)));
|
||||
} while (w1 == w2);
|
||||
|
||||
wordLen = w2 - w1;
|
||||
|
||||
if (wordLen < 20) {
|
||||
char *text = new char[wordLen + 1];
|
||||
strncpy(text, w1, wordLen);
|
||||
text[wordLen] = 0;
|
||||
dict[i] = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void readTI99ImplicitActions(DataHeader dh) {
|
||||
uint8_t *ptr, *implicitStart;
|
||||
int loopFlag;
|
||||
|
||||
implicitStart = _G(_entireFile) + fixAddress(fixWord(dh._pImplicit));
|
||||
ptr = implicitStart;
|
||||
loopFlag = 0;
|
||||
|
||||
/* fall out, if no auto acts in the game. */
|
||||
if (*ptr == 0x0)
|
||||
loopFlag = 1;
|
||||
|
||||
while (loopFlag == 0) {
|
||||
if (ptr[1] == 0)
|
||||
loopFlag = 1;
|
||||
|
||||
/* skip code chunk */
|
||||
ptr += 1 + ptr[1];
|
||||
}
|
||||
|
||||
_G(_ti99ImplicitExtent) = MIN(_G(_fileLength), static_cast<size_t>(ptr - _G(_entireFile)));
|
||||
if (_G(_ti99ImplicitExtent)) {
|
||||
_G(_ti99ImplicitActions) = new uint8_t[_G(_ti99ImplicitExtent)];
|
||||
memcpy(_G(_ti99ImplicitActions), implicitStart, _G(_ti99ImplicitExtent));
|
||||
}
|
||||
}
|
||||
|
||||
void readTI99ExplicitActions(DataHeader dh) {
|
||||
uint8_t *ptr, *start, *end, *blockstart;
|
||||
uint16_t address;
|
||||
int loopFlag;
|
||||
int i;
|
||||
|
||||
start = _G(_entireFile) + _G(_fileLength);
|
||||
end = _G(_entireFile);
|
||||
|
||||
size_t explicitOffset = fixAddress(fixWord(dh._pExplicit));
|
||||
blockstart = _G(_entireFile) + explicitOffset;
|
||||
|
||||
_G(_verbActionOffsets) = new uint8_t*[dh._numVerbs + 1];
|
||||
|
||||
for (i = 0; i <= dh._numVerbs; i++) {
|
||||
ptr = blockstart;
|
||||
address = getWord(ptr + ((i)*2));
|
||||
|
||||
_G(_verbActionOffsets)[i] = nullptr;
|
||||
|
||||
if (address != 0) {
|
||||
ptr = _G(_entireFile) + fixAddress(address);
|
||||
if (ptr < start)
|
||||
start = ptr;
|
||||
_G(_verbActionOffsets)[i] = ptr;
|
||||
loopFlag = 0;
|
||||
|
||||
while (loopFlag != 1) {
|
||||
if (ptr[1] == 0)
|
||||
loopFlag = 1;
|
||||
|
||||
/* go to next block. */
|
||||
ptr += 1 + ptr[1];
|
||||
if (ptr > end)
|
||||
end = ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_G(_ti99ExplicitExtent) = end - start;
|
||||
_G(_ti99ExplicitActions) = new uint8_t[_G(_ti99ExplicitExtent)];
|
||||
memcpy(_G(_ti99ExplicitActions), start, _G(_ti99ExplicitExtent));
|
||||
for (i = 0; i <= dh._numVerbs; i++) {
|
||||
if (_G(_verbActionOffsets)[i] != nullptr) {
|
||||
_G(_verbActionOffsets)[i] = _G(_ti99ExplicitActions) + (_G(_verbActionOffsets)[i] - start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *loadTitleScreen() {
|
||||
char buf[3074];
|
||||
int offset = 0;
|
||||
uint8_t *p;
|
||||
int lines;
|
||||
|
||||
/* title screen offset starts at 0x80 */
|
||||
p = _G(_entireFile) + 0x80 + _G(_fileBaselineOffset);
|
||||
if (static_cast<size_t>(p - _G(_entireFile)) > _G(_fileLength))
|
||||
return nullptr;
|
||||
int parens = 0;
|
||||
for (lines = 0; lines < 24; lines++) {
|
||||
for (int i = 0; i < 40; i++) {
|
||||
char c = *(p++);
|
||||
if (static_cast<size_t>(p - _G(_entireFile)) >= _G(_fileLength))
|
||||
return nullptr;
|
||||
if (c & 0x80) /* if not 7-bit ascii */
|
||||
c = '?';
|
||||
switch (c) {
|
||||
case '\\':
|
||||
c = ' ';
|
||||
break;
|
||||
case '(':
|
||||
parens = 1;
|
||||
break;
|
||||
case ')':
|
||||
if (!parens)
|
||||
c = '@';
|
||||
parens = 0;
|
||||
break;
|
||||
case '|':
|
||||
if (*p != ' ')
|
||||
c = 12;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
buf[offset++] = c;
|
||||
if (offset >= 3072)
|
||||
return nullptr;
|
||||
}
|
||||
buf[offset++] = '\n';
|
||||
}
|
||||
|
||||
buf[offset] = '\0';
|
||||
uint8_t *result = new uint8_t[offset + 1];
|
||||
memcpy(result, buf, offset + 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
int tryLoadingTI994A(DataHeader dh, int loud) {
|
||||
int ni, nw, nr, mc, pr, tr, wl, lt, mn, trm;
|
||||
int ct;
|
||||
|
||||
Room *rp;
|
||||
Item *ip;
|
||||
/* Load the header */
|
||||
|
||||
ni = dh._numObjects;
|
||||
nw = MAX(dh._numVerbs, dh._numNouns);
|
||||
nr = dh._redRoom;
|
||||
mc = dh._maxItemsCarried;
|
||||
pr = dh._beginLocn;
|
||||
tr = 0;
|
||||
trm = dh._treasureLocn;
|
||||
wl = dh._cmdLength;
|
||||
lt = fixWord(dh._lightTurns);
|
||||
mn = _G(_maxMessages);
|
||||
|
||||
uint8_t *ptr = _G(_entireFile);
|
||||
|
||||
_G(_gameHeader)->_numItems = ni;
|
||||
_G(_items).resize(ni + 1);
|
||||
_G(_gameHeader)->_numActions = 0;
|
||||
_G(_gameHeader)->_numWords = nw;
|
||||
_G(_gameHeader)->_wordLength = wl;
|
||||
_G(_verbs).resize(nw + 2);
|
||||
_G(_nouns).resize(nw + 2);
|
||||
_G(_gameHeader)->_numRooms = nr;
|
||||
_G(_rooms).resize(nr + 1);
|
||||
_G(_gameHeader)->_maxCarry = mc;
|
||||
_G(_gameHeader)->_playerRoom = pr;
|
||||
_G(_gameHeader)->_lightTime = lt;
|
||||
_G(_lightRefill) = lt;
|
||||
_G(_gameHeader)->_numMessages = mn;
|
||||
_G(_messages).resize(mn + 1);
|
||||
_G(_gameHeader)->_treasureRoom = trm;
|
||||
|
||||
int offset;
|
||||
|
||||
if (seekIfNeeded(fixAddress(fixWord(dh._pRoomDescr)), &offset, &ptr) == 0)
|
||||
return 0;
|
||||
|
||||
ct = 0;
|
||||
rp = &_G(_rooms)[0];
|
||||
|
||||
do {
|
||||
char *res = getTI994AString(dh._pRoomDescr, ct);
|
||||
rp->_text = res ? res : ".\0";
|
||||
if (loud)
|
||||
debug("Room %d: %s", ct, rp->_text.c_str());
|
||||
rp->_image = 255;
|
||||
ct++;
|
||||
rp++;
|
||||
} while (ct < nr + 1);
|
||||
|
||||
ct = 0;
|
||||
while (ct < mn + 1) {
|
||||
char *res = getTI994AString(dh._pMessage, ct);
|
||||
_G(_messages)[ct] = res ? res : ".\0";
|
||||
if (loud)
|
||||
debug("Message %d: %s", ct, _G(_messages)[ct].c_str());
|
||||
ct++;
|
||||
}
|
||||
|
||||
ct = 0;
|
||||
ip = &_G(_items)[0];
|
||||
do {
|
||||
char *res = getTI994AString(dh._pObjDescr, ct);
|
||||
ip->_text = res ? res : ".\0";
|
||||
if (ip->_text.size() && ip->_text[0] == '*')
|
||||
tr++;
|
||||
if (loud)
|
||||
debug("Item %d: %s", ct, ip->_text.c_str());
|
||||
ct++;
|
||||
ip++;
|
||||
} while (ct < ni + 1);
|
||||
|
||||
_G(_gameHeader)->_treasures = tr;
|
||||
if (loud)
|
||||
debug("Number of treasures %d", _G(_gameHeader)->_treasures);
|
||||
|
||||
if (seekIfNeeded(fixAddress(fixWord(dh._pRoomExit)), &offset, &ptr) == 0)
|
||||
return 0;
|
||||
|
||||
ct = 0;
|
||||
rp = &_G(_rooms)[0];
|
||||
|
||||
while (ct < nr + 1) {
|
||||
for (int j = 0; j < 6; j++) {
|
||||
rp->_exits[j] = *(ptr++ - _G(_fileBaselineOffset));
|
||||
}
|
||||
ct++;
|
||||
rp++;
|
||||
}
|
||||
|
||||
if (seekIfNeeded(fixAddress(fixWord(dh._pOrigItems)), &offset, &ptr) == 0)
|
||||
return 0;
|
||||
|
||||
ct = 0;
|
||||
ip = &_G(_items)[0];
|
||||
while (ct < ni + 1) {
|
||||
ip->_location = *(ptr++ - _G(_fileBaselineOffset));
|
||||
ip->_initialLoc = ip->_location;
|
||||
ip++;
|
||||
ct++;
|
||||
}
|
||||
|
||||
loadTI994ADict(0, dh._pVerbTable, dh._numVerbs + 1, _G(_verbs));
|
||||
loadTI994ADict(1, dh._pNounTable, dh._numNouns + 1, _G(_nouns));
|
||||
|
||||
for (int i = 1; i <= dh._numNouns - dh._numVerbs; i++)
|
||||
_G(_verbs)[dh._numVerbs + i] = ".\0";
|
||||
|
||||
for (int i = 1; i <= dh._numVerbs - dh._numNouns; i++)
|
||||
_G(_nouns)[dh._numNouns + i] = ".\0";
|
||||
|
||||
if (loud) {
|
||||
for (int i = 0; i <= _G(_gameHeader)->_numWords; i++)
|
||||
debug("Verb %d: %s", i, _G(_verbs)[i].c_str());
|
||||
for (int i = 0; i <= _G(_gameHeader)->_numWords; i++)
|
||||
debug("Noun %d: %s", i, _G(_nouns)[i].c_str());
|
||||
}
|
||||
|
||||
ct = 0;
|
||||
ip = &_G(_items)[0];
|
||||
|
||||
if (seekIfNeeded(fixAddress(fixWord(dh._pObjLink)), &offset, &ptr) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int *objectlinks = new int[ni + 1];
|
||||
|
||||
do {
|
||||
objectlinks[ct] = *(ptr++ - _G(_fileBaselineOffset));
|
||||
if (objectlinks[ct] && objectlinks[ct] <= nw) {
|
||||
ip->_autoGet = _G(_nouns)[objectlinks[ct]];
|
||||
if (ct == 3 && scumm_strnicmp("bird", _G(_items)[ct]._text.c_str(), 4) == 0)
|
||||
ip->_autoGet = "BIRD";
|
||||
} else {
|
||||
ip->_autoGet = "";
|
||||
}
|
||||
ct++;
|
||||
ip++;
|
||||
} while (ct < ni + 1);
|
||||
|
||||
delete[] objectlinks;
|
||||
|
||||
readTI99ImplicitActions(dh);
|
||||
readTI99ExplicitActions(dh);
|
||||
|
||||
_G(_autoInventory) = 1;
|
||||
_G(_sys)[INVENTORY] = "I'm carrying: ";
|
||||
|
||||
_G(_titleScreen) = (char *)loadTitleScreen();
|
||||
delete[] _G(_entireFile);
|
||||
|
||||
for (int i = 0; i < MAX_SYSMESS && g_sysDictTI994A[i] != nullptr; i++) {
|
||||
_G(_sys)[i] = g_sysDictTI994A[i];
|
||||
}
|
||||
|
||||
_G(_options) |= TI994A_STYLE;
|
||||
return TI994A;
|
||||
}
|
||||
|
||||
void readHeader(Common::SeekableReadStream *f, DataHeader &dh) {
|
||||
f->seek(0);
|
||||
f->seek(_G(_fileBaselineOffset) + 0x8a0);
|
||||
dh._numObjects = f->readByte();
|
||||
dh._numVerbs = f->readByte();
|
||||
dh._numNouns = f->readByte();
|
||||
dh._redRoom = f->readByte();
|
||||
dh._maxItemsCarried = f->readByte();
|
||||
dh._beginLocn = f->readByte();
|
||||
dh._numTreasures = f->readByte();
|
||||
dh._cmdLength = f->readByte();
|
||||
dh._lightTurns = f->readUint16LE();
|
||||
dh._treasureLocn = f->readByte();
|
||||
dh._strange = f->readByte();
|
||||
|
||||
dh._pObjTable = f->readUint16LE();
|
||||
dh._pOrigItems = f->readUint16LE();
|
||||
dh._pObjLink = f->readUint16LE();
|
||||
dh._pObjDescr = f->readUint16LE();
|
||||
dh._pMessage = f->readUint16LE();
|
||||
dh._pRoomExit = f->readUint16LE();
|
||||
dh._pRoomDescr = f->readUint16LE();
|
||||
|
||||
dh._pNounTable = f->readUint16LE();
|
||||
dh._pVerbTable = f->readUint16LE();
|
||||
|
||||
dh._pExplicit = f->readUint16LE();
|
||||
dh._pImplicit = f->readUint16LE();
|
||||
}
|
||||
|
||||
GameIDType detectTI994A(Common::SeekableReadStream *f, uint8_t **sf, size_t *extent) {
|
||||
int offset = findCode("\x30\x30\x30\x30\x00\x30\x30\x00\x28\x28", 0);
|
||||
if (offset == -1)
|
||||
return UNKNOWN_GAME;
|
||||
|
||||
_G(_fileBaselineOffset) = offset - 0x589;
|
||||
|
||||
DataHeader dh;
|
||||
readHeader(f, dh);
|
||||
|
||||
getMaxTI99Messages(dh);
|
||||
getMaxTI99Items(dh);
|
||||
|
||||
return static_cast<GameIDType>(tryLoadingTI994A(dh, 0));
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
48
engines/glk/scott/load_ti99_4a.h
Normal file
48
engines/glk/scott/load_ti99_4a.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_LOAD_TI99_4A_H
|
||||
#define GLK_SCOTT_LOAD_TI99_4A_H
|
||||
|
||||
#include "common/file.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/definitions.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
GameIDType detectTI994A(Common::SeekableReadStream *f, uint8_t **sf, size_t *extent);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
1101
engines/glk/scott/resource.cpp
Normal file
1101
engines/glk/scott/resource.cpp
Normal file
File diff suppressed because it is too large
Load Diff
54
engines/glk/scott/resource.h
Normal file
54
engines/glk/scott/resource.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_RESOURCE_H
|
||||
#define GLK_SCOTT_RESOURCE_H
|
||||
|
||||
#include "common/stream.h"
|
||||
#include "glk/scott/definitions.h"
|
||||
#include "glk/scott/types.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void readHeader(uint8_t *ptr);
|
||||
int parseHeader(int *h, HeaderType type, int *ni, int *na, int *nw, int *nr, int *mc, int *pr, int *tr, int *wl, int *lt, int *mn, int *trm);
|
||||
uint8_t *seekToPos(uint8_t *buf, size_t offset);
|
||||
int seekIfNeeded(int expectedStart, int *offset, uint8_t **ptr);
|
||||
int tryLoading(GameInfo info, int dictStart, int loud);
|
||||
DictionaryType getId(int *offset);
|
||||
int findCode(const char *x, int base);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
169
engines/glk/scott/restore_state.cpp
Normal file
169
engines/glk/scott/restore_state.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "glk/scott/scott.h"
|
||||
#include "glk/scott/globals.h"
|
||||
#include "glk/scott/definitions.h"
|
||||
#include "glk/scott/restore_state.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
#define MAX_UNDOS 100
|
||||
|
||||
void saveUndo() {
|
||||
if (_G(_justUndid)) {
|
||||
_G(_justUndid) = 0;
|
||||
return;
|
||||
}
|
||||
if (_G(_lastUndo) == nullptr) {
|
||||
_G(_lastUndo) = saveCurrentState();
|
||||
_G(_oldestUndo) = _G(_lastUndo);
|
||||
_G(_numberOfUndos) = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_G(_numberOfUndos) == 0)
|
||||
g_scott->fatal("Number of undos == 0 but _G(_lastUndo) != nullptr!");
|
||||
|
||||
_G(_lastUndo)->_nextState = saveCurrentState();
|
||||
SavedState *current = _G(_lastUndo)->_nextState;
|
||||
current->_previousState = _G(_lastUndo);
|
||||
_G(_lastUndo) = current;
|
||||
if (_G(_numberOfUndos) == MAX_UNDOS) {
|
||||
SavedState *oldest = _G(_oldestUndo);
|
||||
_G(_oldestUndo) = _G(_oldestUndo)->_nextState;
|
||||
_G(_oldestUndo)->_previousState = nullptr;
|
||||
delete[] oldest->_itemLocations;
|
||||
delete oldest;
|
||||
} else {
|
||||
_G(_numberOfUndos)++;
|
||||
}
|
||||
}
|
||||
|
||||
void restoreUndo() {
|
||||
if (_G(_justStarted)) {
|
||||
g_scott->output(_G(_sys)[CANT_UNDO_ON_FIRST_TURN]);
|
||||
return;
|
||||
}
|
||||
if (_G(_lastUndo) == nullptr || _G(_lastUndo)->_previousState == nullptr) {
|
||||
g_scott->output(_G(_sys)[NO_UNDO_STATES]);
|
||||
return;
|
||||
}
|
||||
SavedState *current = _G(_lastUndo);
|
||||
_G(_lastUndo) = current->_previousState;
|
||||
if (_G(_lastUndo)->_previousState == nullptr)
|
||||
_G(_oldestUndo) = _G(_lastUndo);
|
||||
restoreState(_G(_lastUndo));
|
||||
g_scott->output(_G(_sys)[MOVE_UNDONE]);
|
||||
delete[] current->_itemLocations;
|
||||
delete current;
|
||||
_G(_numberOfUndos)--;
|
||||
_G(_justUndid) = 1;
|
||||
}
|
||||
|
||||
void ramSave() {
|
||||
if (_G(_ramSave) != nullptr) {
|
||||
delete[] _G(_ramSave)->_itemLocations;
|
||||
delete _G(_ramSave);
|
||||
}
|
||||
|
||||
_G(_ramSave) = saveCurrentState();
|
||||
g_scott->output(_G(_sys)[STATE_SAVED]);
|
||||
}
|
||||
|
||||
void ramRestore() {
|
||||
if (_G(_ramSave) == nullptr) {
|
||||
g_scott->output(_G(_sys)[NO_SAVED_STATE]);
|
||||
return;
|
||||
}
|
||||
|
||||
restoreState(_G(_ramSave));
|
||||
g_scott->output(_G(_sys)[STATE_RESTORED]);
|
||||
saveUndo();
|
||||
}
|
||||
|
||||
SavedState *saveCurrentState() {
|
||||
SavedState *s = new SavedState;
|
||||
for (int ct = 0; ct < 16; ct++) {
|
||||
s->_counters[ct] = _G(_counters)[ct];
|
||||
s->_roomSaved[ct] = _G(_roomSaved)[ct];
|
||||
}
|
||||
|
||||
s->_bitFlags = _G(_bitFlags);
|
||||
s->_currentLoc = MY_LOC;
|
||||
s->_currentCounter = _G(_currentCounter);
|
||||
s->_savedRoom = _G(_savedRoom);
|
||||
s->_lightTime = _G(_gameHeader)->_lightTime;
|
||||
s->_autoInventory = _G(_autoInventory);
|
||||
|
||||
s->_itemLocations = new uint8_t[_G(_gameHeader)->_numItems + 1];
|
||||
|
||||
for (int ct = 0; ct <= _G(_gameHeader)->_numItems; ct++) {
|
||||
s->_itemLocations[ct] = _G(_items)[ct]._location;
|
||||
}
|
||||
|
||||
s->_previousState = nullptr;
|
||||
s->_nextState = nullptr;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void recoverFromBadRestore(SavedState *state) {
|
||||
g_scott->output(_G(_sys)[BAD_DATA]);
|
||||
restoreState(state);
|
||||
delete state;
|
||||
}
|
||||
|
||||
void restoreState(SavedState *state) {
|
||||
for (int ct = 0; ct < 16; ct++) {
|
||||
_G(_counters)[ct] = state->_counters[ct];
|
||||
_G(_roomSaved)[ct] = state->_roomSaved[ct];
|
||||
}
|
||||
|
||||
_G(_bitFlags) = state->_bitFlags;
|
||||
|
||||
MY_LOC = state->_currentLoc;
|
||||
_G(_currentCounter) = state->_currentCounter;
|
||||
_G(_savedRoom) = state->_savedRoom;
|
||||
_G(_gameHeader)->_lightTime = state->_lightTime;
|
||||
_G(_autoInventory) = state->_autoInventory;
|
||||
|
||||
for (int ct = 0; ct <= _G(_gameHeader)->_numItems; ct++) {
|
||||
_G(_items)[ct]._location = state->_itemLocations[ct];
|
||||
}
|
||||
|
||||
_G(_stopTime) = 1;
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
66
engines/glk/scott/restore_state.h
Normal file
66
engines/glk/scott/restore_state.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_RESTORESTATE_H
|
||||
#define GLK_SCOTT_RESTORESTATE_H
|
||||
|
||||
#include "glk/scott/types.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
struct SavedState {
|
||||
int _counters[16];
|
||||
int _roomSaved[16];
|
||||
uint32_t _bitFlags = 0;
|
||||
int _currentLoc = 0;
|
||||
int _currentCounter = 0;
|
||||
int _savedRoom = 0;
|
||||
int _lightTime = 0;
|
||||
int _autoInventory = 0;
|
||||
uint8_t *_itemLocations = nullptr;
|
||||
SavedState *_previousState = nullptr;
|
||||
SavedState *_nextState = nullptr;
|
||||
};
|
||||
|
||||
void saveUndo();
|
||||
void restoreUndo();
|
||||
void ramSave();
|
||||
void ramRestore();
|
||||
SavedState *saveCurrentState();
|
||||
void recoverFromBadRestore(SavedState *state);
|
||||
void restoreState(SavedState *state);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
145
engines/glk/scott/ring_buffer.cpp
Normal file
145
engines/glk/scott/ring_buffer.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "glk/scott/ring_buffer.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
// The hidden definition of our circular buffer structure
|
||||
struct CircularBuf {
|
||||
uint8_t *_buffer;
|
||||
size_t _head;
|
||||
size_t _tail;
|
||||
size_t _max; // of the buffer
|
||||
bool _full;
|
||||
};
|
||||
|
||||
// Return a pointer to a struct instance
|
||||
cbuf_handle_t circularBufInit(uint8_t *buffer, size_t size) {
|
||||
cbuf_handle_t cbuf = new CircularBuf;
|
||||
cbuf->_buffer = buffer;
|
||||
cbuf->_max = size;
|
||||
circularBufReset(cbuf);
|
||||
|
||||
return cbuf;
|
||||
}
|
||||
|
||||
void circularBufReset(cbuf_handle_t me) {
|
||||
me->_head = 0;
|
||||
me->_tail = 0;
|
||||
me->_full = false;
|
||||
}
|
||||
|
||||
void circularBufFree(cbuf_handle_t me) {
|
||||
delete me;
|
||||
}
|
||||
|
||||
bool circularBufFull(cbuf_handle_t me) {
|
||||
return me->_full;
|
||||
}
|
||||
|
||||
bool circularBufEmpty(cbuf_handle_t me) {
|
||||
return (!me->_full && (me->_head == me->_tail));
|
||||
}
|
||||
|
||||
size_t circularBufCapacity(cbuf_handle_t me) {
|
||||
return me->_max;
|
||||
}
|
||||
|
||||
size_t circularBufSize(cbuf_handle_t me) {
|
||||
size_t size = me->_max;
|
||||
|
||||
if (!me->_full) {
|
||||
if (me->_head >= me->_tail) {
|
||||
size = (me->_head - me->_tail);
|
||||
} else {
|
||||
size = (me->_max + me->_head - me->_tail);
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void advancePointer(cbuf_handle_t me) {
|
||||
if (me->_full) {
|
||||
if (++(me->_tail) == me->_max) {
|
||||
me->_tail = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (++(me->_head) == me->_max) {
|
||||
me->_head = 0;
|
||||
}
|
||||
me->_full = (me->_head == me->_tail);
|
||||
}
|
||||
|
||||
static void retreatPointer(cbuf_handle_t me) {
|
||||
|
||||
me->_full = false;
|
||||
if (++(me->_tail) == me->_max) {
|
||||
me->_tail = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int circularBufPut(cbuf_handle_t me, uint8_t x, uint8_t y) {
|
||||
int r = -1;
|
||||
|
||||
if (!circularBufFull(me)) {
|
||||
me->_buffer[me->_head] = x;
|
||||
advancePointer(me);
|
||||
if (!circularBufFull(me)) {
|
||||
me->_buffer[me->_head] = y;
|
||||
advancePointer(me);
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int circularBufGet(cbuf_handle_t me, int *x, int *y) {
|
||||
int r = -1;
|
||||
|
||||
if (!circularBufEmpty(me)) {
|
||||
*x = me->_buffer[me->_tail];
|
||||
retreatPointer(me);
|
||||
if (!circularBufEmpty(me)) {
|
||||
*y = me->_buffer[me->_tail];
|
||||
retreatPointer(me);
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
80
engines/glk/scott/ring_buffer.h
Normal file
80
engines/glk/scott/ring_buffer.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_RINGBUFFER_H
|
||||
#define GLK_SCOTT_RINGBUFFER_H
|
||||
|
||||
#include "glk/scott/types.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
// Opaque circular buffer structure
|
||||
struct CircularBuf;
|
||||
// Handle type, the way users interact with the API
|
||||
typedef CircularBuf *cbuf_handle_t;
|
||||
|
||||
/// Pass in a storage buffer and size
|
||||
/// Returns a circular buffer handle
|
||||
cbuf_handle_t circularBufInit(uint8_t *buffer, size_t size);
|
||||
|
||||
/// Free a circular buffer structure.
|
||||
/// Does not free data buffer; owner is responsible for that
|
||||
void circularBufFree(cbuf_handle_t me);
|
||||
|
||||
/// Reset the circular buffer to empty, head == tail
|
||||
void circularBufReset(cbuf_handle_t me);
|
||||
|
||||
/// Rejects new data if the buffer is full
|
||||
/// Returns 0 on success, -1 if buffer is full
|
||||
int circularBufPut(cbuf_handle_t me, uint8_t x, uint8_t y);
|
||||
|
||||
/// Retrieve a value from the buffer
|
||||
/// Returns 0 on success, -1 if the buffer is empty
|
||||
int circularBufGet(cbuf_handle_t me, int *x, int *y);
|
||||
|
||||
/// Returns true if the buffer is empty
|
||||
bool circularBufEmpty(cbuf_handle_t me);
|
||||
|
||||
/// Returns true if the buffer is full
|
||||
bool circularBufFull(cbuf_handle_t me);
|
||||
|
||||
/// Returns the maximum capacity of the buffer
|
||||
size_t circularBufCapacity(cbuf_handle_t me);
|
||||
|
||||
/// Returns the current number of elements in the buffer
|
||||
size_t circularBufSize(cbuf_handle_t me);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
448
engines/glk/scott/robin_of_sherwood.cpp
Normal file
448
engines/glk/scott/robin_of_sherwood.cpp
Normal file
@@ -0,0 +1,448 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "glk/scott/scott.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/globals.h"
|
||||
#include "glk/scott/resource.h"
|
||||
#include "glk/scott/saga_draw.h"
|
||||
#include "glk/scott/decompress_text.h"
|
||||
#include "glk/scott/robin_of_sherwood.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
#define WATERFALL_ANIMATION_RATE 15
|
||||
|
||||
void animateLightning(int stage);
|
||||
|
||||
void sherwoodAction(int p) {
|
||||
event_t ev;
|
||||
|
||||
switch (p) {
|
||||
case 0:
|
||||
// Flash animation
|
||||
_G(_animationFlag) = 1;
|
||||
g_scott->glk_request_timer_events(15);
|
||||
|
||||
while (_G(_animationFlag) < 11) {
|
||||
g_scott->glk_select(&ev);
|
||||
if (ev.type == evtype_Timer) {
|
||||
_G(_animationFlag)++;
|
||||
animateLightning(_G(_animationFlag));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
g_scott->drawImage(0); /* Herne */
|
||||
g_scott->display(_G(_bottomWindow), "\n%s\n", _G(_sys)[HIT_ENTER].c_str());
|
||||
g_scott->hitEnter();
|
||||
_G(_items)[39]._location = 79;
|
||||
g_scott->look();
|
||||
break;
|
||||
case 2:
|
||||
// Climbing tree in forest
|
||||
_G(_savedRoom) = MY_LOC;
|
||||
MY_LOC = 93;
|
||||
g_scott->look();
|
||||
break;
|
||||
default:
|
||||
error("sherwoodAction: Unhandled SherwoodAction %d!", p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int isForestLocation(void) { return (MY_LOC >= 11 && MY_LOC <= 73); }
|
||||
|
||||
#define TREES 0
|
||||
#define BUSHES 1
|
||||
|
||||
void drawSherwood(int loc) {
|
||||
g_scott->glk_window_clear(_G(_graphics));
|
||||
int subimage_index = 0;
|
||||
|
||||
for (int i = 0; i < loc - 11; i++) {
|
||||
// BUSHES type images are made up of 5 smaller images
|
||||
int skip = 5;
|
||||
if (_G(_forestImages)[subimage_index] < 128)
|
||||
// Those with bit 7 unset have 10 (trees only) or 11 (trees with path)
|
||||
skip = 11;
|
||||
subimage_index += skip;
|
||||
}
|
||||
|
||||
int forest_type = TREES;
|
||||
int subimages;
|
||||
|
||||
// if bit 7 of the image index is set then this image is BUSHES
|
||||
if (_G(_forestImages)[subimage_index] >= 128) {
|
||||
forest_type = BUSHES;
|
||||
subimages = 5;
|
||||
// if the last subimage value is 255, there is no path
|
||||
} else if (_G(_forestImages)[subimage_index + 10] == 0xff) {
|
||||
// Trees only
|
||||
subimages = 10;
|
||||
} else {
|
||||
// Trees with path
|
||||
subimages = 11;
|
||||
}
|
||||
|
||||
int xpos = 0, ypos = 0, image_number;
|
||||
|
||||
for (int i = 0; i < subimages; i++) {
|
||||
if (forest_type == TREES) {
|
||||
if (i >= 8) {
|
||||
if (i == 8) { // Undergrowth
|
||||
ypos = 7;
|
||||
xpos = 0;
|
||||
} else if (i == 9) { // _G(_bottomWindow) path
|
||||
ypos = 10;
|
||||
xpos = 0;
|
||||
} else { // Forward path
|
||||
ypos = 7;
|
||||
xpos = 12;
|
||||
}
|
||||
} else { // Trees (every tree image is 4 characters wide)
|
||||
ypos = 0;
|
||||
xpos = i * 4;
|
||||
}
|
||||
}
|
||||
|
||||
image_number = _G(_forestImages)[subimage_index++] & 127;
|
||||
|
||||
drawSagaPictureAtPos(image_number, xpos, ypos);
|
||||
|
||||
if (forest_type == BUSHES) {
|
||||
xpos += _G(_images)[image_number]._width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void animateWaterfall(int stage) {
|
||||
rectFill(88, 16, 48, 64, _G(_whiteColour));
|
||||
for (int line = 2; line < 10; line++) {
|
||||
for (int col = 11; col < 17; col++) {
|
||||
for (int i = 0; i < 8; i++)
|
||||
for (int j = 0; j < 8; j++)
|
||||
if ((_G(_screenchars)[col + line * 32][i] & (1 << j)) != 0) {
|
||||
int ypos = line * 8 + i + stage;
|
||||
if (ypos > 79)
|
||||
ypos = ypos - 64;
|
||||
putPixel(col * 8 + j, ypos, _G(_blueColour));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void animateWaterfallCave(int stage) {
|
||||
rectFill(248, 24, 8, 64, _G(_whiteColour));
|
||||
for (int line = 3; line < 11; line++) {
|
||||
for (int i = 0; i < 8; i++)
|
||||
for (int j = 0; j < 8; j++)
|
||||
if ((_G(_screenchars)[31 + line * 32][i] & (1 << j)) != 0) {
|
||||
int ypos = line * 8 + i + stage;
|
||||
if (ypos > 87)
|
||||
ypos = ypos - 64;
|
||||
putPixel(248 + j, ypos, _G(_blueColour));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void animateLightning(int stage) {
|
||||
// swich blue and bright yellow
|
||||
if (_G(_palChosen) == C64B)
|
||||
switchPalettes(6, 7);
|
||||
else {
|
||||
switchPalettes(1, 14);
|
||||
switchPalettes(9, 6);
|
||||
}
|
||||
drawSagaPictureNumber(77);
|
||||
if (stage == 11) {
|
||||
g_scott->glk_request_timer_events(0);
|
||||
} else if (stage == 3) {
|
||||
g_scott->glk_request_timer_events(700);
|
||||
} else {
|
||||
g_scott->glk_request_timer_events(40);
|
||||
}
|
||||
}
|
||||
|
||||
void robinOfSherwoodLook(void) {
|
||||
if (!isForestLocation()) {
|
||||
if (_G(_rooms)[MY_LOC]._image == 255) {
|
||||
g_scott->closeGraphicsWindow();
|
||||
} else {
|
||||
g_scott->drawImage(_G(_rooms)[MY_LOC]._image);
|
||||
for (int ct = 0; ct <= _G(_gameHeader)->_numItems; ct++)
|
||||
if (_G(_items)[ct]._image) {
|
||||
if ((_G(_items)[ct]._flag & 127) == MY_LOC && _G(_items)[ct]._location == MY_LOC) {
|
||||
g_scott->drawImage(_G(_items)[ct]._image);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (MY_LOC == 82) // Dummy room where exit from Up a tree goes
|
||||
MY_LOC = _G(_savedRoom);
|
||||
if (MY_LOC == 93) // Up a tree
|
||||
for (int i = 0; i < _G(_gameHeader)->_numItems; i++)
|
||||
if (_G(_items)[i]._location == 93)
|
||||
_G(_items)[i]._location = _G(_savedRoom);
|
||||
if (MY_LOC == 7 && _G(_items)[62]._location == 7) // Left bedroom, open treasure chest
|
||||
g_scott->drawImage(70);
|
||||
if (isForestLocation()) {
|
||||
g_scott->openGraphicsWindow();
|
||||
drawSherwood(MY_LOC);
|
||||
|
||||
if (_G(_items)[36]._location == MY_LOC) {
|
||||
//"Gregory the tax collector with his horse and cart"
|
||||
g_scott->drawImage(15); // Horse and cart
|
||||
g_scott->drawImage(3); // Sacks of grain
|
||||
}
|
||||
if (_G(_items)[60]._location == MY_LOC || _G(_items)[77]._location == MY_LOC) {
|
||||
// "A serf driving a horse and cart"
|
||||
g_scott->drawImage(15); // Horse and cart
|
||||
g_scott->drawImage(12); // Hay
|
||||
}
|
||||
if (MY_LOC == 73) {
|
||||
// Outlaws camp
|
||||
g_scott->drawImage(36); // Campfire
|
||||
}
|
||||
}
|
||||
|
||||
if (MY_LOC == 86 || MY_LOC == 79) {
|
||||
g_scott->glk_request_timer_events(WATERFALL_ANIMATION_RATE);
|
||||
}
|
||||
}
|
||||
|
||||
void updateRobinOfSherwoodAnimations(void) {
|
||||
_G(_animationFlag)++;
|
||||
if (_G(_animationFlag) > 63)
|
||||
_G(_animationFlag) = 0;
|
||||
if (MY_LOC == 86 || MY_LOC == 79 || MY_LOC == 84) {
|
||||
/* If we're in room 84, the stone circle, we just */
|
||||
/* want the timer to not switch off */
|
||||
if (MY_LOC == 86) {
|
||||
animateWaterfall(_G(_animationFlag));
|
||||
} else if (MY_LOC == 79) {
|
||||
animateWaterfallCave(_G(_animationFlag));
|
||||
}
|
||||
} else {
|
||||
g_scott->glk_request_timer_events(0);
|
||||
}
|
||||
}
|
||||
|
||||
GameIDType loadExtraSherwoodData(void) {
|
||||
int offset = 0x3d99 + _G(_fileBaselineOffset);
|
||||
uint8_t *ptr;
|
||||
/* Load the room images */
|
||||
|
||||
ptr = seekToPos(_G(_entireFile), offset);
|
||||
if (ptr == 0)
|
||||
return UNKNOWN_GAME;
|
||||
|
||||
int ct;
|
||||
Room *rp = &_G(_rooms)[0];
|
||||
|
||||
for (ct = 0; ct <= _G(_gameHeader)->_numRooms; ct++) {
|
||||
rp->_image = *(ptr++);
|
||||
rp++;
|
||||
if (ct == 10) {
|
||||
for (int i = 0; i < 63; i++) {
|
||||
rp++;
|
||||
ct++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ct = 0;
|
||||
rp = &_G(_rooms)[0];
|
||||
|
||||
//int actual_room_number = 0;
|
||||
|
||||
ptr = seekToPos(_G(_entireFile), 0x5b7e + _G(_fileBaselineOffset));
|
||||
if (ptr == 0)
|
||||
return UNKNOWN_GAME;
|
||||
|
||||
do {
|
||||
rp->_text = decompressText(ptr, ct);
|
||||
rp->_text.toLowercase();
|
||||
ct++;
|
||||
//actual_room_number++;
|
||||
if (ct == 11) {
|
||||
for (int i = 0; i < 61; i++) {
|
||||
rp++;
|
||||
rp->_text = "in Sherwood Forest";
|
||||
//actual_room_number++;
|
||||
}
|
||||
}
|
||||
rp++;
|
||||
} while (ct < 33);
|
||||
|
||||
for (int i = I_DONT_UNDERSTAND; i <= THATS_BEYOND_MY_POWER; i++)
|
||||
_G(_sys)[i] = _G(_systemMessages)[4 - I_DONT_UNDERSTAND + i];
|
||||
|
||||
for (int i = YOU_SEE; i <= HIT_ENTER; i++)
|
||||
_G(_sys)[i] = _G(_systemMessages)[15 - YOU_SEE + i];
|
||||
|
||||
_G(_sys)[OK] = _G(_systemMessages)[2];
|
||||
_G(_sys)[TAKEN] = _G(_systemMessages)[2];
|
||||
_G(_sys)[DROPPED] = _G(_systemMessages)[2];
|
||||
_G(_sys)[PLAY_AGAIN] = _G(_systemMessages)[3];
|
||||
_G(_sys)[YOURE_CARRYING_TOO_MUCH] = _G(_systemMessages)[21];
|
||||
_G(_sys)[YOU_CANT_GO_THAT_WAY] = _G(_systemMessages)[12];
|
||||
_G(_sys)[YOU_ARE] = _G(_systemMessages)[13];
|
||||
_G(_sys)[EXITS_DELIMITER] = " ";
|
||||
_G(_sys)[MESSAGE_DELIMITER] = ". ";
|
||||
|
||||
ptr = seekToPos(_G(_entireFile), 0x3b6e + _G(_fileBaselineOffset));
|
||||
if (ptr == 0)
|
||||
return UNKNOWN_GAME;
|
||||
|
||||
int cells = 555;
|
||||
_G(_forestImages) = new uint8_t[cells];
|
||||
|
||||
for (int i = 0; i < cells; i++)
|
||||
_G(_forestImages)[i] = *(ptr++);
|
||||
|
||||
return ROBIN_OF_SHERWOOD;
|
||||
}
|
||||
|
||||
GameIDType loadExtraSherwoodData64(void) {
|
||||
|
||||
// white_colour = 1;
|
||||
// blue = 6;
|
||||
|
||||
int offset = 0x1ffd + _G(_fileBaselineOffset);
|
||||
uint8_t *ptr;
|
||||
/* Load the room images */
|
||||
|
||||
ptr = seekToPos(_G(_entireFile), offset);
|
||||
if (ptr == 0)
|
||||
return UNKNOWN_GAME;
|
||||
|
||||
int ct;
|
||||
Room *rp = &_G(_rooms)[0];
|
||||
|
||||
for (ct = 0; ct <= _G(_gameHeader)->_numRooms; ct++) {
|
||||
rp->_image = *(ptr++);
|
||||
rp++;
|
||||
|
||||
if (ct == 10) {
|
||||
for (int i = 0; i < 63; i++) {
|
||||
rp++;
|
||||
ct++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ct = 0;
|
||||
rp = &_G(_rooms)[0];
|
||||
|
||||
//int actual_room_number = 0;
|
||||
|
||||
offset = 0x402e + _G(_fileBaselineOffset);
|
||||
|
||||
ptr = seekToPos(_G(_entireFile), offset);
|
||||
if (ptr == 0)
|
||||
return UNKNOWN_GAME;
|
||||
|
||||
do {
|
||||
rp->_text = decompressText(ptr, ct);
|
||||
rp->_text.toLowercase();
|
||||
ct++;
|
||||
//actual_room_number++;
|
||||
if (ct == 11) {
|
||||
for (int i = 0; i < 61; i++) {
|
||||
rp++;
|
||||
rp->_text = "in Sherwood Forest";
|
||||
//actual_room_number++;
|
||||
}
|
||||
}
|
||||
rp++;
|
||||
} while (ct < 33);
|
||||
|
||||
SysMessageType messagekey[] = {NORTH,
|
||||
SOUTH,
|
||||
EAST,
|
||||
WEST,
|
||||
UP,
|
||||
DOWN,
|
||||
EXITS,
|
||||
YOU_SEE,
|
||||
YOU_ARE,
|
||||
HIT_ENTER,
|
||||
YOU_CANT_GO_THAT_WAY,
|
||||
OK,
|
||||
WHAT_NOW,
|
||||
HUH,
|
||||
YOU_HAVE_IT,
|
||||
TAKEN,
|
||||
DROPPED,
|
||||
YOU_HAVENT_GOT_IT,
|
||||
INVENTORY,
|
||||
YOU_DONT_SEE_IT,
|
||||
THATS_BEYOND_MY_POWER,
|
||||
DIRECTION,
|
||||
YOURE_CARRYING_TOO_MUCH,
|
||||
PLAY_AGAIN,
|
||||
RESUME_A_SAVED_GAME,
|
||||
YOU_CANT_DO_THAT_YET,
|
||||
I_DONT_UNDERSTAND,
|
||||
NOTHING};
|
||||
|
||||
for (int i = 0; i < 26; i++) {
|
||||
_G(_sys)[messagekey[i]] = _G(_systemMessages)[i];
|
||||
}
|
||||
|
||||
_G(_sys)[HIT_ENTER] = _G(_systemMessages)[30];
|
||||
_G(_sys)[WHAT] = _G(_systemMessages)[13];
|
||||
|
||||
_G(_sys)[EXITS_DELIMITER] = " ";
|
||||
_G(_sys)[MESSAGE_DELIMITER] = ". ";
|
||||
|
||||
offset = 0x2300 + _G(_fileBaselineOffset);
|
||||
|
||||
ptr = seekToPos(_G(_entireFile), offset);
|
||||
if (ptr == 0)
|
||||
return UNKNOWN_GAME;
|
||||
|
||||
int cells = 555;
|
||||
_G(_forestImages) = new uint8_t[cells];
|
||||
|
||||
for (int i = 0; i < cells; i++) {
|
||||
_G(_forestImages)[i] = *(ptr++);
|
||||
}
|
||||
|
||||
return ROBIN_OF_SHERWOOD_C64;
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
51
engines/glk/scott/robin_of_sherwood.h
Normal file
51
engines/glk/scott/robin_of_sherwood.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_ROBIN_OF_SHERWOOD_H
|
||||
#define GLK_SCOTT_ROBIN_OF_SHERWOOD_H
|
||||
|
||||
#include "glk/scott/definitions.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void updateRobinOfSherwoodAnimations();
|
||||
void robinOfSherwoodLook();
|
||||
GameIDType loadExtraSherwoodData();
|
||||
GameIDType loadExtraSherwoodData64();
|
||||
int isForestLocation();
|
||||
void sherwoodAction(int p);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
727
engines/glk/scott/saga_draw.cpp
Normal file
727
engines/glk/scott/saga_draw.cpp
Normal file
@@ -0,0 +1,727 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "glk/scott/scott.h"
|
||||
#include "glk/scott/definitions.h"
|
||||
#include "glk/scott/resource.h"
|
||||
#include "glk/scott/globals.h"
|
||||
#include "glk/scott/saga_draw.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
#define INVALID_COLOR 16
|
||||
|
||||
void rot90(uint8_t character[]) {
|
||||
int32_t i, j;
|
||||
uint8_t work2[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
for (j = 0; j < 8; j++)
|
||||
if ((character[j] & (1 << i)) != 0)
|
||||
work2[7 - i] += 1 << j;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
character[i] = work2[i];
|
||||
}
|
||||
|
||||
void rot180(uint8_t character[]) {
|
||||
int32_t i, j;
|
||||
uint8_t work2[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
for (j = 0; j < 8; j++)
|
||||
if ((character[i] & (1 << j)) != 0)
|
||||
work2[7 - i] += 1 << (7 - j);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
character[i] = work2[i];
|
||||
}
|
||||
|
||||
void rot270(uint8_t character[]) {
|
||||
int32_t i, j;
|
||||
uint8_t work2[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
for (j = 0; j < 8; j++)
|
||||
if ((character[j] & (1 << i)) != 0)
|
||||
work2[i] += 1 << (7 - j);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
character[i] = work2[i];
|
||||
}
|
||||
|
||||
void flip(uint8_t character[]) {
|
||||
int32_t i, j;
|
||||
uint8_t work2[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
for (j = 0; j < 8; j++)
|
||||
if ((character[i] & (1 << j)) != 0)
|
||||
work2[i] += 1 << (7 - j);
|
||||
for (i = 0; i < 8; i++)
|
||||
character[i] = work2[i];
|
||||
}
|
||||
|
||||
void background(int32_t x, int32_t y, int32_t color) {
|
||||
/* Draw the background */
|
||||
rectFill(x * 8, y * 8, 8, 8, color);
|
||||
}
|
||||
|
||||
void plotsprite(int32_t character, int32_t x, int32_t y, int32_t fg, int32_t bg) {
|
||||
int32_t i, j;
|
||||
background(x, y, bg);
|
||||
for (i = 0; i < 8; i++) {
|
||||
for (j = 0; j < 8; j++)
|
||||
if ((_G(_screenchars)[character][i] & (1 << j)) != 0)
|
||||
putPixel(x * 8 + j, y * 8 + i, fg);
|
||||
}
|
||||
}
|
||||
|
||||
void transform(int32_t character, int32_t flipMode, int32_t ptr) {
|
||||
if (character > 255)
|
||||
return;
|
||||
uint8_t work[8];
|
||||
int32_t i;
|
||||
|
||||
#ifdef DRAWDEBUG
|
||||
debug("Plotting char: %d with flip: %02x (%s) at %d: %d,%d\n",
|
||||
character, flip_mode, flipdescription[(flip_mode & 48) >> 4],
|
||||
ptr, ptr % 0x20, ptr / 0x20);
|
||||
#endif
|
||||
|
||||
// first copy the character into work
|
||||
for (i = 0; i < 8; i++)
|
||||
work[i] = _G(_sprite)[character][i];
|
||||
|
||||
// Now flip it
|
||||
if ((flipMode & 0x30) == 0x10) {
|
||||
rot90(work);
|
||||
}
|
||||
if ((flipMode & 0x30) == 0x20) {
|
||||
rot180(work);
|
||||
}
|
||||
if ((flipMode & 0x30) == 0x30) {
|
||||
rot270(work);
|
||||
}
|
||||
if ((flipMode & 0x40) != 0) {
|
||||
flip(work);
|
||||
}
|
||||
flip(work);
|
||||
|
||||
// Now mask it onto the previous character
|
||||
for (i = 0; i < 8; i++) {
|
||||
if ((flipMode & 0x0c) == 12)
|
||||
_G(_screenchars)[ptr][i] ^= work[i];
|
||||
else if ((flipMode & 0x0c) == 8)
|
||||
_G(_screenchars)[ptr][i] &= work[i];
|
||||
else if ((flipMode & 0x0c) == 4)
|
||||
_G(_screenchars)[ptr][i] |= work[i];
|
||||
else
|
||||
_G(_screenchars)[ptr][i] = work[i];
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *drawSagaPictureFromData(uint8_t *dataptr, int xSize, int ySize, int xOff, int yOff) {
|
||||
int32_t offset = 0, cont = 0;
|
||||
int32_t i, x, y, mask_mode;
|
||||
uint8_t data, data2, old = 0;
|
||||
int32_t ink[0x22][14], paper[0x22][14];
|
||||
|
||||
// uint8_t *origptr = dataptr;
|
||||
int version = _G(_game)->_pictureFormatVersion;
|
||||
|
||||
offset = 0;
|
||||
int32_t character = 0;
|
||||
int32_t count;
|
||||
do {
|
||||
count = 1;
|
||||
|
||||
/* first handle mode */
|
||||
data = *dataptr++;
|
||||
if (data < 0x80) {
|
||||
if (character > 127 && version > 2) {
|
||||
data += 128;
|
||||
}
|
||||
character = data;
|
||||
#ifdef DRAWDEBUG
|
||||
debug("******* SOLO CHARACTER: %04x\n", character);
|
||||
#endif
|
||||
transform(character, 0, offset);
|
||||
offset++;
|
||||
if (offset > 767)
|
||||
break;
|
||||
} else {
|
||||
// first check for a count
|
||||
if ((data & 2) == 2) {
|
||||
count = (*dataptr++) + 1;
|
||||
}
|
||||
|
||||
// Next get character and plot (count) times
|
||||
character = *dataptr++;
|
||||
|
||||
// Plot the initial character
|
||||
if ((data & 1) == 1 && character < 128)
|
||||
character += 128;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
transform(character, (data & 0x0c) ? (data & 0xf3) : data, offset + i);
|
||||
|
||||
// Now check for overlays
|
||||
if ((data & 0xc) != 0) {
|
||||
// We have overlays so grab each member of the stream and work out what
|
||||
// to do with it
|
||||
|
||||
mask_mode = (data & 0xc);
|
||||
data2 = *dataptr++;
|
||||
old = data;
|
||||
do {
|
||||
cont = 0;
|
||||
if (data2 < 0x80) {
|
||||
if (version == 4 && (old & 1) == 1)
|
||||
data2 += 128;
|
||||
#ifdef DRAWDEBUG
|
||||
debug("Plotting %d directly (overlay) at %d\n", data2, offset);
|
||||
#endif
|
||||
for (i = 0; i < count; i++)
|
||||
transform(data2, old & 0x0c, offset + i);
|
||||
} else {
|
||||
character = *dataptr++;
|
||||
if ((data2 & 1) == 1)
|
||||
character += 128;
|
||||
#ifdef DRAWDEBUG
|
||||
debug("Plotting %d with flip %02x (%s) at %d %d\n", character, (data2 | mask_mode), flipdescription[((data2 | mask_mode) & 48) >> 4],
|
||||
offset, count);
|
||||
#endif
|
||||
for (i = 0; i < count; i++)
|
||||
transform(character, (data2 & 0xf3) | mask_mode, offset + i);
|
||||
if ((data2 & 0x0c) != 0) {
|
||||
mask_mode = (data2 & 0x0c);
|
||||
old = data2;
|
||||
cont = 1;
|
||||
data2 = *dataptr++;
|
||||
}
|
||||
}
|
||||
} while (cont != 0);
|
||||
}
|
||||
offset += count;
|
||||
}
|
||||
} while (offset < xSize * ySize);
|
||||
|
||||
y = 0;
|
||||
x = 0;
|
||||
|
||||
uint8_t colour = 0;
|
||||
// Note version 3 count is inverse it is repeat previous colour
|
||||
// Whilst version0-2 count is repeat next character
|
||||
while (y < ySize) {
|
||||
if (dataptr > _G(_entireFile) && static_cast<size_t>(dataptr - _G(_entireFile)) > _G(_fileLength))
|
||||
return dataptr - 1;
|
||||
data = *dataptr++;
|
||||
if ((data & 0x80)) {
|
||||
count = (data & 0x7f) + 1;
|
||||
if (version >= 3) {
|
||||
count--;
|
||||
} else {
|
||||
colour = *dataptr++;
|
||||
}
|
||||
} else {
|
||||
count = 1;
|
||||
colour = data;
|
||||
}
|
||||
while (count > 0) {
|
||||
// Now split up depending on which version we're using
|
||||
|
||||
// For version 3+
|
||||
|
||||
if (_G(_drawToBuffer))
|
||||
_G(_buffer)[(yOff + y) * 32 + (xOff + x)][8] = colour;
|
||||
else {
|
||||
if (version > 2) {
|
||||
if (x > 33)
|
||||
return nullptr;
|
||||
// ink is 0-2, screen is 3-5, 6 in bright flag
|
||||
ink[x][y] = colour & 0x07;
|
||||
paper[x][y] = (colour & 0x38) >> 3;
|
||||
|
||||
if ((colour & 0x40) == 0x40) {
|
||||
paper[x][y] += 8;
|
||||
ink[x][y] += 8;
|
||||
}
|
||||
} else {
|
||||
if (x > 33)
|
||||
return nullptr;
|
||||
paper[x][y] = colour & 0x07;
|
||||
ink[x][y] = ((colour & 0x70) >> 4);
|
||||
|
||||
if ((colour & 0x08) == 0x08 || version < 2) {
|
||||
paper[x][y] += 8;
|
||||
ink[x][y] += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x++;
|
||||
if (x == xSize) {
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
count--;
|
||||
}
|
||||
}
|
||||
offset = 0;
|
||||
int32_t xoff2;
|
||||
for (y = 0; y < ySize; y++)
|
||||
for (x = 0; x < xSize; x++) {
|
||||
xoff2 = xOff;
|
||||
if (version > 0 && version < 3)
|
||||
xoff2 = xOff - 4;
|
||||
|
||||
if (_G(_drawToBuffer)) {
|
||||
for (i = 0; i < 8; i++)
|
||||
_G(_buffer)[(y + yOff) * 32 + x + xoff2][i] = _G(_screenchars)[offset][i];
|
||||
} else {
|
||||
plotsprite(offset, x + xoff2, y + yOff, remap(ink[x][y]), remap(paper[x][y]));
|
||||
}
|
||||
|
||||
#ifdef DRAWDEBUG
|
||||
debug("(gfx#:plotting %d,%d:paper=%s,ink=%s)\n", x + xoff2, y + yoff,
|
||||
colortext(remap(paper[x][y])), colortext(remap(ink[x][y])));
|
||||
#endif
|
||||
offset++;
|
||||
if (offset > 766)
|
||||
break;
|
||||
}
|
||||
return dataptr;
|
||||
}
|
||||
|
||||
void drawSagaPictureNumber(int pictureNumber) {
|
||||
int numgraphics = _G(_game)->_numberOfPictures;
|
||||
if (pictureNumber >= numgraphics) {
|
||||
|
||||
error("drawSagaPictureNumber: Invalid image number % d !Last image: % d", pictureNumber, numgraphics - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
Image img = _G(_images)[pictureNumber];
|
||||
|
||||
if (img._imageData == nullptr)
|
||||
return;
|
||||
|
||||
drawSagaPictureFromData(img._imageData, img._width, img._height, img._xOff, img._yOff);
|
||||
}
|
||||
|
||||
void drawSagaPictureAtPos(int pictureNumber, int x, int y) {
|
||||
Image img = _G(_images)[pictureNumber];
|
||||
|
||||
drawSagaPictureFromData(img._imageData, img._width, img._height, x, y);
|
||||
}
|
||||
|
||||
void drawSagaPictureFromBuffer() {
|
||||
for (int line = 0; line < 12; line++) {
|
||||
for (int col = 0; col < 32; col++) {
|
||||
|
||||
uint8_t colour = _G(_buffer)[col + line * 32][8];
|
||||
|
||||
int paper = (colour >> 3) & 0x7;
|
||||
paper += 8 * ((colour & 0x40) == 0x40);
|
||||
paper = remap(paper);
|
||||
int ink = (colour & 0x7);
|
||||
ink += 8 * ((colour & 0x40) == 0x40);
|
||||
ink = remap(ink);
|
||||
|
||||
background(col, line, paper);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (_G(_buffer)[col + line * 32][i] == 0)
|
||||
continue;
|
||||
if (_G(_buffer)[col + line * 32][i] == 255) {
|
||||
|
||||
glui32 glk_color = (_G(_pal)[ink][0] << 16) | (_G(_pal)[ink][1] << 8) | _G(_pal)[ink][2];
|
||||
|
||||
g_scott->glk_window_fill_rect(_G(_graphics), glk_color, col * 8 * _G(_pixelSize) + _G(_xOffset),
|
||||
(line * 8 + i) * _G(_pixelSize), 8 * _G(_pixelSize), _G(_pixelSize));
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < 8; j++)
|
||||
if ((_G(_buffer)[col + line * 32][i] & (1 << j)) != 0) {
|
||||
int ypos = line * 8 + i;
|
||||
putPixel(col * 8 + j, ypos, ink);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sagaSetup(size_t imgOffset) {
|
||||
int32_t i, y;
|
||||
|
||||
Common::Array<uint16_t> imageOffsets(_G(_game)->_numberOfPictures);
|
||||
|
||||
if (_G(_palChosen) == NO_PALETTE) {
|
||||
_G(_palChosen) = _G(_game)->_palette;
|
||||
}
|
||||
|
||||
if (_G(_palChosen) == NO_PALETTE) {
|
||||
error("sagaSetup: unknown palette");
|
||||
}
|
||||
|
||||
definePalette();
|
||||
|
||||
int version = _G(_game)->_pictureFormatVersion;
|
||||
|
||||
int32_t CHAR_START = _G(_game)->_startOfCharacters + _G(_fileBaselineOffset);
|
||||
int32_t OFFSET_TABLE_START = _G(_game)->_startOfImageData + _G(_fileBaselineOffset);
|
||||
|
||||
if (_G(_game)->_startOfImageData == FOLLOWS) {
|
||||
OFFSET_TABLE_START = CHAR_START + 0x800;
|
||||
}
|
||||
|
||||
int32_t DATA_OFFSET = _G(_game)->_imageAddressOffset + _G(_fileBaselineOffset);
|
||||
if (imgOffset)
|
||||
DATA_OFFSET = imgOffset;
|
||||
uint8_t *pos;
|
||||
int numgraphics = _G(_game)->_numberOfPictures;
|
||||
|
||||
pos = seekToPos(_G(_entireFile), CHAR_START);
|
||||
|
||||
#ifdef DRAWDEBUG
|
||||
debug("Grabbing Character details\n");
|
||||
debug("Character Offset: %04x\n", CHAR_START - _G(_fileBaselineOffset));
|
||||
#endif
|
||||
for (i = 0; i < 256; i++) {
|
||||
for (y = 0; y < 8; y++) {
|
||||
_G(_sprite)[i][y] = *(pos++);
|
||||
}
|
||||
}
|
||||
|
||||
_G(_images).resize(numgraphics);
|
||||
Image *img = &_G(_images)[0];
|
||||
|
||||
pos = seekToPos(_G(_entireFile), OFFSET_TABLE_START);
|
||||
pos = seekToPos(_G(_entireFile), OFFSET_TABLE_START);
|
||||
|
||||
for (i = 0; i < numgraphics; i++) {
|
||||
if (_G(_game)->_pictureFormatVersion == 0) {
|
||||
uint16_t address;
|
||||
|
||||
if (i < 11) {
|
||||
address = _G(_game)->_startOfImageData + (i * 2);
|
||||
} else if (i < 28) {
|
||||
address = _G(_hulkItemImageOffsets) + (i - 10) * 2;
|
||||
} else if (i < 34) {
|
||||
address = _G(_hulkLookImageOffsets) + (i - 28) * 2;
|
||||
} else {
|
||||
address = _G(_hulkSpecialImageOffsets) + (i - 34) * 2;
|
||||
}
|
||||
|
||||
address += _G(_fileBaselineOffset);
|
||||
address = _G(_entireFile)[address] + _G(_entireFile)[address + 1] * 0x100;
|
||||
|
||||
imageOffsets[i] = address + _G(_hulkImageOffset);
|
||||
} else {
|
||||
imageOffsets[i] = *(pos++);
|
||||
imageOffsets[i] += *(pos++) * 0x100;
|
||||
}
|
||||
}
|
||||
|
||||
for (int picture_number = 0; picture_number < numgraphics; picture_number++) {
|
||||
pos = seekToPos(_G(_entireFile), imageOffsets[picture_number] + DATA_OFFSET);
|
||||
if (pos == 0)
|
||||
return;
|
||||
|
||||
img->_width = *(pos++);
|
||||
if (img->_width > 32)
|
||||
img->_width = 32;
|
||||
|
||||
img->_height = *(pos++);
|
||||
if (img->_height > 12)
|
||||
img->_height = 12;
|
||||
|
||||
if (version > 0) {
|
||||
img->_xOff = *(pos++);
|
||||
if (img->_xOff > 32)
|
||||
img->_xOff = 4;
|
||||
img->_yOff = *(pos++);
|
||||
if (img->_yOff > 12)
|
||||
img->_yOff = 0;
|
||||
} else {
|
||||
if (picture_number > 9 && picture_number < 28) {
|
||||
img->_xOff = _G(_entireFile)[_G(_hulkCoordinates) + picture_number - 10 + _G(_fileBaselineOffset)];
|
||||
img->_yOff = _G(_entireFile)[_G(_hulkCoordinates) + 18 + picture_number - 10 + _G(_fileBaselineOffset)];
|
||||
} else {
|
||||
img->_xOff = img->_yOff = 0;
|
||||
}
|
||||
}
|
||||
|
||||
img->_imageData = pos;
|
||||
|
||||
img++;
|
||||
}
|
||||
}
|
||||
|
||||
void putPixel(glsi32 x, glsi32 y, int32_t color) {
|
||||
int yOffset = 0;
|
||||
|
||||
glui32 glk_color = ((_G(_pal)[color][0] << 16)) | ((_G(_pal)[color][1] << 8)) | (_G(_pal)[color][2]);
|
||||
|
||||
g_scott->glk_window_fill_rect(_G(_graphics), glk_color, x * _G(_pixelSize) + _G(_xOffset),
|
||||
y * _G(_pixelSize) + yOffset, _G(_pixelSize), _G(_pixelSize));
|
||||
}
|
||||
|
||||
void rectFill(int32_t x, int32_t y, int32_t width, int32_t height, int32_t color) {
|
||||
int yOffset = 0;
|
||||
|
||||
int bufferpos = (y / 8) * 32 + (x / 8);
|
||||
if (bufferpos >= 0xD80)
|
||||
return;
|
||||
_G(_buffer)[bufferpos][8] = _G(_buffer)[bufferpos][8] | (color << 3);
|
||||
|
||||
glui32 glk_color = ((_G(_pal)[color][0] << 16)) | ((_G(_pal)[color][1] << 8)) | (_G(_pal)[color][2]);
|
||||
|
||||
g_scott->glk_window_fill_rect(_G(_graphics), glk_color, x * _G(_pixelSize) + _G(_xOffset),
|
||||
y * _G(_pixelSize) + yOffset, width * _G(_pixelSize), height * _G(_pixelSize));
|
||||
}
|
||||
|
||||
void switchPalettes(int pal1, int pal2) {
|
||||
uint8_t temp[3];
|
||||
|
||||
temp[0] = _G(_pal)[pal1][0];
|
||||
temp[1] = _G(_pal)[pal1][1];
|
||||
temp[2] = _G(_pal)[pal1][2];
|
||||
|
||||
_G(_pal)[pal1][0] = _G(_pal)[pal2][0];
|
||||
_G(_pal)[pal1][1] = _G(_pal)[pal2][1];
|
||||
_G(_pal)[pal1][2] = _G(_pal)[pal2][2];
|
||||
|
||||
_G(_pal)[pal2][0] = temp[0];
|
||||
_G(_pal)[pal2][1] = temp[1];
|
||||
_G(_pal)[pal2][2] = temp[2];
|
||||
}
|
||||
|
||||
void setColor(int32_t index, RGB *colour) {
|
||||
_G(_pal)[index][0] = (*colour)[0];
|
||||
_G(_pal)[index][1] = (*colour)[1];
|
||||
_G(_pal)[index][2] = (*colour)[2];
|
||||
}
|
||||
|
||||
void definePalette() {
|
||||
/* set up the palette */
|
||||
if (_G(_palChosen) == VGA) {
|
||||
RGB black = {0, 0, 0};
|
||||
RGB blue = {0, 0, 255};
|
||||
RGB red = {255, 0, 0};
|
||||
RGB magenta = {255, 0, 255};
|
||||
RGB green = {0, 255, 0};
|
||||
RGB cyan = {0, 255, 255};
|
||||
RGB yellow = {255, 255, 0};
|
||||
RGB white = {255, 255, 255};
|
||||
RGB brblack = {0, 0, 0};
|
||||
RGB brblue = {0, 0, 255};
|
||||
RGB brred = {255, 0, 0};
|
||||
RGB brmagenta = {255, 0, 255};
|
||||
RGB brgreen = {0, 255, 0};
|
||||
RGB brcyan = {0, 255, 255};
|
||||
RGB bryellow = {255, 255, 0};
|
||||
RGB brwhite = {255, 255, 255};
|
||||
|
||||
setColor(0, &black);
|
||||
setColor(1, &blue);
|
||||
setColor(2, &red);
|
||||
setColor(3, &magenta);
|
||||
setColor(4, &green);
|
||||
setColor(5, &cyan);
|
||||
setColor(6, &yellow);
|
||||
setColor(7, &white);
|
||||
setColor(8, &brblack);
|
||||
setColor(9, &brblue);
|
||||
setColor(10, &brred);
|
||||
setColor(11, &brmagenta);
|
||||
setColor(12, &brgreen);
|
||||
setColor(13, &brcyan);
|
||||
setColor(14, &bryellow);
|
||||
setColor(15, &brwhite);
|
||||
} else if (_G(_palChosen) == ZX) {
|
||||
/* corrected Sinclair ZX palette (pretty dull though) */
|
||||
RGB black = {0, 0, 0};
|
||||
RGB blue = {0, 0, 154};
|
||||
RGB red = {154, 0, 0};
|
||||
RGB magenta = {154, 0, 154};
|
||||
RGB green = {0, 154, 0};
|
||||
RGB cyan = {0, 154, 154};
|
||||
RGB yellow = {154, 154, 0};
|
||||
RGB white = {154, 154, 154};
|
||||
RGB brblack = {0, 0, 0};
|
||||
RGB brblue = {0, 0, 170};
|
||||
RGB brred = {186, 0, 0};
|
||||
RGB brmagenta = {206, 0, 206};
|
||||
RGB brgreen = {0, 206, 0};
|
||||
RGB brcyan = {0, 223, 223};
|
||||
RGB bryellow = {239, 239, 0};
|
||||
RGB brwhite = {255, 255, 255};
|
||||
|
||||
setColor(0, &black);
|
||||
setColor(1, &blue);
|
||||
setColor(2, &red);
|
||||
setColor(3, &magenta);
|
||||
setColor(4, &green);
|
||||
setColor(5, &cyan);
|
||||
setColor(6, &yellow);
|
||||
setColor(7, &white);
|
||||
setColor(8, &brblack);
|
||||
setColor(9, &brblue);
|
||||
setColor(10, &brred);
|
||||
setColor(11, &brmagenta);
|
||||
setColor(12, &brgreen);
|
||||
setColor(13, &brcyan);
|
||||
setColor(14, &bryellow);
|
||||
setColor(15, &brwhite);
|
||||
|
||||
_G(_whiteColour) = 15;
|
||||
_G(_blueColour) = 9;
|
||||
_G(_diceColour) = 0xff0000;
|
||||
} else if (_G(_palChosen) == ZXOPT) {
|
||||
/* optimized but not realistic Sinclair ZX palette (SPIN emu) */
|
||||
RGB black = {0, 0, 0};
|
||||
RGB blue = {0, 0, 202};
|
||||
RGB red = {202, 0, 0};
|
||||
RGB magenta = {202, 0, 202};
|
||||
RGB green = {0, 202, 0};
|
||||
RGB cyan = {0, 202, 202};
|
||||
RGB yellow = {202, 202, 0};
|
||||
RGB white = {202, 202, 202};
|
||||
/*
|
||||
old David Lodge palette:
|
||||
|
||||
RGB black = { 0, 0, 0 };
|
||||
RGB blue = { 0, 0, 214 };
|
||||
RGB red = { 214, 0, 0 };
|
||||
RGB magenta = { 214, 0, 214 };
|
||||
RGB green = { 0, 214, 0 };
|
||||
RGB cyan = { 0, 214, 214 };
|
||||
RGB yellow = { 214, 214, 0 };
|
||||
RGB white = { 214, 214, 214 };
|
||||
*/
|
||||
RGB brblack = {0, 0, 0};
|
||||
RGB brblue = {0, 0, 255};
|
||||
RGB brred = {255, 0, 20};
|
||||
RGB brmagenta = {255, 0, 255};
|
||||
RGB brgreen = {0, 255, 0};
|
||||
RGB brcyan = {0, 255, 255};
|
||||
RGB bryellow = {255, 255, 0};
|
||||
RGB brwhite = {255, 255, 255};
|
||||
|
||||
setColor(0, &black);
|
||||
setColor(1, &blue);
|
||||
setColor(2, &red);
|
||||
setColor(3, &magenta);
|
||||
setColor(4, &green);
|
||||
setColor(5, &cyan);
|
||||
setColor(6, &yellow);
|
||||
setColor(7, &white);
|
||||
setColor(8, &brblack);
|
||||
setColor(9, &brblue);
|
||||
setColor(10, &brred);
|
||||
setColor(11, &brmagenta);
|
||||
setColor(12, &brgreen);
|
||||
setColor(13, &brcyan);
|
||||
setColor(14, &bryellow);
|
||||
setColor(15, &brwhite);
|
||||
|
||||
_G(_whiteColour) = 15;
|
||||
_G(_blueColour) = 9;
|
||||
_G(_diceColour) = 0xff0000;
|
||||
|
||||
} else if ((_G(_palChosen) == C64A) || (_G(_palChosen) == C64B)) {
|
||||
/* and now: C64 palette (pepto/VICE) */
|
||||
RGB black = {0, 0, 0};
|
||||
RGB white = {255, 255, 255};
|
||||
RGB red = {191, 97, 72};
|
||||
RGB cyan = {153, 230, 249};
|
||||
RGB purple = {177, 89, 185};
|
||||
RGB green = {121, 213, 112};
|
||||
RGB blue = {95, 72, 233};
|
||||
RGB yellow = {247, 255, 108};
|
||||
RGB orange = {186, 134, 32};
|
||||
RGB brown = {116, 105, 0};
|
||||
RGB lred = {180, 105, 164};
|
||||
RGB dgrey = {69, 69, 69};
|
||||
RGB grey = {167, 167, 167};
|
||||
RGB lgreen = {154, 210, 134};
|
||||
RGB lblue = {162, 143, 255};
|
||||
RGB lgrey = {150, 150, 150};
|
||||
|
||||
setColor(0, &black);
|
||||
setColor(1, &white);
|
||||
setColor(2, &red);
|
||||
setColor(3, &cyan);
|
||||
setColor(4, &purple);
|
||||
setColor(5, &green);
|
||||
setColor(6, &blue);
|
||||
setColor(7, &yellow);
|
||||
setColor(8, &orange);
|
||||
setColor(9, &brown);
|
||||
setColor(10, &lred);
|
||||
setColor(11, &dgrey);
|
||||
setColor(12, &grey);
|
||||
setColor(13, &lgreen);
|
||||
setColor(14, &lblue);
|
||||
setColor(15, &lgrey);
|
||||
|
||||
_G(_whiteColour) = 1;
|
||||
_G(_blueColour) = 6;
|
||||
_G(_diceColour) = 0x5f48e9;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t remap(int32_t color) {
|
||||
int32_t mapcol;
|
||||
|
||||
if ((_G(_palChosen) == ZX) || (_G(_palChosen) == ZXOPT)) {
|
||||
/* nothing to remap here; shows that the gfx were created on a ZX */
|
||||
mapcol = (((color >= 0) && (color <= 15)) ? color : INVALID_COLOR);
|
||||
} else if (_G(_palChosen) == C64A) {
|
||||
/* remap A determined from Golden Baton, applies to S1/S3/S13 too (8col) */
|
||||
int32_t c64remap[] = {0, 6, 2, 4, 5, 3, 7, 1, 8, 1, 1, 1, 7, 12, 8, 7};
|
||||
mapcol = (((color >= 0) && (color <= 15)) ? c64remap[color] : INVALID_COLOR);
|
||||
} else if (_G(_palChosen) == C64B) {
|
||||
/* remap B determined from Spiderman (16col) */
|
||||
int32_t c64remap[] = {0, 6, 9, 4, 5, 14, 8, 12, 0, 6, 2, 4, 5, 3, 7, 1};
|
||||
mapcol = (((color >= 0) && (color <= 15)) ? c64remap[color] : INVALID_COLOR);
|
||||
} else
|
||||
mapcol = (((color >= 0) && (color <= 15)) ? color : INVALID_COLOR);
|
||||
|
||||
return (mapcol);
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
71
engines/glk/scott/saga_draw.h
Normal file
71
engines/glk/scott/saga_draw.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_SAGADRAW_H
|
||||
#define GLK_SCOTT_SAGADRAW_H
|
||||
|
||||
#include "glk/glk_types.h"
|
||||
#include "glk/scott/types.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
struct Image {
|
||||
uint8_t *_imageData;
|
||||
uint8_t _xOff;
|
||||
uint8_t _yOff;
|
||||
uint8_t _width;
|
||||
uint8_t _height;
|
||||
};
|
||||
|
||||
typedef uint8_t RGB[3];
|
||||
typedef RGB PALETTE[16];
|
||||
|
||||
uint8_t *drawSagaPictureFromData(uint8_t *dataptr, int xSize, int ySize, int xOff, int yOff);
|
||||
void drawSagaPictureNumber(int pictureNumber);
|
||||
void drawSagaPictureAtPos(int pictureNumber, int x, int y);
|
||||
void drawSagaPictureFromBuffer();
|
||||
void flip(uint8_t character[]);
|
||||
|
||||
void sagaSetup(size_t imgOffset);
|
||||
|
||||
void putPixel(glsi32 x, glsi32 y, int32_t color);
|
||||
void rectFill(int32_t x, int32_t y, int32_t width, int32_t height, int32_t color);
|
||||
void switchPalettes(int pal1, int pal2);
|
||||
void definePalette();
|
||||
|
||||
int32_t remap(int32_t color);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
2179
engines/glk/scott/scott.cpp
Normal file
2179
engines/glk/scott/scott.cpp
Normal file
File diff suppressed because it is too large
Load Diff
269
engines/glk/scott/scott.h
Normal file
269
engines/glk/scott/scott.h
Normal file
@@ -0,0 +1,269 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_H
|
||||
#define GLK_SCOTT_H
|
||||
|
||||
/*
|
||||
* Controlling block
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "glk/glk_api.h"
|
||||
#include "glk/scott/definitions.h"
|
||||
#include "glk/scott/globals.h"
|
||||
#include "glk/scott/types.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
struct Command;
|
||||
|
||||
#define LIGHT_SOURCE 9 // Always 9 how odd
|
||||
#define CARRIED 255 // Carried
|
||||
#define DESTROYED 0 // Destroyed
|
||||
#define DARKBIT 15
|
||||
#define LIGHTOUTBIT 16 // Light gone out
|
||||
|
||||
enum GameOption {
|
||||
YOUARE = 1, ///< You are not I am
|
||||
SCOTTLIGHT = 2, ///< Authentic Scott Adams light messages
|
||||
DEBUGGING = 4, ///< Info from database load
|
||||
TRS80_STYLE = 8, ///< Display in style used on TRS-80
|
||||
PREHISTORIC_LAMP = 16, ///< Destroy the lamp (very old databases)
|
||||
SPECTRUM_STYLE = 32, ///< Display in style used on ZX Spectrum
|
||||
TI994A_STYLE = 64, ///< Display in style used on TI-99/4A
|
||||
NO_DELAYS = 128, ///< Skip all pauses
|
||||
FORCE_PALETTE_ZX = 256, ///< Force ZX Spectrum image palette
|
||||
FORCE_PALETTE_C64 = 512, ///< Force CBM 64 image palette
|
||||
FORCE_INVENTORY = 1024, ///< Inventory in upper window always on
|
||||
FORCE_INVENTORY_OFF = 2048 ///< Inventory in upper window always off
|
||||
};
|
||||
|
||||
#define GLK_BUFFER_ROCK 1
|
||||
#define GLK_STATUS_ROCK 1010
|
||||
#define GLK_GRAPHICS_ROCK 1020
|
||||
|
||||
#define TRS80_LINE "\n<------------------------------------------------------------>\n"
|
||||
#define MY_LOC (_G(_gameHeader)->_playerRoom)
|
||||
#define CURRENT_GAME (_G(_game->_gameID))
|
||||
|
||||
struct Header {
|
||||
int _unknown;
|
||||
int _numItems;
|
||||
int _numActions;
|
||||
int _numWords; ///< Smaller of verb/noun is padded to same size
|
||||
int _numRooms;
|
||||
int _maxCarry;
|
||||
int _playerRoom;
|
||||
int _treasures;
|
||||
int _wordLength;
|
||||
int _lightTime;
|
||||
int _numMessages;
|
||||
int _treasureRoom;
|
||||
|
||||
Header() : _unknown(0), _numItems(0), _numActions(0), _numWords(0), _numRooms(0),
|
||||
_maxCarry(0), _playerRoom(0), _treasures(0), _wordLength(0), _lightTime(0),
|
||||
_numMessages(0), _treasureRoom(0) {}
|
||||
};
|
||||
|
||||
struct Action {
|
||||
int _vocab;
|
||||
int _condition[5];
|
||||
int _action[2];
|
||||
|
||||
Action() : _vocab(0) {
|
||||
Common::fill(&_condition[0], &_condition[5], 0);
|
||||
Common::fill(&_action[0], &_action[2], 0);
|
||||
}
|
||||
};
|
||||
|
||||
struct Room {
|
||||
Common::String _text;
|
||||
int _exits[6];
|
||||
byte _image;
|
||||
|
||||
Room() : _image(255) {
|
||||
Common::fill(&_exits[0], &_exits[6], 0);
|
||||
}
|
||||
};
|
||||
|
||||
struct Item {
|
||||
Common::String _text;
|
||||
byte _location;
|
||||
byte _initialLoc;
|
||||
Common::String _autoGet;
|
||||
byte _flag;
|
||||
byte _image;
|
||||
|
||||
Item() : _location(0), _initialLoc(0), _flag(0), _image(0) {}
|
||||
};
|
||||
|
||||
struct Tail {
|
||||
int _version;
|
||||
int _adventureNumber;
|
||||
int _unknown;
|
||||
|
||||
Tail() : _version(0), _adventureNumber(0), _unknown(0) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Scott Adams game interpreter
|
||||
*/
|
||||
class Scott : public GlkAPI {
|
||||
private:
|
||||
Globals _globals;
|
||||
char _nounText[16];
|
||||
//int _width = 0; ///< Terminal width
|
||||
int _topHeight = 0; ///< Height of top window
|
||||
int _topWidth = 0;
|
||||
|
||||
bool _splitScreen = true;
|
||||
int _saveSlot = -1; ///< Save slot when loading savegame from launcher
|
||||
|
||||
int _printLookToTranscript = 0;
|
||||
int _pauseNextRoomDescription = 0;
|
||||
|
||||
strid_t _roomDescriptionStream = nullptr;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Initialization code
|
||||
*/
|
||||
void initialize();
|
||||
void clearScreen(void);
|
||||
int matchUpItem(int noun, int loc);
|
||||
Common::String readString(Common::SeekableReadStream *f);
|
||||
void loadDatabase(Common::SeekableReadStream *f, bool loud);
|
||||
int whichWord(const char *word, const Common::StringArray &list);
|
||||
|
||||
ActionResultType performLine(int ct);
|
||||
ExplicitResultType performActions(int vb, int no);
|
||||
|
||||
void readInts(Common::SeekableReadStream *f, size_t count, ...);
|
||||
void writeToRoomDescriptionStream(const char *fmt, ...);
|
||||
void flushRoomDescription(char *buf);
|
||||
void printWindowDelimiter();
|
||||
void listExits();
|
||||
void listExitsSpectrumStyle();
|
||||
void listInventoryInUpperWindow();
|
||||
int itemEndsWithPeriod(int item);
|
||||
winid_t findGlkWindowWithRock(glui32 rock);
|
||||
glui32 optimalPictureSize(uint *width, uint *height);
|
||||
void openTopWindow();
|
||||
void cleanupAndExit();
|
||||
void drawBlack();
|
||||
void drawRoomImage();
|
||||
void restartGame();
|
||||
void transcriptOn();
|
||||
void transcriptOff();
|
||||
int yesOrNo();
|
||||
void lookWithPause();
|
||||
void printTakenOrDropped(int index);
|
||||
void printTitleScreenBuffer();
|
||||
void printTitleScreenGrid();
|
||||
|
||||
public:
|
||||
void drawImage(int image);
|
||||
void output(const Common::String &a);
|
||||
void output(const Common::U32String &a);
|
||||
void outputNumber(int a);
|
||||
void display(winid_t w, const char *fmt, ...);
|
||||
template<class... TParam> void display(winid_t w, const Common::U32String &fmt, TParam... param);
|
||||
void fatal(const char *x);
|
||||
void hitEnter();
|
||||
void updates(event_t ev);
|
||||
const char *mapSynonym(int noun);
|
||||
int performExtraCommand(int extraStopTime);
|
||||
void look(void);
|
||||
void openGraphicsWindow();
|
||||
void closeGraphicsWindow();
|
||||
void listInventory();
|
||||
void updateSettings();
|
||||
uint getRandomNumber(uint max);
|
||||
bool randomPercent(uint n);
|
||||
int countCarried(void);
|
||||
void playerIsDead();
|
||||
void doneIt();
|
||||
void putItemAInRoomB(int itemA, int roomB);
|
||||
int printScore();
|
||||
void swapItemLocations(int itemA, int itemB);
|
||||
void moveItemAToLocOfItemB(int itemA, int itemB);
|
||||
void goToStoredLoc();
|
||||
void swapLocAndRoomFlag(int index);
|
||||
void swapCounters(int index);
|
||||
void printNoun();
|
||||
void delay(double seconds);
|
||||
void printMessage(int index);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Scott(OSystem *syst, const GlkGameDescription &gameDesc);
|
||||
|
||||
/**
|
||||
* Returns the running interpreter type
|
||||
*/
|
||||
InterpreterType getInterpreterType() const override { return INTERPRETER_SCOTT; }
|
||||
|
||||
/**
|
||||
* Execute the game
|
||||
*/
|
||||
void runGame() override;
|
||||
|
||||
/**
|
||||
* Load a savegame from the passed Quetzal file chunk stream
|
||||
*/
|
||||
Common::Error readSaveData(Common::SeekableReadStream *rs) override;
|
||||
|
||||
/**
|
||||
* Save the game. The passed write stream represents access to the UMem chunk
|
||||
* in the Quetzal save file that will be created
|
||||
*/
|
||||
Common::Error writeGameData(Common::WriteStream *ws) override;
|
||||
|
||||
private:
|
||||
void display_u32_internal(winid_t w, const Common::U32String *fmt, ...);
|
||||
};
|
||||
|
||||
template<class... TParam>
|
||||
inline void Scott::display(winid_t w, const Common::U32String &fmt, TParam... param) {
|
||||
display_u32_internal(w, &fmt, Common::forward<TParam>(param)...);
|
||||
}
|
||||
|
||||
extern Scott *g_scott;
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
859
engines/glk/scott/seas_of_blood.cpp
Normal file
859
engines/glk/scott/seas_of_blood.cpp
Normal file
@@ -0,0 +1,859 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "glk/scott/scott.h"
|
||||
#include "glk/scott/saga_draw.h"
|
||||
#include "glk/scott/resource.h"
|
||||
#include "glk/scott/decompress_text.h"
|
||||
#include "glk/scott/seas_of_blood.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
#define VICTORY 0
|
||||
#define LOSS 1
|
||||
#define DRAW 2
|
||||
#define FLEE 3
|
||||
#define ERROR 99
|
||||
|
||||
int getEnemyStats(int *strike, int *stamina, int *boatFlag);
|
||||
void battleLoop(int enemy, int strike, int stamina, int boatFlag);
|
||||
void swapStaminaAndCrewStrength(void);
|
||||
void bloodBattle(void);
|
||||
|
||||
void adventureSheet(void) {
|
||||
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(_G(_bottomWindow)));
|
||||
g_scott->glk_set_style(style_Preformatted);
|
||||
g_scott->output("\nADVENTURE SHEET\n\n");
|
||||
g_scott->output("SKILL :");
|
||||
g_scott->outputNumber(9);
|
||||
g_scott->output(" STAMINA :");
|
||||
g_scott->outputNumber(_G(_counters)[3]);
|
||||
g_scott->output("\nLOG :");
|
||||
g_scott->outputNumber(_G(_counters)[6]);
|
||||
if (_G(_counters)[6] < 10)
|
||||
g_scott->output(" PROVISIONS :");
|
||||
else
|
||||
g_scott->output(" PROVISIONS :"); // one less space!
|
||||
g_scott->outputNumber(_G(_counters)[5]);
|
||||
g_scott->output("\nCREW STRIKE:");
|
||||
g_scott->outputNumber(9);
|
||||
g_scott->output(" CREW STRENGTH:");
|
||||
g_scott->outputNumber(_G(_counters)[7]);
|
||||
g_scott->output("\n\n * * * * * * * * * * * * * * * * * * * * *\n\n");
|
||||
g_scott->listInventory();
|
||||
g_scott->output("\n");
|
||||
g_scott->glk_set_style(style_Normal);
|
||||
}
|
||||
|
||||
void bloodAction(int p) {
|
||||
switch (p) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
// Update LOG
|
||||
_G(_counters)[6]++;
|
||||
break;
|
||||
case 2:
|
||||
// Battle
|
||||
g_scott->look();
|
||||
g_scott->output("You are attacked \n");
|
||||
g_scott->output("<HIT ENTER> \n");
|
||||
g_scott->hitEnter();
|
||||
bloodBattle();
|
||||
break;
|
||||
default:
|
||||
error("bloodAction: Unhandled special action %d", p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void mirrorLeftHalf(void) {
|
||||
for (int line = 0; line < 12; line++) {
|
||||
for (int col = 32; col > 16; col--) {
|
||||
_G(_buffer)[line * 32 + col - 1][8] = _G(_buffer)[line * 32 + (32 - col)][8];
|
||||
for (int pixrow = 0; pixrow < 8; pixrow++)
|
||||
_G(_buffer)[line * 32 + col - 1][pixrow] = _G(_buffer)[line * 32 + (32 - col)][pixrow];
|
||||
flip(_G(_buffer)[line * 32 + col - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void replaceColour(uint8_t before, uint8_t after) {
|
||||
|
||||
// I don't think any of the data has bit 7 set,
|
||||
// so masking it is probably unnecessary, but this is what
|
||||
// the original code does.
|
||||
uint8_t beforeink = before & 7;
|
||||
uint8_t afterink = after & 7;
|
||||
uint8_t inkmask = 0x07;
|
||||
|
||||
uint8_t beforepaper = beforeink << 3;
|
||||
uint8_t afterpaper = afterink << 3;
|
||||
uint8_t papermask = 0x38;
|
||||
|
||||
for (int j = 0; j < 384; j++) {
|
||||
if ((_G(_buffer)[j][8] & inkmask) == beforeink) {
|
||||
_G(_buffer)[j][8] = (_G(_buffer)[j][8] & ~inkmask) | afterink;
|
||||
}
|
||||
|
||||
if ((_G(_buffer)[j][8] & papermask) == beforepaper) {
|
||||
_G(_buffer)[j][8] = (_G(_buffer)[j][8] & ~papermask) | afterpaper;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawColour(uint8_t x, uint8_t y, uint8_t colour, uint8_t length) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
_G(_buffer)[y * 32 + x + i][8] = colour;
|
||||
}
|
||||
}
|
||||
|
||||
void makeLight(void) {
|
||||
for (int i = 0; i < 384; i++) {
|
||||
_G(_buffer)[i][8] = _G(_buffer)[i][8] | 0x40;
|
||||
}
|
||||
}
|
||||
|
||||
void flipImage(void) {
|
||||
|
||||
uint8_t mirror[384][9];
|
||||
|
||||
for (int line = 0; line < 12; line++) {
|
||||
for (int col = 32; col > 0; col--) {
|
||||
for (int pixrow = 0; pixrow < 9; pixrow++)
|
||||
mirror[line * 32 + col - 1][pixrow] = _G(_buffer)[line * 32 + (32 - col)][pixrow];
|
||||
flip(mirror[line * 32 + col - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(_G(_buffer), mirror, 384 * 9);
|
||||
}
|
||||
|
||||
void drawObjectImage(uint8_t x, uint8_t y) {
|
||||
for (int i = 0; i < _G(_gameHeader)->_numItems; i++) {
|
||||
if (_G(_items)[i]._flag != MY_LOC)
|
||||
continue;
|
||||
if (_G(_items)[i]._location != MY_LOC)
|
||||
continue;
|
||||
drawSagaPictureAtPos(_G(_items)[i]._image, x, y);
|
||||
_G(_shouldDrawObjectImages) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void drawBlood(int loc) {
|
||||
memset(_G(_buffer), 0, 384 * 9);
|
||||
uint8_t *ptr = _G(_bloodImageData);
|
||||
for (int i = 0; i < loc; i++) {
|
||||
while (*(ptr) != 0xff)
|
||||
ptr++;
|
||||
ptr++;
|
||||
}
|
||||
while (ptr < _G(_bloodImageData) + 2010) {
|
||||
switch (*ptr) {
|
||||
case 0xff:
|
||||
if (loc == 13) {
|
||||
_G(_buffer)[8 * 32 + 18][8] = _G(_buffer)[8 * 32 + 18][8] & ~0x40;
|
||||
_G(_buffer)[8 * 32 + 17][8] = _G(_buffer)[8 * 32 + 17][8] & ~0x40;
|
||||
|
||||
_G(_buffer)[8 * 32 + 9][8] = _G(_buffer)[8 * 32 + 9][8] & ~0x40;
|
||||
_G(_buffer)[8 * 32 + 10][8] = _G(_buffer)[8 * 32 + 10][8] & ~0x40;
|
||||
}
|
||||
return;
|
||||
case 0xfe:
|
||||
mirrorLeftHalf();
|
||||
break;
|
||||
case 0xfD:
|
||||
replaceColour(*(ptr + 1), *(ptr + 2));
|
||||
ptr += 2;
|
||||
break;
|
||||
case 0xfc: // Draw colour: x, y, attribute, length
|
||||
drawColour(*(ptr + 1), *(ptr + 2), *(ptr + 3), *(ptr + 4));
|
||||
ptr = ptr + 4;
|
||||
break;
|
||||
case 0xfb: // Make all screen colours bright
|
||||
makeLight();
|
||||
break;
|
||||
case 0xfa: // Flip entire image horizontally
|
||||
flipImage();
|
||||
break;
|
||||
case 0xf9: // Draw object image (if present) at x, y
|
||||
drawObjectImage(*(ptr + 1), *(ptr + 2));
|
||||
ptr = ptr + 2;
|
||||
break;
|
||||
default: // else draw image *ptr at x, y
|
||||
drawSagaPictureAtPos(*ptr, *(ptr + 1), *(ptr + 2));
|
||||
ptr = ptr + 2;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
void seasOfBloodRoomImage(void) {
|
||||
_G(_shouldDrawObjectImages) = 1;
|
||||
drawBlood(MY_LOC);
|
||||
for (int ct = 0; ct <= _G(_gameHeader)->_numItems; ct++)
|
||||
if (_G(_items)[ct]._image && _G(_shouldDrawObjectImages)) {
|
||||
if ((_G(_items)[ct]._flag & 127) == MY_LOC && _G(_items)[ct]._location == MY_LOC) {
|
||||
g_scott->drawImage(_G(_items)[ct]._image);
|
||||
}
|
||||
}
|
||||
drawSagaPictureFromBuffer();
|
||||
}
|
||||
|
||||
//static void SOBPrint(winid_t w, const char *fmt, ...)
|
||||
//#ifdef __GNUC__
|
||||
// __attribute__((__format__(__printf__, 2, 3)))
|
||||
//#endif
|
||||
// ;
|
||||
|
||||
static void SOBPrint(winid_t w, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
char msg[2048];
|
||||
|
||||
int size = sizeof msg;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(msg, size, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
g_scott->glk_put_string_stream(g_scott->glk_window_get_stream(w), msg);
|
||||
}
|
||||
|
||||
glui32 optimalDicePixelSize(glui32 *width, glui32 *height) {
|
||||
int idealWidth = 8;
|
||||
int idealHeight = 8;
|
||||
|
||||
*width = idealWidth;
|
||||
*height = idealHeight;
|
||||
int multiplier = 1;
|
||||
uint graphwidth, graphheight;
|
||||
g_scott->glk_window_get_size(_G(_leftDiceWin), &graphwidth, &graphheight);
|
||||
multiplier = graphheight / idealHeight;
|
||||
if ((glui32)(idealWidth * multiplier) > graphwidth)
|
||||
multiplier = graphwidth / idealWidth;
|
||||
|
||||
if (multiplier < 2)
|
||||
multiplier = 2;
|
||||
|
||||
multiplier = multiplier / 2;
|
||||
|
||||
*width = idealWidth * multiplier;
|
||||
*height = idealHeight * multiplier;
|
||||
|
||||
return multiplier;
|
||||
}
|
||||
|
||||
static void drawBorder(winid_t win) {
|
||||
uint width, height;
|
||||
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(win));
|
||||
g_scott->glk_window_get_size(win, &width, &height);
|
||||
height--;
|
||||
width -= 2;
|
||||
g_scott->glk_window_move_cursor(win, 0, 0);
|
||||
g_scott->glk_put_char_uni(0x250F); // Top left corner
|
||||
for (glui32 i = 1; i < width; i++)
|
||||
g_scott->glk_put_char_uni(0x2501); // Top
|
||||
g_scott->glk_put_char_uni(0x2513); // Top right corner
|
||||
for (glui32 i = 1; i < height; i++) {
|
||||
g_scott->glk_window_move_cursor(win, 0, i);
|
||||
g_scott->glk_put_char_uni(0x2503);
|
||||
g_scott->glk_window_move_cursor(win, width, i);
|
||||
g_scott->glk_put_char_uni(0x2503);
|
||||
}
|
||||
g_scott->glk_window_move_cursor(win, 0, height);
|
||||
g_scott->glk_put_char_uni(0x2517);
|
||||
for (glui32 i = 1; i < width; i++)
|
||||
g_scott->glk_put_char_uni(0x2501);
|
||||
g_scott->glk_put_char_uni(0x251B);
|
||||
}
|
||||
|
||||
static void redrawStaticText(winid_t win, int boatFlag) {
|
||||
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(win));
|
||||
g_scott->glk_window_move_cursor(win, 2, 4);
|
||||
|
||||
if (boatFlag) {
|
||||
g_scott->glk_put_string("STRIKE :\n");
|
||||
g_scott->glk_window_move_cursor(win, 2, 5);
|
||||
g_scott->glk_put_string("CRW STR :");
|
||||
} else {
|
||||
g_scott->glk_put_string("SKILL :\n");
|
||||
g_scott->glk_window_move_cursor(win, 2, 5);
|
||||
g_scott->glk_put_string("STAMINA :");
|
||||
}
|
||||
|
||||
if (win == _G(_battleRight)) {
|
||||
uint width;
|
||||
g_scott->glk_window_get_size(_G(_battleRight), &width, 0);
|
||||
g_scott->glk_window_move_cursor(_G(_battleRight), width - 6, 1);
|
||||
g_scott->glk_put_string("YOU");
|
||||
}
|
||||
}
|
||||
|
||||
static void redrawBattleScreen(int boatFlag) {
|
||||
uint graphwidth, graphheight;
|
||||
glui32 optimal_width, optimal_height;
|
||||
|
||||
g_scott->glk_window_get_size(_G(_leftDiceWin), &graphwidth, &graphheight);
|
||||
|
||||
_G(_dicePixelSize) = optimalDicePixelSize(&optimal_width, &optimal_height);
|
||||
_G(_diceXOffset) = (graphwidth - optimal_width) / 2;
|
||||
_G(_diceYOffset) = (graphheight - optimal_height - _G(_dicePixelSize)) / 2;
|
||||
|
||||
drawBorder(_G(_topWindow));
|
||||
drawBorder(_G(_battleRight));
|
||||
|
||||
redrawStaticText(_G(_topWindow), boatFlag);
|
||||
redrawStaticText(_G(_battleRight), boatFlag);
|
||||
}
|
||||
|
||||
static void setupBattleScreen(int boatFlag) {
|
||||
winid_t parent = g_scott->glk_window_get_parent(_G(_topWindow));
|
||||
g_scott->glk_window_set_arrangement(parent, winmethod_Above | winmethod_Fixed, 7, _G(_topWindow));
|
||||
|
||||
g_scott->glk_window_clear(_G(_topWindow));
|
||||
g_scott->glk_window_clear(_G(_bottomWindow));
|
||||
_G(_battleRight) = g_scott->glk_window_open(_G(_topWindow), winmethod_Right | winmethod_Proportional,
|
||||
50, wintype_TextGrid, 0);
|
||||
|
||||
_G(_leftDiceWin) = g_scott->glk_window_open(_G(_topWindow), winmethod_Right | winmethod_Proportional,
|
||||
30, wintype_Graphics, 0);
|
||||
_G(_rightDiceWin) = g_scott->glk_window_open(_G(_battleRight), winmethod_Left | winmethod_Proportional, 30,
|
||||
wintype_Graphics, 0);
|
||||
|
||||
// Set the graphics window background to match the top window background, best as we can, and clear the window.
|
||||
|
||||
if (g_scott->glk_style_measure(_G(_topWindow), style_Normal, stylehint_BackColor,
|
||||
&_G(_backgroundColour))) {
|
||||
g_scott->glk_window_set_background_color(_G(_leftDiceWin), _G(_backgroundColour));
|
||||
g_scott->glk_window_set_background_color(_G(_rightDiceWin), _G(_backgroundColour));
|
||||
|
||||
g_scott->glk_window_clear(_G(_leftDiceWin));
|
||||
g_scott->glk_window_clear(_G(_rightDiceWin));
|
||||
}
|
||||
|
||||
if (_G(_palChosen) == C64B)
|
||||
_G(_diceColour) = 0x5f48e9;
|
||||
else
|
||||
_G(_diceColour) = 0xff0000;
|
||||
|
||||
redrawBattleScreen(boatFlag);
|
||||
}
|
||||
|
||||
void bloodBattle(void) {
|
||||
int enemy, strike, stamina, boatFlag;
|
||||
enemy = getEnemyStats(&strike, &stamina, &boatFlag); // Determine their stats
|
||||
if (enemy == 0) {
|
||||
error("Seas of blood battle: No enemy in location?\n");
|
||||
return;
|
||||
}
|
||||
setupBattleScreen(boatFlag);
|
||||
battleLoop(enemy, strike, stamina, boatFlag); // Into the battle loops
|
||||
if (boatFlag)
|
||||
swapStaminaAndCrewStrength(); // Switch back stamina - crew strength
|
||||
g_scott->glk_window_close(_G(_leftDiceWin), nullptr);
|
||||
g_scott->glk_window_close(_G(_rightDiceWin), nullptr);
|
||||
g_scott->glk_window_close(_G(_battleRight), nullptr);
|
||||
g_scott->closeGraphicsWindow();
|
||||
g_scott->openGraphicsWindow();
|
||||
seasOfBloodRoomImage();
|
||||
}
|
||||
|
||||
int getEnemyStats(int *strike, int *stamina, int *boatFlag) {
|
||||
int enemy, i = 0;
|
||||
while (i < 124) {
|
||||
enemy = _G(_enemyTable)[i];
|
||||
if (_G(_items)[enemy]._location == MY_LOC) {
|
||||
i++;
|
||||
*strike = _G(_enemyTable)[i++];
|
||||
*stamina = _G(_enemyTable)[i++];
|
||||
*boatFlag = _G(_enemyTable)[i];
|
||||
if (*boatFlag) {
|
||||
swapStaminaAndCrewStrength(); // Switch stamina - crew strength
|
||||
}
|
||||
|
||||
return enemy;
|
||||
}
|
||||
i = i + 4; // Skip to next entry
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void drawRect(winid_t win, int32_t x, int32_t y, int32_t width, int32_t height,
|
||||
int32_t color) {
|
||||
g_scott->glk_window_fill_rect(win, color, x * _G(_dicePixelSize) + _G(_diceXOffset),
|
||||
y * _G(_dicePixelSize) + _G(_diceYOffset),
|
||||
width * _G(_dicePixelSize), height * _G(_dicePixelSize));
|
||||
}
|
||||
|
||||
void drawGraphicalDice(winid_t win, int number) {
|
||||
// The eye-less dice backgrounds consist of two rectangles on top of each
|
||||
// other
|
||||
drawRect(win, 1, 2, 7, 5, _G(_diceColour));
|
||||
drawRect(win, 2, 1, 5, 7, _G(_diceColour));
|
||||
|
||||
switch (number + 1) {
|
||||
case 1:
|
||||
drawRect(win, 4, 4, 1, 1, _G(_backgroundColour));
|
||||
break;
|
||||
case 2:
|
||||
drawRect(win, 2, 6, 1, 1, _G(_backgroundColour));
|
||||
drawRect(win, 6, 2, 1, 1, _G(_backgroundColour));
|
||||
break;
|
||||
case 3:
|
||||
drawRect(win, 2, 6, 1, 1, _G(_backgroundColour));
|
||||
drawRect(win, 4, 4, 1, 1, _G(_backgroundColour));
|
||||
drawRect(win, 6, 2, 1, 1, _G(_backgroundColour));
|
||||
break;
|
||||
case 4:
|
||||
drawRect(win, 2, 6, 1, 1, _G(_backgroundColour));
|
||||
drawRect(win, 6, 2, 1, 1, _G(_backgroundColour));
|
||||
drawRect(win, 2, 2, 1, 1, _G(_backgroundColour));
|
||||
drawRect(win, 6, 6, 1, 1, _G(_backgroundColour));
|
||||
break;
|
||||
case 5:
|
||||
drawRect(win, 2, 6, 1, 1, _G(_backgroundColour));
|
||||
drawRect(win, 6, 2, 1, 1, _G(_backgroundColour));
|
||||
drawRect(win, 2, 2, 1, 1, _G(_backgroundColour));
|
||||
drawRect(win, 6, 6, 1, 1, _G(_backgroundColour));
|
||||
drawRect(win, 4, 4, 1, 1, _G(_backgroundColour));
|
||||
break;
|
||||
case 6:
|
||||
drawRect(win, 2, 6, 1, 1, _G(_backgroundColour));
|
||||
drawRect(win, 6, 2, 1, 1, _G(_backgroundColour));
|
||||
drawRect(win, 2, 2, 1, 1, _G(_backgroundColour));
|
||||
drawRect(win, 2, 4, 1, 1, _G(_backgroundColour));
|
||||
drawRect(win, 6, 4, 1, 1, _G(_backgroundColour));
|
||||
drawRect(win, 6, 6, 1, 1, _G(_backgroundColour));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void updateDice(int ourTurn, int leftDice, int rightDice) {
|
||||
leftDice--;
|
||||
rightDice--;
|
||||
g_scott->glk_window_clear(_G(_leftDiceWin));
|
||||
g_scott->glk_window_clear(_G(_rightDiceWin));
|
||||
|
||||
_G(_diceXOffset) = _G(_diceXOffset) - _G(_dicePixelSize);
|
||||
drawGraphicalDice(_G(_leftDiceWin), leftDice);
|
||||
_G(_diceXOffset) = _G(_diceXOffset) + _G(_dicePixelSize);
|
||||
drawGraphicalDice(_G(_rightDiceWin), rightDice);
|
||||
|
||||
winid_t win = ourTurn ? _G(_battleRight) : _G(_topWindow);
|
||||
|
||||
g_scott->glk_window_move_cursor(win, 2, 1);
|
||||
|
||||
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(win));
|
||||
|
||||
g_scott->glk_put_char_uni(0x2680 + leftDice);
|
||||
g_scott->glk_put_char('+');
|
||||
g_scott->glk_put_char_uni(0x2680 + rightDice);
|
||||
|
||||
g_scott->glk_window_move_cursor(win, 2, 2);
|
||||
SOBPrint(win, "%d %d", leftDice + 1, rightDice + 1);
|
||||
}
|
||||
|
||||
void printSum(int ourTurn, int sum, int strike) {
|
||||
winid_t win = ourTurn ? _G(_battleRight) : _G(_topWindow);
|
||||
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(win));
|
||||
|
||||
g_scott->glk_window_move_cursor(win, 6, 1);
|
||||
|
||||
SOBPrint(win, "+ %d = %d", strike, sum);
|
||||
|
||||
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(_G(_battleRight)));
|
||||
g_scott->glk_window_move_cursor(_G(_battleRight), 6, 1);
|
||||
g_scott->glk_put_string("+ 9 = ");
|
||||
}
|
||||
|
||||
void updateResult(int ourTurn, int strike, int stamina, int boatFlag) {
|
||||
winid_t win = ourTurn ? _G(_battleRight) : _G(_topWindow);
|
||||
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(win));
|
||||
|
||||
g_scott->glk_window_move_cursor(win, 2, 4);
|
||||
|
||||
if (boatFlag) {
|
||||
SOBPrint(win, "STRIKE : %d\n", strike);
|
||||
g_scott->glk_window_move_cursor(win, 2, 5);
|
||||
SOBPrint(win, "CRW STR : %d", stamina);
|
||||
} else {
|
||||
SOBPrint(win, "SKILL : %d\n", strike);
|
||||
g_scott->glk_window_move_cursor(win, 2, 5);
|
||||
SOBPrint(win, "STAMINA : %d", stamina);
|
||||
}
|
||||
}
|
||||
|
||||
void clearResult(void) {
|
||||
winid_t win = _G(_topWindow);
|
||||
|
||||
uint width;
|
||||
for (int j = 0; j < 2; j++) {
|
||||
g_scott->glk_window_get_size(win, &width, 0);
|
||||
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(win));
|
||||
|
||||
g_scott->glk_window_move_cursor(win, 11, 1);
|
||||
for (int i = 0; i < 10; i++)
|
||||
g_scott->glk_put_string(" ");
|
||||
drawBorder(win);
|
||||
win = _G(_battleRight);
|
||||
}
|
||||
}
|
||||
|
||||
void clearStamina(void) {
|
||||
winid_t win = _G(_topWindow);
|
||||
|
||||
uint width;
|
||||
for (int j = 0; j < 2; j++) {
|
||||
g_scott->glk_window_get_size(win, &width, 0);
|
||||
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(win));
|
||||
|
||||
g_scott->glk_window_move_cursor(win, 11, 5);
|
||||
for (int i = 0; i < (int)width - 13; i++)
|
||||
g_scott->glk_put_string(" ");
|
||||
drawBorder(win);
|
||||
win = _G(_battleRight);
|
||||
}
|
||||
}
|
||||
|
||||
static void rearrangeBattleDisplay(int strike, int stamina, int boatFlag) {
|
||||
g_scott->updateSettings();
|
||||
g_scott->glk_cancel_char_event(_G(_topWindow));
|
||||
g_scott->closeGraphicsWindow();
|
||||
g_scott->glk_window_close(_G(_battleRight), nullptr);
|
||||
g_scott->glk_window_close(_G(_leftDiceWin), nullptr);
|
||||
g_scott->glk_window_close(_G(_rightDiceWin), nullptr);
|
||||
seasOfBloodRoomImage();
|
||||
setupBattleScreen(boatFlag);
|
||||
updateResult(0, strike, stamina, boatFlag);
|
||||
updateResult(1, 9, _G(_counters)[3], boatFlag);
|
||||
drawBorder(_G(_topWindow));
|
||||
drawBorder(_G(_battleRight));
|
||||
redrawStaticText(_G(_topWindow), boatFlag);
|
||||
redrawStaticText(_G(_battleRight), boatFlag);
|
||||
g_scott->glk_request_char_event(_G(_topWindow));
|
||||
}
|
||||
|
||||
int rollDice(int strike, int stamina, int boatFlag) {
|
||||
clearResult();
|
||||
redrawStaticText(_G(_battleRight), boatFlag);
|
||||
|
||||
g_scott->glk_request_timer_events(60);
|
||||
int rolls = 0;
|
||||
int ourTurn = 0;
|
||||
int leftDice = 1 + g_scott->getRandomNumber(100) % 6;
|
||||
int rightDice = 1 + g_scott->getRandomNumber(100) % 6;
|
||||
int ourResult;
|
||||
int theirResult = 0;
|
||||
int theirDiceStopped = 0;
|
||||
|
||||
event_t event;
|
||||
int enemyRolls = 20 + g_scott->getRandomNumber(100) % 10;
|
||||
g_scott->glk_cancel_char_event(_G(_topWindow));
|
||||
g_scott->glk_request_char_event(_G(_topWindow));
|
||||
|
||||
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(_G(_bottomWindow)));
|
||||
g_scott->glk_put_string("Their throw");
|
||||
|
||||
int delay = 60;
|
||||
|
||||
while (!g_vm->shouldQuit()) {
|
||||
g_scott->glk_select(&event);
|
||||
if (event.type == evtype_Timer) {
|
||||
if (theirDiceStopped) {
|
||||
g_scott->glk_request_timer_events(60);
|
||||
theirDiceStopped = 0;
|
||||
printSum(ourTurn, theirResult, strike);
|
||||
ourTurn = 1;
|
||||
g_scott->glk_window_clear(_G(_bottomWindow));
|
||||
g_scott->glk_cancel_char_event(_G(_topWindow));
|
||||
g_scott->glk_request_char_event(_G(_topWindow));
|
||||
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(_G(_bottomWindow)));
|
||||
g_scott->glk_put_string("Your throw\n");
|
||||
g_scott->glk_put_string("<ENTER> to stop dice");
|
||||
if (!boatFlag)
|
||||
g_scott->glk_put_string(" <X> to run");
|
||||
} else if (ourTurn == 0) {
|
||||
g_scott->glk_request_timer_events(delay);
|
||||
}
|
||||
|
||||
rolls++;
|
||||
|
||||
if (rolls % 2)
|
||||
leftDice = 1 + g_scott->getRandomNumber(100) % 6;
|
||||
else
|
||||
rightDice = 1 + g_scott->getRandomNumber(100) % 6;
|
||||
|
||||
updateDice(ourTurn, leftDice, rightDice);
|
||||
if (ourTurn == 0 && rolls == enemyRolls) {
|
||||
g_scott->glk_window_clear(_G(_bottomWindow));
|
||||
theirResult = leftDice + rightDice + strike;
|
||||
SOBPrint(_G(_bottomWindow), "Their result: %d + %d + %d = %d\n", leftDice,
|
||||
rightDice, strike, theirResult);
|
||||
g_scott->glk_request_timer_events(1000);
|
||||
theirDiceStopped = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.type == evtype_CharInput) {
|
||||
if (ourTurn && (event.val1 == keycode_Return)) {
|
||||
updateDice(ourTurn, leftDice, rightDice);
|
||||
ourResult = leftDice + rightDice + 9;
|
||||
printSum(ourTurn, ourResult, 9);
|
||||
if (theirResult > ourResult) {
|
||||
return LOSS;
|
||||
} else if (ourResult > theirResult) {
|
||||
return VICTORY;
|
||||
} else {
|
||||
return DRAW;
|
||||
}
|
||||
} else if (MY_LOC != 1 && (event.val1 == 'X' || event.val1 == 'x')) {
|
||||
MY_LOC = _G(_savedRoom);
|
||||
return FLEE;
|
||||
} else {
|
||||
g_scott->glk_request_char_event(_G(_topWindow));
|
||||
}
|
||||
}
|
||||
if (event.type == evtype_Arrange) {
|
||||
rearrangeBattleDisplay(strike, stamina, boatFlag);
|
||||
}
|
||||
}
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
void battleHitEnter(int strike, int stamina, int boatFlag) {
|
||||
g_scott->glk_request_char_event(_G(_bottomWindow));
|
||||
event_t ev;
|
||||
int result = 0;
|
||||
do {
|
||||
g_scott->glk_select(&ev);
|
||||
if (ev.type == evtype_CharInput) {
|
||||
if (ev.val1 == keycode_Return) {
|
||||
result = 1;
|
||||
} else {
|
||||
g_scott->glk_request_char_event(_G(_bottomWindow));
|
||||
}
|
||||
}
|
||||
|
||||
if (ev.type == evtype_Arrange) {
|
||||
rearrangeBattleDisplay(strike, stamina, boatFlag);
|
||||
}
|
||||
|
||||
} while (result == 0 && !g_vm->shouldQuit());
|
||||
}
|
||||
|
||||
void battleLoop(int enemy, int strike, int stamina, int boatFlag) {
|
||||
updateResult(0, strike, stamina, boatFlag);
|
||||
updateResult(1, 9, _G(_counters)[3], boatFlag);
|
||||
do {
|
||||
int result = rollDice(strike, stamina, boatFlag);
|
||||
g_scott->glk_cancel_char_event(_G(_topWindow));
|
||||
g_scott->glk_window_clear(_G(_bottomWindow));
|
||||
clearStamina();
|
||||
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(_G(_bottomWindow)));
|
||||
if (result == LOSS) {
|
||||
_G(_counters)[3] -= 2;
|
||||
|
||||
if (_G(_counters)[3] <= 0) {
|
||||
SOBPrint(_G(_bottomWindow), "%s\n",
|
||||
boatFlag ? "THE BANSHEE HAS BEEN SUNK!"
|
||||
: "YOU HAVE BEEN KILLED!");
|
||||
_G(_counters)[3] = 0;
|
||||
_G(_bitFlags) |= (1 << 6);
|
||||
_G(_counters)[7] = 0;
|
||||
} else {
|
||||
SOBPrint(_G(_bottomWindow), "%s", _G(_battleMessages)[1 + g_scott->getRandomNumber(100) % 5 + 16 * boatFlag]);
|
||||
}
|
||||
} else if (result == VICTORY) {
|
||||
stamina -= 2;
|
||||
if (stamina <= 0) {
|
||||
g_scott->glk_put_string("YOU HAVE WON!\n");
|
||||
_G(_bitFlags) &= ~(1 << 6);
|
||||
stamina = 0;
|
||||
} else {
|
||||
SOBPrint(_G(_bottomWindow), "%s", _G(_battleMessages)[6 + g_scott->getRandomNumber(100) % 5 + 16 * boatFlag]);
|
||||
}
|
||||
} else if (result == FLEE) {
|
||||
_G(_bitFlags) |= (1 << 6);
|
||||
MY_LOC = _G(_savedRoom);
|
||||
return;
|
||||
} else {
|
||||
SOBPrint(_G(_bottomWindow), "%s", _G(_battleMessages)[11 + g_scott->getRandomNumber(100) % 5 + 16 * boatFlag]);
|
||||
}
|
||||
|
||||
g_scott->glk_put_string("\n\n");
|
||||
|
||||
if (_G(_counters)[3] > 0 && stamina > 0) {
|
||||
g_scott->glk_put_string("<ENTER> to roll dice");
|
||||
if (!boatFlag)
|
||||
g_scott->glk_put_string(" <X> to run");
|
||||
}
|
||||
|
||||
updateResult(0, strike, stamina, boatFlag);
|
||||
updateResult(1, 9, _G(_counters)[3], boatFlag);
|
||||
|
||||
battleHitEnter(strike, stamina, boatFlag);
|
||||
g_scott->glk_window_clear(_G(_bottomWindow));
|
||||
} while (stamina > 0 && _G(_counters)[3] > 0 && !g_vm->shouldQuit());
|
||||
}
|
||||
|
||||
void swapStaminaAndCrewStrength(void) {
|
||||
uint8_t temp = _G(_counters)[7]; // Crew strength
|
||||
_G(_counters)[7] = _G(_counters)[3]; // Stamina
|
||||
_G(_counters)[3] = temp;
|
||||
}
|
||||
|
||||
int loadExtraSeasOfBloodData(void) {
|
||||
_G(_drawToBuffer) = 1;
|
||||
|
||||
int offset;
|
||||
|
||||
offset = 0x47b7 + _G(_fileBaselineOffset);
|
||||
|
||||
uint8_t *ptr = seekToPos(_G(_entireFile), offset);
|
||||
|
||||
int ct;
|
||||
|
||||
for (ct = 0; ct < 124; ct++) {
|
||||
_G(_enemyTable)[ct] = *(ptr++);
|
||||
if (_G(_enemyTable)[ct] == 0xff)
|
||||
break;
|
||||
}
|
||||
|
||||
ptr = seekToPos(_G(_entireFile), 0x71DA + _G(_fileBaselineOffset));
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
_G(_battleMessages)[i] = decompressText(ptr, i);
|
||||
}
|
||||
|
||||
offset = 0x7af5 - 16357 + _G(_fileBaselineOffset);
|
||||
|
||||
int data_length = 2010;
|
||||
|
||||
_G(_bloodImageData) = new uint8_t[data_length];
|
||||
ptr = seekToPos(_G(_entireFile), offset);
|
||||
for (int i = 0; i < data_length; i++)
|
||||
_G(_bloodImageData)[i] = *(ptr++);
|
||||
|
||||
for (int i = I_DONT_UNDERSTAND; i <= THATS_BEYOND_MY_POWER; i++)
|
||||
_G(_sys)[i] = _G(_systemMessages)[4 - I_DONT_UNDERSTAND + i];
|
||||
|
||||
for (int i = YOU_ARE; i <= HIT_ENTER; i++)
|
||||
_G(_sys)[i] = _G(_systemMessages)[13 - YOU_ARE + i];
|
||||
|
||||
_G(_sys)[OK] = _G(_systemMessages)[2];
|
||||
_G(_sys)[PLAY_AGAIN] = _G(_systemMessages)[3];
|
||||
_G(_sys)[YOURE_CARRYING_TOO_MUCH] = _G(_systemMessages)[27];
|
||||
|
||||
_G(_items)[125]._text = "A loose plank";
|
||||
_G(_items)[125]._autoGet = "PLAN";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int loadExtraSeasOfBlood64Data(void) {
|
||||
_G(_drawToBuffer) = 1;
|
||||
|
||||
int offset;
|
||||
|
||||
offset = 0x3fee + _G(_fileBaselineOffset);
|
||||
uint8_t *ptr;
|
||||
|
||||
ptr = seekToPos(_G(_entireFile), offset);
|
||||
|
||||
int ct;
|
||||
for (ct = 0; ct < 124; ct++) {
|
||||
_G(_enemyTable)[ct] = *(ptr++);
|
||||
if (_G(_enemyTable)[ct] == 0xff)
|
||||
break;
|
||||
}
|
||||
|
||||
offset = 0x82f6 + _G(_fileBaselineOffset);
|
||||
ptr = seekToPos(_G(_entireFile), offset);
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
_G(_battleMessages)[i] = decompressText(ptr, i);
|
||||
}
|
||||
|
||||
offset = 0x5299 + _G(_fileBaselineOffset);
|
||||
|
||||
int data_length = 2010;
|
||||
|
||||
_G(_bloodImageData) = new uint8_t[data_length];
|
||||
|
||||
ptr = seekToPos(_G(_entireFile), offset);
|
||||
for (int i = 0; i < data_length; i++) {
|
||||
_G(_bloodImageData)[i] = *(ptr++);
|
||||
}
|
||||
|
||||
SysMessageType messagekey[] = {
|
||||
NORTH,
|
||||
SOUTH,
|
||||
EAST,
|
||||
WEST,
|
||||
UP,
|
||||
DOWN,
|
||||
EXITS,
|
||||
YOU_SEE,
|
||||
YOU_ARE,
|
||||
YOU_CANT_GO_THAT_WAY,
|
||||
OK,
|
||||
WHAT_NOW,
|
||||
HUH,
|
||||
YOU_HAVE_IT,
|
||||
YOU_HAVENT_GOT_IT,
|
||||
DROPPED,
|
||||
TAKEN,
|
||||
INVENTORY,
|
||||
YOU_DONT_SEE_IT,
|
||||
THATS_BEYOND_MY_POWER,
|
||||
DIRECTION,
|
||||
YOURE_CARRYING_TOO_MUCH,
|
||||
PLAY_AGAIN,
|
||||
RESUME_A_SAVED_GAME,
|
||||
YOU_CANT_DO_THAT_YET,
|
||||
I_DONT_UNDERSTAND,
|
||||
NOTHING};
|
||||
|
||||
for (int i = 0; i < 27; i++) {
|
||||
_G(_sys)[messagekey[i]] = _G(_systemMessages)[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
|
||||
50
engines/glk/scott/seas_of_blood.h
Normal file
50
engines/glk/scott/seas_of_blood.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_SEAS_OF_BLOOD_H
|
||||
#define GLK_SCOTT_SEAS_OF_BLOOD_H
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
int loadExtraSeasOfBloodData();
|
||||
int loadExtraSeasOfBlood64Data();
|
||||
void seasOfBloodRoomImage();
|
||||
void adventureSheet();
|
||||
void bloodAction(int p);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
501
engines/glk/scott/ti99_4a_terp.cpp
Normal file
501
engines/glk/scott/ti99_4a_terp.cpp
Normal file
@@ -0,0 +1,501 @@
|
||||
#include "ti99_4a_terp.h"
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#include "glk/scott/scott.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/globals.h"
|
||||
#include "glk/scott/ti99_4a_terp.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
ActionResultType performTI99Line(uint8_t *actionLine) {
|
||||
if (actionLine == nullptr)
|
||||
return ACT_FAILURE;
|
||||
|
||||
uint8_t *ptr = actionLine;
|
||||
int runCode = 0;
|
||||
int index = 0;
|
||||
ActionResultType result = ACT_FAILURE;
|
||||
int opcode, param;
|
||||
|
||||
int tryIndex;
|
||||
int tryArr[32];
|
||||
|
||||
tryIndex = 0;
|
||||
|
||||
while (runCode == 0) {
|
||||
opcode = *(ptr++);
|
||||
|
||||
switch (opcode) {
|
||||
case 183: /* is p in inventory? */
|
||||
if (_G(_items)[*(ptr++)]._location != CARRIED) {
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 184: /* is p in room? */
|
||||
if (_G(_items)[*(ptr++)]._location != MY_LOC) {
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 185: /* is p available? */
|
||||
if (_G(_items)[*ptr]._location != CARRIED && _G(_items)[*ptr]._location != MY_LOC) {
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
}
|
||||
ptr++;
|
||||
break;
|
||||
|
||||
case 186: /* is p here? */
|
||||
if (_G(_items)[*(ptr++)]._location == MY_LOC) {
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 187: /* is p NOT in inventory? */
|
||||
if (_G(_items)[*(ptr++)]._location == CARRIED) {
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 188: /* is p NOT available? */
|
||||
if (_G(_items)[*ptr]._location == CARRIED || _G(_items)[*ptr]._location == MY_LOC) {
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
}
|
||||
ptr++;
|
||||
break;
|
||||
|
||||
case 189: /* is p in play? */
|
||||
if (_G(_items)[*(ptr++)]._location == 0) {
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 190: /* Is object p NOT in play? */
|
||||
if (_G(_items)[*(ptr++)]._location != 0) {
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 191: /* Is player is in room p? */
|
||||
if (MY_LOC != *(ptr++)) {
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 192: /* Is player NOT in room p? */
|
||||
if (MY_LOC == *(ptr++)) {
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 193: /* Is bitflag p clear? */
|
||||
if ((_G(_bitFlags) & (1 << *(ptr++))) == 0) {
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 194: /* Is bitflag p set? */
|
||||
if (_G(_bitFlags) & (1 << *(ptr++))) {
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 195: /* Does the player carry anything? */
|
||||
if (g_scott->countCarried() == 0) {
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 196: /* Does the player carry nothing? */
|
||||
if (g_scott->countCarried()) {
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 197: /* Is _G(_currentCounter) <= p? */
|
||||
if (_G(_currentCounter) > *(ptr++)) {
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 198: /* Is _G(_currentCounter) > p? */
|
||||
if (_G(_currentCounter) <= *(ptr++)) {
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 199: /* Is _G(_currentCounter) == p? */
|
||||
if (_G(_currentCounter) != *(ptr++)) {
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 200: /* Is item p still in initial room? */
|
||||
if (_G(_items)[*ptr]._location != _G(_items)[*ptr]._initialLoc) {
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
}
|
||||
ptr++;
|
||||
break;
|
||||
|
||||
case 201: /* Has item p been moved? */
|
||||
if (_G(_items)[*ptr]._location == _G(_items)[*ptr]._initialLoc) {
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
}
|
||||
ptr++;
|
||||
break;
|
||||
|
||||
case 212: /* clear screen */
|
||||
g_scott->glk_window_clear(_G(_bottomWindow));
|
||||
break;
|
||||
|
||||
case 214: /* inv */
|
||||
_G(_autoInventory) = 1;
|
||||
break;
|
||||
|
||||
case 215: /* !inv */
|
||||
_G(_autoInventory) = 0;
|
||||
break;
|
||||
|
||||
case 216:
|
||||
case 217:
|
||||
break;
|
||||
|
||||
case 218:
|
||||
if (tryIndex >= 32) {
|
||||
g_scott->fatal("ERROR Hit upper limit on try method.");
|
||||
}
|
||||
tryArr[tryIndex++] = ptr - actionLine + *ptr;
|
||||
ptr++;
|
||||
break;
|
||||
|
||||
case 219: /* get item */
|
||||
if (g_scott->countCarried() >= _G(_gameHeader)->_maxCarry) {
|
||||
g_scott->output(_G(_sys)[YOURE_CARRYING_TOO_MUCH]);
|
||||
runCode = 1;
|
||||
result = ACT_FAILURE;
|
||||
break;
|
||||
} else {
|
||||
_G(_items)[*ptr]._location = CARRIED;
|
||||
}
|
||||
ptr++;
|
||||
break;
|
||||
|
||||
case 220: /* drop item */
|
||||
_G(_items)[*(ptr++)]._location = MY_LOC;
|
||||
_G(_shouldLookInTranscript) = 1;
|
||||
break;
|
||||
|
||||
case 221: /* go to room */
|
||||
MY_LOC = *(ptr++);
|
||||
_G(_shouldLookInTranscript) = 1;
|
||||
g_scott->look();
|
||||
break;
|
||||
|
||||
case 222: /* move item p to room 0 */
|
||||
_G(_items)[*(ptr++)]._location = 0;
|
||||
break;
|
||||
|
||||
case 223: /* darkness */
|
||||
_G(_bitFlags) |= 1 << DARKBIT;
|
||||
break;
|
||||
|
||||
case 224: /* light */
|
||||
_G(_bitFlags) &= ~(1 << DARKBIT);
|
||||
break;
|
||||
|
||||
case 225: /* set flag p */
|
||||
_G(_bitFlags) |= (1 << *(ptr++));
|
||||
break;
|
||||
|
||||
case 226: /* clear flag p */
|
||||
_G(_bitFlags) &= ~(1 << *(ptr++));
|
||||
break;
|
||||
|
||||
case 227: /* set flag 0 */
|
||||
_G(_bitFlags) |= (1 << 0);
|
||||
break;
|
||||
|
||||
case 228: /* clear flag 0 */
|
||||
_G(_bitFlags) &= ~(1 << 0);
|
||||
break;
|
||||
|
||||
case 229: /* die */
|
||||
g_scott->playerIsDead();
|
||||
g_scott->doneIt();
|
||||
result = ACT_GAMEOVER;
|
||||
break;
|
||||
|
||||
case 230: /* move item p2 to room p */
|
||||
param = *(ptr++);
|
||||
g_scott->putItemAInRoomB(*(ptr++), param);
|
||||
break;
|
||||
|
||||
case 231: /* quit */
|
||||
g_scott->doneIt();
|
||||
return ACT_GAMEOVER;
|
||||
|
||||
case 232: /* print score */
|
||||
if (g_scott->printScore() == 1)
|
||||
return ACT_GAMEOVER;
|
||||
_G(_stopTime) = 2;
|
||||
break;
|
||||
|
||||
case 233: /* list contents of inventory */
|
||||
g_scott->listInventory();
|
||||
_G(_stopTime) = 2;
|
||||
break;
|
||||
|
||||
case 234: /* refill lightsource */
|
||||
_G(_gameHeader)->_lightTime = _G(_lightRefill);
|
||||
_G(_items)[LIGHT_SOURCE]._location = CARRIED;
|
||||
_G(_bitFlags) &= ~(1 << LIGHTOUTBIT);
|
||||
break;
|
||||
|
||||
case 235: /* save */
|
||||
g_scott->saveGame();
|
||||
_G(_stopTime) = 2;
|
||||
break;
|
||||
|
||||
case 236: /* swap items p and p2 around */
|
||||
param = *(ptr++);
|
||||
g_scott->swapItemLocations(param, *(ptr++));
|
||||
break;
|
||||
|
||||
case 237: /* move item p to the inventory */
|
||||
_G(_items)[*(ptr++)]._location = CARRIED;
|
||||
break;
|
||||
|
||||
case 238: /* make item p same room as item p2 */
|
||||
param = *(ptr++);
|
||||
g_scott->moveItemAToLocOfItemB(param, *(ptr++));
|
||||
break;
|
||||
|
||||
case 239: /* nop */
|
||||
break;
|
||||
|
||||
case 240: /* look at room */
|
||||
g_scott->look();
|
||||
_G(_shouldLookInTranscript) = 1;
|
||||
break;
|
||||
|
||||
case 241: /* unknown */
|
||||
break;
|
||||
|
||||
case 242: /* add 1 to current counter */
|
||||
_G(_currentCounter)++;
|
||||
break;
|
||||
|
||||
case 243: /* sub 1 from current counter */
|
||||
if (_G(_currentCounter) >= 1)
|
||||
_G(_currentCounter)--;
|
||||
break;
|
||||
|
||||
case 244: /* print current counter */
|
||||
g_scott->outputNumber(_G(_currentCounter));
|
||||
g_scott->output(" ");
|
||||
break;
|
||||
|
||||
case 245: /* set current counter to p */
|
||||
_G(_currentCounter) = *(ptr++);
|
||||
break;
|
||||
|
||||
case 246: /* add to current counter */
|
||||
_G(_currentCounter) += *(ptr++);
|
||||
break;
|
||||
|
||||
case 247: /* sub from current counter */
|
||||
_G(_currentCounter) -= *(ptr++);
|
||||
if (_G(_currentCounter) < -1)
|
||||
_G(_currentCounter) = -1;
|
||||
break;
|
||||
|
||||
case 248: /* go to stored location */
|
||||
g_scott->goToStoredLoc();
|
||||
break;
|
||||
|
||||
case 249: /* swap room and counter */
|
||||
g_scott->swapLocAndRoomFlag(*(ptr++));
|
||||
break;
|
||||
|
||||
case 250: /* swap current counter */
|
||||
g_scott->swapCounters(*(ptr++));
|
||||
break;
|
||||
|
||||
case 251: /* print noun */
|
||||
g_scott->printNoun();
|
||||
break;
|
||||
|
||||
case 252: /* print noun + newline */
|
||||
g_scott->printNoun();
|
||||
g_scott->output("\n");
|
||||
break;
|
||||
|
||||
case 253: /* print newline */
|
||||
g_scott->output("\n");
|
||||
break;
|
||||
|
||||
case 254: /* delay */
|
||||
g_scott->delay(1);
|
||||
break;
|
||||
|
||||
case 255: /* end of code block. */
|
||||
result = ACT_SUCCESS;
|
||||
runCode = 1;
|
||||
tryIndex = 0; /* drop out of all try blocks! */
|
||||
break;
|
||||
|
||||
default:
|
||||
if (opcode <= 182 && opcode <= _G(_gameHeader)->_numMessages + 1) {
|
||||
g_scott->printMessage(opcode);
|
||||
} else {
|
||||
index = ptr - actionLine;
|
||||
error("Unknown action %d [Param begins %d %d]", opcode, actionLine[index], actionLine[index + 1]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* we are on the 0xff opcode, or have fallen through */
|
||||
if (runCode == 1 && tryIndex > 0) {
|
||||
if (opcode == 0xff) {
|
||||
runCode = 1;
|
||||
} else {
|
||||
/* dropped out of TRY block */
|
||||
/* or at end of TRY block */
|
||||
index = tryArr[tryIndex - 1];
|
||||
|
||||
tryIndex -= 1;
|
||||
tryArr[tryIndex] = 0;
|
||||
runCode = 0;
|
||||
ptr = actionLine + index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void runImplicitTI99Actions() {
|
||||
int probability;
|
||||
uint8_t *ptr;
|
||||
int loopFlag;
|
||||
|
||||
ptr = _G(_ti99ImplicitActions);
|
||||
loopFlag = 0;
|
||||
|
||||
/* bail if no auto acts in the game. */
|
||||
if (*ptr == 0x0)
|
||||
loopFlag = 1;
|
||||
|
||||
while (loopFlag == 0) {
|
||||
/*
|
||||
p + 0 = chance of happening
|
||||
p + 1 = size of code chunk
|
||||
p + 2 = start of code
|
||||
*/
|
||||
|
||||
probability = ptr[0];
|
||||
|
||||
if (g_scott->randomPercent(probability))
|
||||
performTI99Line(ptr + 2);
|
||||
|
||||
if (ptr[1] == 0 || static_cast<size_t>(ptr - _G(_ti99ImplicitActions)) >= _G(_ti99ImplicitExtent))
|
||||
loopFlag = 1;
|
||||
|
||||
/* skip code chunk */
|
||||
ptr += 1 + ptr[1];
|
||||
}
|
||||
}
|
||||
|
||||
ExplicitResultType runExplicitTI99Actions(int verbNum, int nounNum) {
|
||||
uint8_t *p;
|
||||
ExplicitResultType flag = ER_NO_RESULT;
|
||||
int match = 0;
|
||||
ActionResultType runcode;
|
||||
|
||||
p = _G(_verbActionOffsets)[verbNum];
|
||||
|
||||
/* process all code blocks for this verb
|
||||
until success or end. */
|
||||
|
||||
while (flag == ER_NO_RESULT) {
|
||||
/* we match VERB NOUN or VERB ANY */
|
||||
if (p != nullptr && (p[0] == nounNum || p[0] == 0)) {
|
||||
match = 1;
|
||||
runcode = performTI99Line(p + 2);
|
||||
|
||||
if (runcode == ACT_SUCCESS) {
|
||||
return ER_SUCCESS;
|
||||
} else { /* failure */
|
||||
if (p[1] == 0)
|
||||
flag = ER_RAN_ALL_LINES;
|
||||
else
|
||||
p += 1 + p[1];
|
||||
}
|
||||
} else {
|
||||
if (p == nullptr || p[1] == 0)
|
||||
flag = ER_RAN_ALL_LINES_NO_MATCH;
|
||||
else
|
||||
p += 1 + p[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (match)
|
||||
flag = ER_RAN_ALL_LINES;
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
47
engines/glk/scott/ti99_4a_terp.h
Normal file
47
engines/glk/scott/ti99_4a_terp.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_TI99_4A_TERP_H
|
||||
#define GLK_SCOTT_TI99_4A_TERP_H
|
||||
|
||||
#include "glk/scott/definitions.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void runImplicitTI99Actions();
|
||||
ExplicitResultType runExplicitTI99Actions(int verbNum, int nounNum);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
57
engines/glk/scott/types.h
Normal file
57
engines/glk/scott/types.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on ScottFree interpreter version 1.14 developed by Swansea
|
||||
* University Computer Society without disassembly of any other game
|
||||
* drivers, only of game databases as permitted by EEC law (for purposes
|
||||
* of compatibility).
|
||||
*
|
||||
* Licensed under GPLv2
|
||||
*
|
||||
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_TYPES_H
|
||||
#define GLK_SCOTT_TYPES_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
#if !defined(SIZE_MAX)
|
||||
#define SIZE_MAX 0xFFFFFFFF
|
||||
#endif
|
||||
|
||||
typedef uint8 uint8_t;
|
||||
typedef uint16 uint16_t;
|
||||
typedef uint32 uint32_t;
|
||||
typedef int8 int8_t;
|
||||
typedef int16 int16_t;
|
||||
typedef int32 int32_t;
|
||||
typedef int64 int64_t;
|
||||
typedef unsigned long long size_t;
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
1349
engines/glk/scott/unp64/6502_emu.cpp
Normal file
1349
engines/glk/scott/unp64/6502_emu.cpp
Normal file
File diff suppressed because it is too large
Load Diff
68
engines/glk/scott/unp64/6502_emu.h
Normal file
68
engines/glk/scott/unp64/6502_emu.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002 - 2023 Magnus Lind.
|
||||
*
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_6502_EMU_H
|
||||
#define GLK_SCOTT_6502_EMU_H
|
||||
|
||||
#include "glk/scott/types.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
struct CpuCtx {
|
||||
uint32_t _cycles;
|
||||
uint16_t _pc;
|
||||
uint8_t *_mem;
|
||||
uint8_t _sp;
|
||||
uint8_t _flags;
|
||||
uint8_t _a;
|
||||
uint8_t _x;
|
||||
uint8_t _y;
|
||||
};
|
||||
|
||||
int nextInst(CpuCtx *r);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
235
engines/glk/scott/unp64/exo_util.cpp
Normal file
235
engines/glk/scott/unp64/exo_util.cpp
Normal file
@@ -0,0 +1,235 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002 - 2023 Magnus Lind.
|
||||
*
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/util.h"
|
||||
#include "glk/scott/unp64/exo_util.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
int findSys(const byte *buf, int target) {
|
||||
int outstart = -1;
|
||||
int state = 1;
|
||||
int i = 0;
|
||||
/* skip link and line number */
|
||||
buf += 4;
|
||||
/* iAN: workaround for hidden sysline (1001 cruncher, CFB, etc)*/
|
||||
if (buf[0] == 0) {
|
||||
for (i = 5; i < 32; i++)
|
||||
if (buf[i] == 0x9e && (((buf[i + 1] & 0x30) == 0x30) || ((buf[i + 2] & 0x30) == 0x30)))
|
||||
break;
|
||||
}
|
||||
/* exit loop at line end */
|
||||
while (i < 1000 && buf[i] != '\0') {
|
||||
byte *sysEnd;
|
||||
int c = buf[i];
|
||||
switch (state) {
|
||||
/* look for and consume sys token */
|
||||
case 1:
|
||||
if ((target == -1 && (c == 0x9e)) || c == target) {
|
||||
state = 2;
|
||||
}
|
||||
break;
|
||||
/* skip spaces and left parenthesis, if any */
|
||||
case 2:
|
||||
if (strchr(" (", c) != nullptr)
|
||||
break;
|
||||
// fallthrough
|
||||
/* convert string number to int */
|
||||
case 3:
|
||||
outstart = (int)strtol((const char *)(buf + i), (char **)&sysEnd, 10);
|
||||
if ((buf + i) == sysEnd) {
|
||||
/* we got nothing */
|
||||
outstart = -1;
|
||||
} else {
|
||||
c = *sysEnd;
|
||||
if ((c >= 0xaa) && (c <= 0xae)) {
|
||||
i = (int)strtol((char *)(sysEnd + 1), (char **)&sysEnd, 10);
|
||||
switch (c) {
|
||||
case 0xaa:
|
||||
outstart += i;
|
||||
break;
|
||||
case 0xab:
|
||||
outstart -= i;
|
||||
break;
|
||||
case 0xac:
|
||||
outstart *= i;
|
||||
break;
|
||||
case 0xad:
|
||||
if (i > 0)
|
||||
outstart /= i;
|
||||
break;
|
||||
case 0xae:
|
||||
c = outstart;
|
||||
while (--i)
|
||||
outstart *= c;
|
||||
break;
|
||||
}
|
||||
} else if (c == 'E') {
|
||||
i = (int)strtol((char *)(sysEnd + 1), (char **)&sysEnd, 10);
|
||||
i++;
|
||||
while (--i)
|
||||
outstart *= 10;
|
||||
}
|
||||
}
|
||||
state = 4;
|
||||
break;
|
||||
case 4:
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
return outstart;
|
||||
}
|
||||
|
||||
static void loadPrgData(byte mem[65536], uint8_t *data, size_t dataLength, LoadInfo *info) {
|
||||
int len = MIN(65536 - info->_start, static_cast<int>(dataLength));
|
||||
memcpy(mem + info->_start, data, (size_t)len);
|
||||
|
||||
info->_end = info->_start + len;
|
||||
info->_basicVarStart = -1;
|
||||
info->_run = -1;
|
||||
if (info->_basicTxtStart >= info->_start && info->_basicTxtStart < info->_end) {
|
||||
info->_basicVarStart = info->_end;
|
||||
}
|
||||
}
|
||||
|
||||
void loadData(uint8_t *data, size_t dataLength, byte mem[65536], LoadInfo *info) {
|
||||
int load = data[0] + data[1] * 0x100;
|
||||
|
||||
info->_start = load;
|
||||
loadPrgData(mem, data + 2, dataLength - 2, info);
|
||||
}
|
||||
|
||||
int strToInt(const char *str, int *value) {
|
||||
int status = 0;
|
||||
do {
|
||||
char *strEnd;
|
||||
long lval;
|
||||
|
||||
/* base 0 is auto detect */
|
||||
int base = 0;
|
||||
|
||||
if (*str == '\0') {
|
||||
/* no string to parse */
|
||||
status = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*str == '$') {
|
||||
/* a $ prefix specifies base 16 */
|
||||
++str;
|
||||
base = 16;
|
||||
}
|
||||
|
||||
lval = strtol(str, &strEnd, base);
|
||||
|
||||
if (*strEnd != '\0') {
|
||||
/* there is garbage in the string */
|
||||
status = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (value != nullptr) {
|
||||
/* all is well, set the out parameter */
|
||||
*value = static_cast<int>(lval);
|
||||
}
|
||||
} while (0);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool u32eq(const unsigned char *addr, uint32_t val)
|
||||
{
|
||||
return addr[3] == (val >> 24) &&
|
||||
addr[2] == ((val >> 16) & 0xff) &&
|
||||
addr[1] == ((val >> 8) & 0xff) &&
|
||||
addr[0] == (val & 0xff);
|
||||
}
|
||||
|
||||
bool u32eqmasked(const unsigned char *addr, uint32_t mask, uint32_t val)
|
||||
{
|
||||
uint32_t val1 = addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24);
|
||||
return (val1 & mask) == val;
|
||||
}
|
||||
|
||||
bool u32eqxored(const unsigned char *addr, uint32_t xormask, uint32_t val)
|
||||
{
|
||||
uint32_t val1 = addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24);
|
||||
return (val1 ^ xormask) == val;
|
||||
}
|
||||
|
||||
bool u16eqmasked(const unsigned char *addr, uint16_t mask, uint16_t val)
|
||||
{
|
||||
uint16_t val1 = addr[0] | (addr[1] << 8);
|
||||
return (val1 & mask) == val;
|
||||
}
|
||||
|
||||
|
||||
bool u16eq(const unsigned char *addr, uint16_t val)
|
||||
{
|
||||
return addr[1] == (val >> 8) &&
|
||||
addr[0] == (val & 0xff);
|
||||
}
|
||||
|
||||
bool u16noteq(const unsigned char *addr, uint16_t val)
|
||||
{
|
||||
return addr[1] != (val >> 8) ||
|
||||
addr[0] != (val & 0xff);
|
||||
}
|
||||
|
||||
bool u16gteq(const unsigned char *addr, uint16_t val)
|
||||
{
|
||||
uint16_t val2 = addr[0] | (addr[1] << 8);
|
||||
return val2 >= val;
|
||||
}
|
||||
|
||||
bool u16lteq(const unsigned char *addr, uint16_t val)
|
||||
{
|
||||
uint16_t val2 = addr[0] | (addr[1] << 8);
|
||||
return val2 <= val;
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
78
engines/glk/scott/unp64/exo_util.h
Normal file
78
engines/glk/scott/unp64/exo_util.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002 - 2023 Magnus Lind.
|
||||
*
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GLK_SCOTT_EXO_UTIL_H
|
||||
#define GLK_SCOTT_EXO_UTIL_H
|
||||
|
||||
#include "glk/scott/types.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
struct LoadInfo {
|
||||
int _basicTxtStart; /* in */
|
||||
int _basicVarStart; /* out */
|
||||
int _run; /* out */
|
||||
int _start; /* out */
|
||||
int _end; /* out */
|
||||
};
|
||||
|
||||
int findSys(const byte *buf, int target);
|
||||
|
||||
void loadData(uint8_t *data, size_t dataLength, byte mem[65536], LoadInfo *info);
|
||||
|
||||
int strToInt(const char *str, int *value);
|
||||
|
||||
bool u32eq(const unsigned char *addr, uint32_t val);
|
||||
bool u16eq(const unsigned char *addr, uint16_t val);
|
||||
bool u16gteq(const unsigned char *addr, uint16_t val);
|
||||
bool u16lteq(const unsigned char *addr, uint16_t val);
|
||||
bool u16noteq(const unsigned char *addr, uint16_t val);
|
||||
bool u32eqmasked(const unsigned char *addr, uint32_t mask, uint32_t val);
|
||||
bool u32eqxored(const unsigned char *addr, uint32_t ormask, uint32_t val);
|
||||
bool u16eqmasked(const unsigned char *addr, uint16_t mask, uint16_t val);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
53
engines/glk/scott/unp64/scanners/action_packer.cpp
Normal file
53
engines/glk/scott/unp64/scanners/action_packer.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/unp64/unp64.h"
|
||||
#include "glk/scott/unp64/exo_util.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void scnActionPacker(UnpStr *unp) {
|
||||
byte *mem;
|
||||
|
||||
if (unp->_idFlag)
|
||||
return;
|
||||
mem = unp->_mem;
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x811, 0x018538A9) &&
|
||||
u32eq(mem + 0x81d, 0xCEF7D0E8) &&
|
||||
u32eq(mem + 0x82d, 0x0F9D0837) &&
|
||||
u32eq(mem + 0x84b, 0x03D00120)) {
|
||||
unp->_depAdr = 0x110;
|
||||
unp->_forced = 0x811;
|
||||
unp->_strMem = READ_LE_UINT16(&mem[0x848]);
|
||||
unp->_fEndAf = 0x120;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x863]);
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
94
engines/glk/scott/unp64/scanners/byte_boiler.cpp
Normal file
94
engines/glk/scott/unp64/scanners/byte_boiler.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/unp64/unp64.h"
|
||||
#include "glk/scott/unp64/exo_util.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void scnByteBoiler(UnpStr *unp) {
|
||||
byte *mem;
|
||||
int q, p;
|
||||
if (unp->_idFlag)
|
||||
return;
|
||||
mem = unp->_mem;
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x813, 0xE800F09D) &&
|
||||
u32eq(mem + 0x818, 0x014E4CF7)) {
|
||||
p = READ_LE_UINT16(&mem[0x811]);
|
||||
if (u32eq(mem + p + 1, 0x02D0FAA5)) {
|
||||
unp->_depAdr = 0x14e;
|
||||
unp->_forced = 0x80b;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[p + 0x5c]);
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[p + 0x0e]);
|
||||
unp->_endAdr++;
|
||||
unp->_fStrAf = 0xfe;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* CPX hack */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x80b, 0xA97800A2) &&
|
||||
u32eq(mem + 0x815, 0x4C01E6D0)) {
|
||||
q = READ_LE_UINT16(&mem[0x819]);
|
||||
if (u32eq(mem + q + 3, 0xE800F09D) &&
|
||||
u32eq(mem + q + 8, 0x014E4CF7)) {
|
||||
p = READ_LE_UINT16(&mem[q + 1]);
|
||||
if (u32eq(mem + p + 1, 0x02D0FAA5)) {
|
||||
unp->_depAdr = 0x14e;
|
||||
unp->_forced = 0x80b;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[p + 0x5c]);
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[p + 0x0e]);
|
||||
unp->_endAdr++;
|
||||
unp->_fStrAf = 0xfe;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* SCS hack */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x813, 0xE800F09D) &&
|
||||
u32eq(mem + 0x818, 0x01bf4CF7)) {
|
||||
p = READ_LE_UINT16(&mem[0x811]);
|
||||
if (u32eq(mem + p + 1, 0x02D0FAA5) &&
|
||||
u32eq(mem + p + 0xdd, 0x014e4c01)) {
|
||||
unp->_depAdr = 0x14e;
|
||||
unp->_forced = 0x80b;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[p + 0x5c]);
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[p + 0x0e]);
|
||||
unp->_endAdr++;
|
||||
unp->_fStrAf = 0xfe;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
135
engines/glk/scott/unp64/scanners/caution.cpp
Normal file
135
engines/glk/scott/unp64/scanners/caution.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/unp64/unp64.h"
|
||||
#include "glk/scott/unp64/exo_util.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void scnCaution(UnpStr *unp) {
|
||||
byte *mem;
|
||||
|
||||
if (unp->_idFlag)
|
||||
return;
|
||||
mem = unp->_mem;
|
||||
/* quickpacker 1.0 sysless */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x801, 0xE67800A2) &&
|
||||
u32eq(mem + 0x805, 0x07EDBD01) &&
|
||||
u32eq(mem + 0x80d, 0x00284CF8) &&
|
||||
u32eq(mem + 0x844, 0xAC00334C)) {
|
||||
unp->_forced = 0x801;
|
||||
unp->_depAdr = 0x28;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x86b]);
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[0x85a]);
|
||||
unp->_fStrAf = mem[0x863];
|
||||
unp->_strAdC = EA_ADDFF | 0xffff;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* quickpacker 2.x + sys */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eqmasked(mem + 0x80b, 0xf0ffffff, 0x60A200A0) &&
|
||||
u32eq(mem + 0x80f, 0x0801BD78) &&
|
||||
u32eq(mem + 0x813, 0xD0CA0095) &&
|
||||
u32eq(mem + 0x81e, 0xD0C80291) &&
|
||||
u32eq(mem + 0x817, 0x001A4CF8)) {
|
||||
unp->_forced = 0x80b;
|
||||
unp->_depAdr = 0x01a;
|
||||
if (mem[0x80e] == 0x69) {
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x842]);
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[0x850]);
|
||||
unp->_endAdr += 0x100;
|
||||
unp->_fStrAf = 0x4f;
|
||||
unp->_strAdC = 0xffff | EA_USE_Y;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
} else if (mem[0x80e] == 0x6c) {
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x844]);
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[0x84e]);
|
||||
unp->_endAdr++;
|
||||
unp->_fStrAf = 0x4d;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* strangely enough, sysless v2.0 depacker is at $0002 */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x83d, 0xAA004A20) &&
|
||||
u32eq(mem + 0x801, 0xA27800A0) &&
|
||||
u32eq(mem + 0x805, 0x080FBD55) &&
|
||||
u32eq(mem + 0x809, 0xD0CA0095) &&
|
||||
u32eq(mem + 0x80d, 0x00024CF8)) {
|
||||
unp->_forced = 0x801;
|
||||
unp->_depAdr = 0x2;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x83b]);
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[0x845]);
|
||||
unp->_endAdr++;
|
||||
unp->_fStrAf = mem[0x849];
|
||||
// unp->_StrAdC=0xffff;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* same goes for v2.5 sysless, seems almost another packer */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x83b, 0xAA005520) &&
|
||||
u32eq(mem + 0x801, 0x60A200A0) &&
|
||||
u32eq(mem + 0x805, 0x0801BD78) &&
|
||||
u32eq(mem + 0x809, 0xD0CA0095) &&
|
||||
u32eq(mem + 0x80d, 0x00104CF8)) {
|
||||
unp->_forced = 0x801;
|
||||
unp->_depAdr = 0x10;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x839]);
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[0x847]);
|
||||
unp->_endAdr += 0x100;
|
||||
unp->_fStrAf = 0x46;
|
||||
unp->_strAdC = 0xffff | EA_USE_Y;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* hardpacker */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x80d, 0x8534A978) &&
|
||||
u32eq(mem + 0x811, 0xB9B3A001) &&
|
||||
u32eq(mem + 0x815, 0x4C99081F) &&
|
||||
u32eq(mem + 0x819, 0xF7D08803) &&
|
||||
u32eq(mem + 0x81d, 0xB9034D4C)) {
|
||||
unp->_forced = 0x80d;
|
||||
unp->_depAdr = 0x34d;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x87f]);
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[0x88d]);
|
||||
unp->_fStrAf = 0x3ba;
|
||||
unp->_strAdC = EA_ADDFF | 0xffff;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
208
engines/glk/scott/unp64/scanners/ccs.cpp
Normal file
208
engines/glk/scott/unp64/scanners/ccs.cpp
Normal file
@@ -0,0 +1,208 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/unp64/unp64.h"
|
||||
#include "glk/scott/unp64/exo_util.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void scnCCS(UnpStr *unp) {
|
||||
byte *mem;
|
||||
int p;
|
||||
if (unp->_idFlag)
|
||||
return;
|
||||
mem = unp->_mem;
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x817, 0xB901E678) &&
|
||||
u32eq(mem + 0x81b, 0xFD990831) &&
|
||||
u32eq(mem + 0x8ff, 0xFEE60290) &&
|
||||
u32eq(mem + 0x90f, 0x02903985)) {
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = 0x817;
|
||||
unp->_depAdr = 0x0ff;
|
||||
unp->_fEndAf = 0x2d;
|
||||
unp->_endAdC = 0xffff;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x8ed]);
|
||||
if (unp->_retAdr == 0xa659) {
|
||||
mem[0x8ec] = 0x2c;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x8f0]);
|
||||
}
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* derived from supercomp/eqseq */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x80b, 0x8C7800A0) &&
|
||||
u32eq(mem + 0x812, 0x0099082F) &&
|
||||
u32eq(mem + 0x846, 0x0DADF2D0) &&
|
||||
u32eq(mem + 0x8c0, 0xF001124C)) {
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = 0x80b;
|
||||
unp->_depAdr = 0x100;
|
||||
unp->_endAdr = 0xae;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x8f1]);
|
||||
if (unp->_retAdr == 0xa659) {
|
||||
mem[0x8f0] = 0x2c;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x8f4]);
|
||||
}
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x814, 0xB901E678) &&
|
||||
u32eq(mem + 0x818, 0xFD990829) &&
|
||||
u32eq(mem + 0x8a1, 0xFDA6FDB1) &&
|
||||
u32eq(mem + 0x8a5, 0xFEC602D0)) {
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = 0x814;
|
||||
unp->_depAdr = 0x0ff;
|
||||
unp->_fEndBf = 0x39;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x818, 0x2CB901E6) &&
|
||||
u32eq(mem + 0x81c, 0x00FB9908) &&
|
||||
u32eq(mem + 0x850, 0xFBB1C84A) &&
|
||||
u32eq(mem + 0x854, 0xB1C81185)) {
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = 0x812;
|
||||
unp->_depAdr = 0x0ff;
|
||||
unp->_endAdr = 0xae;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x818, 0x2CB901E6) &&
|
||||
u32eq(mem + 0x81c, 0x00FB9908) &&
|
||||
u32eq(mem + 0x851, 0xFBB1C812) &&
|
||||
u32eq(mem + 0x855, 0xB1C81185)) {
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = 0x812;
|
||||
unp->_depAdr = 0x0ff;
|
||||
unp->_endAdr = 0xae;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x82c, 0x018538A9) &&
|
||||
u32eq(mem + 0x831, 0xFD990842) &&
|
||||
u32eq(mem + 0x83e, 0x00FF4CF1) &&
|
||||
u32eq(mem + 0x8a5, 0x50C651C6)) {
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = 0x822;
|
||||
unp->_depAdr = 0x0ff;
|
||||
unp->_fEndBf = 0x39;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x8ea]);
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u16eq(mem + 0x81a, 0x00A0) &&
|
||||
(u32eq(mem + 0x820, 0xFB990837) ||
|
||||
u32eq(mem + 0x824, 0xFB990837)) &&
|
||||
u32eq(mem + 0x83b, 0xFD91FBB1) &&
|
||||
u32eq(mem + 0x8bc, 0xEE00FC99)) {
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = 0x81a;
|
||||
unp->_depAdr = 0x0ff;
|
||||
unp->_fEndAf = 0x39;
|
||||
unp->_endAdC = 0xffff;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x8b3]);
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x812, 0xE67800A0) &&
|
||||
u32eq(mem + 0x816, 0x0823B901) &&
|
||||
u32eq(mem + 0x81a, 0xC800FD99) &&
|
||||
u32eq(mem + 0x81e, 0xFF4CF7D0) &&
|
||||
u32eq(mem + 0x885, 0xFDA6FDB1)) {
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = 0x812;
|
||||
unp->_depAdr = 0x0ff;
|
||||
// $2d is unreliable, Executer uses line number at $0803/4,
|
||||
// which is read at $0039/3a by basic, as end address,
|
||||
// then can set arbitrarily $2d/$ae pointers after unpack.
|
||||
// unp->_fEndAf=0x2d;
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[0x803]);
|
||||
unp->_endAdr++;
|
||||
if (u32eq(mem + 0x87f, 0x4CA65920))
|
||||
mem[0x87f] = 0x2c;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x883]);
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x812, 0xE67800A0) &&
|
||||
u32eq(mem + 0x816, 0x084CB901) &&
|
||||
u32eq(mem + 0x81a, 0xA900FB99) &&
|
||||
u32eq(mem + 0x848, 0x00FF4CE2)) {
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = 0x812;
|
||||
unp->_depAdr = 0x0ff;
|
||||
unp->_fEndAf = 0x2d;
|
||||
unp->_endAdC = 0xffff;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Triad Hack */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x838, 0xB9080099) &&
|
||||
u32eq(mem + 0x83f, 0xD0880816) &&
|
||||
u32eq(mem + 0x8ff, 0xFEE60290) &&
|
||||
u32eq(mem + 0x90f, 0x02903985)) {
|
||||
if (unp->_info->_run == -1) {
|
||||
for (p = 0x80b; p < 0x820; p++) {
|
||||
if ((mem[p] & 0xa0) == 0xa0) {
|
||||
unp->_forced = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
unp->_depAdr = 0x0ff;
|
||||
unp->_fEndAf = 0x2d;
|
||||
unp->_endAdC = 0xffff;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x8ed]);
|
||||
if (unp->_retAdr == 0xa659) {
|
||||
mem[0x8ec] = 0x2c;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x8f0]);
|
||||
}
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
374
engines/glk/scott/unp64/scanners/cruel.cpp
Normal file
374
engines/glk/scott/unp64/scanners/cruel.cpp
Normal file
@@ -0,0 +1,374 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/unp64/unp64.h"
|
||||
#include "glk/scott/unp64/exo_util.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void scnCruel(UnpStr *unp) {
|
||||
byte *mem;
|
||||
int q, p, strtmp = 0;
|
||||
if (unp->_idFlag)
|
||||
return;
|
||||
mem = unp->_mem;
|
||||
if (unp->_depAdr == 0) {
|
||||
if (mem[0x810] == 0xb9 &&
|
||||
((*(unsigned int *)(mem + 0x813) & 0xfffffeff) == 0xC800FA99) &&
|
||||
u16eq(mem + 0x818, 0x4CF7)) {
|
||||
if (mem[0x814] == 0xFA) {
|
||||
p = READ_LE_UINT16(&mem[0x811]); // mem[0x811] | mem[0x812] << 8;
|
||||
if (u32eq(mem + p + 9, 0xC8071C99)) {
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[p + 2]); // mem[p + 2] | mem[p + 3] << 8;
|
||||
unp->_depAdr = 0x100;
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = 0x80b;
|
||||
unp->_fStrAf = 0xfc;
|
||||
q = READ_LE_UINT16(&mem[p + 7]); // mem[p + 7] | mem[p + 8] << 8;
|
||||
if ((mem[q + 0x8e] == 0xc6) && (mem[q + 0x8f] == 0x01) &&
|
||||
(mem[q + 0x93] == 0xe6) && (mem[q + 0x94] == 0x01)) {
|
||||
mem[q + 0x90] = 0x2c;
|
||||
}
|
||||
/* retadr is not always at the same addr, but at least can't
|
||||
be anything < $07e8
|
||||
*/
|
||||
// unp->_retAdr=0x7e8;
|
||||
q = READ_LE_UINT16(&mem[p + 7]); // mem[p + 7] | mem[p + 8] << 8;
|
||||
if (mem[q + 0x3c] == 0x4c) {
|
||||
/* v2.2/dynamix, v2.5/cross, v2.5/crest */
|
||||
strtmp = *(unsigned short int *)(mem + q + 0x3d);
|
||||
} else if (mem[q + 0x4a] == 0x4c) {
|
||||
strtmp = *(unsigned short int *)(mem + q + 0x4b);
|
||||
} else if (mem[q + 0x3f] == 0x4c) {
|
||||
/* v2.2/oneway+scs, also hacked as cruel 2mhz 1.0 */
|
||||
strtmp = *(unsigned short int *)(mem + q + 0x40);
|
||||
} else {
|
||||
/* todo: determine real retadr, for now a default seems ok */
|
||||
strtmp = 0;
|
||||
}
|
||||
if (strtmp) {
|
||||
if (strtmp >= unp->_retAdr) {
|
||||
unp->_retAdr = strtmp;
|
||||
} else { /* now search it... variable code here */
|
||||
strtmp += p - *(unsigned short int *)(mem + 0x814);
|
||||
for (q = strtmp; q < unp->_info->_end; q++) {
|
||||
if ((mem[q] == 0xa9) || (mem[q] == 0x85)) {
|
||||
q++;
|
||||
continue;
|
||||
}
|
||||
if (mem[q] == 0x8d) {
|
||||
q += 2;
|
||||
continue;
|
||||
}
|
||||
if (mem[q] == 0x4c) {
|
||||
unp->_retAdr = *(unsigned short int *)(mem + q + 1);
|
||||
;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (mem[0x814] == 0xFB) {
|
||||
/* not Cruel2 but MSCRUNCH by Marco/Taboo
|
||||
v1.0 works only with some old AR cart (unless patched ;)
|
||||
v1.5 is infact more common
|
||||
*/
|
||||
p = READ_LE_UINT16(&mem[0x811]); // mem[0x811] | mem[0x812] << 8;
|
||||
if (u32eq(mem + p + 7, 0xC8071C99)) {
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[p + 3]); // mem[p + 3] | mem[p + 4] << 8;
|
||||
unp->_depAdr = 0x100;
|
||||
unp->_forced = 0x80b;
|
||||
unp->_fStrAf = 0xfe;
|
||||
if ((mem[p + 0x93] == 0x4c) && (mem[p + 0xa1] == 0x4c)) {
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[p + 0xa2]); // mem[p + 0xa2] | mem[p + 0xa3] << 8;
|
||||
} else if ((mem[p + 0x8c] == 0x4c) && (mem[p + 0x94] == 0x4c)) {
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[p + 0x95]); // mem[p + 0x95] | mem[p + 0x96] << 8;
|
||||
} else if ((mem[p + 0x20] == 0x4c) && (mem[p + 0x28] == 0x4c)) {
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[p + 0x29]); // mem[p + 0x29] | mem[p + 0x2a] << 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr) {
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* MSCRUNCH 1.5 hack by Anubis */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (mem[0x819] == 0x4c) {
|
||||
p = READ_LE_UINT16(&mem[0x81a]); //mem[0x81a] | mem[0x81b] << 8;
|
||||
if ((mem[p] == 0xa9) && (mem[p + 0x0f] == 0x30) &&
|
||||
u32eq(mem + p + 0x13, 0xCA04009D) &&
|
||||
u32eq(mem + p + 0x38, 0x01084C01)) {
|
||||
q = READ_LE_UINT16(&mem[p + 0x1f]); // mem[p + 0x1f] | mem[p + 0x20] << 8;
|
||||
if (u32eq(mem + q + 7, 0xC8071C99)) {
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[q + 3]); // mem[q + 3] | mem[q + 4] << 8;
|
||||
unp->_depAdr = 0x100;
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = 0x819;
|
||||
unp->_fStrAf = 0xfe;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[q + 0xa2]); // mem[q + 0xa2] | mem[q + 0xa3] << 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* fast cruel 4.x */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x80b, 0xE67800A0) &&
|
||||
u32eq(mem + 0x813, 0xC8034099) &&
|
||||
(u32eq(mem + 0x818, 0x03404cF7) ||
|
||||
u32eq(mem + 0x818, 0x03b34cF7) ||
|
||||
u32eq(mem + 0x818, 0x03db4cF7))) {
|
||||
p = READ_LE_UINT16(&mem[0x811]); // mem[0x811] | mem[0x812] << 8;
|
||||
if (u32eq(mem + p, 0xa75801c6)) {
|
||||
p += 0x45;
|
||||
q = READ_LE_UINT16(&mem[p]); // mem[p] | mem[p + 1] << 8;
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[q + 2]); // mem[q + 2] | mem[q + 3] << 8;
|
||||
unp->_depAdr = 0x340;
|
||||
unp->_forced = 0x80b;
|
||||
unp->_fStrAf = 0xfc;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Cruel 2.0 / (BB) packer header */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x837, 0x9D0845BD) &&
|
||||
u32eq(mem + 0x84f, 0xE808039D) &&
|
||||
u32eq(mem + 0x83b, 0xC9E803B7)) {
|
||||
unp->_depAdr = READ_LE_UINT16(&mem[0x843]); // mem[0x843] | mem[0x844] << 8;
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = 0x80d;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x868]); // mem[0x868] | mem[0x869] << 8;
|
||||
unp->_endAdr = unp->_info->_end - 0x90;
|
||||
unp->_strMem = 0x801;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
if (u32eq(mem + 0x845, 0x03E04CF2) &&
|
||||
u32eq(mem + 0x852, 0x9D0893BD) &&
|
||||
u32eq(mem + 0x856, 0xD0E80803)) {
|
||||
unp->_depAdr = READ_LE_UINT16(&mem[0x847]); // mem[0x847] | mem[0x848] << 8;
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = 0x80d;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x869]); // mem[0x869] | mem[0x86a] << 8;
|
||||
unp->_endAdr = unp->_info->_end - 0x90;
|
||||
unp->_strMem = 0x801;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
if (u32eq(mem + 0x841, 0x03B74CF5) &&
|
||||
u32eq(mem + 0x84c, 0x9D089BBD) &&
|
||||
u32eq(mem + 0x850, 0xD0E8080B)) {
|
||||
unp->_depAdr = READ_LE_UINT16(&mem[0x843]); // mem[0x843] | mem[0x844] << 8;
|
||||
if (unp->_info->_run == -1) {
|
||||
unp->_forced = 0x811;
|
||||
} else {
|
||||
mem[0x808] = '5'; /* just to be safe, change sys for next layer */
|
||||
mem[0x809] = '9'; /* this hdr leaves it as sys2065 */
|
||||
}
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x868]); // mem[0x868] | mem[0x869] << 8; /* fixed $080b */
|
||||
unp->_endAdr = unp->_info->_end - 0x90;
|
||||
unp->_strMem = 0x801;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
/* this is a totally useless header, cheers TCOM! */
|
||||
if (u32eq(mem + 0x80b, 0x1BB900A0) &&
|
||||
u32eq(mem + 0x80f, 0x03B79908) &&
|
||||
u32eq(mem + 0x823, 0x039D0840)) {
|
||||
unp->_depAdr = READ_LE_UINT16(&mem[0x819]); // mem[0x819] | mem[0x81a] << 8;
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = 0x80b;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x83e]); // mem[0x83e] | mem[0x83f] << 8;
|
||||
unp->_endAdr = unp->_info->_end - 0x3d;
|
||||
unp->_strMem = 0x801;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Cruel 2.0 / (BB) packer sysless */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eqmasked(mem + 0x80b, 0x0000ffff, 0x000000A0) &&
|
||||
u32eq(mem + 0x817, 0xC800CB99) &&
|
||||
u32eq(mem + 0x81b, 0x004CF7D0) && mem[0x81f] == 1) {
|
||||
p = READ_LE_UINT16(&mem[0x815]); // mem[0x815] | mem[0x816] << 8;
|
||||
p += 0x31;
|
||||
if ((mem[p + 4] == 0xb9) &&
|
||||
u32eq(mem + p + 7, 0xC8072099)) {
|
||||
unp->_forced = 0x80b;
|
||||
unp->_depAdr = 0x100;
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[p]); // mem[p] | mem[p + 1] << 8;
|
||||
unp->_fStrAf = 0xfc;
|
||||
/* patch: some version contain a zp cleaner sub at $01a2 */
|
||||
if (u32eq(mem + p + 0xa6, 0x00A9CBA2) &&
|
||||
u32eq(mem + p + 0xaa, 0xD0E80095)) {
|
||||
mem[p + 0xa6] = 0x60;
|
||||
}
|
||||
/* patch: some version expects $01==#$34 already set from the header */
|
||||
if (u32eq(mem + 0x811, 0xb9eaeaea)) {
|
||||
mem[0x811] = 0xe6;
|
||||
mem[0x812] = 0x01;
|
||||
}
|
||||
q = READ_LE_UINT16(&mem[p + 5]); // mem[p + 5] | mem[p + 6] << 8;
|
||||
unp->_retAdr = 0x7e8;
|
||||
if (mem[q + 0x6c] == 0x4c)
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[q + 0x6d]); // mem[q + 0x6d] | mem[q + 0x6e] << 8;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Cruel 2.1 / STA */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (mem[0x80b] == 0xa0 && u32eq(mem + 0x817, 0xC800CB99) &&
|
||||
u32eq(mem + 0x81b, 0x004CF7D0) && mem[0x81f] == 1) {
|
||||
p = READ_LE_UINT16(&mem[0x815]); // mem[0x815] | mem[0x816] << 8;
|
||||
p += 0x31;
|
||||
if (mem[p + 6] == 0xb9 &&
|
||||
u32eq(mem + p + 9, 0xC8072099)) {
|
||||
unp->_forced = 0x80b;
|
||||
unp->_depAdr = 0x100;
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[p]); // mem[p] | mem[p + 1] << 8;
|
||||
unp->_fStrAf = 0xfc;
|
||||
q = READ_LE_UINT16(&mem[p + 7]); // mem[p + 7] | mem[p + 8] << 8;
|
||||
unp->_retAdr = 0x7e8;
|
||||
if (mem[q + 0x6c] == 0x4c)
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[q + 0x6d]); // mem[q + 0x6d] | mem[q + 0x6e] << 8;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* unknown cruel, jmp $00e9, found in Illusion/Random warez */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (mem[0x810] == 0xb9 && u32eq(mem + 0x813, 0xC800e999) &&
|
||||
u32eq(mem + 0x818, 0x00e94CF7)) {
|
||||
p = READ_LE_UINT16(&mem[0x811]); // mem[0x811] | mem[0x812] << 8;
|
||||
q = p - 0xed;
|
||||
if (u32eq(mem + p, 0x13F01284) &&
|
||||
u32eq(mem + q, 0xA9C8C8C8)) {
|
||||
unp->_depAdr = 0xe9;
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[p + 0x13]); // mem[p + 0x13] | mem[p + 0x14] << 8;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[q + 0x38]); // mem[q + 0x38] | mem[q + 0x39] << 8;
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = 0x80b;
|
||||
unp->_fStrAf = 0xfc;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr == 0) {
|
||||
if (mem[0x810] == 0xb9 && u32eq(mem + 0x813, 0xC800ed99) &&
|
||||
u32eq(mem + 0x818, 0x01004CF7)) {
|
||||
p = READ_LE_UINT16(&mem[0x811]); // mem[0x811] | mem[0x812] << 8;
|
||||
q = p - 0xed;
|
||||
if (u32eq(mem + p, 0x01C60888) &&
|
||||
u32eq(mem + q, 0xA9C8C8C8)) {
|
||||
unp->_depAdr = 0x100;
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[p + 0x0f]); // mem[p + 0x0f] | mem[p + 0x10] << 8;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[q + 0x38]); // mem[q + 0x38] | mem[q + 0x39] << 8;
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = 0x80b;
|
||||
unp->_fStrAf = 0xfc;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* cruel 1.2 / unknown 2059 */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x80b, 0xE67800A0) &&
|
||||
u32eq(mem + 0x80f, 0x0803B901) &&
|
||||
u32eq(mem + 0x813, 0xC800E399) &&
|
||||
u32eq(mem + 0x817, 0x004CF7D0) &&
|
||||
u32eq(mem + 0x90b, 0xC068FEC6)) {
|
||||
unp->_depAdr = 0x100;
|
||||
unp->_forced = 0x80b;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x91c]); // mem[0x91c] | mem[0x91d] << 8;
|
||||
unp->_endAdr = 0x2d;
|
||||
unp->_fStrAf = 0xfc;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
/* this was found in Agile and S451 cracks, Galleon's "Cruel+Search"
|
||||
it's actually the real v1.0
|
||||
*/
|
||||
if (u32eq(mem + 0x80b, 0xE67800A0) &&
|
||||
u32eq(mem + 0x80f, 0x0803B901) &&
|
||||
u32eq(mem + 0x813, 0xC800E399) &&
|
||||
u32eq(mem + 0x8c5, 0x011D4C04) &&
|
||||
u32eq(mem + 0x90b, 0xB1486018)) {
|
||||
unp->_depAdr = 0x100;
|
||||
unp->_forced = 0x80b;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x92d]); // mem[0x92d] | mem[0x92e] << 8;
|
||||
unp->_endAdr = 0x2d;
|
||||
unp->_fStrAf = 0xfc;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
if (u32eq(mem + 0x80b, 0xE67800A0) &&
|
||||
u32eq(mem + 0x80f, 0x0803B901) &&
|
||||
u32eq(mem + 0x813, 0xC800E399) &&
|
||||
u32eq(mem + 0x8b7, 0x011D4C04) &&
|
||||
u32eq(mem + 0x8fc, 0xB1486018)) {
|
||||
unp->_depAdr = 0x100;
|
||||
unp->_forced = 0x80b;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x91e]); // mem[0x91e] | mem[0x91f] << 8;
|
||||
unp->_endAdr = 0x2d;
|
||||
unp->_fStrAf = 0xfc;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* TKC "proggy crueler 2.3" (and 2.5) */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (mem[0x810] == 0xb9 && mem[0x819] == 0xa9 &&
|
||||
u32eq(mem + 0x813, 0xC800fa99) &&
|
||||
u32eq(mem + 0x822, 0x4CAF86AE)) {
|
||||
p = READ_LE_UINT16(&mem[0x811]); // mem[0x811] | mem[0x812] << 8;
|
||||
q = p - 0x100;
|
||||
|
||||
if (u32eq(mem + p + 0x0c, 0x20F7D0C8) &&
|
||||
u32eq(mem + q, 0xA9C8C8C8)) {
|
||||
unp->_depAdr = 0x100;
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[p + 0x02]); // mem[p + 0x02] | mem[p + 0x03] << 8;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[q + 0x3f]); // mem[q + 0x3f] | mem[q + 0x40] << 8;
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = 0x80b;
|
||||
unp->_fStrAf = 0xfc;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
185
engines/glk/scott/unp64/scanners/eca.cpp
Normal file
185
engines/glk/scott/unp64/scanners/eca.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/unp64/unp64.h"
|
||||
#include "glk/scott/unp64/exo_util.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void scnECA(UnpStr *unp) {
|
||||
byte *mem;
|
||||
int q, p;
|
||||
if (unp->_idFlag)
|
||||
return;
|
||||
mem = unp->_mem;
|
||||
if (unp->_depAdr == 0) {
|
||||
// for(p=0x810;p<0x830;p+=0x4)
|
||||
for (p = 0x80d; p < 0x830; p += 0x1) {
|
||||
if (u32eq(mem + p + 0x08, (unsigned int)(0x2D9D0032 + p)) &&
|
||||
u32eq(mem + p + 0x3a, 0x2a2a2a2a) &&
|
||||
u32eq(mem + p + 0x0c, 0xF710CA00)) {
|
||||
if (((*(unsigned int *)(mem + p + 0x00) & 0xf4fff000) == 0x8434A000) &&
|
||||
u32eq(mem + p + 0x04, 0xBD05A201)) {
|
||||
unp->_forced = p + 1;
|
||||
} else if (((*(unsigned int *)(mem + p + 0x00) & 0xffffff00) == 0x04A27800) &&
|
||||
u32eq(mem + p + 0x04, 0xBDE80186)) {
|
||||
unp->_forced = p + 1;
|
||||
} else if (((*(unsigned int *)(mem + p - 0x03) & 0xffffff00) == 0x04A27800) &&
|
||||
u32eq(mem + p + 0x04, 0xBDE80186)) {
|
||||
unp->_forced = p - 2;
|
||||
} else if (u32eq(mem + p - 0x03, 0x8D00a978)) {
|
||||
unp->_forced = p - 2;
|
||||
}
|
||||
}
|
||||
if (!unp->_forced) {
|
||||
if (u32eq(mem + p + 0x3a, 0x2a2a2a2a) &&
|
||||
u32eq(mem + p + 0x02, 0x8534A978) &&
|
||||
mem[p - 3] == 0xa0) {
|
||||
unp->_forced = p - 3;
|
||||
if (mem[p + 0x0d6] == 0x20 && mem[p + 0x0d7] == 0xe0 &&
|
||||
mem[p + 0x0d8] == 0x03 && mem[p + 0x1da] == 0x5b &&
|
||||
mem[p + 0x1e7] == 0x59) {
|
||||
/* antiprotection :D */
|
||||
mem[p + 0x0d6] = 0x4c;
|
||||
mem[p + 0x0d7] = 0xae;
|
||||
mem[p + 0x0d8] = 0xa7;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!unp->_forced) { /* FDT */
|
||||
if (u32eq(mem + p + 0x3a, 0x2a2a2a2a) &&
|
||||
u32eq(mem + p + 0x03, 0x8604A278) &&
|
||||
u32eq(mem + p + 0x0a, 0x2D950842)) {
|
||||
unp->_forced = p + 3;
|
||||
}
|
||||
}
|
||||
if (!unp->_forced) {
|
||||
/* decibel hacks */
|
||||
if (u32eq(mem + p + 0x3a, 0x2a2a2a2a) &&
|
||||
u32eq(mem + p + 0x00, 0x9D085EBD) &&
|
||||
u32eq(mem + p - 0x06, 0x018534A9)) {
|
||||
unp->_forced = p - 0x6;
|
||||
}
|
||||
}
|
||||
if (unp->_forced) {
|
||||
for (q = 0xd6; q < 0xde; q++) {
|
||||
if (mem[p + q] == 0x20) {
|
||||
if (u16eq(mem + p + q + 1, 0xa659) ||
|
||||
u16eq(mem + p + q + 1, 0xff81) ||
|
||||
u16eq(mem + p + q + 1, 0xe3bf) ||
|
||||
u16eq(mem + p + q + 1, 0xe5a0) ||
|
||||
u16eq(mem + p + q + 1, 0xe518)) {
|
||||
mem[p + q] = 0x2c;
|
||||
q += 2;
|
||||
continue;
|
||||
} else {
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[p + q + 1]); // mem[p + q + 1] | mem[p + q + 2] << 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mem[p + q] == 0x4c) {
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[p + q + 1]); // mem[p + q + 1] | mem[p + q + 2] << 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
unp->_depAdr = READ_LE_UINT16(&mem[p + 0x30]); // mem[p + 0x30] | mem[p + 0x31] << 8;
|
||||
// some use $2d, some $ae
|
||||
for (q = 0xed; q < 0x108; q++) {
|
||||
if (u32eq(mem + p + q, 0xA518F7D0)) {
|
||||
unp->_endAdr = mem[p + q + 4];
|
||||
// if(unp->_DebugP)
|
||||
// printf("EndAdr from $%02x\n",unp->_endAdr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
if anything it's unpacked to $d000-efff, it will be copied
|
||||
to $e000-ffff as last action in unpacker before starting.
|
||||
0196 20 DA 01 JSR $01DA ; some have this jsr nopped, reloc doesn't
|
||||
happen 0199 A9 37 LDA #$37 019b 85 01 STA $01 019d 58 CLI
|
||||
019e 20 00 0D JSR $0D00 ; retaddr can be either here or following
|
||||
01a1 4C AE A7 JMP $A7AE
|
||||
01da B9 00 EF LDA $EF00,Y
|
||||
01dd 99 00 FF STA $FF00,Y
|
||||
01e0 C8 INY
|
||||
01e1 D0 F7 BNE $01DA
|
||||
01e3 CE DC 01 DEC $01DC
|
||||
01e6 CE DF 01 DEC $01DF
|
||||
01e9 AD DF 01 LDA $01DF
|
||||
01ec C9 DF CMP #$DF ;<< not fixed, found as lower as $44 for
|
||||
example 01ee D0 EA BNE $01DA 01f0 60 RTS Because of this,
|
||||
$d000-dfff will be a copy of $e000-efff. So if $2d points to >= $d000,
|
||||
SOMETIMES it's better save up to $ffff or: mem[$2d]|(mem[$2e]+$10)<<8
|
||||
Still it's not a rule and I don't know exactly when.
|
||||
17/06/09: Implemented but still experimental, so better check
|
||||
extensively. use -v to know when it does the adjustments. 28/10/09:
|
||||
whoops, was clearing ONLY $d000-dfff =)
|
||||
*/
|
||||
unp->_strMem = READ_LE_UINT16(&mem[p + 0x32]); // mem[p + 0x32] | mem[p + 0x33] << 8;
|
||||
for (q = 0xcd; q < 0xd0; q++) {
|
||||
if (u32eqmasked(mem + p + q, 0xffff00ff, 0xa9010020)) {
|
||||
unp->_ecaFlg = READ_LE_UINT16(&mem[p + q + 1]); // mem[p + q + 1] | mem[p + q + 2] << 8;
|
||||
for (q = 0x110; q < 0x11f; q++) {
|
||||
if (u32eq(mem + p + q, 0x99EF00B9) &&
|
||||
mem[p + q + 0x12] == 0xc9) {
|
||||
unp->_ecaFlg |= (mem[p + q + 0x13] - 0xf) << 24;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* radwar hack has a BRK here, fffe/f used as IRQ/BRK vector */
|
||||
if (mem[0x8e1] == 0) {
|
||||
mem[0x8e1] = 0x6c;
|
||||
mem[0x8e2] = 0xfe;
|
||||
mem[0x8e3] = 0xff;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr) {
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* old packer, many old 1985 warez used this */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x81b, 0x018534A9) &&
|
||||
u32eq(mem + 0x822, 0xAFC600A0) &&
|
||||
u32eq(mem + 0x826, 0xB1082DCE) &&
|
||||
u32eq(mem + 0x85b, 0x2A2A2A2A)) {
|
||||
unp->_forced = 0x81b;
|
||||
unp->_depAdr = 0x100;
|
||||
unp->_strMem = READ_LE_UINT16(&mem[0x853]); // mem[0x853] | mem[0x854] << 8;
|
||||
unp->_endAdr = mem[0x895];
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x885]); // mem[0x885] | mem[0x886] << 8;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
177
engines/glk/scott/unp64/scanners/exomizer.cpp
Normal file
177
engines/glk/scott/unp64/scanners/exomizer.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/unp64/unp64.h"
|
||||
#include "glk/scott/unp64/exo_util.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void scnExomizer(UnpStr *unp) {
|
||||
byte *mem;
|
||||
int q, p;
|
||||
if (unp->_idFlag)
|
||||
return;
|
||||
mem = unp->_mem;
|
||||
/* exomizer 3.x */
|
||||
if (unp->_depAdr == 0) {
|
||||
for (p = unp->_info->_end - 4; p > unp->_info->_start; p--) {
|
||||
if (u32eq(mem + p, 0x100A8069) &&
|
||||
u32eq(mem + p + 4, 0xD0FD060F) &&
|
||||
mem[p - 6] == 0x4c && mem[p - 4] == 0x01) {
|
||||
p -= 5;
|
||||
q = 2;
|
||||
if (mem[p - q] == 0x8a)
|
||||
q++;
|
||||
|
||||
/* low byte of EndAdr, it's a lda $ff00,y */
|
||||
|
||||
if ((mem[p - q - 1] == mem[p - q - 3]) &&
|
||||
(mem[p - q - 2] == mem[p - q])) { /* a0 xx a0 xx -> exomizer 3.0/3.01 */
|
||||
unp->_exoFnd = 0x30;
|
||||
} else { /* d0 c1 a0 xx -> exomizer 3.0.2, force +1 in start/end */
|
||||
unp->_exoFnd = 0x32;
|
||||
}
|
||||
unp->_exoFnd |= (mem[p - q] << 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (unp->_exoFnd) {
|
||||
unp->_depAdr = 0x100 | mem[p];
|
||||
for (; p < unp->_info->_end; p++) {
|
||||
if (u32eq(mem + p, 0x7d010020))
|
||||
break;
|
||||
}
|
||||
for (; p < unp->_info->_end; p++) {
|
||||
if (mem[p] == 0x4c) {
|
||||
unp->_retAdr = 0;
|
||||
if ((unp->_retAdr = READ_LE_UINT16(&mem[p + 1])) >= 0x200) {
|
||||
break;
|
||||
} else { /* it's a jmp $01xx, goto next */
|
||||
p++;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unp->_info->_run == -1) {
|
||||
p = unp->_info->_start;
|
||||
q = p + 0x10;
|
||||
for (; p < q; p++) {
|
||||
if ((mem[p] == 0xba) && (mem[p + 1] == 0xbd)) {
|
||||
unp->_forced = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (q = p - 1; q >= unp->_info->_start; q--) {
|
||||
if (mem[q] == 0xe6)
|
||||
unp->_forced = q;
|
||||
if (mem[q] == 0xa0)
|
||||
unp->_forced = q;
|
||||
if (mem[q] == 0x78)
|
||||
unp->_forced = q;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* exomizer 1.x/2.x */
|
||||
if (unp->_depAdr == 0) {
|
||||
for (p = unp->_info->_end - 4; p > unp->_info->_start; p--) {
|
||||
if (((u32eq(mem + p, 0x4CF7D088) &&
|
||||
u32eq(mem + p - 0x0d, 0xD034C0C8)) ||
|
||||
(u32eq(mem + p, 0x4CA7A438) &&
|
||||
u32eq(mem + p - 0x0c, 0x799FA5AE)) ||
|
||||
(u32eq(mem + p, 0x4CECD08A) &&
|
||||
u32eq(mem + p - 0x13, 0xCECA0EB0)) ||
|
||||
(u32eq(mem + p, 0x4C00A0D3) &&
|
||||
u32eq(mem + p - 0x04, 0xD034C0C8)) ||
|
||||
(u32eq(mem + p, 0x4C00A0D2) &&
|
||||
u32eq(mem + p - 0x04, 0xD034C0C8))) &&
|
||||
mem[p + 5] == 1) {
|
||||
p += 4;
|
||||
unp->_exoFnd = 1;
|
||||
break;
|
||||
} else if (((u32eq(mem + p, 0x8C00A0d2) &&
|
||||
u32eq(mem + p - 0x04, 0xD034C0C8)) ||
|
||||
(u32eq(mem + p, 0x8C00A0d3) &&
|
||||
u32eq(mem + p - 0x04, 0xD034C0C8)) ||
|
||||
(u32eq(mem + p, 0x8C00A0cf) &&
|
||||
u32eq(mem + p - 0x04, 0xD034C0C8))) &&
|
||||
mem[p + 6] == 0x4c && mem[p + 8] == 1) {
|
||||
p += 7;
|
||||
unp->_exoFnd = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (unp->_exoFnd) {
|
||||
unp->_depAdr = 0x100 | mem[p];
|
||||
if (unp->_depAdr >= 0x134 && unp->_depAdr <= 0x14a /*0x13e*/) {
|
||||
for (p = unp->_info->_end - 4; p > unp->_info->_start;
|
||||
p--) { /* 02 04 04 30 20 10 80 00 */
|
||||
if (u32eq(mem + p, 0x30040402))
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// exception for exo v1.x, otherwise add 8 to the counter and
|
||||
// scan backward from here
|
||||
if (unp->_depAdr != 0x143)
|
||||
p += 0x08;
|
||||
else
|
||||
p -= 0xb8;
|
||||
}
|
||||
for (; p > unp->_info->_start; p--) {
|
||||
// incredibly there can be a program starting at $4c00 :P
|
||||
if ((mem[p] == 0x4c) && (mem[p - 1] != 0x4c) && (mem[p - 2] != 0x4c)) {
|
||||
unp->_retAdr = 0;
|
||||
if ((unp->_retAdr = READ_LE_UINT16(&mem[p + 1])) >= 0x200) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unp->_info->_run == -1) {
|
||||
p = unp->_info->_start;
|
||||
q = p + 0x10;
|
||||
for (; p < q; p++) {
|
||||
if ((mem[p] == 0xba) && (mem[p + 1] == 0xbd)) {
|
||||
unp->_forced = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (q = p - 1; q >= unp->_info->_start; q--) {
|
||||
if (mem[q] == 0xe6)
|
||||
unp->_forced = q;
|
||||
if (mem[q] == 0xa0)
|
||||
unp->_forced = q;
|
||||
if (mem[q] == 0x78)
|
||||
unp->_forced = q;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr != 0) {
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
247
engines/glk/scott/unp64/scanners/expert.cpp
Normal file
247
engines/glk/scott/unp64/scanners/expert.cpp
Normal file
@@ -0,0 +1,247 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/unp64/unp64.h"
|
||||
#include "glk/scott/unp64/exo_util.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void scnExpert(UnpStr *unp) {
|
||||
byte *mem;
|
||||
int q, p;
|
||||
if (unp->_idFlag)
|
||||
return;
|
||||
mem = unp->_mem;
|
||||
if (unp->_depAdr == 0) {
|
||||
for (q = 0x81b; q < 0x81d; q++) {
|
||||
if (u32eq(mem + q + 0x00, 0x852FA978) &&
|
||||
u32eq(mem + q + 0x04, 0x8534A900) &&
|
||||
u32eq(mem + q + 0x14, 0x03860286)) {
|
||||
for (p = 0x900; p < 0xfff0; p++) {
|
||||
if (u32eq(mem + p + 1, 0x00084C9A) &&
|
||||
u32eq(mem + p - 4, 0xA2058604)) {
|
||||
if (unp->_info->_run == -1) {
|
||||
unp->_forced = q;
|
||||
unp->_info->_run = q;
|
||||
}
|
||||
q = 0x100 + mem[p] + 1;
|
||||
if (q != 0x100) {
|
||||
unp->_depAdr = q;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr) {
|
||||
unp->_rtiFrc = 1;
|
||||
if (u32eq(mem + 0x835, 0x6E8D48A9)) {
|
||||
p = 0;
|
||||
if (u32eq(mem + 0x92c, 0x4902B100)) {
|
||||
if (!unp->_idOnly) {
|
||||
p = 0x876;
|
||||
mem[p] = 0x00; /* 1st anti hack */
|
||||
p = mem[0x930];
|
||||
}
|
||||
} else if (u32eq(mem + 0x92f, 0x4902B100)) {
|
||||
if (!unp->_idOnly) {
|
||||
p = 0x873;
|
||||
mem[p] = 0xa9; /* 1st anti hack */
|
||||
mem[p + 1] = 0x02;
|
||||
p = mem[0x933];
|
||||
}
|
||||
}
|
||||
if (p && !unp->_idOnly) {
|
||||
p |= (p << 24) | (p << 16) | (p << 8);
|
||||
for (q = 0x980; q < 0xfff0; q++) {
|
||||
if (((mem[q] ^ (p & 0xff)) == 0xac) &&
|
||||
((mem[q + 3] ^ (p & 0xff)) == 0xc0) &&
|
||||
u32eqxored(mem + q + 7, (unsigned int)p, 0xC001F2AC)) {
|
||||
mem[q + 0x06] = (p & 0xff); /* 2nd anti hack */
|
||||
mem[q + 0x0d] = (p & 0xff);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x81b, 0x2FA9D878) &&
|
||||
u32eq(mem + 0x82d, 0x0873BDB0)) {
|
||||
for (p = 0x900; p < 0xfff0; p++) {
|
||||
if (u32eq(mem + p, 0xA2F3D0CA) &&
|
||||
mem[p + 0x05] == 0x4c) {
|
||||
q = READ_LE_UINT16(&mem[p + 0x06]); // mem[p + 0x06] | mem[p + 0x07] << 8;
|
||||
if (q != 0x100) {
|
||||
unp->_depAdr = q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr) {
|
||||
unp->_rtiFrc = 1;
|
||||
unp->_forced = 0x81b;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 2.9 Expert User Club version, found in
|
||||
BloodMoney/HTL & SWIV/Inceria
|
||||
*/
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x81b, 0x8C00A078) &&
|
||||
u32eq(mem + 0x831, 0x05860485) &&
|
||||
u32eq(mem + 0x998, 0x00084C9A)) {
|
||||
p = mem[0x919];
|
||||
q = p << 24 | p << 16 | p << 8 | p;
|
||||
for (p = 0x900; p < 0xfff0; p++) {
|
||||
if (((*(unsigned int *)(mem + p) ^ (unsigned int)q) == 0xA2F3D0CA) &&
|
||||
((mem[p + 0x05] ^ (q & 0xff)) == 0x4c)) {
|
||||
q = (mem[p + 0x06] ^ (q & 0xff)) | (mem[p + 0x07] ^ (q & 0xff)) << 8;
|
||||
if (q != 0x100) {
|
||||
unp->_depAdr = q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr) {
|
||||
unp->_rtiFrc = 1;
|
||||
unp->_forced = 0x81b;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* sys2070 A.S.S. */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x817, 0x00852FA9) &&
|
||||
u32eq(mem + 0x823, 0x05860485) &&
|
||||
u32eq(mem + 0x9a0, 0x00084C9A)) {
|
||||
p = mem[0x923];
|
||||
q = p << 24 | p << 16 | p << 8 | p;
|
||||
for (p = 0x900; p < 0xfff0; p++) {
|
||||
if (((*(unsigned int *)(mem + p) ^ (unsigned int)q) == 0xA2F3D0CA) &&
|
||||
((mem[p + 0x05] ^ (q & 0xff)) == 0x4c)) {
|
||||
q = (mem[p + 0x06] ^ (q & 0xff)) | (mem[p + 0x07] ^ (q & 0xff)) << 8;
|
||||
if (q != 0x100) {
|
||||
unp->_depAdr = q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr) {
|
||||
unp->_rtiFrc = 1;
|
||||
unp->_forced = 0x81b;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x81b, 0x7FA978D8) ||
|
||||
u32eq(mem + 0x81b, 0x7FA9D878) ||
|
||||
u32eq(mem + 0x816, 0x7FA978D8)) {
|
||||
for (p = 0x900; p < 0xfff0; p++) {
|
||||
if (u32eq(mem + p, 0xA2F3D0CA) &&
|
||||
mem[p + 0x05] == 0x4c) {
|
||||
q = READ_LE_UINT16(&mem[p + 0x06]); // mem[p + 0x06] | mem[p + 0x07] << 8;
|
||||
if (q != 0x100) {
|
||||
unp->_depAdr = q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr) {
|
||||
unp->_rtiFrc = 1;
|
||||
if (u32eq(mem + 0x816, 0x7FA978D8)) {
|
||||
q = 0x816;
|
||||
if (!unp->_idOnly) {
|
||||
for (p = 0x900; p < 0xfff0; p++) {
|
||||
if (u32eq(mem + p, 0xE0A9F0A2) &&
|
||||
u32eq(mem + p + 4, 0xE807135D) &&
|
||||
mem[p + 0x8] == 0xd0) {
|
||||
mem[p + 0x1] = 0x00;
|
||||
mem[p + 0x3] = 0x98;
|
||||
memset(mem + p + 4, 0xea, 6);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
q = 0x81b;
|
||||
if (!unp->_idOnly) {
|
||||
for (p = 0x900; p < 0xfff0; p++) {
|
||||
if (u32eq(mem + p, 0xCA08015D) &&
|
||||
u32eq(mem + p + 4, 0xF8D003E0) &&
|
||||
mem[p + 0xa] == 0xd0) {
|
||||
p += 0xa;
|
||||
mem[p] = 0x24;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unp->_info->_run == -1) {
|
||||
unp->_forced = q;
|
||||
unp->_info->_run = q;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr == 0) {
|
||||
q = 0x81b;
|
||||
if (u32eq(mem + q + 0x00, 0x852FA978) &&
|
||||
u32eq(mem + q + 0x04, 0x8534A900) &&
|
||||
u32eq(mem + q + 0x14, 0x03860286) &&
|
||||
u32eq(mem + q + 0x4f, 0xA200594C) &&
|
||||
u32eq(mem + q + 0xad, 0x2000124C)) {
|
||||
unp->_forced = q;
|
||||
unp->_info->_run = q;
|
||||
unp->_depAdr = 0x12;
|
||||
unp->_rtiFrc = 1;
|
||||
}
|
||||
}
|
||||
/* expert 2.11 (sys2074) & unknown sys2061 */
|
||||
if (unp->_depAdr == 0) {
|
||||
for (q = 0x80d; q < 0x820; q++) {
|
||||
if (u32eq(mem + q + 0x00, 0x852FA978) &&
|
||||
u32eq(mem + q + 0x04, 0x8534A900) &&
|
||||
u32eq(mem + q + 0x13, 0x03840284) &&
|
||||
u32eq(mem + q + 0x4f, 0x084C003A) &&
|
||||
u32eq(mem + q + 0xad, 0x00AA2048)) {
|
||||
unp->_forced = q;
|
||||
unp->_info->_run = q;
|
||||
unp->_depAdr = 0x100 + mem[q + 0x17a] + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr != 0) {
|
||||
unp->_rtiFrc = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (unp->_depAdr != 0) {
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
125
engines/glk/scott/unp64/scanners/master_compressor.cpp
Normal file
125
engines/glk/scott/unp64/scanners/master_compressor.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/unp64/unp64.h"
|
||||
#include "glk/scott/unp64/exo_util.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void scnMasterCompressor(UnpStr *unp) {
|
||||
byte *mem;
|
||||
int p;
|
||||
if (unp->_idFlag)
|
||||
return;
|
||||
mem = unp->_mem;
|
||||
if (unp->_depAdr == 0) {
|
||||
for (p = 0x80d; p < 0x880; p++) {
|
||||
if (u32eqmasked(mem + p + 0x005, 0x00ffffff, 0x00BDD2A2) &&
|
||||
u32eq(mem + p + 0x00a, 0xE000F99D) &&
|
||||
u32eq(mem + p + 0x017, 0xCAEDD0CA) &&
|
||||
u32eq(mem + p + 0x031, 0x84C82E86) &&
|
||||
u32eqmasked(mem + p + 0x035, 0x0000ffff, 0x00004C2D) &&
|
||||
u32eq(mem + p + 0x134, 0xDBD0FFE6)) {
|
||||
if (/*mem[p]==0x78&&*/ mem[p + 1] == 0xa9 &&
|
||||
u32eq(mem + p + 0x003, 0xD2A20185)) {
|
||||
unp->_depAdr = READ_LE_UINT16(&mem[p + 0x37]);
|
||||
unp->_forced = p + 1;
|
||||
if (mem[p + 0x12b] == 0x020) // jsr $0400, unuseful fx
|
||||
mem[p + 0x12b] = 0x2c;
|
||||
} else if (u32eq(mem + p, 0xD024E0E8)) {
|
||||
/* HTL version */
|
||||
unp->_depAdr = READ_LE_UINT16(&mem[p + 0x37]);
|
||||
unp->_forced = 0x840;
|
||||
}
|
||||
if (unp->_depAdr) {
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[p + 0x13e]);
|
||||
unp->_endAdr = 0x2d;
|
||||
unp->_fStrBf = unp->_endAdr;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr == 0) {
|
||||
for (p = 0x80d; p < 0x880; p++) {
|
||||
if (u32eqmasked(mem + p + 0x005, 0x00ffffff, 0x00BDD2A2) &&
|
||||
u32eq(mem + p + 0x00a, 0xE000F99D) &&
|
||||
u32eq(mem + p + 0x017, 0xCAEDD0CA) &&
|
||||
u32eq(mem + p + 0x031, 0x84C82E86) &&
|
||||
u32eqmasked(mem + p + 0x035, 0x0000ffff, 0x00004C2D) &&
|
||||
u32eq(mem + p + 0x12d, 0xe2D0FFE6)) {
|
||||
if (mem[p + 1] == 0xa9 &&
|
||||
u32eq(mem + p + 0x003, 0xD2A20185)) {
|
||||
unp->_depAdr = READ_LE_UINT16(&mem[p + 0x37]);
|
||||
unp->_forced = p + 1;
|
||||
}
|
||||
if (unp->_depAdr) {
|
||||
if (mem[p + 0x136] == 0x4c)
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[p + 0x137]);
|
||||
else if (mem[p + 0x13d] == 0x4c)
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[p + 0x13e]);
|
||||
unp->_endAdr = 0x2d;
|
||||
unp->_fStrBf = unp->_endAdr;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr == 0) {
|
||||
p = 0x812;
|
||||
if (u32eq(mem + p + 0x000, 0xE67800A0) &&
|
||||
u32eq(mem + p + 0x004, 0x0841B901) &&
|
||||
u32eq(mem + p + 0x008, 0xB900FA99) &&
|
||||
u32eq(mem + p + 0x00c, 0x34990910)) {
|
||||
unp->_depAdr = 0x100;
|
||||
unp->_forced = p;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x943]); // mem[0x943] | mem[0x944] << 8;
|
||||
unp->_endAdr = 0x2d;
|
||||
unp->_fStrBf = unp->_endAdr;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Fred/Channel4 hack */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x811, 0xA9A98078) &&
|
||||
u32eq(mem + 0x815, 0x85EE8034) &&
|
||||
u32eq(mem + 0x819, 0x802DA201) &&
|
||||
u32eq(mem + 0x882, 0x01004C2D)) {
|
||||
unp->_depAdr = 0x100;
|
||||
unp->_forced = 0x811;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x98b]); // mem[0x98b] | mem[0x98c] << 8;
|
||||
if (unp->_retAdr < 0x800)
|
||||
unp->_rtAFrc = 1;
|
||||
unp->_endAdr = 0x2d;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
82
engines/glk/scott/unp64/scanners/megabyte.cpp
Normal file
82
engines/glk/scott/unp64/scanners/megabyte.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/unp64/unp64.h"
|
||||
#include "glk/scott/unp64/exo_util.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void scnMegabyte(UnpStr *unp) {
|
||||
byte *mem;
|
||||
int p;
|
||||
if (unp->_idFlag)
|
||||
return;
|
||||
mem = unp->_mem;
|
||||
if (unp->_depAdr == 0) {
|
||||
p = 0;
|
||||
if (mem[0x816] == 0x4c)
|
||||
p = READ_LE_UINT16(&mem[0x817]); // mem[0x817] | mem[0x818] << 8;
|
||||
else if (unp->_info->_run == 0x810 && mem[0x814] == 0x4c &&
|
||||
u32eqmasked(mem + 0x810, 0xffff00ff, 0x018500A9))
|
||||
p = READ_LE_UINT16(&mem[0x815]); // mem[0x815] | mem[0x816] << 8;
|
||||
if (p) {
|
||||
if (mem[p + 0] == 0x78 && mem[p + 1] == 0xa2 &&
|
||||
mem[p + 3] == 0xa0 &&
|
||||
u32eq(mem + p + 0x05, 0x15841486) &&
|
||||
u32eq(mem + p + 0x1d, 0x03804CF7)) {
|
||||
unp->_depAdr = 0x380;
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[p + 0x55]); // mem[p + 0x55] | mem[p + 0x56] << 8;
|
||||
unp->_endAdr++;
|
||||
unp->_strMem = 0x801;
|
||||
unp->_retAdr = 0x801; /* usually it just runs */
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr == 0) {
|
||||
p = 0;
|
||||
if (mem[0x81a] == 0x4c &&
|
||||
u32eqmasked(mem + 0x816, 0xffff00ff, 0x018500A9))
|
||||
p = READ_LE_UINT16(&mem[0x81b]); // mem[0x81b] | mem[0x81c] << 8;
|
||||
if (p) {
|
||||
if (mem[p + 0] == 0x78 && mem[p + 1] == 0xa2 &&
|
||||
mem[p + 3] == 0xa0 &&
|
||||
u32eq(mem + p + 0x05, 0x15841486) &&
|
||||
u32eq(mem + p + 0x1d, 0x03844CF7)) {
|
||||
unp->_depAdr = 0x384;
|
||||
unp->_forced = 0x816;
|
||||
unp->_endAdr = READ_LE_UINT16(&mem[p + 0x59]); // mem[p + 0x59] | mem[p + 0x5a] << 8;
|
||||
unp->_endAdr++;
|
||||
unp->_strMem = 0x801;
|
||||
unp->_retAdr = 0x801; /* usually it just runs */
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
194
engines/glk/scott/unp64/scanners/pu_crunch.cpp
Normal file
194
engines/glk/scott/unp64/scanners/pu_crunch.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/unp64/unp64.h"
|
||||
#include "glk/scott/unp64/exo_util.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void scnPuCrunch(UnpStr *unp) {
|
||||
byte *mem;
|
||||
int q, p;
|
||||
if (unp->_idFlag)
|
||||
return;
|
||||
mem = unp->_mem;
|
||||
if (unp->_depAdr == 0) {
|
||||
if (mem[0x80d] == 0x78 &&
|
||||
u32eq(mem + 0x813, 0x34A20185) &&
|
||||
u32eq(mem + 0x817, 0x9D0842BD) &&
|
||||
u32eq(mem + 0x81b, 0xD0CA01FF) &&
|
||||
u32eq(mem + 0x83d, 0x4CEDD088)) {
|
||||
for (p = 0x912; p < 0x938; p++) {
|
||||
if (u32eq(mem + p, 0x2D85FAA5) &&
|
||||
u32eq(mem + p + 4, 0x2E85FBA5)) {
|
||||
unp->_endAdr = 0xfa;
|
||||
unp->_strMem = READ_LE_UINT16(&mem[0x879]); // mem[0x879] | mem[0x87a] << 8;
|
||||
unp->_depAdr = READ_LE_UINT16(&mem[0x841]); // mem[0x841] | mem[0x842] << 8;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[p + 0xa]); // mem[p + 0xa] | mem[p + 0xb] << 8;
|
||||
unp->_forced = 0x80d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (mem[0x80d] == 0x78 &&
|
||||
u32eq(mem + 0x81a, 0x10CA4B95) &&
|
||||
u32eq(mem + 0x81e, 0xBD3BA2F8) &&
|
||||
u32eq(mem + 0x847, 0x4CEDD088)) {
|
||||
for (p = 0x912; p < 0x938; p++) {
|
||||
if (u32eq(mem + p, 0x2D85FAA5) &&
|
||||
u32eq(mem + p + 4, 0x2E85FBA5)) {
|
||||
unp->_endAdr = 0xfa;
|
||||
unp->_strMem = READ_LE_UINT16(&mem[p + 0x88a]); // mem[0x88a] | mem[0x88b] << 8;
|
||||
unp->_depAdr = READ_LE_UINT16(&mem[p + 0x84b]); // mem[0x84b] | mem[0x84c] << 8;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[p + 0xa]); // mem[p + 0xa] | mem[p + 0xb] << 8;
|
||||
unp->_forced = 0x80d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (mem[0x80d] == 0x78 &&
|
||||
u32eq(mem + 0x811, 0x85AAA901) &&
|
||||
u32eq(mem + 0x81d, 0xF69D083C) &&
|
||||
u32eq(mem + 0x861, 0xC501C320) &&
|
||||
u32eq(mem + 0x839, 0x01164CED)) {
|
||||
unp->_endAdr = 0xfa;
|
||||
unp->_strMem = READ_LE_UINT16(&mem[0x840]); // mem[0x840] | mem[0x841] << 8;
|
||||
unp->_depAdr = 0x116;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x8df]); // mem[0x8df] | mem[0x8e0] << 8;
|
||||
unp->_forced = 0x80d;
|
||||
} else if (mem[0x80d] == 0x78 &&
|
||||
u32eq(mem + 0x811, 0x85AAA901) &&
|
||||
u32eq(mem + 0x81d, 0xF69D083C) &&
|
||||
u32eq(mem + 0x861, 0xC501C820) &&
|
||||
u32eq(mem + 0x839, 0x01164CED)) {
|
||||
unp->_endAdr = 0xfa;
|
||||
unp->_strMem = READ_LE_UINT16(&mem[0x840]); // mem[0x840] | mem[0x841] << 8;
|
||||
unp->_depAdr = 0x116;
|
||||
if (mem[0x8de] == 0xa9) {
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x8e1]); // mem[0x8e1] | mem[0x8e2] << 8;
|
||||
if ((unp->_retAdr == 0xa871) && (mem[0x8e0] == 0x20) &&
|
||||
(mem[0x8e3] == 0x4c)) {
|
||||
mem[0x8e0] = 0x2c;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x8e4]); // mem[0x8e4] | mem[0x8e5] << 8;
|
||||
}
|
||||
} else {
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x8df]); // mem[0x8df] | mem[0x8e0] << 8;
|
||||
}
|
||||
unp->_forced = 0x80d;
|
||||
} else {
|
||||
/* unknown old/hacked pucrunch ? */
|
||||
for (p = 0x80d; p < 0x820; p++) {
|
||||
if (mem[p] == 0x78) {
|
||||
q = p;
|
||||
for (; p < 0x824; p++) {
|
||||
if (u32eqmasked(mem + p, 0xf0ffffff, 0xF0BD53A2) &&
|
||||
u32eq(mem + p + 4, 0x01FF9D08) &&
|
||||
u32eq(mem + p + 8, 0xA2F7D0CA)) {
|
||||
unp->_forced = q;
|
||||
q = mem[p + 3] & 0xf; /* can be $f0 or $f2, q&0x0f as offset */
|
||||
p = READ_LE_UINT16(&mem[p + 0xe]); // mem[p + 0xe] | mem[p + 0xf] << 8;
|
||||
if (mem[p - 2] == 0x4c && mem[p + 0xa0 + q] == 0x85) {
|
||||
unp->_depAdr = READ_LE_UINT16(&mem[p - 1]); // mem[p - 1] | mem[p] << 8;
|
||||
unp->_strMem = READ_LE_UINT16(&mem[p + 4]); // mem[p + 4] | mem[p + 5] << 8;
|
||||
unp->_endAdr = 0xfa;
|
||||
p += 0xa2;
|
||||
q = p + 8;
|
||||
for (; p < q; p++) {
|
||||
if (u32eq(mem + p, 0x2D85FAA5) &&
|
||||
mem[p + 9] == 0x4c) {
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[p + 0xa]); // mem[p + 0xa] | mem[p + 0xb] << 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* various old/hacked pucrunch */
|
||||
/* common pattern, variable pos from 0x79 to 0xd1
|
||||
90 ?? C8 20 ?? 0? 85 ?? C9 ?0 90 0B A2 0? 20 ?? 0? 85 ?? 20 ?? 0? A8 20 ??
|
||||
0? AA BD ?? 0? E0 20 90 0? 8A (A2 03) not always 20 ?? 02 A6
|
||||
?? E8 20 F9
|
||||
*/
|
||||
if (unp->_depAdr == 0) {
|
||||
unp->_idFlag = 0;
|
||||
for (q = 0x70; q < 0xff; q++) {
|
||||
if (u32eqmasked(mem + 0x801 + q, 0xFFFF00FF, 0x20C80090) &&
|
||||
u32eqmasked(mem + 0x801 + q + 8, 0xFFFF0FFF,
|
||||
0x0B9000C9) &&
|
||||
u32eqmasked(mem + 0x801 + q + 12, 0x00FFF0FF,
|
||||
0x002000A2) &&
|
||||
u32eqmasked(mem + 0x801 + q + 30, 0xF0FFFFFf,
|
||||
0x009020E0)) {
|
||||
unp->_idFlag = 385;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (unp->_idFlag) {
|
||||
for (p = 0x801 + q + 34; p < 0x9ff; p++) {
|
||||
if (u32eq(mem + p, 0x00F920E8)) {
|
||||
for (; p < 0x9ff; p++) {
|
||||
if (mem[p] == 0x4c) {
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[p + 1]);
|
||||
if (unp->_retAdr > 0x257)
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (p = 0; p < 0x40; p++) {
|
||||
if (unp->_info->_run == -1)
|
||||
if (unp->_forced == 0) {
|
||||
if (mem[0x801 + p] == 0x78) {
|
||||
unp->_forced = 0x801 + p;
|
||||
unp->_info->_run = unp->_forced;
|
||||
}
|
||||
}
|
||||
if (u32eq(mem + 0x801 + p, 0xCA00F69D) &&
|
||||
mem[0x801 + p + 0x1b] == 0x4c) {
|
||||
q = 0x801 + p + 0x1c;
|
||||
unp->_depAdr = READ_LE_UINT16(&mem[q]);
|
||||
q = 0x801 + p - 2;
|
||||
p = READ_LE_UINT16(&mem[q]);
|
||||
if ((mem[p + 3] == 0x8d) && (mem[p + 6] == 0xe6)) {
|
||||
unp->_strMem = READ_LE_UINT16(&mem[p + 4]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
unp->_endAdr = 0xfa; // some hacks DON'T xfer fa/b to 2d/e
|
||||
unp->_idFlag = 1;
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr) {
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
72
engines/glk/scott/unp64/scanners/scanners.cpp
Normal file
72
engines/glk/scott/unp64/scanners/scanners.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/* 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 "glk/scott/unp64/unp64.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void scnECA(UnpStr *unp);
|
||||
void scnExpert(UnpStr *unp);
|
||||
void scnCruel(UnpStr *unp);
|
||||
void scnPuCrunch(UnpStr *unp);
|
||||
void scnByteBoiler(UnpStr *unp);
|
||||
void scnMasterCompressor(UnpStr *unp);
|
||||
void scnTCScrunch(UnpStr *unp);
|
||||
void scnTBCMultiComp(UnpStr *unp);
|
||||
void scnXTC(UnpStr *unp);
|
||||
void scnCCS(UnpStr *unp);
|
||||
void scnMegabyte(UnpStr *unp);
|
||||
void scnSection8(UnpStr *unp);
|
||||
void scnCaution(UnpStr *unp);
|
||||
void scnActionPacker(UnpStr *unp);
|
||||
void scnExomizer(UnpStr *unp);
|
||||
|
||||
Scnptr g_scanFunc[] = {
|
||||
scnECA,
|
||||
scnExpert,
|
||||
scnCruel,
|
||||
scnPuCrunch,
|
||||
scnByteBoiler,
|
||||
scnMasterCompressor,
|
||||
scnTCScrunch,
|
||||
scnTBCMultiComp,
|
||||
scnXTC,
|
||||
scnCCS,
|
||||
scnMegabyte,
|
||||
scnSection8,
|
||||
scnCaution,
|
||||
scnActionPacker,
|
||||
scnExomizer
|
||||
};
|
||||
|
||||
void scanners(UnpStr* unp) {
|
||||
int x, y;
|
||||
y = sizeof(g_scanFunc) / sizeof(*g_scanFunc);
|
||||
for (x = 0; x < y; x++) {
|
||||
(g_scanFunc[x])(unp);
|
||||
if (unp->_idFlag)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
103
engines/glk/scott/unp64/scanners/section8.cpp
Normal file
103
engines/glk/scott/unp64/scanners/section8.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/unp64/unp64.h"
|
||||
#include "glk/scott/unp64/exo_util.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void scnSection8(UnpStr *unp) {
|
||||
byte *mem;
|
||||
int p;
|
||||
if (unp->_idFlag)
|
||||
return;
|
||||
mem = unp->_mem;
|
||||
if (unp->_depAdr == 0) {
|
||||
for (p = 0x810; p <= 0x828; p++) {
|
||||
if (u32eq(mem + p, (unsigned int)(0x00BD00A2 + (((p & 0xff) + 0x11) << 24))) &&
|
||||
u32eq(mem + p + 0x04, 0x01009D08) &&
|
||||
u32eq(mem + p + 0x10, 0x34A97801) &&
|
||||
u32eq(mem + p + 0x6a, 0xB1017820) &&
|
||||
u32eq(mem + p + 0x78, 0x017F20AE)) {
|
||||
unp->_depAdr = 0x100;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr) {
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = p;
|
||||
unp->_strMem = mem[p + 0x47] | mem[p + 0x4b] << 8;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[p + 0x87]); // mem[p + 0x87] | mem[p + 0x88] << 8;
|
||||
if (unp->_retAdr == 0xf7) {
|
||||
unp->_retAdr = 0xa7ae;
|
||||
mem[p + 0x87] = 0xae;
|
||||
mem[p + 0x88] = 0xa7;
|
||||
}
|
||||
unp->_endAdr = 0xae;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Crackman variant? */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x827, 0x38BD00A2) &&
|
||||
u32eq(mem + 0x82b, 0x01009D08) &&
|
||||
u32eq(mem + 0x837, 0x34A97801) &&
|
||||
u32eq(mem + 0x891, 0xB1018420) &&
|
||||
u32eq(mem + 0x89f, 0x018b20AE)) {
|
||||
unp->_depAdr = 0x100;
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = 0x827;
|
||||
unp->_strMem = mem[0x86e] | mem[0x872] << 8;
|
||||
if (u16eq(mem + 0x8b7, 0xff5b)) {
|
||||
mem[0x8b6] = 0x2c;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x8ba]); // mem[0x8ba] | mem[0x8bb] << 8;
|
||||
} else {
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x8b7]); // mem[0x8b7] | mem[0x8b8] << 8;
|
||||
}
|
||||
unp->_endAdr = 0xae;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* PET||SLAN variant? */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x812, 0x20BD00A2) &&
|
||||
u32eq(mem + 0x816, 0x033c9D08) &&
|
||||
u32eq(mem + 0x863, 0xB103B420) &&
|
||||
u32eq(mem + 0x86c, 0x03BB20AE)) {
|
||||
unp->_depAdr = 0x33c;
|
||||
if (unp->_info->_run == -1)
|
||||
unp->_forced = 0x812;
|
||||
unp->_strMem = mem[0x856] | mem[0x85a] << 8;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x896]); // mem[0x896] | mem[0x897] << 8;
|
||||
unp->_endAdr = 0xae;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
166
engines/glk/scott/unp64/scanners/tbc_multicomp.cpp
Normal file
166
engines/glk/scott/unp64/scanners/tbc_multicomp.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/unp64/unp64.h"
|
||||
#include "glk/scott/unp64/exo_util.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void scnTBCMultiComp(UnpStr *unp) {
|
||||
byte *mem;
|
||||
int p = 0, q = 0, strtmp;
|
||||
if (unp->_idFlag)
|
||||
return;
|
||||
mem = unp->_mem;
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eqmasked(mem + 0x82c, 0xfffffffd, 0x9ACA0184) &&
|
||||
u32eq(mem + 0x830, 0xA001004C) &&
|
||||
u32eq(mem + 0x834, 0x84FD8400) &&
|
||||
u32eq(mem + 0x8a2, 0x01494C01)) {
|
||||
/*normal 2080*/
|
||||
if (mem[0x84a] == 0x81) {
|
||||
if (u32eq(mem + 0x820, 0x32BDE9A2)) {
|
||||
unp->_forced = 0x820;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x8b2]); // mem[0x8b2] | mem[0x8b3] << 8;
|
||||
if (unp->_retAdr == 0x1e1) {
|
||||
if (u32eq(mem + 0x916, 0x4CA87120)) {
|
||||
p = *(unsigned short int *)(mem + 0x91a);
|
||||
if (p == 0xa7ae) {
|
||||
unp->_retAdr = p;
|
||||
mem[0x8b2] = 0xae;
|
||||
mem[0x8b3] = 0xa7;
|
||||
} else {
|
||||
mem[0x916] = 0x2c;
|
||||
unp->_retAdr = p;
|
||||
}
|
||||
} else if ((mem[0x916] == 0x4C) || (mem[0x916] == 0x20)) {
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x917]); // mem[0x917] | mem[0x918] << 8;
|
||||
} else if (mem[0x919] == 0x4c) {
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x91a]); // mem[0x91a] | mem[0x91b] << 8;
|
||||
}
|
||||
}
|
||||
if ((unp->_retAdr == 0) && (mem[0x8b1] == 0)) {
|
||||
unp->_retAdr = 0xa7ae;
|
||||
mem[0x8b1] = 0x4c;
|
||||
mem[0x8b2] = 0xae;
|
||||
mem[0x8b3] = 0xa7;
|
||||
}
|
||||
p = 0x8eb;
|
||||
}
|
||||
}
|
||||
/*firelord 2076*/
|
||||
else if (mem[0x84a] == 0x7b) {
|
||||
if (u32eq(mem + 0x81d, 0x32BDE9A2)) {
|
||||
unp->_forced = 0x81d;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x8ac]); // mem[0x8ac] | mem[0x8ad] << 8;
|
||||
p = 0x8eb;
|
||||
}
|
||||
}
|
||||
if (unp->_forced) {
|
||||
unp->_depAdr = 0x100;
|
||||
unp->_strMem = READ_LE_UINT16(&mem[p + 1]); // mem[p + 1] | mem[p + 2] << 8;
|
||||
q = p;
|
||||
q += mem[p];
|
||||
unp->_endAdr = 0;
|
||||
for (; q > p; q -= 4) {
|
||||
strtmp = READ_LE_UINT16(&mem[q - 1]); //(mem[q - 1] | mem[q] << 8);
|
||||
if (strtmp == 0)
|
||||
strtmp = 0x10000;
|
||||
if (strtmp > unp->_endAdr)
|
||||
unp->_endAdr = strtmp;
|
||||
}
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* TBC Multicompactor ? very similar but larger code */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x822, 0x9D083DBD) &&
|
||||
u32eq(mem + 0x826, 0xD0CA0333) &&
|
||||
u32eq(mem + 0x832, 0xF7D0CA00) &&
|
||||
u32eq(mem + 0x836, 0xCA018678) &&
|
||||
u32eq(mem + 0x946, 0xADC5AFA5)) {
|
||||
if (unp->_info->_run == -1) {
|
||||
for (p = 0x81e; p < 0x821; p++) {
|
||||
if (mem[p] == 0xa2) {
|
||||
unp->_forced = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
unp->_depAdr = 0x334;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x92a]); // mem[0x92a] | mem[0x92b] << 8;
|
||||
p = 0x94d;
|
||||
unp->_strMem = READ_LE_UINT16(&mem[p + 1]); // mem[p + 1] | mem[p + 2] << 8;
|
||||
q = p;
|
||||
q += mem[p];
|
||||
unp->_endAdr = 0;
|
||||
for (; q > p; q -= 4) {
|
||||
strtmp = READ_LE_UINT16(&mem[q - 1]); //(mem[q - 1] | mem[q] << 8);
|
||||
if (strtmp == 0)
|
||||
strtmp = 0x10000;
|
||||
if (strtmp > unp->_endAdr)
|
||||
unp->_endAdr = strtmp;
|
||||
}
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/*"AUTOMATIC BREAK SYSTEM" found in Manowar Cracks*/
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x835, 0x9D0845BD) &&
|
||||
u32eq(mem + 0x839, 0xD0CA00ff) &&
|
||||
u32eq(mem + 0x83e, 0xCA018678) &&
|
||||
u32eq(mem + 0x8e1, 0xADC5AFA5)) {
|
||||
if (unp->_info->_run == -1) {
|
||||
for (p = 0x830; p < 0x834; p++) {
|
||||
if (mem[p] == 0xa2) {
|
||||
unp->_forced = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
unp->_depAdr = 0x100;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x8c5]); // mem[0x8c5] | mem[0x8c6] << 8;
|
||||
p = 0x8fe;
|
||||
unp->_strMem = READ_LE_UINT16(&mem[p + 1]); // mem[p + 1] | mem[p + 2] << 8;
|
||||
q = p;
|
||||
q += mem[p];
|
||||
unp->_endAdr = 0;
|
||||
for (; q > p; q -= 4) {
|
||||
strtmp = READ_LE_UINT16(&mem[q - 1]); //(mem[q - 1] | mem[q] << 8);
|
||||
if (strtmp == 0)
|
||||
strtmp = 0x10000;
|
||||
if (strtmp > unp->_endAdr)
|
||||
unp->_endAdr = strtmp;
|
||||
}
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
78
engines/glk/scott/unp64/scanners/tcs_crunch.cpp
Normal file
78
engines/glk/scott/unp64/scanners/tcs_crunch.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/unp64/unp64.h"
|
||||
#include "glk/scott/unp64/exo_util.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void scnTCScrunch(UnpStr *unp) {
|
||||
byte *mem;
|
||||
int q, p;
|
||||
if (unp->_idFlag)
|
||||
return;
|
||||
mem = unp->_mem;
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x819, 0x018536A9) && mem[0x81d] == 0x4c) {
|
||||
p = READ_LE_UINT16(&mem[0x81e]); // mem[0x81e] | mem[0x81f] << 8;
|
||||
if (mem[p] == 0xa2 && mem[p + 2] == 0xbd &&
|
||||
u32eq(mem + p + 0x05, 0xE801109D) &&
|
||||
(u32eq(mem + p + 0x38, 0x01524CFB) ||
|
||||
(u32eq(mem + p + 0x38, 0x8DE1A9FB) &&
|
||||
u32eq(mem + p + 0x3c, 0x524C0328)))) {
|
||||
unp->_depAdr = 0x334;
|
||||
unp->_forced = 0x819;
|
||||
unp->_endAdr = 0x2d;
|
||||
}
|
||||
} else if (u32eq(mem + 0x819, 0x018534A9) && mem[0x81d] == 0x4c) {
|
||||
p = READ_LE_UINT16(&mem[0x81e]); // mem[0x81e] | mem[0x81f] << 8;
|
||||
if (mem[p] == 0xa2 && mem[p + 2] == 0xbd &&
|
||||
u32eq(mem + p + 0x05, 0xE801109D) &&
|
||||
u32eq(mem + p + 0x38, 0x01304CFB)) {
|
||||
unp->_depAdr = 0x334;
|
||||
unp->_forced = 0x818;
|
||||
if (mem[unp->_forced] != 0x78)
|
||||
unp->_forced++;
|
||||
unp->_endAdr = 0x2d;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[p + 0xd9]); // mem[p + 0xd9] | mem[p + 0xda] << 8;
|
||||
p += 0xc8;
|
||||
q = p + 6;
|
||||
for (; p < q; p += 3) {
|
||||
if (mem[p] == 0x20 &&
|
||||
u16gteq(mem + p + 1, 0xa000) &&
|
||||
u16lteq(mem + p + 1, 0xbfff)) {
|
||||
mem[p] = 0x2c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr) {
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
162
engines/glk/scott/unp64/scanners/xtc.cpp
Normal file
162
engines/glk/scott/unp64/scanners/xtc.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/unp64/unp64.h"
|
||||
#include "glk/scott/unp64/exo_util.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void scnXTC(UnpStr *unp) {
|
||||
byte *mem;
|
||||
int q = 0, p;
|
||||
if (unp->_idFlag)
|
||||
return;
|
||||
mem = unp->_mem;
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u16eq(mem + 0x80d, 0xE678) &&
|
||||
u32eq(mem + 0x811, 0x1BCE0818) &&
|
||||
u32eq(mem + 0x819, 0xC8000099) &&
|
||||
u32eq(mem + 0x82c, 0x4CF7D0CA) &&
|
||||
mem[0x85c] == 0x99) {
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x872]); // mem[0x872] | mem[0x873] << 8;
|
||||
unp->_depAdr = 0x100;
|
||||
unp->_forced = 0x80d; /* the ldy #$00 can be missing, skipped */
|
||||
unp->_fEndAf = 0x121;
|
||||
unp->_endAdC = 0xffff | EA_USE_Y;
|
||||
unp->_strMem = READ_LE_UINT16(&mem[0x85d]); // mem[0x85d] | mem[0x85e] << 8;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* XTC packer 1.0 & 2.2/2.4 */
|
||||
if (unp->_depAdr == 0) {
|
||||
for (p = 0x801; p < 0x80c; p += 0x0a) {
|
||||
if (u16eq(mem + p + 0x02, 0xE678) &&
|
||||
u32eq(mem + p + 0x07, (unsigned int)(0xce08 | ((p + 0x10) << 16))) &&
|
||||
u32eq(mem + p + 0x0e, 0xC8000099) &&
|
||||
u32eq(mem + p + 0x23, 0x4CF7D0CA)) {
|
||||
/* has variable codebytes so addresses varies */
|
||||
for (q = p + 0x37; q < p + 0x60; q += 4) {
|
||||
if (mem[q] == 0xc9)
|
||||
continue;
|
||||
if (mem[q] == 0x99) {
|
||||
unp->_depAdr = 0x100;
|
||||
break;
|
||||
}
|
||||
break; /* unexpected byte, get out */
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr) {
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[q + 0x16]); // mem[q + 0x16] | mem[q + 0x17] << 8;
|
||||
if (u16noteq(mem + p, 0x00a0))
|
||||
unp->_forced = p + 2; /* the ldy #$00 can be missing, skipped */
|
||||
else
|
||||
unp->_forced = p;
|
||||
|
||||
unp->_fEndAf = READ_LE_UINT16(&mem[q + 0x7]); // mem[q + 0x7] | mem[q + 0x8] << 8;
|
||||
unp->_fEndAf--;
|
||||
unp->_endAdC = 0xffff | EA_USE_Y;
|
||||
unp->_strMem = READ_LE_UINT16(&mem[q + 1]); // mem[q + 1] | mem[q + 2] << 8;
|
||||
if (u32eq(mem + q + 0x1f, 0xDDD00285)) {
|
||||
} else if (u32eq(mem + q + 0x1f, 0xF620DFD0)) {
|
||||
/* rockstar's 2.2+ & shade/light's 2.4 are all the same */
|
||||
} else { /* actually found to be Visiomizer 6.2/Zagon */
|
||||
unp->_depAdr = READ_LE_UINT16(&mem[p + 0x27]); // mem[p + 0x27] | mem[p + 0x28] << 8;
|
||||
}
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* XTC 2.3 / 6codezipper */
|
||||
if (unp->_depAdr == 0) {
|
||||
if (u32eq(mem + 0x803, 0xB9018478) &&
|
||||
u32eq(mem + 0x80b, 0xF7D0C8FF) &&
|
||||
u32eq(mem + 0x81b, 0x00FC9D08) &&
|
||||
u32eq(mem + 0x85b, 0xD0D0FFE4)) {
|
||||
unp->_depAdr = READ_LE_UINT16(&mem[0x823]); // mem[0x823] | mem[0x824] << 8;
|
||||
unp->_forced = 0x803;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x865]); // mem[0x865] | mem[0x866] << 8;
|
||||
unp->_strMem = READ_LE_UINT16(&mem[0x850]); // mem[0x850] | mem[0x851] << 8;
|
||||
unp->_endAdC = 0xffff | EA_USE_Y;
|
||||
unp->_fEndAf = 0x128;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* XTC 2.3 / G*P, probably by Rockstar */
|
||||
if (unp->_depAdr == 0) {
|
||||
if ((u32eq(mem + 0x803, 0xB901e678) ||
|
||||
u32eq(mem + 0x803, 0xB9018478)) &&
|
||||
u32eq(mem + 0x80b, 0xF7D0C8FF) &&
|
||||
u32eq(mem + 0x81b, 0x00F59D08) &&
|
||||
u32eq(mem + 0x85b, 0xD0D0F8E4)) {
|
||||
unp->_depAdr = READ_LE_UINT16(&mem[0x823]); // mem[0x823] | mem[0x824] << 8;
|
||||
unp->_forced = 0x803;
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[0x865]); // mem[0x865] | mem[0x866] << 8;
|
||||
unp->_strMem = READ_LE_UINT16(&mem[0x850]); // mem[0x850] | mem[0x851] << 8;
|
||||
unp->_endAdC = 0xffff | EA_USE_Y;
|
||||
unp->_fEndAf = 0x121;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* XTC packer 2.x? found in G*P/NEI/Armageddon warez
|
||||
just some different byte on copy loop, else is equal to 2.3
|
||||
*/
|
||||
if (unp->_depAdr == 0) {
|
||||
for (p = 0x801; p < 0x80c; p += 0x0a) {
|
||||
if (u32eqmasked(mem + p + 0x00, 0xffff0000, 0xE6780000) &&
|
||||
u32eqmasked(mem + p + 0x05, 0xffff00ff, 0xB90800CE) &&
|
||||
u32eq(mem + p + 0x0b, 0xC8000099) &&
|
||||
u32eq(mem + p + 0x1e, 0x4CF7D0CA)) {
|
||||
/* has variable codebytes so addresses varies */
|
||||
for (q = p + 0x36; q < p + 0x60; q += 4) {
|
||||
if (mem[q] == 0xc9)
|
||||
continue;
|
||||
if (mem[q] == 0x99) {
|
||||
unp->_depAdr = 0x100;
|
||||
break;
|
||||
}
|
||||
break; /* unexpected byte, get out */
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (unp->_depAdr) {
|
||||
unp->_retAdr = READ_LE_UINT16(&mem[q + 0x16]); // mem[q + 0x16] | mem[q + 0x17] << 8;
|
||||
unp->_forced = p + 2;
|
||||
unp->_fEndAf = READ_LE_UINT16(&mem[q + 0x7]); // mem[q + 0x7] | mem[q + 0x8] << 8;
|
||||
unp->_fEndAf--;
|
||||
unp->_endAdC = 0xffff | EA_USE_Y;
|
||||
unp->_strMem = READ_LE_UINT16(&mem[q + 1]); // mem[q + 1] | mem[q + 2] << 8;
|
||||
unp->_idFlag = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
735
engines/glk/scott/unp64/unp64.cpp
Normal file
735
engines/glk/scott/unp64/unp64.cpp
Normal file
@@ -0,0 +1,735 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// This is a cut-down version of UNP64 with only the bare minimum
|
||||
// needed to decompress a number of Scott Adams Commodore 64 games
|
||||
// for the ScottFree interpreter.
|
||||
|
||||
/*
|
||||
UNP64 - generic Commodore 64 prg unpacker
|
||||
(C) 2008-2018 iAN CooG/HVSC Crew^C64Intros
|
||||
original source and idea: testrun.c, taken from exo20b7
|
||||
|
||||
Follows original disclaimer
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002 - 2023 Magnus Lind.
|
||||
*
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/scott/globals.h"
|
||||
#include "glk/scott/types.h"
|
||||
#include "glk/scott/unp64/6502_emu.h"
|
||||
#include "glk/scott/unp64/exo_util.h"
|
||||
#include "glk/scott/unp64/unp64.h"
|
||||
|
||||
#include "common/util.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
void reinitUnp(void) {
|
||||
_G(_unp)._idFlag = 0;
|
||||
_G(_unp)._forced = 0;
|
||||
_G(_unp)._strMem = 0x800;
|
||||
_G(_unp)._retAdr = 0x800;
|
||||
_G(_unp)._depAdr = 0;
|
||||
_G(_unp)._endAdr = 0x10000;
|
||||
_G(_unp)._rtAFrc = 0;
|
||||
_G(_unp)._wrMemF = 0;
|
||||
_G(_unp)._lfMemF = 0;
|
||||
_G(_unp)._exoFnd = 0;
|
||||
_G(_unp)._ecaFlg = 0;
|
||||
_G(_unp)._fEndBf = 0;
|
||||
_G(_unp)._fEndAf = 0;
|
||||
_G(_unp)._fStrAf = 0;
|
||||
_G(_unp)._fStrBf = 0;
|
||||
_G(_unp)._mon1st = 0;
|
||||
}
|
||||
|
||||
int isBasicRun1(int pc) {
|
||||
if (pc == 0xa7ae || pc == 0xa7ea || pc == 0xa7b1 || pc == 0xa474 || pc == 0xa533 || pc == 0xa871 || pc == 0xa888 || pc == 0xa8bc)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int isBasicRun2(int pc) {
|
||||
if (isBasicRun1(pc) || ((pc >= 0xA57C) && (pc <= 0xA659)) || pc == 0xa660 || pc == 0xa68e)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unp64(byte *compressed, size_t length, byte *destinationBuffer, size_t *finalLength, const char *switches) {
|
||||
|
||||
char settings[4][64];
|
||||
int numSettings = 0;
|
||||
|
||||
if (switches != NULL) {
|
||||
char string[100];
|
||||
size_t string_length = strlen(switches);
|
||||
if (string_length > 0 && string_length < 100) {
|
||||
snprintf(string, sizeof string, "%s", switches);
|
||||
char *setting = strtok(string, " ");
|
||||
while (setting != NULL && numSettings < 4) {
|
||||
snprintf(settings[numSettings], sizeof settings[numSettings], "%s", setting);
|
||||
numSettings++;
|
||||
setting = strtok(NULL, " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CpuCtx r[1];
|
||||
LoadInfo info[1];
|
||||
char name[260] = {0}, forcedname[260] = {0};
|
||||
byte mem[65536] = {0}, oldmem[65536] = {0};
|
||||
byte vector[0x20] = {0x31, 0xEA, 0x66, 0xFE, 0x47, 0xFE, 0x4A, 0xF3,
|
||||
0x91, 0xF2, 0x0E, 0xF2, 0x50, 0xF2, 0x33, 0xF3,
|
||||
0x57, 0xF1, 0xCA, 0xF1, 0xED, 0xF6, 0x3E, 0xF1,
|
||||
0x2F, 0xF3, 0x66, 0xFE, 0xA5, 0xF4, 0xED, 0xF5};
|
||||
|
||||
byte stack[0x100] = {0x33, 0x38, 0x39, 0x31, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7D,
|
||||
0xEA, 0x00, 0x00, 0x82, 0x22, 0x0E, 0xBC, 0x81, 0x64, 0xB8,
|
||||
0x0C, 0xBD, 0xBA, 0xB7, 0xBC, 0x03, 0x00, 0x46, 0xE1, 0xE9,
|
||||
0xA7, 0xA7, 0x79, 0xA6, 0x9C, 0xE3};
|
||||
|
||||
int iterMax = ITERMAX;
|
||||
int p;
|
||||
|
||||
memset(&_G(_unp), 0, sizeof(_G(_unp)));
|
||||
reinitUnp();
|
||||
_G(_unp)._fStack = 1;
|
||||
_G(_unp)._mem = mem;
|
||||
_G(_unp)._r = r;
|
||||
_G(_unp)._name = name;
|
||||
_G(_unp)._info = info;
|
||||
|
||||
p = 0;
|
||||
|
||||
if (numSettings != 0) {
|
||||
if (settings[0][0] == '-' && _G(_parsePar) && settings[0][1] == 'f') {
|
||||
strToInt(settings[p] + 2, (int *)&_G(_unp)._filler);
|
||||
if (_G(_unp)._filler) {
|
||||
memset(mem + (_G(_unp)._filler >> 16), _G(_unp)._filler & 0xff, 0x10000 - (_G(_unp)._filler >> 16));
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
looprecurse:
|
||||
info->_basicTxtStart = 0x801;
|
||||
loadData(compressed, length, mem, info);
|
||||
/* no start address from load */
|
||||
if (info->_run == -1) {
|
||||
/* look for sys line */
|
||||
info->_run = findSys(mem + info->_basicTxtStart, 0x9e);
|
||||
}
|
||||
|
||||
scanners(&_G(_unp));
|
||||
if (_G(_unp)._idFlag == 2)
|
||||
return 0;
|
||||
|
||||
if ((_G(_unp)._recurs == 0) && (numSettings > 0)) {
|
||||
while (p < numSettings) {
|
||||
if (settings[p][0] == '-') {
|
||||
switch (settings[p][1]) {
|
||||
case '-':
|
||||
p = numSettings;
|
||||
break;
|
||||
case 'e':
|
||||
strToInt(settings[p] + 2, &_G(_unp)._forced);
|
||||
_G(_unp)._forced &= 0xffff;
|
||||
if (_G(_unp)._forced < 0x1)
|
||||
_G(_unp)._forced = 0;
|
||||
break;
|
||||
case 'a':
|
||||
_G(_unp)._strMem = 2;
|
||||
_G(_unp)._endAdr = 0x10001;
|
||||
_G(_unp)._fEndAf = 0;
|
||||
_G(_unp)._fStrAf = 0;
|
||||
_G(_unp)._strAdC = 0;
|
||||
_G(_unp)._endAdC = 0;
|
||||
_G(_unp)._monEnd = 0;
|
||||
_G(_unp)._monStr = 0;
|
||||
break;
|
||||
case 'r':
|
||||
strToInt(settings[p] + 2, &_G(_unp)._retAdr);
|
||||
_G(_unp)._retAdr &= 0xffff;
|
||||
break;
|
||||
case 'R':
|
||||
strToInt(settings[p] + 2, &_G(_unp)._retAdr);
|
||||
_G(_unp)._retAdr &= 0xffff;
|
||||
_G(_unp)._rtAFrc = 1;
|
||||
break;
|
||||
case 'd':
|
||||
strToInt(settings[p] + 2, &_G(_unp)._depAdr);
|
||||
_G(_unp)._depAdr &= 0xffff;
|
||||
break;
|
||||
case 't':
|
||||
strToInt(settings[p] + 2, &_G(_unp)._endAdr);
|
||||
_G(_unp)._endAdr &= 0xffff;
|
||||
if (_G(_unp)._endAdr >= 0x100)
|
||||
_G(_unp)._endAdr++;
|
||||
break;
|
||||
case 'u':
|
||||
_G(_unp)._wrMemF = 1;
|
||||
break;
|
||||
case 'l':
|
||||
_G(_unp)._lfMemF = info->_end;
|
||||
break;
|
||||
case 's':
|
||||
_G(_unp)._fStack = 0;
|
||||
break;
|
||||
case 'x':
|
||||
break;
|
||||
case 'B':
|
||||
//copyRoms[0][1] = 1;
|
||||
break;
|
||||
case 'K':
|
||||
//copyRoms[1][1] = 1;
|
||||
break;
|
||||
case 'c':
|
||||
_G(_unp)._recurs++;
|
||||
break;
|
||||
case 'm': // keep undocumented for now
|
||||
strToInt(settings[p] + 2, &iterMax);
|
||||
}
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
if (_G(_unp)._idOnly) {
|
||||
if (_G(_unp)._depAdr == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_G(_unp)._wrMemF | _G(_unp)._lfMemF) {
|
||||
memcpy(oldmem, mem, sizeof(oldmem));
|
||||
}
|
||||
|
||||
if (_G(_unp)._forced) {
|
||||
info->_run = _G(_unp)._forced;
|
||||
}
|
||||
|
||||
if (info->_run == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_G(_unp)._strMem > _G(_unp)._retAdr) {
|
||||
_G(_unp)._strMem = _G(_unp)._retAdr;
|
||||
}
|
||||
|
||||
mem[0] = 0x60;
|
||||
r->_cycles = 0;
|
||||
mem[1] = 0x37;
|
||||
|
||||
if (((_G(_unp)._forced >= 0xa000) && (_G(_unp)._forced < 0xc000)) || (_G(_unp)._forced >= 0xd000))
|
||||
mem[1] = 0x38;
|
||||
|
||||
/* some packers rely on basic pointers already set */
|
||||
mem[0x2b] = info->_basicTxtStart & 0xff;
|
||||
mem[0x2c] = info->_basicTxtStart >> 8;
|
||||
|
||||
if (info->_basicVarStart == -1) {
|
||||
mem[0x2d] = info->_end & 0xff;
|
||||
mem[0x2e] = info->_end >> 8;
|
||||
} else {
|
||||
mem[0x2d] = info->_basicVarStart & 0xff;
|
||||
mem[0x2e] = info->_basicVarStart >> 8;
|
||||
}
|
||||
|
||||
mem[0x2f] = mem[0x2d];
|
||||
mem[0x30] = mem[0x2e];
|
||||
mem[0x31] = mem[0x2d];
|
||||
mem[0x32] = mem[0x2e];
|
||||
mem[0xae] = info->_end & 0xff;
|
||||
mem[0xaf] = info->_end >> 8;
|
||||
|
||||
/* CCS unpacker requires $39/$3a (current basic line number) set */
|
||||
mem[0x39] = mem[0x803];
|
||||
mem[0x3a] = mem[0x804];
|
||||
mem[0x52] = 0;
|
||||
mem[0x53] = 3;
|
||||
|
||||
if (_G(_unp)._fStack) {
|
||||
memcpy(mem + 0x100, stack,
|
||||
sizeof(stack)); /* stack as found on clean start */
|
||||
r->_sp = 0xf6; /* sys from immediate mode leaves $f6 in stackptr */
|
||||
} else {
|
||||
r->_sp = 0xff;
|
||||
}
|
||||
|
||||
if (info->_start > (long int)(0x314 + sizeof(vector))) {
|
||||
/* some packers use values in irq pointers to decrypt themselves */
|
||||
memcpy(mem + 0x314, vector, sizeof(vector));
|
||||
}
|
||||
|
||||
mem[0x200] = 0x8a;
|
||||
r->_mem = mem;
|
||||
r->_pc = info->_run;
|
||||
r->_flags = 0x20;
|
||||
r->_a = 0;
|
||||
r->_y = 0;
|
||||
|
||||
if (info->_run > 0x351) /* temporary for XIP */ {
|
||||
r->_x = 0;
|
||||
}
|
||||
|
||||
_G(_iter) = 0;
|
||||
while ((_G(_unp)._depAdr ? r->_pc != _G(_unp)._depAdr : r->_pc >= _G(_unp)._retAdr)) {
|
||||
if ((((mem[1] & 0x7) >= 6) && (r->_pc >= 0xe000)) || ((r->_pc >= 0xa000) && (r->_pc <= 0xbfff) && ((mem[1] & 0x7) > 6))) {
|
||||
/* some packer relies on regs set at return from CLRSCR */
|
||||
if ((r->_pc == 0xe536) || (r->_pc == 0xe544) || (r->_pc == 0xff5b) || ((r->_pc == 0xffd2) && (r->_a == 0x93))) {
|
||||
if (r->_pc != 0xffd2) {
|
||||
r->_x = 0x01;
|
||||
r->_y = 0x84;
|
||||
|
||||
if (r->_pc == 0xff5b)
|
||||
r->_a = 0x97; /* actually depends on $d012 */
|
||||
else
|
||||
r->_a = 0xd8;
|
||||
|
||||
r->_flags &= ~(128 | 2);
|
||||
r->_flags |= (r->_a == 0 ? 2 : 0) | (r->_a & 128);
|
||||
}
|
||||
memset(mem + 0x400, 0x20, 1000);
|
||||
}
|
||||
/* intros */
|
||||
if ((r->_pc == 0xffe4) || (r->_pc == 0xf13e)) {
|
||||
static int flipspe4 = -1;
|
||||
static unsigned char fpressedchars[] = {0x20, 0, 0x4e, 0, 3, 0, 0x5f, 0, 0x11, 00, 0x0d, 0, 0x31, 0};
|
||||
flipspe4++;
|
||||
|
||||
if (flipspe4 > ARRAYSIZE(fpressedchars))
|
||||
flipspe4 = 0;
|
||||
|
||||
r->_a = fpressedchars[flipspe4];
|
||||
r->_flags &= ~(128 | 2);
|
||||
r->_flags |= (r->_a == 0 ? 2 : 0) | (r->_a & 128);
|
||||
}
|
||||
|
||||
if (r->_pc == 0xfd15) {
|
||||
r->_a = 0x31;
|
||||
r->_x = 0x30;
|
||||
r->_y = 0xff;
|
||||
}
|
||||
|
||||
if (r->_pc == 0xfda3) {
|
||||
mem[0x01] = 0xe7;
|
||||
r->_a = 0xd7;
|
||||
r->_x = 0xff;
|
||||
}
|
||||
|
||||
if (r->_pc == 0xffbd) {
|
||||
mem[0xB7] = r->_a;
|
||||
mem[0xBB] = r->_x;
|
||||
mem[0xBC] = r->_y;
|
||||
}
|
||||
|
||||
if ((r->_pc == 0xffd5) || (r->_pc == 0xf4a2)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (isBasicRun1(r->_pc)) {
|
||||
info->_run = findSys(mem + info->_basicTxtStart, 0x9e);
|
||||
if (info->_run > 0) {
|
||||
r->_sp = 0xf6;
|
||||
r->_pc = info->_run;
|
||||
} else {
|
||||
mem[0] = 0x60;
|
||||
r->_pc = 0; /* force a RTS instead of executing ROM code */
|
||||
}
|
||||
} else {
|
||||
mem[0] = 0x60;
|
||||
r->_pc = 0; /* force a RTS instead of executing ROM code */
|
||||
}
|
||||
}
|
||||
|
||||
if (nextInst(r) == 1)
|
||||
return 0;
|
||||
|
||||
_G(_iter)++;
|
||||
if (_G(_iter) == iterMax) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_G(_unp)._exoFnd && (_G(_unp)._endAdr == 0x10000) && (r->_pc >= 0x100) && (r->_pc <= 0x200) && (_G(_unp)._strMem != 2)) {
|
||||
_G(_unp)._endAdr = r->_mem[0xfe] + (r->_mem[0xff] << 8);
|
||||
if ((_G(_unp)._exoFnd & 0xff) == 0x30) { /* low byte of _endAdr, it's a lda $ff00,y */
|
||||
_G(_unp)._endAdr = (_G(_unp)._exoFnd >> 8) + (r->_mem[0xff] << 8);
|
||||
} else if ((_G(_unp)._exoFnd & 0xff) == 0x32) { /* add 1 */
|
||||
_G(_unp)._endAdr = 1 + ((_G(_unp)._exoFnd >> 8) + (r->_mem[0xff] << 8));
|
||||
}
|
||||
|
||||
if (_G(_unp)._endAdr == 0)
|
||||
_G(_unp)._endAdr = 0x10001;
|
||||
}
|
||||
|
||||
if (_G(_unp)._fEndBf && (_G(_unp)._endAdr == 0x10000) && (r->_pc == _G(_unp)._depAdr)) {
|
||||
_G(_unp)._endAdr = r->_mem[_G(_unp)._fEndBf] | r->_mem[_G(_unp)._fEndBf + 1] << 8;
|
||||
_G(_unp)._endAdr++;
|
||||
|
||||
if (_G(_unp)._endAdr == 0)
|
||||
_G(_unp)._endAdr = 0x10001;
|
||||
|
||||
_G(_unp)._fEndBf = 0;
|
||||
}
|
||||
|
||||
if (_G(_unp)._fStrBf && (_G(_unp)._strMem != 0x2) && (r->_pc == _G(_unp)._depAdr)) {
|
||||
_G(_unp)._strMem = r->_mem[_G(_unp)._fStrBf] | r->_mem[_G(_unp)._fStrBf + 1] << 8;
|
||||
_G(_unp)._fStrBf = 0;
|
||||
}
|
||||
|
||||
if (_G(_unp)._debugP) {
|
||||
for (p = 0; p < 0x20; p += 2) {
|
||||
if (*(unsigned short int *)(mem + 0x314 + p) != *(unsigned short int *)(vector + p)) {
|
||||
*(unsigned short int *)(vector + p) = *(unsigned short int *)(mem + 0x314 + p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_G(_iter) = 0;
|
||||
while (_G(_unp)._rtAFrc ? r->_pc != _G(_unp)._retAdr : r->_pc < _G(_unp)._retAdr) {
|
||||
if (_G(_unp)._monEnd && r->_pc == _G(_unp)._depAdr) {
|
||||
p = r->_mem[_G(_unp)._monEnd >> 16] | r->_mem[_G(_unp)._monEnd & 0xffff] << 8;
|
||||
if (p > (_G(_unp)._endAdr & 0xffff)) {
|
||||
_G(_unp)._endAdr = p;
|
||||
}
|
||||
}
|
||||
if (_G(_unp)._monStr && r->_pc == _G(_unp)._depAdr) {
|
||||
p = r->_mem[_G(_unp)._monStr >> 16] | r->_mem[_G(_unp)._monStr & 0xffff] << 8;
|
||||
if (p > 0) {
|
||||
if (_G(_unp)._mon1st == 0) {
|
||||
_G(_unp)._strMem = p;
|
||||
}
|
||||
_G(_unp)._mon1st = (unsigned int)_G(_unp)._strMem;
|
||||
_G(_unp)._strMem = (p < _G(_unp)._strMem ? p : _G(_unp)._strMem);
|
||||
}
|
||||
}
|
||||
|
||||
if (r->_pc >= 0xe000) {
|
||||
if (((mem[1] & 0x7) >= 6) && ((mem[1] & 0x7) <= 7)) {
|
||||
mem[0] = 0x60;
|
||||
r->_pc = 0;
|
||||
}
|
||||
}
|
||||
if (nextInst(r) == 1)
|
||||
return 0;
|
||||
|
||||
if ((mem[r->_pc] == 0x40) && (_G(_unp)._rtiFrc == 1)) {
|
||||
_G(_unp)._retAdr = r->_pc;
|
||||
_G(_unp)._rtAFrc = 1;
|
||||
if (_G(_unp)._retAdr < _G(_unp)._strMem)
|
||||
_G(_unp)._strMem = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
_G(_iter)++;
|
||||
if (_G(_iter) == iterMax) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((r->_pc >= 0xa000) && (r->_pc <= 0xbfff) && ((mem[1] & 0x7) == 7)) {
|
||||
if (isBasicRun2(r->_pc)) {
|
||||
r->_pc = 0xa7ae;
|
||||
break;
|
||||
} else {
|
||||
mem[0] = 0x60;
|
||||
r->_pc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (r->_pc >= 0xe000) {
|
||||
if (((mem[1] & 0x7) >= 6) && ((mem[1] & 0x7) <= 7)) {
|
||||
if (r->_pc == 0xffbd) {
|
||||
mem[0xB7] = r->_a;
|
||||
mem[0xBB] = r->_x;
|
||||
mem[0xBC] = r->_y;
|
||||
}
|
||||
/* return into IRQ handler, better stop here */
|
||||
if (((r->_pc >= 0xea31) && (r->_pc <= 0xeb76)) || (r->_pc == 0xffd5) || (r->_pc == 0xfce2)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (r->_pc == 0xfda3) {
|
||||
mem[0x01] = 0xe7;
|
||||
r->_a = 0xd7;
|
||||
r->_x = 0xff;
|
||||
}
|
||||
mem[0] = 0x60;
|
||||
r->_pc = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_G(_unp)._fEndAf && _G(_unp)._monEnd) {
|
||||
_G(_unp)._endAdC = (unsigned int)(mem[_G(_unp)._fEndAf] | mem[_G(_unp)._fEndAf + 1] << 8);
|
||||
if ((int)_G(_unp)._endAdC > _G(_unp)._endAdr)
|
||||
_G(_unp)._endAdr = (int)_G(_unp)._endAdC;
|
||||
|
||||
_G(_unp)._endAdC = 0;
|
||||
_G(_unp)._fEndAf = 0;
|
||||
}
|
||||
|
||||
if (_G(_unp)._fEndAf && (_G(_unp)._endAdr == 0x10000)) {
|
||||
_G(_unp)._endAdr = r->_mem[_G(_unp)._fEndAf] | r->_mem[_G(_unp)._fEndAf + 1] << 8;
|
||||
if (_G(_unp)._endAdr == 0)
|
||||
_G(_unp)._endAdr = 0x10000;
|
||||
else
|
||||
_G(_unp)._endAdr++;
|
||||
_G(_unp)._fEndAf = 0;
|
||||
}
|
||||
|
||||
if (_G(_unp)._fStrAf /*&&(_G(_unp)._strMem==0x800)*/) {
|
||||
_G(_unp)._strMem = r->_mem[_G(_unp)._fStrAf] | r->_mem[_G(_unp)._fStrAf + 1] << 8;
|
||||
_G(_unp)._strMem++;
|
||||
_G(_unp)._fStrAf = 0;
|
||||
}
|
||||
|
||||
if (_G(_unp)._exoFnd && (_G(_unp)._strMem != 2)) {
|
||||
_G(_unp)._strMem = r->_mem[0xfe] + (r->_mem[0xff] << 8);
|
||||
|
||||
if ((_G(_unp)._exoFnd & 0xff) == 0x30) {
|
||||
_G(_unp)._strMem += r->_y;
|
||||
} else if ((_G(_unp)._exoFnd & 0xff) == 0x32) {
|
||||
_G(_unp)._strMem += r->_y + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (r->_pc == 0xfce2) {
|
||||
if ((*(unsigned int *)(mem + 0x8004) == 0x38cdc2c3) && (mem[0x8008] == 0x30)) {
|
||||
r->_pc = r->_mem[0x8000] + (r->_mem[0x8001] << 8);
|
||||
}
|
||||
} else if (r->_pc == 0xa7ae) {
|
||||
info->_basicTxtStart = mem[0x2b] | mem[0x2c] << 8;
|
||||
if (info->_basicTxtStart == 0x801) {
|
||||
info->_run = findSys(mem + info->_basicTxtStart, 0x9e);
|
||||
if (info->_run > 0)
|
||||
r->_pc = info->_run;
|
||||
}
|
||||
}
|
||||
|
||||
if (_G(_unp)._wrMemF) {
|
||||
_G(_unp)._wrMemF = 0;
|
||||
for (p = 0x800; p < 0x10000; p += 4) {
|
||||
if (*(unsigned int *)(oldmem + p) == *(unsigned int *)(mem + p)) {
|
||||
*(unsigned int *)(mem + p) = 0;
|
||||
_G(_unp)._wrMemF = 1;
|
||||
}
|
||||
}
|
||||
/* clean also the $fd30 table copy in RAM */
|
||||
if (memcmp(mem + 0xfd30, vector, sizeof(vector)) == 0) {
|
||||
memset(mem + 0xfd30, 0, sizeof(vector));
|
||||
}
|
||||
}
|
||||
|
||||
if (_G(_unp)._lfMemF) {
|
||||
for (p = 0xffff; p > 0x0800; p--) {
|
||||
if (oldmem[--_G(_unp)._lfMemF] == mem[p])
|
||||
mem[p] = 0x0;
|
||||
else {
|
||||
if (p >= 0xffff)
|
||||
_G(_unp)._lfMemF = 0 | _G(_unp)._ecaFlg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (*forcedname) {
|
||||
Common::sprintf_s(name, sizeof name, "%s", forcedname);
|
||||
} else {
|
||||
size_t ln = strlen(name);
|
||||
if (ln > 248) {/* dirty hack in case name is REALLY long */
|
||||
name[248] = 0;
|
||||
ln = 248;
|
||||
}
|
||||
|
||||
Common::sprintf_s(name + ln, sizeof(name) - ln, ".%04x%s", r->_pc, ((_G(_unp)._wrMemF | _G(_unp)._lfMemF) ? ".clean" : ""));
|
||||
}
|
||||
|
||||
/* endadr is set to a ZP location? then use it as a pointer
|
||||
todo: use __fEndAf instead, it can be used for any location, not only ZP. */
|
||||
if (_G(_unp)._endAdr && (_G(_unp)._endAdr < 0x100)) {
|
||||
p = (mem[_G(_unp)._endAdr] | mem[_G(_unp)._endAdr + 1] << 8) & 0xffff;
|
||||
_G(_unp)._endAdr = p;
|
||||
}
|
||||
|
||||
if (_G(_unp)._ecaFlg && (_G(_unp)._strMem != 2)) /* checkme */ {
|
||||
if (_G(_unp)._endAdr >= ((_G(_unp)._ecaFlg >> 16) & 0xffff)) {
|
||||
/* most of the times transfers $2000 byte from $d000-efff to $e000-ffff but there are exceptions */
|
||||
if (_G(_unp)._lfMemF)
|
||||
memset(mem + ((_G(_unp)._ecaFlg >> 16) & 0xffff), 0, 0x1000);
|
||||
_G(_unp)._endAdr += 0x1000;
|
||||
}
|
||||
}
|
||||
|
||||
if (_G(_unp)._endAdr <= 0)
|
||||
_G(_unp)._endAdr = 0x10000;
|
||||
|
||||
if (_G(_unp)._endAdr > 0x10000)
|
||||
_G(_unp)._endAdr = 0x10000;
|
||||
|
||||
if (_G(_unp)._endAdr < _G(_unp)._strMem)
|
||||
_G(_unp)._endAdr = 0x10000;
|
||||
|
||||
if (_G(_unp)._endAdC & 0xffff) {
|
||||
_G(_unp)._endAdr += (_G(_unp)._endAdC & 0xffff);
|
||||
_G(_unp)._endAdr &= 0xffff;
|
||||
}
|
||||
|
||||
if (_G(_unp)._endAdC & EA_USE_A) {
|
||||
_G(_unp)._endAdr += r->_a;
|
||||
_G(_unp)._endAdr &= 0xffff;
|
||||
}
|
||||
|
||||
if (_G(_unp)._endAdC & EA_USE_X) {
|
||||
_G(_unp)._endAdr += r->_x;
|
||||
_G(_unp)._endAdr &= 0xffff;
|
||||
}
|
||||
|
||||
if (_G(_unp)._endAdC & EA_USE_Y) {
|
||||
_G(_unp)._endAdr += r->_y;
|
||||
_G(_unp)._endAdr &= 0xffff;
|
||||
}
|
||||
|
||||
if (_G(_unp)._strAdC & 0xffff) {
|
||||
_G(_unp)._strMem += (_G(_unp)._strAdC & 0xffff);
|
||||
_G(_unp)._strMem &= 0xffff;
|
||||
/* only if ea_addff, no reg involved */
|
||||
if (((_G(_unp)._strAdC & 0xffff0000) == EA_ADDFF) && ((_G(_unp)._strMem & 0xff) == 0)) {
|
||||
_G(_unp)._strMem += 0x100;
|
||||
_G(_unp)._strMem &= 0xffff;
|
||||
}
|
||||
}
|
||||
|
||||
if (_G(_unp)._strAdC & EA_USE_A) {
|
||||
_G(_unp)._strMem += r->_a;
|
||||
_G(_unp)._strMem &= 0xffff;
|
||||
if (_G(_unp)._strAdC & EA_ADDFF) {
|
||||
if ((_G(_unp)._strMem & 0xff) == 0xff)
|
||||
_G(_unp)._strMem++;
|
||||
|
||||
if (r->_a == 0) {
|
||||
_G(_unp)._strMem += 0x100;
|
||||
_G(_unp)._strMem &= 0xffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_G(_unp)._strAdC & EA_USE_X) {
|
||||
_G(_unp)._strMem += r->_x;
|
||||
_G(_unp)._strMem &= 0xffff;
|
||||
|
||||
if (_G(_unp)._strAdC & EA_ADDFF) {
|
||||
if ((_G(_unp)._strMem & 0xff) == 0xff)
|
||||
_G(_unp)._strMem++;
|
||||
|
||||
if (r->_x == 0) {
|
||||
_G(_unp)._strMem += 0x100;
|
||||
_G(_unp)._strMem &= 0xffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_G(_unp)._strAdC & EA_USE_Y) {
|
||||
_G(_unp)._strMem += r->_y;
|
||||
_G(_unp)._strMem &= 0xffff;
|
||||
|
||||
if (_G(_unp)._strAdC & EA_ADDFF) {
|
||||
if ((_G(_unp)._strMem & 0xff) == 0xff)
|
||||
_G(_unp)._strMem++;
|
||||
|
||||
if (r->_y == 0) {
|
||||
_G(_unp)._strMem += 0x100;
|
||||
_G(_unp)._strMem &= 0xffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_G(_unp)._endAdr <= 0)
|
||||
_G(_unp)._endAdr = 0x10000;
|
||||
|
||||
if (_G(_unp)._endAdr > 0x10000)
|
||||
_G(_unp)._endAdr = 0x10000;
|
||||
|
||||
if (_G(_unp)._endAdr < _G(_unp)._strMem)
|
||||
_G(_unp)._endAdr = 0x10000;
|
||||
|
||||
mem[_G(_unp)._strMem - 2] = _G(_unp)._strMem & 0xff;
|
||||
mem[_G(_unp)._strMem - 1] = _G(_unp)._strMem >> 8;
|
||||
|
||||
memcpy(destinationBuffer, mem + (_G(_unp)._strMem - 2), (size_t)(_G(_unp)._endAdr - _G(_unp)._strMem + 2));
|
||||
*finalLength = (size_t)(_G(_unp)._endAdr - _G(_unp)._strMem + 2);
|
||||
|
||||
if (_G(_unp)._recurs) {
|
||||
if (++_G(_unp)._recurs > RECUMAX)
|
||||
return 1;
|
||||
reinitUnp();
|
||||
goto looprecurse;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
78
engines/glk/scott/unp64/unp64.h
Normal file
78
engines/glk/scott/unp64/unp64.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/* 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 GLK_SCOTT_UNP64_H
|
||||
#define GLK_SCOTT_UNP64_H
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
struct LoadInfo;
|
||||
struct CpuCtx;
|
||||
|
||||
struct UnpStr {
|
||||
int _idFlag; /* flag, 1=packer identified; 2=not a packer, stop scanning */
|
||||
int _forced; /* forced entry point */
|
||||
int _strMem; /* start of unpacked memory */
|
||||
int _retAdr; /* return address after unpacking */
|
||||
int _depAdr; /* unpacker entry point */
|
||||
int _endAdr; /* end of unpacked memory */
|
||||
int _rtAFrc; /* flag, return address must be exactly RetAdr, else anything >= RetAdr */
|
||||
int _wrMemF; /* flag, clean unwritten memory */
|
||||
int _lfMemF; /* flag, clean end memory leftovers */
|
||||
int _exoFnd; /* flag, Exomizer detected */
|
||||
int _fStack; /* flag, fill stack with 0 and SP=$ff, else as in C64 */
|
||||
int _ecaFlg; /* ECA found, holds relocated areas high bytes */
|
||||
int _fEndBf; /* End memory address pointer before unpacking, set when DepAdr is reached */
|
||||
int _fEndAf; /* End memory address pointer after unpacking, set when RetAdr is reached */
|
||||
int _fStrBf; /* Start memory address pointer before unpacking, set when DepAdr is reached */
|
||||
int _fStrAf; /* Start memory address pointer after unpacking, set when RetAdr is reached */
|
||||
int _idOnly; /* flag, just identify packer and exit */
|
||||
int _debugP; /* flag, verbosely emit various infos */
|
||||
int _rtiFrc; /* flag, RTI instruction forces return from unpacker */
|
||||
int _recurs; /* recursion counter */
|
||||
unsigned int _monEnd; /* End memory address pointers monitored during execution, updated every time DepAdr is reached */
|
||||
unsigned int _monStr; /* Start memory address pointers monitored during execution, updated every time DepAdr is reached */
|
||||
unsigned int _mon1st; /* flag for forcingly assign monitored str/end ptr the 1st time */
|
||||
unsigned int _endAdC; /* add fixed values and/or registers AXY to End memory address */
|
||||
unsigned int _strAdC; /* add fixed values and/or registers AXY to Start memory address */
|
||||
unsigned int _filler; /* Memory filler byte*/
|
||||
unsigned char *_mem; /* pointer to the memory array */
|
||||
char *_name; /* name of the prg file */
|
||||
LoadInfo *_info; /* pointer to the loaded prg info struct */
|
||||
CpuCtx *_r; /* pointer to the registers struct */
|
||||
};
|
||||
|
||||
typedef void (*Scnptr)(UnpStr *);
|
||||
|
||||
#define EA_USE_A 0x01000000
|
||||
#define EA_USE_X 0x00100000
|
||||
#define EA_USE_Y 0x00010000
|
||||
#define EA_ADDFF 0x10000000
|
||||
#define ITERMAX 0x02000000
|
||||
#define RECUMAX 16
|
||||
|
||||
void scanners(UnpStr *);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
35
engines/glk/scott/unp64/unp64_interface.h
Normal file
35
engines/glk/scott/unp64/unp64_interface.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/* 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 GLK_SCOTT_UNP64_INTERFACE_H
|
||||
#define GLK_SCOTT_UNP64_INTERFACE_H
|
||||
|
||||
#include "glk/scott/types.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Scott {
|
||||
|
||||
int unp64(uint8_t *compressed, size_t length, uint8_t *destinationBuffer, size_t *finalLength, const char *settings);
|
||||
|
||||
} // End of namespace Scott
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user