Initial commit
This commit is contained in:
2
engines/private/POTFILES
Normal file
2
engines/private/POTFILES
Normal file
@@ -0,0 +1,2 @@
|
||||
engines/private/detection.cpp
|
||||
engines/private/metaengine.cpp
|
||||
439
engines/private/code.cpp
Normal file
439
engines/private/code.cpp
Normal file
@@ -0,0 +1,439 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Heavily inspired by hoc
|
||||
// Copyright (C) AT&T 1995
|
||||
// All Rights Reserved
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software and
|
||||
// its documentation for any purpose and without fee is hereby
|
||||
// granted, provided that the above copyright notice appear in all
|
||||
// copies and that both that the copyright notice and this
|
||||
// permission notice and warranty disclaimer appear in supporting
|
||||
// documentation, and that the name of AT&T or any of its entities
|
||||
// not be used in advertising or publicity pertaining to
|
||||
// distribution of the software without specific, written prior
|
||||
// permission.
|
||||
//
|
||||
// AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
// INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||
// IN NO EVENT SHALL AT&T OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
|
||||
// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
// THIS SOFTWARE.
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/hash-ptr.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "private/grammar.h"
|
||||
#include "private/private.h"
|
||||
#include "private/tokens.h"
|
||||
|
||||
namespace Private {
|
||||
|
||||
Gen::VM *Gen::g_vm;
|
||||
|
||||
void Gen::VM::run() {
|
||||
Gen::execute(Gen::g_vm->_prog);
|
||||
}
|
||||
|
||||
namespace Settings {
|
||||
|
||||
using namespace Gen;
|
||||
|
||||
SettingMaps *g_setts;
|
||||
|
||||
SettingMaps::SettingMaps() :
|
||||
_setting(nullptr) {
|
||||
}
|
||||
|
||||
SettingMaps::~SettingMaps() {
|
||||
for (uint i = 0; i < _settings.size(); i++) {
|
||||
free(_settings[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize setting for code generation */
|
||||
void SettingMaps::init() {
|
||||
_setting = (Setting *)malloc(sizeof(Setting));
|
||||
_settings.push_back(_setting);
|
||||
memset((void *)_setting, 0, sizeof(Setting));
|
||||
|
||||
g_vm->_prog = (Inst *)&_setting->prog;
|
||||
g_vm->_stack = (Datum *)&_setting->stack;
|
||||
|
||||
g_vm->_progp = Gen::g_vm->_prog;
|
||||
g_vm->_stackp = Gen::g_vm->_stack;
|
||||
}
|
||||
|
||||
void SettingMaps::save(const char *name) {
|
||||
_map.setVal(name, _setting);
|
||||
}
|
||||
|
||||
void SettingMaps::load(const Common::String &name) {
|
||||
assert(_map.contains(name));
|
||||
_setting = _map.getVal(name);
|
||||
|
||||
debugC(1, kPrivateDebugCode, "loading setting %s", name.c_str());
|
||||
|
||||
g_vm->_prog = (Inst *)&_setting->prog;
|
||||
g_vm->_stack = (Datum *)&_setting->stack;
|
||||
|
||||
g_vm->_stackp = g_vm->_stack;
|
||||
g_vm->_progp = g_vm->_prog;
|
||||
}
|
||||
|
||||
} // end of namespace Settings
|
||||
|
||||
namespace Gen {
|
||||
|
||||
/* pop and return top elem from stack */
|
||||
Datum pop() {
|
||||
assert(!(g_vm->_stackp <= g_vm->_stack));
|
||||
return *--g_vm->_stackp;
|
||||
}
|
||||
|
||||
/* push d onto stack */
|
||||
int push(const Datum &d) {
|
||||
assert(!(g_vm->_stackp >= &g_vm->_stack[NSTACK]));
|
||||
*g_vm->_stackp++ = d;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* push constant onto stack */
|
||||
int constpush() {
|
||||
Datum d;
|
||||
Symbol *s = (Symbol *)*g_vm->_pc++;
|
||||
d.type = NUM;
|
||||
d.u.val = s->u.val;
|
||||
|
||||
debugC(1, kPrivateDebugCode, "pushing const %d with name %s", d.u.val, s->name->c_str());
|
||||
push(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strpush() { /* push constant onto stack */
|
||||
Datum d;
|
||||
d.type = STRING;
|
||||
Symbol *s = (Symbol *)*g_vm->_pc++;
|
||||
d.u.str = s->u.str;
|
||||
debugC(1, kPrivateDebugCode, "pushing const %s with name %s", d.u.str, s->name->c_str());
|
||||
|
||||
push(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int varpush() { /* push variable onto stack */
|
||||
Datum d;
|
||||
d.type = NAME;
|
||||
d.u.sym = (Symbol *)(*g_vm->_pc++);
|
||||
debugC(1, kPrivateDebugCode, "var pushing %s", d.u.sym->name->c_str());
|
||||
push(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int funcpush() {
|
||||
Datum s = pop();
|
||||
Datum n = pop();
|
||||
ArgArray args;
|
||||
|
||||
debugC(1, kPrivateDebugCode, "executing %s with %d params", s.u.str, n.u.val);
|
||||
for (int i = 0; i < n.u.val; i++) {
|
||||
Datum arg = pop();
|
||||
args.insert(args.begin(), arg);
|
||||
}
|
||||
|
||||
call(s.u.str, args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* evaluate variable on stack */
|
||||
int eval() {
|
||||
Datum d = pop();
|
||||
if (d.u.sym->type == NUM) {
|
||||
d.type = NUM;
|
||||
d.u.val = d.u.sym->u.val;
|
||||
debugC(1, kPrivateDebugCode, "eval NUM returned %d", d.u.val);
|
||||
} else if (d.u.sym->type == STRING) {
|
||||
d.type = STRING;
|
||||
d.u.str = d.u.sym->u.str;
|
||||
debugC(1, kPrivateDebugCode, "eval STR returned %s", d.u.str);
|
||||
} else if (d.u.sym->type == RECT) {
|
||||
d.type = RECT;
|
||||
d.u.rect = d.u.sym->u.rect;
|
||||
debugC(1, kPrivateDebugCode, "eval RECT");
|
||||
} else if (d.u.sym->type == NAME) {
|
||||
debugC(1, kPrivateDebugCode, "eval NAME is noop");
|
||||
// No evaluation until is absolutely needed
|
||||
} else
|
||||
assert(0);
|
||||
|
||||
push(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* add top two elems on stack */
|
||||
int add() {
|
||||
Datum d2 = pop();
|
||||
Datum d1 = pop();
|
||||
if (d1.type == NAME) {
|
||||
d1.u.sym = g_private->maps.lookupVariable(d1.u.sym->name);
|
||||
d1.u.val = d1.u.sym->u.val;
|
||||
d1.type = NUM;
|
||||
}
|
||||
|
||||
if (d2.type == NAME) {
|
||||
d2.u.sym = g_private->maps.lookupVariable(d2.u.sym->name);
|
||||
d2.u.val = d2.u.sym->u.val;
|
||||
d2.type = NUM;
|
||||
}
|
||||
|
||||
assert(d1.type == NUM);
|
||||
assert(d2.type == NUM);
|
||||
|
||||
debugC(1, kPrivateDebugCode, "adding %d %d\n", d1.u.val, d2.u.val);
|
||||
d1.u.val += d2.u.val;
|
||||
push(d1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int negate() {
|
||||
Datum d = pop();
|
||||
int v = 0;
|
||||
if (d.type == NAME) {
|
||||
d.u.sym = g_private->maps.lookupVariable(d.u.sym->name);
|
||||
v = d.u.sym->u.val;
|
||||
d.type = NUM;
|
||||
} else if (d.type == NUM) {
|
||||
v = d.u.val;
|
||||
} else
|
||||
assert(0);
|
||||
|
||||
debugC(1, kPrivateDebugCode, "negating %d\n", d.u.val);
|
||||
d.u.val = !v;
|
||||
push(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gt() {
|
||||
Datum d2 = pop();
|
||||
Datum d1 = pop();
|
||||
if (d1.type == NAME) {
|
||||
//char *name = d1.u.sym->name->c_str();
|
||||
//debug("eval %s to %d",
|
||||
d1.u.sym = g_private->maps.lookupVariable(d1.u.sym->name);
|
||||
d1.u.val = d1.u.sym->u.val;
|
||||
d1.type = NUM;
|
||||
}
|
||||
|
||||
if (d2.type == NAME) {
|
||||
//char *name = d1.u.sym->name->c_str();
|
||||
//debug("eval %s to %d",
|
||||
d2.u.sym = g_private->maps.lookupVariable(d2.u.sym->name);
|
||||
d2.u.val = d2.u.sym->u.val;
|
||||
d2.type = NUM;
|
||||
}
|
||||
|
||||
d1.u.val = (int)(d1.u.val > d2.u.val);
|
||||
push(d1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lt() {
|
||||
Datum d2 = pop();
|
||||
Datum d1 = pop();
|
||||
if (d1.type == NAME) {
|
||||
//char *name = d1.u.sym->name->c_str();
|
||||
//debug("eval %s to %d",
|
||||
d1.u.sym = g_private->maps.lookupVariable(d1.u.sym->name);
|
||||
d1.u.val = d1.u.sym->u.val;
|
||||
d1.type = NUM;
|
||||
}
|
||||
|
||||
if (d2.type == NAME) {
|
||||
//char *name = d1.u.sym->name->c_str();
|
||||
//debug("eval %s to %d",
|
||||
d2.u.sym = g_private->maps.lookupVariable(d2.u.sym->name);
|
||||
d2.u.val = d2.u.sym->u.val;
|
||||
d2.type = NUM;
|
||||
}
|
||||
|
||||
d1.u.val = (int)(d1.u.val < d2.u.val);
|
||||
push(d1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ge() {
|
||||
Datum d2 = pop();
|
||||
Datum d1 = pop();
|
||||
if (d1.type == NAME) {
|
||||
//char *name = d1.u.sym->name->c_str();
|
||||
//debug("eval %s to %d",
|
||||
d1.u.sym = g_private->maps.lookupVariable(d1.u.sym->name);
|
||||
d1.u.val = d1.u.sym->u.val;
|
||||
d1.type = NUM;
|
||||
}
|
||||
|
||||
if (d2.type == NAME) {
|
||||
//char *name = d1.u.sym->name->c_str();
|
||||
//debug("eval %s to %d",
|
||||
d2.u.sym = g_private->maps.lookupVariable(d2.u.sym->name);
|
||||
d2.u.val = d2.u.sym->u.val;
|
||||
d2.type = NUM;
|
||||
}
|
||||
|
||||
d1.u.val = (int)(d1.u.val >= d2.u.val);
|
||||
push(d1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int le() {
|
||||
Datum d2 = pop();
|
||||
Datum d1 = pop();
|
||||
if (d1.type == NAME) {
|
||||
//char *name = d1.u.sym->name->c_str();
|
||||
//debug("eval %s to %d",
|
||||
d1.u.sym = g_private->maps.lookupVariable(d1.u.sym->name);
|
||||
d1.u.val = d1.u.sym->u.val;
|
||||
d1.type = NUM;
|
||||
}
|
||||
|
||||
if (d2.type == NAME) {
|
||||
//char *name = d1.u.sym->name->c_str();
|
||||
//debug("eval %s to %d",
|
||||
d2.u.sym = g_private->maps.lookupVariable(d2.u.sym->name);
|
||||
d2.u.val = d2.u.sym->u.val;
|
||||
d2.type = NUM;
|
||||
}
|
||||
|
||||
d1.u.val = (int)(d1.u.val <= d2.u.val);
|
||||
push(d1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eq() {
|
||||
Datum d2 = pop();
|
||||
Datum d1 = pop();
|
||||
if (d1.type == NAME) {
|
||||
//char *name = d1.u.sym->name->c_str();
|
||||
//debug("eval %s to %d",
|
||||
d1.u.sym = g_private->maps.lookupVariable(d1.u.sym->name);
|
||||
d1.u.val = d1.u.sym->u.val;
|
||||
d1.type = NUM;
|
||||
}
|
||||
|
||||
if (d2.type == NAME) {
|
||||
//char *name = d1.u.sym->name->c_str();
|
||||
//debug("eval %s to %d",
|
||||
d2.u.sym = g_private->maps.lookupVariable(d2.u.sym->name);
|
||||
d2.u.val = d2.u.sym->u.val;
|
||||
d2.type = NUM;
|
||||
}
|
||||
|
||||
d1.u.val = (int)(d1.u.val == d2.u.val);
|
||||
push(d1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ne() {
|
||||
Datum d2 = pop();
|
||||
Datum d1 = pop();
|
||||
if (d1.type == NAME) {
|
||||
d1.u.sym = g_private->maps.lookupVariable(d1.u.sym->name);
|
||||
d1.u.val = d1.u.sym->u.val;
|
||||
d1.type = NUM;
|
||||
}
|
||||
|
||||
if (d2.type == NAME) {
|
||||
d2.u.sym = g_private->maps.lookupVariable(d2.u.sym->name);
|
||||
d2.u.val = d2.u.sym->u.val;
|
||||
d2.type = NUM;
|
||||
}
|
||||
|
||||
d1.u.val = (int)(d1.u.val != d2.u.val);
|
||||
push(d1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* install one instruction or operand */
|
||||
Inst *code(const Inst &f) {
|
||||
//debugC(1, kPrivateDebugCode, "pushing code at %x", progp);
|
||||
Inst *oprogp = g_vm->_progp;
|
||||
assert(!(g_vm->_progp >= &g_vm->_prog[NPROG]));
|
||||
*g_vm->_progp++ = f;
|
||||
return oprogp;
|
||||
}
|
||||
|
||||
int ifcode() {
|
||||
Inst *savepc = g_vm->_pc; /* then part */
|
||||
debugC(1, kPrivateDebugCode, "ifcode: evaluating condition");
|
||||
|
||||
execute(savepc + 3); /* condition */
|
||||
Datum d = pop();
|
||||
|
||||
debugC(1, kPrivateDebugCode, "ifcode: selecting branch");
|
||||
|
||||
if (d.type == NAME) {
|
||||
debugC(1, kPrivateDebugCode, "name %s", d.u.sym->name->c_str());
|
||||
d.u.sym = g_private->maps.lookupVariable(d.u.sym->name);
|
||||
d.u.val = d.u.sym->u.val;
|
||||
}
|
||||
|
||||
if (d.u.val) {
|
||||
debugC(1, kPrivateDebugCode, "ifcode: true branch");
|
||||
execute(*((Inst **)(savepc)));
|
||||
} else if (*((Inst **)(savepc + 1))) { /* else part? */
|
||||
debugC(1, kPrivateDebugCode, "ifcode: false branch");
|
||||
execute(*((Inst **)(savepc + 1)));
|
||||
}
|
||||
debugC(1, kPrivateDebugCode, "ifcode finished");
|
||||
g_vm->_pc = *((Inst **)(savepc + 2)); /* next stmt */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int randbool() {
|
||||
Datum d = pop();
|
||||
|
||||
int v = g_private->getRandomBool(d.u.val);
|
||||
|
||||
d.u.val = v;
|
||||
push(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fail() {
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* run the machine */
|
||||
void execute(Inst *p) {
|
||||
for (g_vm->_pc = p; *(g_vm->_pc) != STOP;) {
|
||||
(*(*(g_vm->_pc++)))();
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Gen
|
||||
|
||||
} // End of namespace Private
|
||||
3
engines/private/configure.engine
Normal file
3
engines/private/configure.engine
Normal file
@@ -0,0 +1,3 @@
|
||||
# This file is included from the main "configure" script
|
||||
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
|
||||
add_engine private "Private Eye" yes "" "" "highres"
|
||||
3
engines/private/credits.pl
Normal file
3
engines/private/credits.pl
Normal file
@@ -0,0 +1,3 @@
|
||||
begin_section("Private");
|
||||
add_person("Gustavo Grieco", "neuromancer", "");
|
||||
end_section();
|
||||
165
engines/private/cursors.cpp
Normal file
165
engines/private/cursors.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
/* 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/rect.h"
|
||||
#include "graphics/cursorman.h"
|
||||
|
||||
#include "common/compression/installshieldv3_archive.h"
|
||||
|
||||
#include "common/formats/winexe_ne.h"
|
||||
#include "common/formats/winexe_pe.h"
|
||||
|
||||
#include "common/macresman.h"
|
||||
|
||||
#include "graphics/maccursor.h"
|
||||
#include "graphics/wincursor.h"
|
||||
|
||||
#include "private/private.h"
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
namespace Private {
|
||||
|
||||
struct CursorEntry {
|
||||
const char *name;
|
||||
const char *aname;
|
||||
uint windowsId;
|
||||
uint japaneseWindowsId;
|
||||
uint macId;
|
||||
};
|
||||
|
||||
void PrivateEngine::loadCursors() {
|
||||
const CursorEntry cursorIDReference[] = {
|
||||
{ "kTurnLeft", "k1", 23, 17, 133 },
|
||||
{ "kTurnRight", "k2", 9, 3, 132 },
|
||||
{ "kZoomIn", "k3", 17, 11, 138 },
|
||||
{ "kZoomOut", "k4", 11, 5, 135 },
|
||||
{ "kExit", "k5", 7, 1, 130 },
|
||||
{ "kPhone", "k6", 25, 19, 141 },
|
||||
{ "kInventory", "k7", 19, 13, 139 }
|
||||
};
|
||||
|
||||
_defaultCursor = Graphics::makeDefaultWinCursor();
|
||||
|
||||
if (_platform == Common::kPlatformWindows) {
|
||||
Common::WinResources *exe = nullptr;
|
||||
Common::SeekableReadStream *exeStream = nullptr;
|
||||
Common::ArchiveMemberList members;
|
||||
Common::InstallShieldV3 installerArchive;
|
||||
if (installerArchive.open("SUPPORT/PVTEYE.Z")) {
|
||||
const char *exeNames[] = {
|
||||
"PVTEYE.EXE",
|
||||
"PvteyeJ.EXE", // Japan
|
||||
"PVTDEMO.EXE"
|
||||
};
|
||||
for (uint i = 0; i < ARRAYSIZE(exeNames) && exeStream == nullptr; i++) {
|
||||
exeStream = installerArchive.createReadStreamForMember(exeNames[i]);
|
||||
}
|
||||
if (exeStream == nullptr) {
|
||||
error("Executable not found in PVTEYE.Z");
|
||||
}
|
||||
} else {
|
||||
Common::File *file = new Common::File();
|
||||
if (!file->open("SUPPORT/PVTEYE.EX_")) {
|
||||
error("PVTEYE.EX_ not found");
|
||||
}
|
||||
exeStream = file;
|
||||
}
|
||||
|
||||
exe = Common::WinResources::createFromEXE(exeStream);
|
||||
if (exe == nullptr) {
|
||||
error("Executable not found");
|
||||
}
|
||||
|
||||
const Common::Array<Common::WinResourceID> cursorIDs = exe->getIDList(Common::kWinGroupCursor);
|
||||
|
||||
_cursors.resize(cursorIDs.size());
|
||||
assert(cursorIDs.size() > 0);
|
||||
for (uint i = 0; i < cursorIDs.size(); i++) {
|
||||
_cursors[i].winCursorGroup = Graphics::WinCursorGroup::createCursorGroup(exe, cursorIDs[i]);
|
||||
_cursors[i].cursor = _cursors[i].winCursorGroup->cursors[0].cursor;
|
||||
|
||||
for (uint j = 0; j < ARRAYSIZE(cursorIDReference); j++) {
|
||||
const CursorEntry &entry = cursorIDReference[j];
|
||||
|
||||
uint entryId = (_language == Common::JA_JPN) ? entry.japaneseWindowsId : entry.windowsId;
|
||||
if (entryId == _cursors[i].winCursorGroup->cursors[0].id.getID()) {
|
||||
_cursors[i].name = entry.name;
|
||||
_cursors[i].aname = entry.aname;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete exe;
|
||||
delete exeStream;
|
||||
} else {
|
||||
Common::MacResManager resMan;
|
||||
const char *executableFilePath = isDemo() ? "SUPPORT/Private Eye Demo" : "SUPPORT/Private Eye";
|
||||
const char *executableInstallerPath = isDemo() ? "Private Eye Demo" : "Private Eye";
|
||||
Common::ScopedPtr<Common::Archive> macInstaller(loadMacInstaller());
|
||||
if (resMan.open(executableFilePath) || (macInstaller && resMan.open(executableInstallerPath, *macInstaller))) {
|
||||
const Common::MacResIDArray cursorResIDs = resMan.getResIDArray(MKTAG('C', 'U', 'R', 'S'));
|
||||
_cursors.resize(cursorResIDs.size());
|
||||
|
||||
for (uint i = 0; i < cursorResIDs.size(); i++) {
|
||||
Common::SharedPtr<Common::SeekableReadStream> resData(resMan.getResource(MKTAG('C', 'U', 'R', 'S'), cursorResIDs[i]));
|
||||
Graphics::MacCursor *cursor = new Graphics::MacCursor();
|
||||
cursor->readFromStream(*resData);
|
||||
_cursors[i].cursor = cursor;
|
||||
_cursors[i].winCursorGroup = nullptr;
|
||||
|
||||
for (uint j = 0; j < ARRAYSIZE(cursorIDReference); j++) {
|
||||
const CursorEntry &entry = cursorIDReference[j];
|
||||
|
||||
if (entry.macId == cursorResIDs[i]) {
|
||||
_cursors[i].name = entry.name;
|
||||
_cursors[i].aname = entry.aname;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrivateEngine::changeCursor(const Common::String &cursor) {
|
||||
if (_currentCursor == cursor) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cursor == "default") {
|
||||
CursorMan.replaceCursor(_defaultCursor);
|
||||
} else {
|
||||
for (uint i = 0; i < _cursors.size(); i++) {
|
||||
if (_cursors[i].name == cursor || _cursors[i].aname == cursor) {
|
||||
CursorMan.replaceCursor(_cursors[i].cursor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_currentCursor = cursor;
|
||||
|
||||
CursorMan.showMouse(true);
|
||||
}
|
||||
|
||||
} // End of namespace Private
|
||||
179
engines/private/decompiler.cpp
Normal file
179
engines/private/decompiler.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
// Heavily based on code by jdieguez
|
||||
|
||||
#include "private/decompiler.h"
|
||||
|
||||
namespace Private {
|
||||
|
||||
const char *kHeader = "Precompiled Game Matrix";
|
||||
const uint kHeaderSize = 23;
|
||||
|
||||
const byte kCodeString = 0x01;
|
||||
const byte kCodeShortLiteral = 0x02;
|
||||
const byte kCodeBraceClose = 0x04;
|
||||
const byte kCodeRect = 0x2e;
|
||||
const byte kCodeRects = 0x4f;
|
||||
const byte kCodeShortId = 0x50;
|
||||
|
||||
const static char *kCodeTable[] = {"", //
|
||||
"", // 0x01 (string)
|
||||
"", // 0x02 (short literal)
|
||||
" {\n", // 0x03
|
||||
"}\n", // 0x04
|
||||
"(", // 0x05
|
||||
")", // 0x06
|
||||
"", //
|
||||
"", //
|
||||
"", //
|
||||
",", // 0x0a
|
||||
"", //
|
||||
"%", // 0x0c
|
||||
"", //
|
||||
";\n", // 0x0e
|
||||
"!", // 0x0f
|
||||
"-", // 0x10
|
||||
"+", // 0x11
|
||||
"=", // 0x12
|
||||
">", // 0x13
|
||||
"<", // 0x14
|
||||
"if ", // 0x15
|
||||
"else ", // 0x16
|
||||
"Exit", // 0x17
|
||||
"goto ", // 0x18
|
||||
"Mask", // 0x19
|
||||
"MaskDrawn", // 0x1a
|
||||
"Movie", // 0x1b
|
||||
"Transition", // 0x1c
|
||||
"ThumbnailMovie", // 0x1d
|
||||
"BustMovie", // 0x1e
|
||||
"ViewScreen", // 0x1f
|
||||
"VSPicture", // 0x20
|
||||
"Bitmap", // 0x21
|
||||
"Timer", // 0x22
|
||||
"SoundArea", // 0x23
|
||||
"Sound", // 0x24
|
||||
"SoundEffect", // 0x25
|
||||
"SyncSound", // 0x26
|
||||
"LoopedSound", // 0x27
|
||||
"NoStopSounds", // 0x28
|
||||
"Resume", // 0x29
|
||||
"Inventory", // 0x2a
|
||||
"SetFlag", // 0x2b
|
||||
"ChgMode", // 0x2c
|
||||
"PoliceBust", // 0x2d
|
||||
"CRect", // 0x2e overridden with "RECT" if in "define rects" block
|
||||
"", //
|
||||
"Random", // 0x30
|
||||
"SafeDigit", // 0x31
|
||||
"LoseInventory", // 0x32
|
||||
"", //
|
||||
"PaperShuffleSound", // 0x34
|
||||
"Quit", // 0x35
|
||||
"DossierAdd", // 0x36
|
||||
"DossierBitmap", // 0x37
|
||||
"DossierPrevSuspect", // 0x38
|
||||
"DossierNextSuspect", // 0x39
|
||||
"DossierChgSheet", // 0x3a
|
||||
"DiaryLocList", // 0x3b
|
||||
"DiaryPage", // 0x3c
|
||||
"DiaryInvList", // 0x3d
|
||||
"DiaryPageTurn", // 0x3e
|
||||
"DiaryGoLoc", // 0x3f
|
||||
"SaveGame", // 0x40
|
||||
"LoadGame", // 0x41
|
||||
"RestartGame", // 0x42
|
||||
"AskSave", // 0x43
|
||||
"SetModifiedFlag", // 0x44
|
||||
"PhoneClip", // 0x45
|
||||
"PoliceClip", // 0x46
|
||||
"AMRadioClip", // 0x47
|
||||
"\nsetting ", // 0x48
|
||||
"debug ", // 0x49
|
||||
"\ndefine ", // 0x4a
|
||||
"", //
|
||||
"variables", // 0x4c
|
||||
"", //
|
||||
"", //
|
||||
"rects", // 0x4f
|
||||
""}; // 0x50 (short id)
|
||||
|
||||
Decompiler::Decompiler(char *buf, uint32 fileSize, bool mac) {
|
||||
|
||||
Common::Array<byte> array;
|
||||
uint32 i = 0;
|
||||
while (i < fileSize) {
|
||||
array.push_back(buf[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
Common::String firstBytes((const char *)array.begin(), (const char *)array.begin() + kHeaderSize);
|
||||
|
||||
if (firstBytes != kHeader) {
|
||||
_result = Common::String(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
decompile(array, mac);
|
||||
}
|
||||
|
||||
void Decompiler::decompile(Common::Array<byte> &buffer, bool mac) {
|
||||
Common::Array<byte>::iterator it = buffer.begin();
|
||||
|
||||
Common::String ss;
|
||||
bool inDefineRects = false;
|
||||
for (it += kHeaderSize; it != buffer.end();) {
|
||||
byte b = *it++;
|
||||
if (b == kCodeString) {
|
||||
byte len = *it++;
|
||||
Common::String s((const char *)it, (const char *)it + len);
|
||||
it += len;
|
||||
ss += Common::String::format("\"%s\"", s.c_str());
|
||||
} else if (b == kCodeShortLiteral || b == kCodeShortId) {
|
||||
byte b1 = *it++;
|
||||
byte b2 = *it++;
|
||||
uint number = mac ? b2 + (b1 << 8) : b1 + (b2 << 8);
|
||||
if (b == kCodeShortId)
|
||||
ss += "k";
|
||||
ss += Common::String::format("%d", number);
|
||||
} else if (b == kCodeRect && inDefineRects) {
|
||||
ss += "RECT"; // override CRect
|
||||
} else if (b <= kCodeShortId && strlen(kCodeTable[b]) > 0) {
|
||||
ss += kCodeTable[b];
|
||||
} else {
|
||||
error("decompile(): Unknown byte code (%d %c)", b, b);
|
||||
}
|
||||
|
||||
if (b == kCodeRects) {
|
||||
inDefineRects = true;
|
||||
} else if (b == kCodeBraceClose && inDefineRects) {
|
||||
inDefineRects = false;
|
||||
}
|
||||
}
|
||||
ss += "\ndefine locations { k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14 }";
|
||||
_result = ss;
|
||||
}
|
||||
|
||||
Common::String Decompiler::getResult() const {
|
||||
return _result;
|
||||
}
|
||||
|
||||
} // namespace Private
|
||||
44
engines/private/decompiler.h
Normal file
44
engines/private/decompiler.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
// Heavily based on code by jdieguez
|
||||
|
||||
#ifndef PRIVATE_DECOMPILER_H
|
||||
#define PRIVATE_DECOMPILER_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/str.h"
|
||||
|
||||
namespace Private {
|
||||
|
||||
class Decompiler {
|
||||
public:
|
||||
Decompiler(char *buf, uint32 fileSize, bool mac = false);
|
||||
Common::String getResult() const;
|
||||
|
||||
private:
|
||||
void decompile(Common::Array<byte> &buffer, bool mac);
|
||||
Common::String _result;
|
||||
};
|
||||
|
||||
} // namespace Private
|
||||
|
||||
#endif
|
||||
284
engines/private/detection.cpp
Normal file
284
engines/private/detection.cpp
Normal file
@@ -0,0 +1,284 @@
|
||||
/* 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 "base/plugins.h"
|
||||
#include "common/translation.h"
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
#include "private/private.h"
|
||||
#include "private/detection.h"
|
||||
|
||||
static const DebugChannelDef debugFlagList[] = {
|
||||
{Private::kPrivateDebugFunction, "function", "Function execution debug channel"},
|
||||
{Private::kPrivateDebugCode, "code", "Code execution debug channel"},
|
||||
{Private::kPrivateDebugScript, "script", "Script execution debug channel"},
|
||||
DEBUG_CHANNEL_END
|
||||
};
|
||||
|
||||
namespace Private {
|
||||
static const PlainGameDescriptor privateGames[] = {
|
||||
{ "private-eye", "Private Eye" },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
static const ADGameDescription gameDescriptions[] = {
|
||||
{
|
||||
"private-eye", // US release
|
||||
nullptr,
|
||||
AD_ENTRY2s("pvteye.z", "b682118cda6a42fa89833cae2b8824bd", 271895,
|
||||
"intro.smk", "270a1d0a29df122fc3d1d38e655161a7", 7310984),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO3(GUIO_NOMIDI, GAMEOPTION_SFX_SUBTITLES, GAMEOPTION_HIGHLIGHT_MASKS)
|
||||
},
|
||||
{
|
||||
"private-eye", // Demo from the US release v1.0.0.23
|
||||
"Demo",
|
||||
AD_ENTRY2s("pvteye.z", "af383c813157810e89d8d6d595895ff7", 263893,
|
||||
"bklynlgo.bmp", "1dfb703349a46f8ec183de107992b7f5", 33118),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO,
|
||||
GUIO3(GUIO_NOMIDI, GAMEOPTION_SFX_SUBTITLES, GAMEOPTION_HIGHLIGHT_MASKS)
|
||||
},
|
||||
{
|
||||
"private-eye", // EU release (UK)
|
||||
nullptr,
|
||||
AD_ENTRY2s("pvteye.z", "d9ce391395701615e8b5d04bc4bf7ec3", 284699,
|
||||
"bklynlgo.bmp", "1dfb703349a46f8ec183de107992b7f5", 33118),
|
||||
Common::EN_GRB,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO3(GUIO_NOMIDI, GAMEOPTION_SFX_SUBTITLES, GAMEOPTION_HIGHLIGHT_MASKS)
|
||||
},
|
||||
{
|
||||
"private-eye", // Demo from the EU release
|
||||
"Demo",
|
||||
AD_ENTRY2s("pvteye.z", "01ca8641970189cb2ca3a96526026091", 284129,
|
||||
"bklynlgo.bmp", "1dfb703349a46f8ec183de107992b7f5", 33118),
|
||||
Common::EN_GRB,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO,
|
||||
GUIO3(GUIO_NOMIDI, GAMEOPTION_SFX_SUBTITLES, GAMEOPTION_HIGHLIGHT_MASKS)
|
||||
},
|
||||
{
|
||||
"private-eye", // Demo from PCGamer Disc 2.6 JULY 1996 v1.0.0.12
|
||||
"Demo",
|
||||
AD_ENTRY2s("pvteye.z", "8ef908e212bb9c1e10f5e3c81f56682c", 263893,
|
||||
"bklynlgo.bmp", "1dfb703349a46f8ec183de107992b7f5", 33118),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO,
|
||||
GUIO3(GUIO_NOMIDI, GAMEOPTION_SFX_SUBTITLES, GAMEOPTION_HIGHLIGHT_MASKS)
|
||||
},
|
||||
{
|
||||
"private-eye", // Another demo
|
||||
"Demo",
|
||||
AD_ENTRY2s("pvteye.z", "af383c813157810e89d8d6d595895ff7", 271214,
|
||||
"bklynlgo.bmp", "1dfb703349a46f8ec183de107992b7f5", 33118),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO,
|
||||
GUIO3(GUIO_NOMIDI, GAMEOPTION_SFX_SUBTITLES, GAMEOPTION_HIGHLIGHT_MASKS)
|
||||
},
|
||||
{
|
||||
"private-eye", // EU release (ES)
|
||||
nullptr,
|
||||
AD_ENTRY2s("pvteye.ex_", "f41770550ab717086b2d0c805fef4b8f", 498176,
|
||||
"bklynlgo.bmp", "1dfb703349a46f8ec183de107992b7f5", 33118),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO3(GUIO_NOMIDI, GAMEOPTION_SFX_SUBTITLES, GAMEOPTION_HIGHLIGHT_MASKS)
|
||||
},
|
||||
{
|
||||
"private-eye", // Demo from the EU release (ES)
|
||||
"Demo",
|
||||
AD_ENTRY2s("pvtdemo.ex_", "048f751acd7a0f1a87b20d6dc5229210", 497152,
|
||||
"bklynlgo.bmp", "1dfb703349a46f8ec183de107992b7f5", 33118),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO,
|
||||
GUIO3(GUIO_NOMIDI, GAMEOPTION_SFX_SUBTITLES, GAMEOPTION_HIGHLIGHT_MASKS)
|
||||
},
|
||||
{
|
||||
"private-eye", // EU release (FR)
|
||||
nullptr,
|
||||
AD_ENTRY2s("pvteye.ex_", "ae0dec43b2f54d45c8a1c93e97092141", 600576,
|
||||
"bklynlgo.bmp", "1dfb703349a46f8ec183de107992b7f5", 33118),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GUIO_NOMIDI, GAMEOPTION_HIGHLIGHT_MASKS)
|
||||
},
|
||||
{
|
||||
"private-eye", // EU release (DE)
|
||||
nullptr,
|
||||
AD_ENTRY2s("pvteye.ex_", "5ca171c4e8d804c7277887277d049f03", 600576,
|
||||
"bklynlgo.bmp", "1dfb703349a46f8ec183de107992b7f5", 33118),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GUIO_NOMIDI, GAMEOPTION_HIGHLIGHT_MASKS)
|
||||
},
|
||||
{
|
||||
"private-eye", // Promotional demo disc
|
||||
"Demo",
|
||||
AD_ENTRY2s("pvteye.z", "adb2ceca453da546d5e86baad0c73cd1", 262537,
|
||||
"bklynlgo.bmp", "1dfb703349a46f8ec183de107992b7f5", 33118),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO,
|
||||
GUIO2(GUIO_NOMIDI, GAMEOPTION_HIGHLIGHT_MASKS)
|
||||
},
|
||||
{
|
||||
"private-eye", // Demo from the EU release (DE)
|
||||
"Demo",
|
||||
AD_ENTRY2s("pvtdemo.ex_", "17156cbac7d14b08f4e351ac0e16a889", 599040,
|
||||
"bklynlgo.bmp", "1dfb703349a46f8ec183de107992b7f5", 33118),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO,
|
||||
GUIO2(GUIO_NOMIDI, GAMEOPTION_HIGHLIGHT_MASKS)
|
||||
},
|
||||
{
|
||||
"private-eye", // Demo from the EU release (FR)
|
||||
"Demo",
|
||||
AD_ENTRY2s("pvtdemo.ex_", "ad2156a762b3e376fda1b791a9491ea8", 599040,
|
||||
"bklynlgo.bmp", "1dfb703349a46f8ec183de107992b7f5", 33118),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO,
|
||||
GUIO2(GUIO_NOMIDI, GAMEOPTION_HIGHLIGHT_MASKS)
|
||||
},
|
||||
{
|
||||
"private-eye", // RU release
|
||||
nullptr,
|
||||
AD_ENTRY2s("pvteye.z", "b682118cda6a42fa89833cae2b8824bd", 271895,
|
||||
"intro.smk", "61cc13c9e4e2affd574087209df5c4a4", 7241368),
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GUIO_NOMIDI, GAMEOPTION_HIGHLIGHT_MASKS)
|
||||
},
|
||||
{
|
||||
"private-eye", // KO release
|
||||
nullptr,
|
||||
AD_ENTRY2s("pvteye.z", "b682118cda6a42fa89833cae2b8824bd", 271895,
|
||||
"intro.smk", "288f5f61311eb10fc6861707c340c15e", 7195200),
|
||||
Common::KO_KOR,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GUIO_NOMIDI, GAMEOPTION_HIGHLIGHT_MASKS)
|
||||
},
|
||||
{
|
||||
"private-eye", // JP release
|
||||
nullptr,
|
||||
AD_ENTRY2s("pvteye.z", "f5fb6e89e98294a09ff21e72282b58dc", 239066,
|
||||
"intro.smk", "b8d15a522f896ccbe4539394b6b8ec8a", 7202836),
|
||||
Common::JA_JPN,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GUIO_NOMIDI, GAMEOPTION_HIGHLIGHT_MASKS)
|
||||
},
|
||||
{
|
||||
"private-eye", // MacOS release (US)
|
||||
nullptr,
|
||||
AD_ENTRY2s("game.mac", "d:33553cc04813d3f658bbe9d548377878", 81894,
|
||||
"bklynlgo.bmp", "d:1dfb703349a46f8ec183de107992b7f5", 33118),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO3(GUIO_NOMIDI, GAMEOPTION_SFX_SUBTITLES, GAMEOPTION_HIGHLIGHT_MASKS)
|
||||
},
|
||||
{
|
||||
"private-eye", // MacOS release (US) uninstalled
|
||||
0,
|
||||
AD_ENTRY1s("Private Eye Installer", "d:02533427ebdf26d5dd12cee8e9f4de4d", 1647309),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"private-eye", // MacOS release (JP) uninstalled
|
||||
0,
|
||||
AD_ENTRY1s("xn--16jc8na7ay6a0eyg9e5nud0e4525d", "d:113b57e2f6bdaf1146fe83fe0f992891", 1477309),
|
||||
Common::JA_JPN,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"private-eye", // MacOS demo (US)
|
||||
"Demo",
|
||||
AD_ENTRY2s("demogame.mac", "d:cfbceaa8b91f0f53c745db61d1bc9749", 6103,
|
||||
"bklynlgo.bmp", "d:1dfb703349a46f8ec183de107992b7f5", 33118),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_DEMO,
|
||||
GUIO3(GUIO_NOMIDI, GAMEOPTION_SFX_SUBTITLES, GAMEOPTION_HIGHLIGHT_MASKS)
|
||||
},
|
||||
{
|
||||
"private-eye", // MacOS demo (US) uninstalled
|
||||
0,
|
||||
AD_ENTRY1s("Private Eye Demo Installer", "d:e7665ddc5e6d932c4a65598ecc4ec7d2", 1626393),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
AD_TABLE_END_MARKER
|
||||
};
|
||||
} // End of namespace Private
|
||||
|
||||
static const char *const directoryGlobs[] = {
|
||||
"support",
|
||||
"intro",
|
||||
nullptr
|
||||
};
|
||||
|
||||
class PrivateMetaEngineDetection : public AdvancedMetaEngineDetection<ADGameDescription> {
|
||||
public:
|
||||
PrivateMetaEngineDetection() : AdvancedMetaEngineDetection(Private::gameDescriptions, Private::privateGames) {
|
||||
_maxScanDepth = 2;
|
||||
_directoryGlobs = directoryGlobs;
|
||||
}
|
||||
|
||||
const char *getName() const override {
|
||||
return "private";
|
||||
}
|
||||
|
||||
const char *getEngineName() const override {
|
||||
return "Private Eye";
|
||||
}
|
||||
|
||||
const char *getOriginalCopyright() const override {
|
||||
return "Copyright (C) Brooklyn Multimedia";
|
||||
}
|
||||
|
||||
const DebugChannelDef *getDebugChannels() const override {
|
||||
return debugFlagList;
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_PLUGIN_STATIC(PRIVATE_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, PrivateMetaEngineDetection);
|
||||
7
engines/private/detection.h
Normal file
7
engines/private/detection.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef PRIVATE_DETECTION_H
|
||||
#define PRIVATE_DETECTION_H
|
||||
|
||||
#define GAMEOPTION_SFX_SUBTITLES GUIO_GAMEOPTIONS1
|
||||
#define GAMEOPTION_HIGHLIGHT_MASKS GUIO_GAMEOPTIONS2
|
||||
|
||||
#endif // PRIVATE_DETECTION_H
|
||||
903
engines/private/funcs.cpp
Normal file
903
engines/private/funcs.cpp
Normal file
@@ -0,0 +1,903 @@
|
||||
/* 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/str.h"
|
||||
#include "common/system.h"
|
||||
#include "common/timer.h"
|
||||
|
||||
#include "private/grammar.h"
|
||||
#include "private/private.h"
|
||||
#include "private/tokens.h"
|
||||
|
||||
namespace Private {
|
||||
|
||||
static void fChgMode(ArgArray args) {
|
||||
// assert types
|
||||
assert(args.size() == 2 || args.size() == 3);
|
||||
assert(args[0].type == NUM);
|
||||
|
||||
if (args.size() == 2)
|
||||
debugC(1, kPrivateDebugScript, "ChgMode(%d, %s)", args[0].u.val, args[1].u.sym->name->c_str());
|
||||
else if (args.size() == 3)
|
||||
debugC(1, kPrivateDebugScript, "ChgMode(%d, %s, %s)", args[0].u.val, args[1].u.sym->name->c_str(), args[2].u.sym->name->c_str());
|
||||
else
|
||||
assert(0);
|
||||
|
||||
g_private->_mode = args[0].u.val;
|
||||
g_private->_nextSetting = args[1].u.sym->name->c_str();
|
||||
|
||||
if (g_private->_mode == 0) {
|
||||
g_private->_origin = Common::Point(kOriginZero[0], kOriginZero[1]);
|
||||
} else if (g_private->_mode == 1) {
|
||||
g_private->_origin = Common::Point(kOriginOne[0], kOriginOne[1]);
|
||||
} else
|
||||
assert(0);
|
||||
|
||||
if (args.size() == 3) {
|
||||
Symbol *location = g_private->maps.lookupLocation(args[2].u.sym->name);
|
||||
g_private->setLocationAsVisited(location);
|
||||
|
||||
// set a game flag when visiting the police station.
|
||||
if (!g_private->isDemo()) {
|
||||
if (*(args[2].u.sym->name) == g_private->getPoliceStationLocation()) {
|
||||
Common::String beenDowntownName = g_private->getBeenDowntownVariable();
|
||||
Symbol *beenDowntown = g_private->maps.lookupVariable(&beenDowntownName);
|
||||
setSymbol(beenDowntown, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (g_private->_mode == 0) {
|
||||
// This is the only place where this should be used
|
||||
if (g_private->_noStopSounds) {
|
||||
g_private->_noStopSounds = false;
|
||||
} else {
|
||||
g_private->stopSounds();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fVSPicture(ArgArray args) {
|
||||
assert(args[0].type == STRING);
|
||||
debugC(1, kPrivateDebugScript, "VSPicture(%s)", args[0].u.str);
|
||||
g_private->_nextVS = args[0].u.str;
|
||||
}
|
||||
|
||||
static void fDiaryLocList(ArgArray args) {
|
||||
int x1, y1, x2, y2;
|
||||
assert(args[0].type == NUM);
|
||||
assert(args[1].type == NUM);
|
||||
assert(args[2].type == NUM);
|
||||
assert(args[3].type == NUM);
|
||||
|
||||
g_private->_currentDiaryPage = -1;
|
||||
|
||||
debugC(1, kPrivateDebugScript, "DiaryLocList(%d, %d, %d, %d)", args[0].u.val, args[1].u.val, args[2].u.val, args[3].u.val);
|
||||
|
||||
x2 = args[0].u.val;
|
||||
y2 = args[1].u.val;
|
||||
|
||||
x1 = args[2].u.val;
|
||||
y1 = args[3].u.val;
|
||||
|
||||
Common::Rect rect(x1, y1, x2, y2);
|
||||
g_private->loadLocations(rect);
|
||||
}
|
||||
|
||||
static void fDiaryGoLoc(ArgArray args) {
|
||||
debugC(1, kPrivateDebugScript, "DiaryGoLoc(%d, ..)", args[0].u.val);
|
||||
|
||||
ExitInfo e;
|
||||
|
||||
e.rect = *args[1].u.rect;
|
||||
e.nextSetting = g_private->getDiaryMiddleSetting();
|
||||
|
||||
if (args[0].u.val) {
|
||||
e.cursor = "kTurnRight";
|
||||
g_private->_diaryNextPageExit = e;
|
||||
} else {
|
||||
e.cursor = "kTurnLeft";
|
||||
g_private->_diaryPrevPageExit = e;
|
||||
}
|
||||
|
||||
g_private->_exits.push_front(e);
|
||||
}
|
||||
|
||||
static void fDiaryPageTurn(ArgArray args) {
|
||||
debugC(1, kPrivateDebugScript, "DiaryPageTurn(%d, ..)", args[0].u.val);
|
||||
|
||||
ExitInfo e;
|
||||
e.nextSetting = g_private->getDiaryMiddleSetting();
|
||||
e.rect = *args[1].u.rect;
|
||||
|
||||
if (args[0].u.val == 1) {
|
||||
e.cursor = "kTurnRight";
|
||||
|
||||
if (g_private->_currentDiaryPage >= (int)g_private->_diaryPages.size() - 1) {
|
||||
e.nextSetting = g_private->getDiaryLastPageSetting();
|
||||
}
|
||||
|
||||
g_private->_diaryNextPageExit = e;
|
||||
} else {
|
||||
e.cursor = "kTurnLeft";
|
||||
|
||||
if (g_private->_currentDiaryPage <= 0) {
|
||||
e.nextSetting = g_private->getDiaryTOCSetting();
|
||||
}
|
||||
|
||||
g_private->_diaryPrevPageExit = e;
|
||||
}
|
||||
|
||||
g_private->_exits.push_front(e);
|
||||
}
|
||||
|
||||
static void fDiaryPage(ArgArray args) {
|
||||
debugC(1, kPrivateDebugScript, "DiaryPage(%d, %d, %d, %d, ..)", args[0].u.rect->left, args[0].u.rect->top, args[0].u.rect->right, args[0].u.rect->bottom);
|
||||
g_private->loadMemories(*args[0].u.rect, args[1].u.val, args[2].u.val);
|
||||
}
|
||||
|
||||
static void fDiaryInvList(ArgArray args) {
|
||||
debugC(1, kPrivateDebugScript, "DiaryInvList(%d, ..)", args[0].u.val);
|
||||
|
||||
g_private->_currentDiaryPage = g_private->_diaryPages.size();
|
||||
|
||||
const Common::Rect *r1 = args[1].u.rect;
|
||||
const Common::Rect *r2 = args[2].u.rect;
|
||||
|
||||
g_private->loadInventory(args[0].u.val, *r1, *r2);
|
||||
}
|
||||
|
||||
static void fgoto(ArgArray args) {
|
||||
// assert types
|
||||
debugC(1, kPrivateDebugScript, "goto(%s)", args[0].u.str);
|
||||
g_private->_nextSetting = args[0].u.str;
|
||||
}
|
||||
|
||||
static void fSyncSound(ArgArray args) {
|
||||
assert(args[0].type == STRING);
|
||||
assert(args[1].type == NAME);
|
||||
debugC(1, kPrivateDebugScript, "SyncSound(%s, %s)", args[0].u.str, args[1].u.sym->name->c_str());
|
||||
g_private->_nextSetting = args[1].u.sym->name->c_str();
|
||||
Common::String s = args[0].u.str;
|
||||
|
||||
if (s != "\"\"") {
|
||||
g_private->drawScreen();
|
||||
|
||||
g_private->stopSounds();
|
||||
g_private->playForegroundSound(s);
|
||||
g_private->waitForSoundsToStop();
|
||||
}
|
||||
}
|
||||
|
||||
static void fQuit(ArgArray args) {
|
||||
debugC(1, kPrivateDebugScript, "Quit()");
|
||||
g_private->quitGame();
|
||||
}
|
||||
|
||||
static void fLoadGame(ArgArray args) {
|
||||
assert(args[0].type == STRING);
|
||||
assert(args[2].type == NAME);
|
||||
debugC(1, kPrivateDebugScript, "LoadGame(%s, %s)", args[0].u.str, args[2].u.sym->name->c_str());
|
||||
MaskInfo m;
|
||||
if (strcmp(args[0].u.str, "\"\"") == 0) // Not sure why the game tries to load an empty mask
|
||||
return;
|
||||
m.surf = g_private->loadMask(args[0].u.str, 0, 0, true);
|
||||
m.cursor = *args[2].u.sym->name;
|
||||
m.nextSetting = "";
|
||||
m.flag1 = nullptr;
|
||||
m.flag2 = nullptr;
|
||||
g_private->_loadGameMask = m;
|
||||
g_private->_masks.push_front(m);
|
||||
}
|
||||
|
||||
static void fSaveGame(ArgArray args) {
|
||||
// assert types
|
||||
debugC(1, kPrivateDebugScript, "SaveGame(%s, %s)", args[0].u.str, args[1].u.sym->name->c_str());
|
||||
MaskInfo m;
|
||||
m.surf = g_private->loadMask(args[0].u.str, 0, 0, true);
|
||||
m.cursor = *args[1].u.sym->name;
|
||||
m.nextSetting = "";
|
||||
m.flag1 = nullptr;
|
||||
m.flag2 = nullptr;
|
||||
g_private->_saveGameMask = m;
|
||||
g_private->_masks.push_front(m);
|
||||
}
|
||||
|
||||
static void fRestartGame(ArgArray args) {
|
||||
assert(args.size() == 0);
|
||||
g_private->restartGame();
|
||||
}
|
||||
|
||||
static void fPoliceBust(ArgArray args) {
|
||||
// assert types
|
||||
assert(args.size() == 1 || args.size() == 2);
|
||||
int mode = (args.size() == 2) ? args[1].u.val : 0;
|
||||
debugC(1, kPrivateDebugScript, "PoliceBust(%d, %d)", args[0].u.val, mode);
|
||||
|
||||
if (mode == 3) {
|
||||
g_private->completePoliceBust();
|
||||
return;
|
||||
}
|
||||
if (mode == 2) {
|
||||
g_private->wallSafeAlarm();
|
||||
return;
|
||||
}
|
||||
if (mode == 1) {
|
||||
// Not implemented: a special mode for police busts
|
||||
// in Marlowe's office that was removed from the game.
|
||||
return;
|
||||
}
|
||||
|
||||
if (args[0].u.val) {
|
||||
g_private->startPoliceBust();
|
||||
} else {
|
||||
g_private->stopPoliceBust();
|
||||
}
|
||||
}
|
||||
|
||||
static void fBustMovie(ArgArray args) {
|
||||
// assert types
|
||||
assert(args.size() == 1);
|
||||
debugC(1, kPrivateDebugScript, "BustMovie(%s)", args[0].u.sym->name->c_str());
|
||||
|
||||
g_private->_nextMovie = g_private->_policeBustMovie;
|
||||
g_private->_nextSetting = args[0].u.sym->name->c_str();
|
||||
|
||||
Common::String memoryPath = g_private->_policeBustMovie;
|
||||
memoryPath.replace('/', '\\');
|
||||
g_private->addMemory(memoryPath);
|
||||
}
|
||||
|
||||
static void fDossierAdd(ArgArray args) {
|
||||
assert(args.size() == 2);
|
||||
Common::String s1 = args[0].u.str;
|
||||
Common::String s2 = args[1].u.str;
|
||||
|
||||
if (s2 == "\"\"") {
|
||||
s2 = "";
|
||||
}
|
||||
|
||||
g_private->addDossier(s1, s2);
|
||||
}
|
||||
|
||||
static void fDossierBitmap(ArgArray args) {
|
||||
assert(args.size() == 2);
|
||||
int x = args[0].u.val;
|
||||
int y = args[1].u.val;
|
||||
assert(x == 40 && y == 30);
|
||||
g_private->loadDossier();
|
||||
}
|
||||
|
||||
static void fDossierChgSheet(ArgArray args) {
|
||||
assert(args.size() == 4);
|
||||
debugC(1, kPrivateDebugScript, "DossierChgSheet(%s,%d,%d,%d)", args[0].u.str, args[1].u.val, args[2].u.val, args[3].u.val);
|
||||
Common::String s(args[0].u.str);
|
||||
MaskInfo m;
|
||||
|
||||
// do nothing if suspect only has one sheet
|
||||
if (g_private->_dossiers[g_private->_dossierSuspect].page2.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int p = args[1].u.val;
|
||||
int x = args[2].u.val;
|
||||
int y = args[3].u.val;
|
||||
|
||||
m.surf = g_private->loadMask(s, x, y, true);
|
||||
m.cursor = g_private->getExitCursor();
|
||||
m.nextSetting = "";
|
||||
m.flag1 = nullptr;
|
||||
m.flag2 = nullptr;
|
||||
if (p == 0)
|
||||
g_private->_dossierPrevSheetMask = m;
|
||||
else if (p == 1)
|
||||
g_private->_dossierNextSheetMask = m;
|
||||
else
|
||||
error("Invalid sheet number in DossierChgSheet %d", p);
|
||||
|
||||
g_private->_masks.push_front(m);
|
||||
}
|
||||
|
||||
static void fDossierPrevSuspect(ArgArray args) {
|
||||
assert(args.size() == 3);
|
||||
Common::String s(args[0].u.str);
|
||||
MaskInfo m;
|
||||
|
||||
if (g_private->_dossierSuspect == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int x = args[1].u.val;
|
||||
int y = args[2].u.val;
|
||||
|
||||
m.surf = g_private->loadMask(s, x, y, true);
|
||||
m.cursor = g_private->getExitCursor();
|
||||
m.nextSetting = "";
|
||||
m.flag1 = nullptr;
|
||||
m.flag2 = nullptr;
|
||||
g_private->_dossierPrevSuspectMask = m;
|
||||
g_private->_masks.push_front(m);
|
||||
}
|
||||
|
||||
static void fDossierNextSuspect(ArgArray args) {
|
||||
assert(args.size() == 3);
|
||||
Common::String s(args[0].u.str);
|
||||
MaskInfo m;
|
||||
|
||||
if ((g_private->_dossierSuspect + 1) >= g_private->_dossiers.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int x = args[1].u.val;
|
||||
int y = args[2].u.val;
|
||||
|
||||
m.surf = g_private->loadMask(s, x, y, true);
|
||||
m.cursor = g_private->getExitCursor();
|
||||
m.nextSetting = "";
|
||||
m.flag1 = nullptr;
|
||||
m.flag2 = nullptr;
|
||||
g_private->_dossierNextSuspectMask = m;
|
||||
g_private->_masks.push_front(m);
|
||||
}
|
||||
|
||||
static void fNoStopSounds(ArgArray args) {
|
||||
assert(args.size() == 0);
|
||||
debugC(1, kPrivateDebugScript, "NoStopSounds()");
|
||||
g_private->_noStopSounds = true;
|
||||
}
|
||||
|
||||
static void fLoseInventory(ArgArray args) {
|
||||
assert(args.size() == 0);
|
||||
debugC(1, kPrivateDebugScript, "LoseInventory()");
|
||||
|
||||
g_private->removeRandomInventory();
|
||||
}
|
||||
|
||||
static void fInventory(ArgArray args) {
|
||||
// assert types
|
||||
Datum b1 = args[0];
|
||||
Datum v1 = args[1];
|
||||
Datum v2 = args[2];
|
||||
Datum e = args[3];
|
||||
Datum i = args[4];
|
||||
Datum c = args[5];
|
||||
|
||||
Datum snd;
|
||||
if (args.size() >= 9)
|
||||
snd = args[8];
|
||||
else {
|
||||
snd.type = STRING;
|
||||
snd.u.str = "\"\"";
|
||||
}
|
||||
|
||||
assert(v1.type == STRING || v1.type == NAME);
|
||||
assert(b1.type == STRING);
|
||||
assert(e.type == NAME || e.type == NUM);
|
||||
assert(snd.type == STRING);
|
||||
assert(i.type == STRING);
|
||||
|
||||
Common::String bmp(i.u.str);
|
||||
assert(g_private->isDemo() || bmp != "\"\"");
|
||||
|
||||
if (v1.type == STRING)
|
||||
assert(strcmp(v1.u.str, "\"\"") == 0);
|
||||
|
||||
debugC(1, kPrivateDebugScript, "Inventory(...)");
|
||||
Common::String mask(b1.u.str);
|
||||
if (mask != "\"\"") {
|
||||
if (bmp != "\"\"" && g_private->inInventory(bmp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MaskInfo m;
|
||||
m.surf = g_private->loadMask(mask, 0, 0, true);
|
||||
|
||||
if (e.type == NUM) {
|
||||
assert(e.u.val == 0);
|
||||
m.nextSetting = "";
|
||||
} else
|
||||
m.nextSetting = e.u.sym->name->c_str();
|
||||
|
||||
m.cursor = g_private->getInventoryCursor();
|
||||
m.point = Common::Point(0, 0);
|
||||
|
||||
if (v1.type == NAME) {
|
||||
m.flag1 = g_private->maps.lookupVariable(v1.u.sym->name);
|
||||
} else
|
||||
m.flag1 = nullptr;
|
||||
|
||||
if (v2.type == NAME) {
|
||||
m.flag2 = g_private->maps.lookupVariable(v2.u.sym->name);
|
||||
} else
|
||||
m.flag2 = nullptr;
|
||||
|
||||
m.inventoryItem = bmp;
|
||||
g_private->_masks.push_front(m);
|
||||
g_private->_toTake = true;
|
||||
Common::String sound(snd.u.str);
|
||||
|
||||
if (sound == "\"\"") {
|
||||
sound = g_private->getTakeLeaveSound();
|
||||
}
|
||||
g_private->playForegroundSound(g_private->_takeLeaveSound, sound);
|
||||
} else {
|
||||
Common::String flag;
|
||||
if (v1.type == NAME) {
|
||||
if (strcmp(c.u.str, "\"REMOVE\"") == 0) {
|
||||
g_private->removeInventory(bmp);
|
||||
} else {
|
||||
flag = *(v1.u.sym->name);
|
||||
g_private->addInventory(bmp, flag);
|
||||
}
|
||||
} else {
|
||||
g_private->addInventory(bmp, flag);
|
||||
}
|
||||
if (v2.type == NAME) {
|
||||
v2.u.sym = g_private->maps.lookupVariable(v2.u.sym->name);
|
||||
v2.u.sym->u.val = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fSetFlag(ArgArray args) {
|
||||
assert(args.size() == 2);
|
||||
assert(args[0].type == NAME && args[1].type == NUM);
|
||||
debugC(1, kPrivateDebugScript, "SetFlag(%s, %d)", args[0].u.sym->name->c_str(), args[1].u.val);
|
||||
args[0].u.sym = g_private->maps.lookupVariable(args[0].u.sym->name);
|
||||
args[0].u.sym->u.val = args[1].u.val;
|
||||
}
|
||||
|
||||
static void fExit(ArgArray args) {
|
||||
// assert types
|
||||
assert(args[2].type == RECT || args[2].type == NAME);
|
||||
debugC(1, kPrivateDebugScript, "Exit(%d %d %d)", args[0].type, args[1].type, args[2].type); //, args[0].u.str, args[1].u.sym->name->c_str(), "RECT");
|
||||
ExitInfo e;
|
||||
|
||||
if (args[0].type == NUM && args[0].u.val == 0)
|
||||
e.nextSetting = "";
|
||||
else
|
||||
e.nextSetting = args[0].u.sym->name->c_str();
|
||||
|
||||
if (args[1].type == NUM && args[1].u.val == 0)
|
||||
e.cursor = "";
|
||||
else
|
||||
e.cursor = *args[1].u.sym->name;
|
||||
|
||||
if (args[2].type == NAME) {
|
||||
Symbol *rect = g_private->maps.lookupRect(args[2].u.sym->name);
|
||||
assert(rect->type == RECT);
|
||||
args[2].u.rect = rect->u.rect;
|
||||
}
|
||||
|
||||
e.rect = *args[2].u.rect;
|
||||
g_private->_exits.push_front(e);
|
||||
}
|
||||
|
||||
static void fSetModifiedFlag(ArgArray args) {
|
||||
// assert types
|
||||
debugC(1, kPrivateDebugScript, "SetModifiedFlag(%d)", args[0].u.val);
|
||||
g_private->_modified = args[0].u.val != 0;
|
||||
}
|
||||
|
||||
static void fPaperShuffleSound(ArgArray args) {
|
||||
assert(args.size() == 0);
|
||||
debugC(1, kPrivateDebugScript, "PaperShuffleSound()");
|
||||
g_private->playForegroundSound(g_private->getPaperShuffleSound());
|
||||
}
|
||||
|
||||
static void fSoundEffect(ArgArray args) {
|
||||
// assert types
|
||||
debugC(1, kPrivateDebugScript, "SoundEffect(%s)", args[0].u.str);
|
||||
Common::String s(args[0].u.str);
|
||||
if (s != "\"\"") {
|
||||
g_private->playForegroundSound(s);
|
||||
} else {
|
||||
g_private->stopSounds();
|
||||
}
|
||||
}
|
||||
|
||||
static void fSound(ArgArray args) {
|
||||
// assert types
|
||||
debugC(1, kPrivateDebugScript, "Sound(%s)", args[0].u.str);
|
||||
if (args.size() == 4) {
|
||||
bool b1 = args[1].u.val != 0;
|
||||
bool b2 = args[2].u.val != 0;
|
||||
int c = args[3].u.val;
|
||||
|
||||
if (!b1 && !b2 && c == 1) {
|
||||
g_private->stopSounds();
|
||||
} else if (!b1 && !b2 && c == 2) {
|
||||
g_private->stopForegroundSounds();
|
||||
} else
|
||||
assert(0);
|
||||
}
|
||||
|
||||
Common::String s(args[0].u.str);
|
||||
if (s != "\"\"") {
|
||||
g_private->playForegroundSound(s);
|
||||
} else {
|
||||
g_private->stopSounds();
|
||||
}
|
||||
}
|
||||
|
||||
static void fLoopedSound(ArgArray args) {
|
||||
// assert types
|
||||
assert(args.size() == 1);
|
||||
debugC(1, kPrivateDebugScript, "LoopedSound(%s)", args[0].u.str);
|
||||
Common::String s(args[0].u.str);
|
||||
|
||||
if (s != "\"\"") {
|
||||
g_private->playBackgroundSound(s);
|
||||
} else {
|
||||
g_private->stopSounds();
|
||||
}
|
||||
}
|
||||
|
||||
static void fViewScreen(ArgArray args) {
|
||||
// assert types
|
||||
debugC(1, kPrivateDebugScript, "WARNING: ViewScreen not implemented!");
|
||||
}
|
||||
|
||||
static void fTransition(ArgArray args) {
|
||||
assert(args[0].type == STRING);
|
||||
assert(args[1].type == NAME);
|
||||
debugC(1, kPrivateDebugScript, "Transition(%s, %s)", args[0].u.str, args[1].u.sym->name->c_str());
|
||||
g_private->_nextMovie = args[0].u.str;
|
||||
g_private->_nextSetting = args[1].u.sym->name->c_str();
|
||||
}
|
||||
|
||||
static void fResume(ArgArray args) {
|
||||
assert(args[0].type == NUM);
|
||||
debugC(1, kPrivateDebugScript, "Resume(%d)", args[0].u.val); // this value is always 1
|
||||
g_private->resumeGame();
|
||||
}
|
||||
|
||||
static void fMovie(ArgArray args) {
|
||||
// assert types
|
||||
assert(args[0].type == STRING);
|
||||
assert(args[1].type == NAME);
|
||||
debugC(1, kPrivateDebugScript, "Movie(%s, %s)", args[0].u.str, args[1].u.sym->name->c_str());
|
||||
Common::String movie = args[0].u.str;
|
||||
Common::String nextSetting = *args[1].u.sym->name;
|
||||
|
||||
if (!g_private->_playedMovies.contains(movie) && movie != "\"\"") {
|
||||
g_private->addMemory(movie);
|
||||
g_private->_nextMovie = movie;
|
||||
g_private->_playedMovies.setVal(movie, true);
|
||||
g_private->_nextSetting = nextSetting;
|
||||
} else if (movie == "\"\"") {
|
||||
g_private->_repeatedMovieExit = nextSetting;
|
||||
debugC(1, kPrivateDebugScript, "repeated movie exit is %s", nextSetting.c_str());
|
||||
} else {
|
||||
debugC(1, kPrivateDebugScript, "movie %s already played", movie.c_str());
|
||||
g_private->_nextSetting = g_private->_repeatedMovieExit;
|
||||
}
|
||||
}
|
||||
|
||||
static void fCRect(ArgArray args) {
|
||||
// assert types
|
||||
debugC(1, kPrivateDebugScript, "CRect(%d, %d, %d, %d)", args[0].u.val, args[1].u.val, args[2].u.val, args[3].u.val);
|
||||
int x1, y1, x2, y2;
|
||||
x1 = args[0].u.val;
|
||||
y1 = args[1].u.val;
|
||||
x2 = args[2].u.val;
|
||||
y2 = args[3].u.val;
|
||||
|
||||
Datum d = Datum();
|
||||
Common::Rect *rect = new Common::Rect(x1, y1, x2, y2);
|
||||
d.type = RECT;
|
||||
d.u.rect = rect;
|
||||
Gen::push(d);
|
||||
g_private->_rects.push_back(rect);
|
||||
}
|
||||
|
||||
static void fBitmap(ArgArray args) {
|
||||
assert(args.size() == 1 || args.size() == 3);
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
const char *f = args[0].u.str;
|
||||
if (args.size() == 3) {
|
||||
x = args[1].u.val;
|
||||
y = args[2].u.val;
|
||||
}
|
||||
|
||||
debugC(1, kPrivateDebugScript, "Bitmap(%s, %d, %d)", f, x, y);
|
||||
Common::String s(args[0].u.str);
|
||||
g_private->loadImage(s, x, y);
|
||||
}
|
||||
|
||||
static void _fMask(ArgArray args, bool drawn) {
|
||||
assert(args.size() == 3 || args.size() == 5);
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
const char *f = args[0].u.str;
|
||||
const char *e = args[1].u.sym->name->c_str();
|
||||
Common::String *c = args[2].u.sym->name;
|
||||
|
||||
if (args.size() == 5) {
|
||||
x = args[3].u.val;
|
||||
y = args[4].u.val;
|
||||
}
|
||||
|
||||
debugC(1, kPrivateDebugScript, "Mask(%s, %s, %s, %d, %d)", f, e, c->c_str(), x, y);
|
||||
const Common::String s(f);
|
||||
|
||||
MaskInfo m;
|
||||
m.surf = g_private->loadMask(s, x, y, drawn);
|
||||
m.nextSetting = e;
|
||||
m.cursor = *c;
|
||||
m.flag1 = nullptr;
|
||||
m.flag2 = nullptr;
|
||||
m.point = Common::Point(x, y);
|
||||
g_private->_masks.push_front(m);
|
||||
}
|
||||
|
||||
static void fMask(ArgArray args) {
|
||||
_fMask(args, false);
|
||||
}
|
||||
static void fMaskDrawn(ArgArray args) {
|
||||
_fMask(args, true);
|
||||
}
|
||||
|
||||
static void fAMRadioClip(ArgArray args) {
|
||||
assert(args.size() <= 4);
|
||||
debugC(1, kPrivateDebugScript, "AMRadioClip(%s,%d,...)", args[0].u.str, args[1].u.val);
|
||||
|
||||
const char *name = args[0].u.str;
|
||||
if (strcmp(name, "\"\"") == 0) {
|
||||
int clipCount = args[1].u.val;
|
||||
g_private->initializeAMRadioChannels(clipCount);
|
||||
return;
|
||||
}
|
||||
|
||||
int priority = args[1].u.val;
|
||||
|
||||
// The third and fourth parameters are numbers followed by an optional '+' character.
|
||||
// Each number is a priority and the '+' indicates that it is to be treated as a range
|
||||
// instead of the default behavior of requiring an exact match.
|
||||
int disabledPriority1 = (args.size() >= 3) ? args[2].u.val : 0;
|
||||
bool exactPriorityMatch1 = (args.size() >= 3) ? (args[2].type != NUM_PLUS) : true;
|
||||
int disabledPriority2 = (args.size() >= 4) ? args[3].u.val : 0;
|
||||
bool exactPriorityMatch2 = (args.size() >= 4) ? (args[3].type != NUM_PLUS) : true;
|
||||
|
||||
Common::String flagName = (args.size() >= 6) ? *(args[4].u.sym->name) : "";
|
||||
int flagValue = (args.size() >= 6) ? args[5].u.val : 0;
|
||||
|
||||
g_private->addRadioClip(g_private->_AMRadio, name, priority,
|
||||
disabledPriority1, exactPriorityMatch1,
|
||||
disabledPriority2, exactPriorityMatch2,
|
||||
flagName, flagValue);
|
||||
}
|
||||
|
||||
static void fPoliceClip(ArgArray args) {
|
||||
assert(args.size() <= 4 || args.size() == 6);
|
||||
debugC(1, kPrivateDebugScript, "PoliceClip(%s,%d,...)", args[0].u.str, args[1].u.val);
|
||||
|
||||
const char *name = args[0].u.str;
|
||||
if (strcmp(name, "\"\"") == 0) {
|
||||
g_private->initializePoliceRadioChannels();
|
||||
return;
|
||||
}
|
||||
|
||||
int priority = args[1].u.val;
|
||||
if (strcmp(name, "\"DISABLE_ONLY\"") == 0) {
|
||||
g_private->disableRadioClips(g_private->_policeRadio, priority);
|
||||
return;
|
||||
}
|
||||
|
||||
// The third and fourth parameters are numbers followed by an optional '+' character.
|
||||
// Each number is a priority and the '+' indicates that it is to be treated as a range
|
||||
// instead of the default behavior of requiring an exact match.
|
||||
int disabledPriority1 = (args.size() >= 3) ? args[2].u.val : 0;
|
||||
bool exactPriorityMatch1 = (args.size() >= 3) ? (args[2].type != NUM_PLUS) : true;
|
||||
int disabledPriority2 = (args.size() >= 4) ? args[3].u.val : 0;
|
||||
bool exactPriorityMatch2 = (args.size() >= 4) ? (args[3].type != NUM_PLUS) : true;
|
||||
|
||||
g_private->addRadioClip(g_private->_policeRadio, name, priority,
|
||||
disabledPriority1, exactPriorityMatch1,
|
||||
disabledPriority2, exactPriorityMatch2,
|
||||
"", 0);
|
||||
}
|
||||
|
||||
static void fPhoneClip(ArgArray args) {
|
||||
if (args.size() == 2) {
|
||||
debugC(1, kPrivateDebugScript, "Unimplemented PhoneClip special case");
|
||||
return;
|
||||
}
|
||||
assert(args.size() == 6);
|
||||
debugC(1, kPrivateDebugScript, "PhoneClip(%s,%d,%d,%d,%s,%d)",
|
||||
args[0].u.str, args[1].u.val, args[2].u.val, args[3].u.val, args[4].u.sym->name->c_str(), args[5].u.val);
|
||||
|
||||
const char *name = args[0].u.str;
|
||||
bool once = (args[1].u.val != 0);
|
||||
int startIndex = args[2].u.val;
|
||||
int endIndex = args[3].u.val;
|
||||
Common::String *flagName = args[4].u.sym->name;
|
||||
int flagValue = args[5].u.val;
|
||||
assert(startIndex <= endIndex);
|
||||
|
||||
g_private->addPhone(name, once, startIndex, endIndex, *flagName, flagValue);
|
||||
}
|
||||
|
||||
static void fSoundArea(ArgArray args) {
|
||||
// assert types
|
||||
//char *n;
|
||||
Common::String n;
|
||||
if (args[1].type == NAME)
|
||||
n = *(args[1].u.sym->name);
|
||||
else if (args[1].type == STRING) {
|
||||
n = Common::String(args[1].u.str);
|
||||
Common::replace(n, "\"", "");
|
||||
Common::replace(n, "\"", "");
|
||||
} else
|
||||
error("Invalid input for SoundArea");
|
||||
|
||||
debugC(1, kPrivateDebugScript, "SoundArea(%s, %s, ..)", args[0].u.str, n.c_str());
|
||||
Common::String s = args[0].u.str;
|
||||
MaskInfo m;
|
||||
if (n == "kAMRadio") {
|
||||
m.surf = g_private->loadMask(s, 0, 0, true);
|
||||
m.cursor = *args[2].u.sym->name;
|
||||
m.nextSetting = "";
|
||||
m.flag1 = nullptr;
|
||||
m.flag2 = nullptr;
|
||||
g_private->_AMRadioArea = m;
|
||||
g_private->_masks.push_front(m);
|
||||
} else if (n == "kPoliceRadio") {
|
||||
m.surf = g_private->loadMask(s, 0, 0, true);
|
||||
m.cursor = *args[2].u.sym->name;
|
||||
m.nextSetting = "";
|
||||
m.flag1 = nullptr;
|
||||
m.flag2 = nullptr;
|
||||
g_private->_policeRadioArea = m;
|
||||
g_private->_masks.push_front(m);
|
||||
} else if (n == "kPhone") {
|
||||
m.surf = g_private->loadMask(s, 0, 0, true);
|
||||
m.cursor = *args[2].u.sym->name;
|
||||
m.nextSetting = "";
|
||||
m.flag1 = nullptr;
|
||||
m.flag2 = nullptr;
|
||||
g_private->_phoneArea = m;
|
||||
g_private->initializePhoneOnDesktop();
|
||||
} else
|
||||
error("Invalid type for SoundArea");
|
||||
}
|
||||
|
||||
static void fSafeDigit(ArgArray args) {
|
||||
assert(args[0].type == NUM);
|
||||
assert(args[1].type == RECT);
|
||||
debugC(1, kPrivateDebugScript, "SafeDigit(%d, ..)", args[0].u.val);
|
||||
g_private->addSafeDigit(args[0].u.val, args[1].u.rect);
|
||||
}
|
||||
|
||||
static void fAskSave(ArgArray args) {
|
||||
// This is not needed, since scummvm will take care of this
|
||||
debugC(1, kPrivateDebugScript, "WARNING: AskSave is partially implemented");
|
||||
g_private->_nextSetting = *args[0].u.sym->name;
|
||||
}
|
||||
|
||||
static void fTimer(ArgArray args) {
|
||||
assert(args.size() == 2 || args.size() == 3);
|
||||
|
||||
if (args.size() == 3)
|
||||
debugC(1, kPrivateDebugScript, "Timer(%d, %s, %s)", args[0].u.val, args[1].u.sym->name->c_str(), args[2].u.sym->name->c_str());
|
||||
else
|
||||
debugC(1, kPrivateDebugScript, "Timer(%d, %s)", args[0].u.val, args[1].u.str);
|
||||
|
||||
int32 delay = args[0].u.val * 1000; // seconds => milliseconds
|
||||
if (delay > 0) {
|
||||
Common::String skipSetting;
|
||||
if (args.size() == 3) {
|
||||
skipSetting = *(args[2].u.sym->name);
|
||||
}
|
||||
g_private->setTimer(delay, *(args[1].u.sym->name), skipSetting);
|
||||
} else if (delay == 0) {
|
||||
g_private->_nextSetting = *(args[1].u.sym->name);
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
const FuncTable funcTable[] = {
|
||||
|
||||
// Control flow
|
||||
{fChgMode, "ChgMode"},
|
||||
{fResume, "Resume"},
|
||||
{fgoto, "goto"},
|
||||
{fTimer, "Timer"},
|
||||
|
||||
// Variables
|
||||
{fSetFlag, "SetFlag"},
|
||||
{fSetModifiedFlag, "SetModifiedFlag"},
|
||||
|
||||
// Sounds
|
||||
{fSound, "Sound"},
|
||||
{fSoundEffect, "SoundEffect"},
|
||||
{fLoopedSound, "LoopedSound"},
|
||||
{fNoStopSounds, "NoStopSounds"},
|
||||
{fSyncSound, "SyncSound"},
|
||||
{fAMRadioClip, "AMRadioClip"},
|
||||
{fPoliceClip, "PoliceClip"},
|
||||
{fPhoneClip, "PhoneClip"},
|
||||
{fSoundArea, "SoundArea"},
|
||||
{fPaperShuffleSound, "PaperShuffleSound"},
|
||||
|
||||
// Images
|
||||
{fBitmap, "Bitmap"},
|
||||
{fMask, "Mask"},
|
||||
{fMaskDrawn, "MaskDrawn"},
|
||||
{fVSPicture, "VSPicture"},
|
||||
{fViewScreen, "ViewScreen"},
|
||||
{fExit, "Exit"},
|
||||
|
||||
// Video
|
||||
{fTransition, "Transition"},
|
||||
{fMovie, "Movie"},
|
||||
|
||||
// Diary
|
||||
{fDiaryLocList, "DiaryLocList"},
|
||||
{fDiaryPageTurn, "DiaryPageTurn"},
|
||||
{fDiaryPage, "DiaryPage"},
|
||||
{fDiaryInvList, "DiaryInvList"},
|
||||
{fDiaryGoLoc, "DiaryGoLoc"},
|
||||
|
||||
// Main menu
|
||||
{fQuit, "Quit"},
|
||||
{fLoadGame, "LoadGame"},
|
||||
{fSaveGame, "SaveGame"},
|
||||
{fAskSave, "AskSave"},
|
||||
{fRestartGame, "RestartGame"},
|
||||
|
||||
// Dossiers
|
||||
{fDossierAdd, "DossierAdd"},
|
||||
{fDossierChgSheet, "DossierChgSheet"},
|
||||
{fDossierBitmap, "DossierBitmap"},
|
||||
{fDossierPrevSuspect, "DossierPrevSuspect"},
|
||||
{fDossierNextSuspect, "DossierNextSuspect"},
|
||||
|
||||
// Inventory
|
||||
{fLoseInventory, "LoseInventory"},
|
||||
{fInventory, "Inventory"},
|
||||
|
||||
// PoliceBust
|
||||
{fPoliceBust, "PoliceBust"},
|
||||
{fBustMovie, "BustMovie"},
|
||||
|
||||
// Others
|
||||
{fSafeDigit, "SafeDigit"},
|
||||
{fCRect, "CRect"},
|
||||
|
||||
{nullptr, nullptr}};
|
||||
|
||||
void call(const char *name, const ArgArray &args) {
|
||||
Common::String n(name);
|
||||
if (!g_private->_functions.contains(n)) {
|
||||
error("I don't know how to execute %s", name);
|
||||
}
|
||||
|
||||
void (*func)(ArgArray) = (void (*)(ArgArray))g_private->_functions.getVal(n);
|
||||
func(args);
|
||||
}
|
||||
|
||||
} // End of namespace Private
|
||||
1726
engines/private/grammar.cpp
Normal file
1726
engines/private/grammar.cpp
Normal file
File diff suppressed because it is too large
Load Diff
147
engines/private/grammar.h
Normal file
147
engines/private/grammar.h
Normal file
@@ -0,0 +1,147 @@
|
||||
/* 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 PRIVATE_GRAMMAR_H
|
||||
#define PRIVATE_GRAMMAR_H
|
||||
|
||||
#include "common/str.h"
|
||||
#include "common/hash-str.h"
|
||||
#include "common/hash-ptr.h"
|
||||
#include "common/queue.h"
|
||||
#include "common/list.h"
|
||||
#include "common/array.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
#include "private/symbol.h"
|
||||
|
||||
#define NSTACK 256
|
||||
#define NPROG 10000
|
||||
|
||||
namespace Private {
|
||||
|
||||
typedef struct Datum { /* interpreter stack type */
|
||||
short type;
|
||||
union {
|
||||
int val;
|
||||
const char *str;
|
||||
Symbol *sym;
|
||||
Common::Rect *rect;
|
||||
} u;
|
||||
} Datum;
|
||||
|
||||
typedef struct Arg {
|
||||
int n;
|
||||
int (** inst)();
|
||||
} Arg;
|
||||
|
||||
typedef int (* Inst)(); /* machine instruction */
|
||||
#define STOP (Inst) 0
|
||||
|
||||
typedef Common::HashMap<void *, Common::String *> PtrToName;
|
||||
|
||||
void initInsts();
|
||||
void initFuncs();
|
||||
|
||||
namespace Settings {
|
||||
|
||||
typedef struct Setting {
|
||||
Datum stack[NSTACK]; /* the stack */
|
||||
Inst prog[NPROG]; /* the machine */
|
||||
} Setting;
|
||||
|
||||
typedef Common::HashMap<Common::String, Setting *> SettingMap;
|
||||
|
||||
class SettingMaps {
|
||||
public:
|
||||
SettingMaps();
|
||||
~SettingMaps();
|
||||
|
||||
Setting *_setting;
|
||||
SettingMap _map;
|
||||
|
||||
void init();
|
||||
void save(const char *);
|
||||
void load(const Common::String &);
|
||||
|
||||
private:
|
||||
Common::Array<Setting *> _settings;
|
||||
};
|
||||
|
||||
extern SettingMaps *g_setts;
|
||||
|
||||
}
|
||||
|
||||
// Funtions
|
||||
|
||||
typedef Common::Array<Datum> ArgArray;
|
||||
void call(const char *, const ArgArray &);
|
||||
|
||||
// Code Generation and Execution
|
||||
|
||||
namespace Gen {
|
||||
|
||||
class VM {
|
||||
public:
|
||||
Datum *_stack; /* the stack */
|
||||
Datum *_stackp; /* next free spot on stack */
|
||||
|
||||
Inst *_progp; /* next free spot for code generation */
|
||||
Inst *_prog; /* the machine */
|
||||
Inst *_pc; /* program counter during execution */
|
||||
void run(); /* run the virtual machine */
|
||||
};
|
||||
|
||||
extern VM *g_vm;
|
||||
|
||||
Datum pop();
|
||||
int push(const Datum &);
|
||||
|
||||
Inst *code(const Inst &);
|
||||
int eval();
|
||||
int add();
|
||||
int negate();
|
||||
int power();
|
||||
int assign();
|
||||
int bltin();
|
||||
int varpush();
|
||||
int constpush();
|
||||
int strpush();
|
||||
int funcpush();
|
||||
int print();
|
||||
int ifcode();
|
||||
int fail();
|
||||
int lt();
|
||||
int gt();
|
||||
int le();
|
||||
int ge();
|
||||
int eq();
|
||||
int ne();
|
||||
int randbool();
|
||||
|
||||
// Code Execution
|
||||
|
||||
void execute(Inst *);
|
||||
|
||||
}
|
||||
|
||||
} // End of namespace Private
|
||||
|
||||
#endif
|
||||
224
engines/private/grammar.y
Normal file
224
engines/private/grammar.y
Normal file
@@ -0,0 +1,224 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Heavily inspired by hoc
|
||||
// Copyright (C) AT&T 1995
|
||||
// All Rights Reserved
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software and
|
||||
// its documentation for any purpose and without fee is hereby
|
||||
// granted, provided that the above copyright notice appear in all
|
||||
// copies and that both that the copyright notice and this
|
||||
// permission notice and warranty disclaimer appear in supporting
|
||||
// documentation, and that the name of AT&T or any of its entities
|
||||
// not be used in advertising or publicity pertaining to
|
||||
// distribution of the software without specific, written prior
|
||||
// permission.
|
||||
//
|
||||
// AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
// INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||
// IN NO EVENT SHALL AT&T OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
|
||||
// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
// THIS SOFTWARE.
|
||||
|
||||
%require "3.6"
|
||||
%defines "engines/private/tokens.h"
|
||||
%output "engines/private/grammar.cpp"
|
||||
%define api.prefix {PRIVATE_}
|
||||
|
||||
%{
|
||||
|
||||
#include "private/private.h"
|
||||
#include "private/grammar.h"
|
||||
|
||||
#undef yyerror
|
||||
#define yyerror PRIVATE_xerror
|
||||
|
||||
#define code1(c1) code(c1);
|
||||
#define code2(c1,c2) code(c1); code(c2)
|
||||
#define code3(c1,c2,c3) code(c1); code(c2); code(c3)
|
||||
|
||||
using namespace Private;
|
||||
using namespace Gen;
|
||||
using namespace Settings;
|
||||
|
||||
extern int PRIVATE_lex();
|
||||
//extern int PRIVATE_parse();
|
||||
|
||||
int markplus();
|
||||
|
||||
void PRIVATE_xerror(const char *str) {
|
||||
}
|
||||
|
||||
int PRIVATE_wrap() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
Private::Symbol *sym; /* symbol table pointer */
|
||||
int (**inst)(); /* machine instruction */
|
||||
char *s; /* string value */
|
||||
int *i; /* integer value */
|
||||
int narg; /* auxiliary value to count function arguments */
|
||||
}
|
||||
|
||||
%token<s> NAME
|
||||
%token<sym> STRING NUM
|
||||
%token NUM_PLUS
|
||||
%type <inst> body if startp cond end expr statements statement fcall value
|
||||
%token LTE GTE NEQ EQ FALSETOK TRUETOK NULLTOK IFTOK ELSETOK RECT GOTOTOK DEBUGTOK EMITCODEONTOK EMITCODEOFFTOK RESETIDTOK DEFINETOK SETTINGTOK RANDOMTOK
|
||||
%type<narg> params
|
||||
|
||||
%%
|
||||
|
||||
lines: line lines
|
||||
| line
|
||||
;
|
||||
|
||||
line: DEBUGTOK '{' debug '}' { /* Not used in the game */ }
|
||||
| EMITCODEONTOK { /* Unclear what this is */ }
|
||||
| EMITCODEOFFTOK { /* Unclear what this is */ }
|
||||
| RESETIDTOK { /* Unclear what this is */ }
|
||||
| DEFINETOK NAME '{' define '}' { g_private->maps.installAll($NAME); }
|
||||
| SETTINGTOK NAME '{' statements '}' { g_setts->save($NAME);
|
||||
g_setts->init(); }
|
||||
;
|
||||
|
||||
debug: /* nothing */
|
||||
| NAME ',' debug
|
||||
;
|
||||
|
||||
statements: /* nothing */ { $$ = g_vm->_progp; }
|
||||
| statement statements
|
||||
|
||||
|
||||
statement: GOTOTOK NAME ';' {
|
||||
$$ = g_vm->_progp;
|
||||
code2(strpush, (Inst) g_private->maps.constant(STRING, 0, $NAME));
|
||||
code2(constpush, (Inst) g_private->maps.constant(NUM, 1, NULL));
|
||||
code2(strpush, (Inst) g_private->maps.constant(STRING, 0, "goto"));
|
||||
code1(funcpush);
|
||||
}
|
||||
| fcall ';' { $$ = $1; }
|
||||
| if cond body end {
|
||||
/* else-less if */
|
||||
($1)[1] = (Inst)$3; /* thenpart */
|
||||
($1)[3] = (Inst)$4;
|
||||
} /* end, if cond fails */
|
||||
| if cond body end ELSETOK body end {
|
||||
/* if with else */
|
||||
($1)[1] = (Inst)$3; /* thenpart */
|
||||
($1)[2] = (Inst)$6; /* elsepart */
|
||||
($1)[3] = (Inst)$7;
|
||||
} /* end, if cond fails */
|
||||
;
|
||||
|
||||
body: statement { $$ = $1; }
|
||||
| '{' statements '}' { $$ = $2; }
|
||||
;
|
||||
|
||||
end: /* nothing */ { code1(STOP); $$ = g_vm->_progp; }
|
||||
;
|
||||
|
||||
if: IFTOK { $$ = code1(ifcode); code3(STOP, STOP, STOP); }
|
||||
;
|
||||
|
||||
cond: '(' expr ')' { code1(STOP); $$ = $2; }
|
||||
;
|
||||
|
||||
define: /* nothing */
|
||||
| NAME ',' RECT '(' NUM ',' NUM ',' NUM ',' NUM ')' ',' define {
|
||||
Common::Rect *r = new Common::Rect($5->u.val, $7->u.val, $9->u.val, $11->u.val);
|
||||
assert(r->isValidRect());
|
||||
g_private->maps.defineSymbol($NAME, r);
|
||||
}
|
||||
| NAME ',' RECT '(' NUM ',' NUM ',' NUM ',' NUM ')' {
|
||||
Common::Rect *r = new Common::Rect($5->u.val, $7->u.val, $9->u.val, $11->u.val);
|
||||
g_private->maps.defineSymbol($NAME, r);
|
||||
}
|
||||
| NAME ',' define { g_private->maps.defineSymbol($NAME, NULL); }
|
||||
| NAME { g_private->maps.defineSymbol($NAME, NULL); }
|
||||
;
|
||||
|
||||
fcall: GOTOTOK '(' NAME ')' {
|
||||
$$ = g_vm->_progp;
|
||||
code2(strpush, (Inst) g_private->maps.constant(STRING, 0, $NAME));
|
||||
code2(constpush, (Inst) g_private->maps.constant(NUM, 1, NULL));
|
||||
code2(strpush, (Inst) g_private->maps.constant(STRING, 0, "goto"));
|
||||
code1(funcpush);
|
||||
}
|
||||
|
||||
| RECT '(' NUM ',' NUM ',' NUM ',' NUM ')' { $$ = g_vm->_progp; }
|
||||
| NAME '(' startp params ')' {
|
||||
$$ = $startp;
|
||||
code2(constpush, (Inst) g_private->maps.constant(NUM, $params, NULL));
|
||||
code2(strpush, (Inst) g_private->maps.constant(STRING, 0, $NAME));
|
||||
code1(funcpush);
|
||||
}
|
||||
;
|
||||
|
||||
startp: /*nothing*/ { $$ = g_vm->_progp; }
|
||||
;
|
||||
|
||||
params: /* nothing */ { $$ = 0; }
|
||||
| fcall ',' params { $$ = $3 + 1; }
|
||||
| expr ',' params { $$ = $3 + 1; }
|
||||
| expr { $$ = 1; }
|
||||
| fcall { $$ = 1; }
|
||||
;
|
||||
|
||||
value: NULLTOK { code2(constpush, (Inst) g_private->maps.constant(NUM, 0, NULL)); }
|
||||
| FALSETOK { code2(constpush, (Inst) g_private->maps.constant(NUM, 0, NULL)); }
|
||||
| TRUETOK { code2(constpush, (Inst) g_private->maps.constant(NUM, 1, NULL)); }
|
||||
| NUM { code2(constpush, (Inst)$NUM); }
|
||||
| STRING { code2(strpush, (Inst)$STRING); }
|
||||
| NAME { code1(varpush); code1((Inst) g_private->maps.lookupName($NAME)); code1(eval); }
|
||||
;
|
||||
|
||||
expr: value { $$ = $1; }
|
||||
| '!' value { code1(negate); $$ = $2; }
|
||||
| value EQ value { code1(eq); }
|
||||
| value NEQ value { code1(ne); }
|
||||
| value '+' value { code1(add); }
|
||||
| value '<' value { code1(lt); }
|
||||
| value '>' value { code1(gt); }
|
||||
| value LTE value { code1(le); }
|
||||
| value GTE value { code1(ge); }
|
||||
| value '+' { code1(markplus); $$ = $1; }
|
||||
| RANDOMTOK '(' NUM '%' ')' { code3(constpush, (Inst)$NUM, randbool); }
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
int markplus() {
|
||||
Datum d = pop();
|
||||
if (d.type == NUM) {
|
||||
d.type = NUM_PLUS;
|
||||
}
|
||||
push(d);
|
||||
return 0;
|
||||
}
|
||||
2205
engines/private/lexer.cpp
Normal file
2205
engines/private/lexer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
94
engines/private/lexer.l
Normal file
94
engines/private/lexer.l
Normal file
@@ -0,0 +1,94 @@
|
||||
%top{
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#define YY_NO_UNISTD_H
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_FILE
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_fprintf
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_fwrite
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_fread
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_stdin
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_stdout
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_stderr
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_exit
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_getc
|
||||
|
||||
#include "private/private.h"
|
||||
#include "private/grammar.h"
|
||||
#include "private/tokens.h"
|
||||
|
||||
using namespace Private;
|
||||
using namespace Gen;
|
||||
using namespace Settings;
|
||||
|
||||
}
|
||||
|
||||
%option noyywrap
|
||||
%option noinput
|
||||
%option nounput
|
||||
%option never-interactive
|
||||
|
||||
%option outfile="engines/private/lexer.cpp"
|
||||
%option prefix="PRIVATE_"
|
||||
|
||||
%%
|
||||
\/\/.* /* ignoring the comment */
|
||||
\<= return LTE;
|
||||
\>= return GTE;
|
||||
!= return NEQ;
|
||||
== return EQ;
|
||||
debug return DEBUGTOK;
|
||||
define return DEFINETOK;
|
||||
setting return SETTINGTOK;
|
||||
EmitCodeOff return EMITCODEOFFTOK;
|
||||
EmitCodeOn return EMITCODEONTOK;
|
||||
ResetIDCounter return RESETIDTOK;
|
||||
if return IFTOK;
|
||||
else return ELSETOK;
|
||||
goto return GOTOTOK;
|
||||
RECT return RECT;
|
||||
FALSE return FALSETOK;
|
||||
TRUE return TRUETOK;
|
||||
NULL return NULLTOK;
|
||||
Random return RANDOMTOK;
|
||||
[A-Za-z_][A-Za-z_0-9]* PRIVATE_lval.s = g_private->maps.string(PRIVATE_text); return NAME;
|
||||
[\-]?[0-9]+ PRIVATE_lval.sym = g_private->maps.constant(NUM, atoi(PRIVATE_text), NULL); return NUM;
|
||||
\"[^\"\r\n]*\" PRIVATE_lval.sym = g_private->maps.constant(STRING, 0, PRIVATE_text); return STRING;
|
||||
[\r|\n]+ /* ignore return */;
|
||||
[ \t]+ /* ignore whitespace */;
|
||||
. return *yytext;
|
||||
%%
|
||||
|
||||
namespace Private {
|
||||
|
||||
int parse(const char *code) {
|
||||
g_setts->init();
|
||||
YY_BUFFER_STATE bp;
|
||||
yy_delete_buffer(YY_CURRENT_BUFFER);
|
||||
bp = yy_scan_string(code);
|
||||
yy_switch_to_buffer(bp);
|
||||
PRIVATE_parse();
|
||||
yy_delete_buffer(bp);
|
||||
yylex_destroy();
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // End of namespace Private
|
||||
157
engines/private/metaengine.cpp
Normal file
157
engines/private/metaengine.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
#include "graphics/scaler.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
#include "private/private.h"
|
||||
#include "private/detection.h"
|
||||
#include "private/savegame.h"
|
||||
|
||||
#include "backends/keymapper/action.h"
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
#include "backends/keymapper/standard-actions.h"
|
||||
|
||||
static const ADExtraGuiOptionsMap optionsList[] = {
|
||||
{
|
||||
GAMEOPTION_SFX_SUBTITLES,
|
||||
{
|
||||
_s("Display SFX subtitles"),
|
||||
_s("Use SFX subtitles (if subtitles are enabled)."),
|
||||
"sfxSubtitles",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
{
|
||||
GAMEOPTION_HIGHLIGHT_MASKS,
|
||||
{
|
||||
_s("Highlight decision areas"),
|
||||
_s("Highlight clickable areas in decision scenes."),
|
||||
"highlightMasks",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
AD_EXTRA_GUI_OPTIONS_TERMINATOR
|
||||
};
|
||||
|
||||
class PrivateMetaEngine : public AdvancedMetaEngine<ADGameDescription> {
|
||||
public:
|
||||
const char *getName() const override {
|
||||
return "private";
|
||||
}
|
||||
|
||||
const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override {
|
||||
return optionsList;
|
||||
}
|
||||
|
||||
Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
|
||||
void getSavegameThumbnail(Graphics::Surface &thumb) override;
|
||||
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override;
|
||||
Common::KeymapArray initKeymaps(const char *target) const override;
|
||||
};
|
||||
|
||||
Common::Error PrivateMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const {
|
||||
*engine = new Private::PrivateEngine(syst, gd);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
void PrivateMetaEngine::getSavegameThumbnail(Graphics::Surface &thumb) {
|
||||
byte *palette;
|
||||
bool isNewPalette;
|
||||
Graphics::Surface *vs = Private::g_private->decodeImage(Private::g_private->_nextVS, &palette, &isNewPalette);
|
||||
::createThumbnail(&thumb, (const uint8 *)vs->getPixels(), vs->w, vs->h, palette);
|
||||
vs->free();
|
||||
delete vs;
|
||||
if (isNewPalette) {
|
||||
free(palette);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* querySaveMetaInfos override that filters out saves with incompatible formats.
|
||||
*
|
||||
* The Private Eye save format was significantly changed to add more engine state.
|
||||
* Older saves are incompatible, and we might have to change the format again.
|
||||
* Save files now contain a version number in their header so that we can detect
|
||||
* that a save is compatible, and not present incompatible saves to users.
|
||||
*/
|
||||
SaveStateDescriptor PrivateMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
|
||||
using namespace Private;
|
||||
|
||||
SaveStateDescriptor desc = MetaEngine::querySaveMetaInfos(target, slot);
|
||||
if (desc.getSaveSlot() == -1) {
|
||||
return desc;
|
||||
}
|
||||
|
||||
// Only saves with compatible metadata headers are allowed.
|
||||
Common::ScopedPtr<Common::InSaveFile> f(g_system->getSavefileManager()->openForLoading(
|
||||
getSavegameFile(slot, target)));
|
||||
if (f) {
|
||||
SavegameMetadata meta;
|
||||
if (!readSavegameMetadata(f.get(), meta)) {
|
||||
return SaveStateDescriptor();
|
||||
}
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
Common::KeymapArray PrivateMetaEngine::initKeymaps(const char *target) const {
|
||||
using namespace Common;
|
||||
using namespace Private;
|
||||
|
||||
Keymap *engineKeymap = new Keymap(Keymap::kKeymapTypeGame, "private-default", _("Default keymappings"));
|
||||
Action *act;
|
||||
|
||||
act = new Action(kStandardActionLeftClick, _("Select / Interact"));
|
||||
act->setLeftClickEvent();
|
||||
act->addDefaultInputMapping("MOUSE_LEFT");
|
||||
act->addDefaultInputMapping("JOY_A");
|
||||
engineKeymap->addAction(act);
|
||||
|
||||
act = new Action("SKIP", _("Skip video"));
|
||||
act->setCustomEngineActionEvent(kActionSkip);
|
||||
act->addDefaultInputMapping("ESCAPE");
|
||||
act->addDefaultInputMapping("JOY_X");
|
||||
engineKeymap->addAction(act);
|
||||
|
||||
return Keymap::arrayOf(engineKeymap);
|
||||
}
|
||||
|
||||
namespace Private {
|
||||
|
||||
bool PrivateEngine::isDemo() const {
|
||||
return (bool)(_gameDescription->flags & ADGF_DEMO);
|
||||
}
|
||||
|
||||
} // End of namespace Private
|
||||
|
||||
#if PLUGIN_ENABLED_DYNAMIC(PRIVATE)
|
||||
REGISTER_PLUGIN_DYNAMIC(PRIVATE, PLUGIN_TYPE_ENGINE, PrivateMetaEngine);
|
||||
#else
|
||||
REGISTER_PLUGIN_STATIC(PRIVATE, PLUGIN_TYPE_ENGINE, PrivateMetaEngine);
|
||||
#endif
|
||||
34
engines/private/module.mk
Normal file
34
engines/private/module.mk
Normal file
@@ -0,0 +1,34 @@
|
||||
MODULE := engines/private
|
||||
|
||||
MODULE_OBJS := \
|
||||
code.o \
|
||||
cursors.o \
|
||||
decompiler.o \
|
||||
funcs.o \
|
||||
grammar.o \
|
||||
lexer.o \
|
||||
metaengine.o \
|
||||
private.o \
|
||||
savegame.o \
|
||||
symbol.o
|
||||
|
||||
MODULE_DIRS += \
|
||||
engines/private
|
||||
|
||||
# HACK: Skip this when including the file for detection objects.
|
||||
ifeq "$(LOAD_RULES_MK)" "1"
|
||||
private-grammar:
|
||||
flex engines/private/lexer.l
|
||||
bison engines/private/grammar.y
|
||||
endif
|
||||
|
||||
# This module can be built as a plugin
|
||||
ifeq ($(ENABLE_PRIVATE), DYNAMIC_PLUGIN)
|
||||
PLUGIN := 1
|
||||
endif
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/rules.mk
|
||||
|
||||
# Detection objects
|
||||
DETECT_OBJS += $(MODULE)/detection.o
|
||||
3291
engines/private/private.cpp
Normal file
3291
engines/private/private.cpp
Normal file
File diff suppressed because it is too large
Load Diff
555
engines/private/private.h
Normal file
555
engines/private/private.h
Normal file
@@ -0,0 +1,555 @@
|
||||
/* 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 PRIVATE_H
|
||||
#define PRIVATE_H
|
||||
|
||||
#include "common/random.h"
|
||||
#include "common/serializer.h"
|
||||
#include "engines/engine.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
#include "graphics/wincursor.h"
|
||||
#include "video/smk_decoder.h"
|
||||
#include "video/subtitles.h"
|
||||
|
||||
#include "private/grammar.h"
|
||||
|
||||
namespace Common {
|
||||
class Archive;
|
||||
}
|
||||
|
||||
namespace Image {
|
||||
class ImageDecoder;
|
||||
}
|
||||
|
||||
namespace Graphics {
|
||||
class ManagedSurface;
|
||||
}
|
||||
|
||||
struct ADGameDescription;
|
||||
|
||||
namespace Private {
|
||||
|
||||
enum PRIVATEActions {
|
||||
kActionSkip,
|
||||
};
|
||||
|
||||
// debug channels
|
||||
enum {
|
||||
kPrivateDebugFunction = 1,
|
||||
kPrivateDebugCode,
|
||||
kPrivateDebugScript,
|
||||
};
|
||||
|
||||
// sounds
|
||||
|
||||
const int kPaperShuffleSound[7] = {32, 33, 34, 35, 36, 37, 39};
|
||||
|
||||
// police
|
||||
|
||||
const int kPoliceBustVideos[6] = {1, 2, 4, 5, 7, 8};
|
||||
|
||||
// points
|
||||
|
||||
const int kOriginZero[2] = {0, 0};
|
||||
const int kOriginOne[2] = {64, 48};
|
||||
|
||||
// vm
|
||||
|
||||
extern Gen::VM *Gen::g_vm;
|
||||
|
||||
// structs
|
||||
|
||||
typedef struct ExitInfo {
|
||||
Common::String nextSetting;
|
||||
Common::Rect rect;
|
||||
Common::String cursor;
|
||||
|
||||
void clear() {
|
||||
nextSetting.clear();
|
||||
rect.setEmpty();
|
||||
cursor.clear();
|
||||
}
|
||||
} ExitInfo;
|
||||
|
||||
typedef struct MaskInfo {
|
||||
Graphics::Surface *surf;
|
||||
Common::String nextSetting;
|
||||
Common::Point point;
|
||||
Symbol *flag1;
|
||||
Symbol *flag2;
|
||||
Common::String cursor;
|
||||
Common::String inventoryItem;
|
||||
bool useBoxCollision;
|
||||
Common::Rect box;
|
||||
|
||||
MaskInfo() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
surf = nullptr;
|
||||
useBoxCollision = false;
|
||||
box = Common::Rect();
|
||||
flag1 = nullptr;
|
||||
flag2 = nullptr;
|
||||
nextSetting.clear();
|
||||
cursor.clear();
|
||||
point = Common::Point();
|
||||
inventoryItem.clear();
|
||||
}
|
||||
} MaskInfo;
|
||||
|
||||
enum PhoneStatus : byte {
|
||||
kPhoneStatusWaiting,
|
||||
kPhoneStatusAvailable,
|
||||
kPhoneStatusCalling,
|
||||
kPhoneStatusMissed,
|
||||
kPhoneStatusAnswered
|
||||
};
|
||||
|
||||
typedef struct Sound {
|
||||
Common::String name;
|
||||
Audio::SoundHandle handle;
|
||||
} Sound;
|
||||
|
||||
typedef struct PhoneInfo {
|
||||
Common::String name;
|
||||
bool once;
|
||||
int startIndex;
|
||||
int endIndex;
|
||||
Common::String flagName;
|
||||
int flagValue;
|
||||
PhoneStatus status;
|
||||
int callCount;
|
||||
uint32 soundIndex;
|
||||
Common::Array<Common::String> sounds;
|
||||
} PhoneInfo;
|
||||
|
||||
typedef struct RadioClip {
|
||||
Common::String name;
|
||||
bool played;
|
||||
int priority;
|
||||
int disabledPriority1; // 0 == none
|
||||
bool exactPriorityMatch1;
|
||||
int disabledPriority2; // 0 == none
|
||||
bool exactPriorityMatch2;
|
||||
Common::String flagName;
|
||||
int flagValue;
|
||||
} RadioClip;
|
||||
|
||||
typedef struct Radio {
|
||||
Common::String path;
|
||||
Sound *sound;
|
||||
Common::Array<RadioClip> clips;
|
||||
int channels[3];
|
||||
|
||||
Radio() : sound(nullptr) {
|
||||
clear();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
clips.clear();
|
||||
for (uint i = 0; i < ARRAYSIZE(channels); i++) {
|
||||
channels[i] = -1;
|
||||
}
|
||||
}
|
||||
} Radio;
|
||||
|
||||
typedef struct DossierInfo {
|
||||
Common::String page1;
|
||||
Common::String page2;
|
||||
} DossierInfo;
|
||||
|
||||
typedef struct CursorInfo {
|
||||
Common::String name;
|
||||
Common::String aname;
|
||||
Graphics::Cursor *cursor;
|
||||
Graphics::WinCursorGroup *winCursorGroup;
|
||||
} CursorInfo;
|
||||
|
||||
typedef struct MemoryInfo {
|
||||
Common::String image;
|
||||
Common::String movie;
|
||||
} MemoryInfo;
|
||||
|
||||
typedef struct DiaryPage {
|
||||
Common::String locationName;
|
||||
Common::Array<MemoryInfo> memories;
|
||||
int locationID;
|
||||
} DiaryPage;
|
||||
|
||||
typedef struct InventoryItem {
|
||||
Common::String diaryImage;
|
||||
Common::String flag;
|
||||
} InventoryItem;
|
||||
|
||||
// funcs
|
||||
|
||||
typedef struct FuncTable {
|
||||
void (*func)(Private::ArgArray);
|
||||
const char *name;
|
||||
} FunctTable;
|
||||
|
||||
typedef Common::HashMap<Common::String, void *> NameToPtr;
|
||||
extern const FuncTable funcTable[];
|
||||
|
||||
// lists
|
||||
|
||||
typedef Common::List<ExitInfo> ExitList;
|
||||
typedef Common::List<MaskInfo> MaskList;
|
||||
typedef Common::List<PhoneInfo> PhoneList;
|
||||
typedef Common::List<InventoryItem> InvList;
|
||||
typedef Common::List<Common::Rect *> RectList;
|
||||
|
||||
// arrays
|
||||
|
||||
typedef Common::Array<DossierInfo> DossierArray;
|
||||
typedef Common::Array<DiaryPage> DiaryPages;
|
||||
|
||||
// hash tables
|
||||
|
||||
typedef Common::HashMap<Common::String, bool> PlayedMediaTable;
|
||||
|
||||
enum SubtitleType {
|
||||
kSubtitleAudio,
|
||||
kSubtitleVideo
|
||||
};
|
||||
|
||||
struct SubtitleSlot {
|
||||
Audio::SoundHandle handle;
|
||||
Video::Subtitles *subs;
|
||||
|
||||
SubtitleSlot() : subs(nullptr) {}
|
||||
};
|
||||
|
||||
class PrivateEngine : public Engine {
|
||||
private:
|
||||
Common::RandomSource *_rnd;
|
||||
Graphics::PixelFormat _pixelFormat;
|
||||
Image::ImageDecoder *_image;
|
||||
int _screenW, _screenH;
|
||||
|
||||
// helper to generate the correct subtitle path
|
||||
Common::Path getSubtitlePath(const Common::String &soundName);
|
||||
|
||||
bool isSfxSubtitle(const Video::Subtitles *subs);
|
||||
bool isSlotActive(const SubtitleSlot &slot);
|
||||
|
||||
public:
|
||||
bool _shouldHighlightMasks;
|
||||
bool _highlightMasks;
|
||||
PrivateEngine(OSystem *syst, const ADGameDescription *gd);
|
||||
~PrivateEngine();
|
||||
|
||||
const ADGameDescription *_gameDescription;
|
||||
bool isDemo() const;
|
||||
Common::Language _language;
|
||||
Common::Platform _platform;
|
||||
|
||||
SymbolMaps maps;
|
||||
|
||||
Video::SmackerDecoder *_videoDecoder;
|
||||
Video::SmackerDecoder *_pausedVideo;
|
||||
Common::String _pausedMovieName;
|
||||
|
||||
Common::Error run() override;
|
||||
void restartGame();
|
||||
void clearAreas();
|
||||
void initializePath(const Common::FSNode &gamePath) override;
|
||||
void pauseEngineIntern(bool pause) override;
|
||||
Common::SeekableReadStream *loadAssets();
|
||||
Common::Archive *loadMacInstaller();
|
||||
|
||||
// Functions
|
||||
|
||||
NameToPtr _functions;
|
||||
void initFuncs();
|
||||
|
||||
// User input
|
||||
void selectPauseGame(Common::Point);
|
||||
bool selectMask(Common::Point);
|
||||
bool selectExit(Common::Point);
|
||||
bool selectLoadGame(Common::Point);
|
||||
bool selectSaveGame(Common::Point);
|
||||
void resumeGame();
|
||||
|
||||
// Cursors
|
||||
void updateCursor(Common::Point);
|
||||
bool cursorPauseMovie(Common::Point);
|
||||
bool cursorExit(Common::Point);
|
||||
bool cursorSafeDigit(Common::Point);
|
||||
bool cursorMask(Common::Point);
|
||||
|
||||
bool hasFeature(EngineFeature f) const override;
|
||||
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override {
|
||||
return true;
|
||||
}
|
||||
bool canSaveAutosaveCurrently() override {
|
||||
return false;
|
||||
}
|
||||
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override {
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::Error loadGameStream(Common::SeekableReadStream *stream) override;
|
||||
Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override;
|
||||
|
||||
static Common::Path convertPath(const Common::String &name);
|
||||
static Common::String getVideoViewScreen(Common::String video);
|
||||
void playVideo(const Common::String &);
|
||||
void skipVideo();
|
||||
void destroyVideo();
|
||||
|
||||
void loadSubtitles(const Common::Path &path, SubtitleType type, Sound *sound = nullptr);
|
||||
// use to clean up sounds which have finished playing once
|
||||
void updateSubtitles();
|
||||
void destroySubtitles();
|
||||
void adjustSubtitleSize();
|
||||
Video::Subtitles *_videoSubtitles;
|
||||
SubtitleSlot _voiceSlot; // high priority (speech)
|
||||
SubtitleSlot _sfxSlot; // low priority (sfxs)
|
||||
bool _useSubtitles;
|
||||
bool _sfxSubtitles;
|
||||
|
||||
Graphics::Surface *decodeImage(const Common::String &file, byte **palette, bool *isNewPalette);
|
||||
//byte *decodePalette(const Common::String &name);
|
||||
void remapImage(uint16 ncolors, const Graphics::Surface *oldImage, const byte *oldPalette, Graphics::Surface *newImage, const byte *currentPalette);
|
||||
static uint32 findMaskTransparentColor(const byte *palette, uint32 defaultColor);
|
||||
static void swapImageColors(Graphics::Surface *image, byte *palette, uint32 a, uint32 b);
|
||||
void loadImage(const Common::String &file, int x, int y);
|
||||
void drawScreenFrame(const byte *videoPalette);
|
||||
|
||||
// Cursors
|
||||
Graphics::Cursor *_defaultCursor;
|
||||
Common::Array<CursorInfo> _cursors;
|
||||
Common::String _currentCursor;
|
||||
void changeCursor(const Common::String &);
|
||||
Common::String getInventoryCursor();
|
||||
Common::String getExitCursor();
|
||||
void loadCursors();
|
||||
|
||||
// Rendering
|
||||
Graphics::ManagedSurface *_compositeSurface;
|
||||
Graphics::Surface *loadMask(const Common::String &, int, int, bool);
|
||||
void loadMaskAndInfo(MaskInfo *m, const Common::String &name, int x, int y, bool drawn);
|
||||
void drawMask(Graphics::Surface *);
|
||||
void fillRect(uint32, Common::Rect);
|
||||
bool inMask(Graphics::Surface *, Common::Point);
|
||||
uint32 _transparentColor;
|
||||
Common::Rect _screenRect;
|
||||
Common::String _framePath;
|
||||
Graphics::Surface *_frameImage;
|
||||
Graphics::Surface *_mframeImage;
|
||||
byte *_framePalette;
|
||||
Common::String _nextVS;
|
||||
Common::String _currentVS;
|
||||
Common::Point _origin;
|
||||
void drawScreen();
|
||||
bool _needToDrawScreenFrame;
|
||||
|
||||
// settings
|
||||
Common::String _nextSetting;
|
||||
Common::String _pausedSetting;
|
||||
Common::String _currentSetting;
|
||||
Common::String getPauseMovieSetting();
|
||||
Common::String getGoIntroSetting();
|
||||
Common::String getMainDesktopSetting();
|
||||
Common::String getDiaryTOCSetting();
|
||||
Common::String getDiaryMiddleSetting();
|
||||
Common::String getDiaryLastPageSetting();
|
||||
Common::String getPOGoBustMovieSetting();
|
||||
Common::String getPoliceBustFromMOSetting();
|
||||
Common::String getListenToPhoneSetting();
|
||||
Common::String getAlternateGameVariable();
|
||||
Common::String getPoliceIndexVariable();
|
||||
Common::String getWallSafeValueVariable();
|
||||
Common::String getPoliceArrivedVariable();
|
||||
Common::String getBeenDowntownVariable();
|
||||
Common::String getPoliceStationLocation();
|
||||
const char *getSymbolName(const char *name, const char *strippedName, const char *demoName = nullptr);
|
||||
|
||||
// movies
|
||||
Common::String _nextMovie;
|
||||
Common::String _currentMovie;
|
||||
|
||||
// Dossiers
|
||||
DossierArray _dossiers;
|
||||
uint _dossierSuspect;
|
||||
uint _dossierPage;
|
||||
MaskInfo _dossierPageMask;
|
||||
MaskInfo _dossierNextSuspectMask;
|
||||
MaskInfo _dossierPrevSuspectMask;
|
||||
MaskInfo _dossierNextSheetMask;
|
||||
MaskInfo _dossierPrevSheetMask;
|
||||
bool selectDossierPage(Common::Point);
|
||||
bool selectDossierNextSuspect(Common::Point);
|
||||
bool selectDossierPrevSuspect(Common::Point);
|
||||
bool selectDossierNextSheet(Common::Point);
|
||||
bool selectDossierPrevSheet(Common::Point);
|
||||
void addDossier(Common::String &page1, Common::String &page2);
|
||||
void loadDossier();
|
||||
|
||||
// Police Bust
|
||||
bool _policeBustEnabled;
|
||||
bool _policeSirenPlayed;
|
||||
int _numberOfClicks;
|
||||
int _numberClicksAfterSiren;
|
||||
int _policeBustMovieIndex;
|
||||
Common::String _policeBustMovie;
|
||||
Common::String _policeBustPreviousSetting;
|
||||
void resetPoliceBust();
|
||||
void startPoliceBust();
|
||||
void stopPoliceBust();
|
||||
void wallSafeAlarm();
|
||||
void completePoliceBust();
|
||||
void checkPoliceBust();
|
||||
|
||||
// Diary
|
||||
InvList inventory;
|
||||
bool inInventory(const Common::String &bmp) const;
|
||||
void addInventory(const Common::String &bmp, Common::String &flag);
|
||||
void removeInventory(const Common::String &bmp);
|
||||
void removeRandomInventory();
|
||||
Common::String _diaryLocPrefix;
|
||||
void loadLocations(const Common::Rect &);
|
||||
void loadInventory(uint32, const Common::Rect &, const Common::Rect &);
|
||||
bool _toTake;
|
||||
bool _haveTakenItem;
|
||||
DiaryPages _diaryPages;
|
||||
int _currentDiaryPage;
|
||||
ExitInfo _diaryNextPageExit;
|
||||
ExitInfo _diaryPrevPageExit;
|
||||
bool selectDiaryNextPage(Common::Point mousePos);
|
||||
bool selectDiaryPrevPage(Common::Point mousePos);
|
||||
void addMemory(const Common::String &path);
|
||||
void loadMemories(const Common::Rect &rect, uint rightPageOffset, uint verticalOffset);
|
||||
bool selectLocation(const Common::Point &mousePos);
|
||||
Common::Array<MaskInfo> _locationMasks;
|
||||
Common::Array<MaskInfo> _memoryMasks;
|
||||
bool selectMemory(const Common::Point &mousePos);
|
||||
void setLocationAsVisited(Symbol *location);
|
||||
int getMaxLocationValue();
|
||||
bool selectSkipMemoryVideo(Common::Point mousePos);
|
||||
|
||||
// Save/Load games
|
||||
MaskInfo _saveGameMask;
|
||||
MaskInfo _loadGameMask;
|
||||
|
||||
int _mode;
|
||||
bool _modified;
|
||||
|
||||
PlayedMediaTable _playedMovies;
|
||||
Common::String _repeatedMovieExit;
|
||||
|
||||
// Masks/Exits
|
||||
ExitList _exits;
|
||||
MaskList _masks;
|
||||
|
||||
// Sounds
|
||||
void playBackgroundSound(const Common::String &name);
|
||||
void playForegroundSound(const Common::String &name);
|
||||
void playForegroundSound(Sound &sound, const Common::String &name);
|
||||
void playSound(Sound &sound, const Common::String &name, bool loop);
|
||||
void stopForegroundSounds();
|
||||
void stopSounds();
|
||||
void stopSound(Sound &sound);
|
||||
bool isSoundPlaying();
|
||||
bool isSoundPlaying(Sound &sound);
|
||||
void waitForSoundsToStop();
|
||||
bool consumeEvents();
|
||||
Sound _bgSound;
|
||||
Sound _fgSounds[4];
|
||||
Sound _phoneCallSound;
|
||||
Sound _AMRadioSound;
|
||||
Sound _policeRadioSound;
|
||||
Sound _takeLeaveSound;
|
||||
bool _noStopSounds;
|
||||
Common::String _pausedBackgroundSoundName;
|
||||
|
||||
Common::String getPaperShuffleSound();
|
||||
Common::String _globalAudioPath;
|
||||
|
||||
Common::String getTakeSound();
|
||||
Common::String getTakeLeaveSound();
|
||||
Common::String getLeaveSound();
|
||||
Common::String _sirenSound;
|
||||
|
||||
// Radios
|
||||
MaskInfo _AMRadioArea;
|
||||
MaskInfo _policeRadioArea;
|
||||
Radio _AMRadio;
|
||||
Radio _policeRadio;
|
||||
void addRadioClip(
|
||||
Radio &radio, const Common::String &name, int priority,
|
||||
int disabledPriority1, bool exactPriorityMatch1,
|
||||
int disabledPriority2, bool exactPriorityMatch2,
|
||||
const Common::String &flagName, int flagValue);
|
||||
void initializeAMRadioChannels(uint clipCount);
|
||||
void initializePoliceRadioChannels();
|
||||
void disableRadioClips(Radio &radio, int priority);
|
||||
void playRadio(Radio &radio, bool randomlyDisableClips);
|
||||
bool selectAMRadioArea(Common::Point);
|
||||
bool selectPoliceRadioArea(Common::Point);
|
||||
|
||||
// Phone
|
||||
MaskInfo _phoneArea;
|
||||
Common::String _phonePrefix;
|
||||
PhoneList _phones;
|
||||
void addPhone(const Common::String &name, bool once, int startIndex, int endIndex, const Common::String &flagName, int flagValue);
|
||||
void initializePhoneOnDesktop();
|
||||
void checkPhoneCall();
|
||||
bool cursorPhoneArea(Common::Point mousePos);
|
||||
bool selectPhoneArea(Common::Point mousePos);
|
||||
|
||||
// Safe
|
||||
Common::String _safeNumberPath;
|
||||
MaskInfo _safeDigitArea[3];
|
||||
Common::Rect _safeDigitRect[3];
|
||||
|
||||
void initializeWallSafeValue();
|
||||
bool selectSafeDigit(Common::Point);
|
||||
void addSafeDigit(uint32, Common::Rect*);
|
||||
int getSafeDigit(uint32 d);
|
||||
void incrementSafeDigit(uint32 d);
|
||||
|
||||
// Random values
|
||||
bool getRandomBool(uint);
|
||||
|
||||
// Timer
|
||||
Common::String _timerSetting;
|
||||
Common::String _timerSkipSetting;
|
||||
uint32 _timerStartTime;
|
||||
uint32 _timerDelay;
|
||||
void setTimer(uint32 duration, const Common::String &setting, const Common::String &skipSetting);
|
||||
void clearTimer();
|
||||
void skipTimer();
|
||||
void checkTimer();
|
||||
|
||||
// VM objects
|
||||
RectList _rects; // created by fCRect
|
||||
};
|
||||
|
||||
extern PrivateEngine *g_private;
|
||||
|
||||
} // End of namespace Private
|
||||
|
||||
#endif
|
||||
67
engines/private/savegame.cpp
Normal file
67
engines/private/savegame.cpp
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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/stream.h"
|
||||
|
||||
#include "engines/private/savegame.h"
|
||||
|
||||
namespace Private {
|
||||
|
||||
static const uint32 kSavegameHeader = MKTAG('P','E','Y','E');
|
||||
|
||||
void writeSavegameMetadata(Common::WriteStream *stream, const SavegameMetadata &meta) {
|
||||
stream->writeUint32BE(kSavegameHeader);
|
||||
stream->writeUint16LE(meta.version);
|
||||
stream->writeSByte(meta.language);
|
||||
stream->writeSByte(meta.platform);
|
||||
}
|
||||
|
||||
bool readSavegameMetadata(Common::SeekableReadStream *stream, SavegameMetadata &meta) {
|
||||
byte buffer[8];
|
||||
stream->read(buffer, 8);
|
||||
if (stream->eos() || stream->err()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 header = READ_BE_UINT32(buffer);
|
||||
if (header != kSavegameHeader) {
|
||||
debug(1, "Save does not have metadata header");
|
||||
return false;
|
||||
}
|
||||
|
||||
meta.version = READ_LE_UINT16(buffer + 4);
|
||||
if (meta.version < kMinimumSavegameVersion) {
|
||||
debug(1, "Save version %d lower than minimum %d", meta.version, kMinimumSavegameVersion);
|
||||
return false;
|
||||
}
|
||||
if (meta.version > kCurrentSavegameVersion) {
|
||||
debug(1, "Save version %d newer than current %d", meta.version, kCurrentSavegameVersion);
|
||||
return false;
|
||||
}
|
||||
|
||||
meta.language = (Common::Language)buffer[6];
|
||||
meta.platform = (Common::Platform)buffer[7];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Private
|
||||
67
engines/private/savegame.h
Normal file
67
engines/private/savegame.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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PRIVATE_SAVEGAME_H
|
||||
#define PRIVATE_SAVEGAME_H
|
||||
|
||||
#include "common/language.h"
|
||||
#include "common/platform.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
class WriteStream;
|
||||
}
|
||||
|
||||
namespace Private {
|
||||
|
||||
// Savegame format history:
|
||||
//
|
||||
// Version - new/changed feature
|
||||
// =============================
|
||||
// 4 - _pausedBackgroundSoundName (December 2025)
|
||||
// 3 - Radio detailed state (December 2025)
|
||||
// 2 - Phone clip detailed state (December 2025)
|
||||
// 1 - Metadata header and more game state (November 2025)
|
||||
//
|
||||
// Earlier versions did not have a header and not supported.
|
||||
|
||||
const uint16 kCurrentSavegameVersion = 4;
|
||||
const uint16 kMinimumSavegameVersion = 3;
|
||||
|
||||
struct SavegameMetadata {
|
||||
uint16 version;
|
||||
Common::Language language;
|
||||
Common::Platform platform;
|
||||
};
|
||||
|
||||
/**
|
||||
* Write the header to a savegame.
|
||||
*/
|
||||
void writeSavegameMetadata(Common::WriteStream *stream, const SavegameMetadata &meta);
|
||||
|
||||
/**
|
||||
* Read the header from a savegame.
|
||||
*/
|
||||
bool readSavegameMetadata(Common::SeekableReadStream *stream, SavegameMetadata &meta);
|
||||
|
||||
} // End of namespace Private
|
||||
|
||||
#endif
|
||||
233
engines/private/symbol.cpp
Normal file
233
engines/private/symbol.cpp
Normal file
@@ -0,0 +1,233 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Heavily inspired by hoc
|
||||
// Copyright (C) AT&T 1995
|
||||
// All Rights Reserved
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software and
|
||||
// its documentation for any purpose and without fee is hereby
|
||||
// granted, provided that the above copyright notice appear in all
|
||||
// copies and that both that the copyright notice and this
|
||||
// permission notice and warranty disclaimer appear in supporting
|
||||
// documentation, and that the name of AT&T or any of its entities
|
||||
// not be used in advertising or publicity pertaining to
|
||||
// distribution of the software without specific, written prior
|
||||
// permission.
|
||||
//
|
||||
// AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
// INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||
// IN NO EVENT SHALL AT&T OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
|
||||
// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
// THIS SOFTWARE.
|
||||
|
||||
#include "common/str.h"
|
||||
#include "private/grammar.h"
|
||||
#include "private/private.h"
|
||||
#include "private/tokens.h"
|
||||
|
||||
namespace Private {
|
||||
|
||||
SymbolMaps::~SymbolMaps() {
|
||||
freeSymbolMap(settings);
|
||||
freeSymbolMap(variables);
|
||||
freeSymbolMap(cursors);
|
||||
freeSymbolMap(locations);
|
||||
freeSymbolMap(rects);
|
||||
freeSymbolList(constants);
|
||||
freeSymbolList(names);
|
||||
freeStringMap(strings);
|
||||
}
|
||||
|
||||
void SymbolMaps::defineSymbol(const char *n, Common::Rect *r) {
|
||||
Common::String s(n);
|
||||
stringToDefine.push(s);
|
||||
rectToDefine.push(r);
|
||||
}
|
||||
|
||||
/*
|
||||
static void showSymbol(const Symbol *s) {
|
||||
if (s->type == NUM)
|
||||
debugC(1, kPrivateDebugCode, "%s %d",s->name->c_str(), s->u.val);
|
||||
else if (s->type == STRING)
|
||||
debugC(1, kPrivateDebugCode, "%s %s", s->name->c_str(), s->u.str);
|
||||
else if (s->type == NAME)
|
||||
debugC(1, kPrivateDebugCode, "%s %d",s->name->c_str(), s->type);
|
||||
else
|
||||
debugC(1, kPrivateDebugCode, "%s %d", s->name->c_str(), s->type);
|
||||
}
|
||||
*/
|
||||
|
||||
void setSymbol(Symbol *s, int v) {
|
||||
s->u.val = v;
|
||||
}
|
||||
|
||||
/* find s in symbol table symlist */
|
||||
static Symbol *lookup(const Common::String &s, const SymbolMap &symlist) {
|
||||
Symbol *r = symlist.getVal(s);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* install some symbol s in a symbol table */
|
||||
static Symbol *install(const Common::String &n, int t, int d, const char *s, Common::Rect *r, SymbolMap *symlist) {
|
||||
Symbol *sp;
|
||||
sp = (Symbol *)malloc(sizeof(Symbol));
|
||||
sp->name = new Common::String(n);
|
||||
sp->type = t;
|
||||
if (t == NUM) {
|
||||
sp->u.val = d;
|
||||
//debug("install NUM: %s %d", name->c_str(), d);
|
||||
} else if (t == NAME) {
|
||||
sp->u.val = d;
|
||||
//debug("installing NAME: %s %d", name->c_str(), d);
|
||||
} else if (t == STRING)
|
||||
sp->u.str = scumm_strdup(s);
|
||||
else if (t == RECT)
|
||||
sp->u.rect = r;
|
||||
else
|
||||
assert(0);
|
||||
|
||||
symlist->setVal(n, sp);
|
||||
assert(symlist->size() > 0);
|
||||
return sp;
|
||||
}
|
||||
|
||||
void SymbolMaps::freeSymbolMap(SymbolMap &symbols) {
|
||||
for (SymbolMap::iterator it = symbols.begin(); it != symbols.end(); ++it) {
|
||||
Symbol *s = it->_value;
|
||||
delete s->name;
|
||||
if (s->type == STRING) {
|
||||
free(s->u.str);
|
||||
} else if (s->type == RECT) {
|
||||
delete s->u.rect;
|
||||
}
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
|
||||
/* lookup some name in some symbol table */
|
||||
Symbol *SymbolMaps::lookupRect(Common::String *n) {
|
||||
assert(rects.contains(*n));
|
||||
return lookup(*n, rects);
|
||||
}
|
||||
|
||||
Symbol *SymbolMaps::lookupVariable(Common::String *n) {
|
||||
assert(variables.contains(*n));
|
||||
return lookup(*n, variables);
|
||||
}
|
||||
|
||||
Symbol *SymbolMaps::lookupLocation(Common::String *n) {
|
||||
assert(locations.contains(*n));
|
||||
return lookup(*n, locations);
|
||||
}
|
||||
|
||||
Symbol *SymbolMaps::lookupName(const char *n) {
|
||||
Symbol *s = (Symbol *)malloc(sizeof(Symbol));
|
||||
Common::String *name = new Common::String(n);
|
||||
s->name = name;
|
||||
s->type = NAME;
|
||||
s->u.val = 0;
|
||||
|
||||
names.push_back(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
void SymbolMaps::installAll(const char *n) {
|
||||
assert(stringToDefine.size() > 0);
|
||||
|
||||
while (!stringToDefine.empty()) {
|
||||
Common::String s = stringToDefine.pop();
|
||||
Common::Rect *r = rectToDefine.pop();
|
||||
|
||||
//debug("name %s", s.c_str());
|
||||
if (strcmp(n, "settings") == 0) {
|
||||
//debug("new setting %s", n);
|
||||
assert(r == nullptr);
|
||||
install(s, NAME, 0, s.c_str(), r, &settings);
|
||||
} else if (strcmp(n, "variables") == 0) {
|
||||
assert(r == nullptr);
|
||||
install(s, NAME, 0, nullptr, r, &variables);
|
||||
variableList.push_front(s);
|
||||
} else if (strcmp(n, "cursors") == 0) {
|
||||
assert(r == nullptr);
|
||||
install(s, NAME, 0, nullptr, r, &cursors);
|
||||
} else if (strcmp(n, "locations") == 0) {
|
||||
assert(r == nullptr);
|
||||
install(s, NAME, 0, nullptr, r, &locations);
|
||||
locationList.push_front(s);
|
||||
} else if (strcmp(n, "rects") == 0) {
|
||||
assert(r != nullptr);
|
||||
install(s, RECT, 0, nullptr, r, &rects);
|
||||
} else
|
||||
error("invalid symbol type");
|
||||
}
|
||||
}
|
||||
|
||||
Symbol *SymbolMaps::constant(int t, int d, const char *s) {
|
||||
Symbol *sp;
|
||||
Common::String *n = new Common::String("<constant>");
|
||||
|
||||
sp = (Symbol *)malloc(sizeof(Symbol));
|
||||
sp->name = n;
|
||||
sp->type = t;
|
||||
if (t == NUM || t == NAME)
|
||||
sp->u.val = d;
|
||||
else if (t == STRING)
|
||||
sp->u.str = scumm_strdup(s);
|
||||
else
|
||||
assert(0);
|
||||
|
||||
constants.push_front(sp);
|
||||
return sp;
|
||||
}
|
||||
|
||||
void SymbolMaps::freeSymbolList(SymbolList &symbols) {
|
||||
for (SymbolList::iterator it = symbols.begin(); it != symbols.end(); ++it) {
|
||||
Symbol *s = (*it);
|
||||
delete s->name;
|
||||
if (s->type == STRING) {
|
||||
free(s->u.str);
|
||||
}
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
|
||||
char *SymbolMaps::string(const char *in) {
|
||||
Common::String str(in);
|
||||
char *out;
|
||||
if (!strings.tryGetVal(in, out)) {
|
||||
out = scumm_strdup(in);
|
||||
strings[str] = out;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void SymbolMaps::freeStringMap(StringMap &strings) {
|
||||
for (StringMap::iterator it = strings.begin(); it != strings.end(); ++it) {
|
||||
char *s = it->_value;
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Private
|
||||
94
engines/private/symbol.h
Normal file
94
engines/private/symbol.h
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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PRIVATE_SYMBOL_H
|
||||
#define PRIVATE_SYMBOL_H
|
||||
|
||||
#include "common/str.h"
|
||||
#include "common/hash-str.h"
|
||||
#include "common/hash-ptr.h"
|
||||
#include "common/queue.h"
|
||||
#include "common/list.h"
|
||||
#include "common/array.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
namespace Private {
|
||||
|
||||
typedef struct Symbol { /* symbol table entry */
|
||||
Common::String *name;
|
||||
short type; /* NAME, NUM, STRING or RECT */
|
||||
union {
|
||||
int val; /* NAME or NUM */
|
||||
char *str; /* STRING */
|
||||
Common::Rect *rect; /* RECT */
|
||||
} u;
|
||||
} Symbol;
|
||||
|
||||
// Symbols
|
||||
|
||||
void setSymbol(Symbol *, int);
|
||||
|
||||
typedef Common::HashMap<Common::String, Symbol *> SymbolMap;
|
||||
typedef Common::List<Common::String> NameList;
|
||||
typedef Common::List<Symbol *> SymbolList;
|
||||
typedef Common::HashMap<Common::String, char *> StringMap;
|
||||
|
||||
typedef Common::Queue<Common::String> StringQueue;
|
||||
typedef Common::Queue<Common::Rect *> RectQueue;
|
||||
|
||||
class SymbolMaps {
|
||||
private:
|
||||
StringQueue stringToDefine;
|
||||
RectQueue rectToDefine;
|
||||
|
||||
static void freeSymbolMap(SymbolMap &symbols);
|
||||
static void freeSymbolList(SymbolList &symbols);
|
||||
static void freeStringMap(StringMap &strings);
|
||||
public:
|
||||
SymbolMap settings;
|
||||
SymbolMap variables;
|
||||
SymbolMap cursors;
|
||||
SymbolMap locations;
|
||||
SymbolMap rects;
|
||||
SymbolList constants;
|
||||
SymbolList names;
|
||||
|
||||
NameList variableList;
|
||||
NameList locationList;
|
||||
|
||||
StringMap strings;
|
||||
|
||||
SymbolMaps() { }
|
||||
~SymbolMaps();
|
||||
|
||||
Symbol *constant(int t, int d, const char *s);
|
||||
Symbol *lookupVariable(Common::String *n);
|
||||
Symbol *lookupLocation(Common::String *n);
|
||||
Symbol *lookupRect(Common::String *n);
|
||||
Symbol *lookupName(const char *n);
|
||||
void installAll(const char *n);
|
||||
void defineSymbol(const char *, Common::Rect *);
|
||||
char *string(const char *in);
|
||||
};
|
||||
|
||||
} // End of namespace Private
|
||||
|
||||
#endif
|
||||
118
engines/private/tokens.h
Normal file
118
engines/private/tokens.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/* A Bison parser, made by GNU Bison 3.8.2. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
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 <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* As a special exception, you may create a larger work that contains
|
||||
part or all of the Bison parser skeleton and distribute that work
|
||||
under terms of your choice, so long as that work isn't itself a
|
||||
parser generator using the skeleton or a modified version thereof
|
||||
as a parser skeleton. Alternatively, if you modify or redistribute
|
||||
the parser skeleton itself, you may (at your option) remove this
|
||||
special exception, which will cause the skeleton and the resulting
|
||||
Bison output files to be licensed under the GNU General Public
|
||||
License without this special exception.
|
||||
|
||||
This special exception was added by the Free Software Foundation in
|
||||
version 2.2 of Bison. */
|
||||
|
||||
/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
|
||||
especially those whose name start with YY_ or yy_. They are
|
||||
private implementation details that can be changed or removed. */
|
||||
|
||||
#ifndef YY_PRIVATE_ENGINES_PRIVATE_TOKENS_H_INCLUDED
|
||||
# define YY_PRIVATE_ENGINES_PRIVATE_TOKENS_H_INCLUDED
|
||||
/* Debug traces. */
|
||||
#ifndef PRIVATE_DEBUG
|
||||
# if defined YYDEBUG
|
||||
#if YYDEBUG
|
||||
# define PRIVATE_DEBUG 1
|
||||
# else
|
||||
# define PRIVATE_DEBUG 0
|
||||
# endif
|
||||
# else /* ! defined YYDEBUG */
|
||||
# define PRIVATE_DEBUG 0
|
||||
# endif /* ! defined YYDEBUG */
|
||||
#endif /* ! defined PRIVATE_DEBUG */
|
||||
#if PRIVATE_DEBUG
|
||||
extern int PRIVATE_debug;
|
||||
#endif
|
||||
|
||||
/* Token kinds. */
|
||||
#ifndef PRIVATE_TOKENTYPE
|
||||
# define PRIVATE_TOKENTYPE
|
||||
enum PRIVATE_tokentype
|
||||
{
|
||||
PRIVATE_EMPTY = -2,
|
||||
PRIVATE_EOF = 0, /* "end of file" */
|
||||
PRIVATE_error = 256, /* error */
|
||||
PRIVATE_UNDEF = 257, /* "invalid token" */
|
||||
NAME = 258, /* NAME */
|
||||
STRING = 259, /* STRING */
|
||||
NUM = 260, /* NUM */
|
||||
NUM_PLUS = 261, /* NUM_PLUS */
|
||||
LTE = 262, /* LTE */
|
||||
GTE = 263, /* GTE */
|
||||
NEQ = 264, /* NEQ */
|
||||
EQ = 265, /* EQ */
|
||||
FALSETOK = 266, /* FALSETOK */
|
||||
TRUETOK = 267, /* TRUETOK */
|
||||
NULLTOK = 268, /* NULLTOK */
|
||||
IFTOK = 269, /* IFTOK */
|
||||
ELSETOK = 270, /* ELSETOK */
|
||||
RECT = 271, /* RECT */
|
||||
GOTOTOK = 272, /* GOTOTOK */
|
||||
DEBUGTOK = 273, /* DEBUGTOK */
|
||||
EMITCODEONTOK = 274, /* EMITCODEONTOK */
|
||||
EMITCODEOFFTOK = 275, /* EMITCODEOFFTOK */
|
||||
RESETIDTOK = 276, /* RESETIDTOK */
|
||||
DEFINETOK = 277, /* DEFINETOK */
|
||||
SETTINGTOK = 278, /* SETTINGTOK */
|
||||
RANDOMTOK = 279 /* RANDOMTOK */
|
||||
};
|
||||
typedef enum PRIVATE_tokentype PRIVATE_token_kind_t;
|
||||
#endif
|
||||
|
||||
/* Value type. */
|
||||
#if ! defined PRIVATE_STYPE && ! defined PRIVATE_STYPE_IS_DECLARED
|
||||
union PRIVATE_STYPE
|
||||
{
|
||||
#line 81 "engines/private/grammar.y"
|
||||
|
||||
Private::Symbol *sym; /* symbol table pointer */
|
||||
int (**inst)(); /* machine instruction */
|
||||
char *s; /* string value */
|
||||
int *i; /* integer value */
|
||||
int narg; /* auxiliary value to count function arguments */
|
||||
|
||||
#line 104 "engines/private/tokens.h"
|
||||
|
||||
};
|
||||
typedef union PRIVATE_STYPE PRIVATE_STYPE;
|
||||
# define PRIVATE_STYPE_IS_TRIVIAL 1
|
||||
# define PRIVATE_STYPE_IS_DECLARED 1
|
||||
#endif
|
||||
|
||||
|
||||
extern PRIVATE_STYPE PRIVATE_lval;
|
||||
|
||||
|
||||
int PRIVATE_parse (void);
|
||||
|
||||
|
||||
#endif /* !YY_PRIVATE_ENGINES_PRIVATE_TOKENS_H_INCLUDED */
|
||||
Reference in New Issue
Block a user