Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,150 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_DCSCRIPT_H
#define WINTERMUTE_DCSCRIPT_H
namespace Wintermute {
#define SCRIPT_MAGIC 0xDEC0ADDE
#define SCRIPT_VERSION 0x0102
// value types
typedef enum {
VAL_NULL,
VAL_STRING,
VAL_INT,
VAL_BOOL,
VAL_FLOAT,
VAL_OBJECT,
VAL_NATIVE,
VAL_VARIABLE_REF
} TValType;
// script states
typedef enum {
SCRIPT_RUNNING,
SCRIPT_WAITING,
SCRIPT_SLEEPING,
SCRIPT_FINISHED,
SCRIPT_PERSISTENT,
SCRIPT_ERROR,
SCRIPT_PAUSED,
SCRIPT_WAITING_SCRIPT,
SCRIPT_THREAD_FINISHED
} TScriptState;
// opcodes
typedef enum {
II_DEF_VAR = 0,
II_DEF_GLOB_VAR,
II_RET,
II_RET_EVENT,
II_CALL,
II_CALL_BY_EXP,
II_EXTERNAL_CALL,
II_SCOPE,
II_CORRECT_STACK,
II_CREATE_OBJECT,
II_POP_EMPTY,
II_PUSH_VAR,
II_PUSH_VAR_REF,
II_POP_VAR,
II_PUSH_VAR_THIS, // push current this on stack
II_PUSH_INT,
II_PUSH_BOOL,
II_PUSH_FLOAT,
II_PUSH_STRING,
II_PUSH_NULL,
II_PUSH_THIS_FROM_STACK,
II_PUSH_THIS,
II_POP_THIS,
II_PUSH_BY_EXP,
II_POP_BY_EXP,
II_JMP,
II_JMP_FALSE,
II_ADD,
II_SUB,
II_MUL,
II_DIV,
II_MODULO,
II_NOT,
II_AND,
II_OR,
II_CMP_EQ,
II_CMP_NE,
II_CMP_L,
II_CMP_G,
II_CMP_LE,
II_CMP_GE,
II_CMP_STRICT_EQ,
II_CMP_STRICT_NE,
II_DBG_LINE,
II_POP_REG1,
II_PUSH_REG1,
II_DEF_CONST_VAR
} TInstruction;
// operation code types
typedef enum {
OPCODES_UNCHANGED = 0
#ifdef ENABLE_FOXTAIL
,
OPCODES_FOXTAIL_1_2_896,
OPCODES_FOXTAIL_1_2_902
#endif
} TOpcodesType;
// external data types
typedef enum {
TYPE_VOID = 0,
TYPE_BOOL,
TYPE_LONG,
TYPE_BYTE,
TYPE_STRING,
TYPE_FLOAT,
TYPE_DOUBLE,
TYPE_MEMBUFFER
} TExternalType;
// call types
typedef enum {
CALL_STDCALL = 0,
CALL_CDECL,
CALL_THISCALL
} TCallType;
// element types
typedef enum {
ELEMENT_STRING = 0
} TElementType;
} // End of namespace Wintermute
#endif

View 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/>.
*
*/
#include "common/tokenizer.h"
#include "debuggable_script.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.h"
#include "engines/wintermute/debugger/breakpoint.h"
#include "engines/wintermute/debugger/script_monitor.h"
#include "engines/wintermute/debugger/watch_instance.h"
namespace Wintermute {
DebuggableScript::DebuggableScript(BaseGame *inGame, DebuggableScEngine *engine) : ScScript(inGame, engine), _engine(engine), _stepDepth(kDefaultStepDepth) {
_engine->_watches.subscribe(this);
for (uint i = 0; i < _engine->_watches.size(); i++) {
_watchInstances.add(new WatchInstance(_engine->_watches[i], this));
}
}
DebuggableScript::~DebuggableScript() {
for (int32 i = 0; i < _watchInstances.getSize(); i++) {
delete _watchInstances[i];
}
_engine->_watches.unsubscribe(this);
}
void DebuggableScript::preInstHook(uint32 inst) {}
void DebuggableScript::postInstHook(uint32 inst) {
if (inst == II_DBG_LINE) {
for (uint j = 0; j < _engine->_breakpoints.size(); j++) {
_engine->_breakpoints[j]->evaluate(this);
}
if (_callStack->_sP <= _stepDepth) {
_engine->_monitor->notifyStep(this);
}
}
for (int32 i = 0; i < _watchInstances.getSize(); i++) {
this->_watchInstances[i]->evaluate();
}
}
void DebuggableScript::setStepDepth(int depth) {
_stepDepth = depth;
}
void DebuggableScript::step() {
setStepDepth(_callStack->_sP);
// TODO double check
}
void DebuggableScript::stepContinue() {
setStepDepth(kDefaultStepDepth);
}
void DebuggableScript::stepFinish() {
setStepDepth(_callStack->_sP - 1);
}
ScValue *DebuggableScript::resolveName(const Common::String &name) {
Common::String trimmed = name;
trimmed.trim();
Common::StringTokenizer st = Common::StringTokenizer(trimmed.c_str(), ".");
Common::String nextToken;
nextToken = st.nextToken();
char cstr[256]; // TODO not pretty
Common::strlcpy(cstr, nextToken.c_str(), nextToken.size() + 1);
cstr[255] = '\0'; // We 0-terminate it just in case it's > 256 chars.
ScValue *value = getVar(cstr);
ScValue *res = new ScValue(_game);
if (value == nullptr) {
return res;
}
nextToken = st.nextToken();
while (nextToken.size() > 0 && (value->isObject() || value->isNative())) {
value = value->getProp(nextToken.c_str());
nextToken = st.nextToken();
if (value == nullptr) {
return res;
}
}
res->copy(value);
return res;
}
uint DebuggableScript::dbgGetLine() const {
return _currentLine;
}
Common::String DebuggableScript::dbgGetFilename() const {
return _filename;
}
void DebuggableScript::updateWatches() {
// We drop obsolete watches
for (int32 i = 0; i < _watchInstances.getSize(); i++) {
Watch *findMe = _watchInstances[i]->_watch;
if (Common::find(_engine->_watches.begin(), _engine->_watches.end(), findMe) == _engine->_watches.end()) {
// Not found on engine-wide list, must have been removed from watches. Must remove it from local list.
delete _watchInstances[i];
_watchInstances.removeAt(i);
}
}
// We add any new watches
for (uint i = 0; i < _engine->_watches.size(); i++) {
Watch *findMe = _engine->_watches[i];
if (Common::find(_engine->_watches.begin(), _engine->_watches.end(), findMe) == _engine->_watches.end()) {
// Not found on local list, must be a new one.
_watchInstances.add(new WatchInstance(_engine->_watches[i], this));
}
}
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,66 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef DEBUGGABLE_SCRIPT_H_
#define DEBUGGABLE_SCRIPT_H_
#include "engines/wintermute/base/scriptables/script.h"
namespace Wintermute {
class ScriptMonitor;
class Watch;
class WatchInstance;
class DebuggableScEngine;
class DebuggableScript : public ScScript {
static const int kDefaultStepDepth = -2;
int32 _stepDepth;
DebuggableScEngine *_engine;
BaseArray<WatchInstance *> _watchInstances;
void preInstHook(uint32 inst) override;
void postInstHook(uint32 inst) override;
void setStepDepth(int depth);
public:
DebuggableScript(BaseGame *inGame, DebuggableScEngine *engine);
~DebuggableScript() override;
ScValue *resolveName(const Common::String &name);
/**
* Return argument to last II_DBG_LINE encountered
*/
virtual uint dbgGetLine() const;
virtual Common::String dbgGetFilename() const;
/**
* Execute one more instruction
*/
void step();
/**
* Continue execution
*/
void stepContinue();
/**
* Continue execution until the activation record on top of the stack is popped
*/
void stepFinish();
void updateWatches();
};
} // End of namespace Wintermute
#endif /* DEBUGGABLE_SCRIPT_H_ */

View File

@@ -0,0 +1,34 @@
/* 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 "debuggable_script_engine.h"
#include "debuggable_script.h"
#include "engines/wintermute/debugger/watch_instance.h"
namespace Wintermute {
DebuggableScEngine::DebuggableScEngine(BaseGame *inGame) : ScEngine(inGame), _monitor(nullptr) {}
void DebuggableScEngine::attachMonitor(ScriptMonitor *monitor) {
_monitor = monitor;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,109 @@
/* 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 DEBUGGABLE_SCRIPT_ENGINE_H_
#define DEBUGGABLE_SCRIPT_ENGINE_H_
#include "engines/wintermute/base/scriptables/script_engine.h"
#include "engines/wintermute/coll_templ.h"
#include "common/algorithm.h"
#include "engines/wintermute/base/scriptables/debuggable/debuggable_script.h"
namespace Wintermute {
class Breakpoint;
class Watch;
class DebuggableScript;
class DebuggableScEngine;
class ScriptMonitor;
class PublisherWArray : private Common::Array<Watch *> {
Common::Array<DebuggableScript *> _subscribers;
void notifySubscribers() {
for (uint i = 0; i < _subscribers.size(); i++) {
_subscribers[i]->updateWatches();
}
}
public:
void subscribe(DebuggableScript *script) {
if (Common::find(_subscribers.begin(), _subscribers.end(), script) == _subscribers.end()) {
// If not already contained
_subscribers.push_back(script);
}
}
void unsubscribe(DebuggableScript *script) {
int location = -1;
for (uint i = 0; i < _subscribers.size() && location == -1; i++) {
if (_subscribers[i] == script) {
location = i;
}
}
if (location >= 0) {
_subscribers.remove_at(location);
} else {
// TODO: If this happens... it's funny. Some script out there forgot to subscribe.
}
}
void push_back(Watch *newElement) {
Common::Array<Watch *>::push_back(newElement);
notifySubscribers();
}
size_type size() {
return Common::Array<Watch *>::size();
}
iterator begin() {
return Common::Array<Watch *>::begin();
}
iterator end() {
return Common::Array<Watch *>::end();
}
Watch *&operator[](size_type idx) {
return Common::Array<Watch *>::operator[](idx);
}
Watch *remove_at(size_type idx) {
Watch *res = Common::Array<Watch *>::remove_at(idx);
notifySubscribers();
return res;
}
};
class DebuggableScEngine : public ScEngine {
Common::Array<Breakpoint *> _breakpoints;
PublisherWArray _watches;
ScriptMonitor *_monitor;
public:
DebuggableScEngine(BaseGame *inGame);
void attachMonitor(ScriptMonitor *);
friend class DebuggerController;
friend class DebuggableScript;
friend class ScScript;
friend class WatchableScriptArray;
};
} // End of namespace Wintermute
#endif /* DEBUGGABLE_SCRIPT_ENGINE_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,178 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_SCSCRIPT_H
#define WINTERMUTE_SCSCRIPT_H
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/base/scriptables/dcscript.h" // Added by ClassView
#include "engines/wintermute/coll_templ.h"
#include "engines/wintermute/persistent.h"
namespace Wintermute {
class BaseScriptHolder;
class BaseObject;
class ScEngine;
class ScStack;
class ScValue;
class ScScript : public BaseClass {
public:
BaseArray<int> _breakpoints;
bool _tracingMode;
ScScript *_parentScript;
bool _unbreakable;
bool finishThreads();
bool copyParameters(ScStack *stack);
void afterLoad();
ScValue *_operand;
ScValue *_reg1;
bool _freezable;
bool resume();
bool pause();
bool canHandleEvent(const char *eventName);
bool canHandleMethod(const char *methodName);
bool createThread(ScScript *original, uint32 initIP, const char *eventName);
bool createMethodThread(ScScript *original, const char *methodName);
ScScript *invokeEventHandler(const char *eventName, bool unbreakable = false);
uint32 _timeSlice;
DECLARE_PERSISTENT(ScScript, BaseClass)
void runtimeError(const char *fmt, ...);
bool run();
bool finish(bool includingThreads = false);
bool sleep(uint32 duration);
bool waitForExclusive(BaseObject *object);
bool waitFor(BaseObject *object);
uint32 _waitTime;
bool _waitFrozen;
BaseObject *_waitObject;
ScScript *_waitScript;
TScriptState _state;
TScriptState _origState;
ScValue *getVar(char *name);
uint32 getFuncPos(const char *name);
uint32 getEventPos(const char *name);
uint32 getMethodPos(const char *name);
typedef struct {
uint32 magic;
uint32 version;
uint32 codeStart;
uint32 funcTable;
uint32 symbolTable;
uint32 eventTable;
uint32 externalsTable;
uint32 methodTable;
} TScriptHeader;
TScriptHeader _header{};
typedef struct {
char *name;
uint32 pos;
} TFunctionPos;
typedef struct {
char *name;
uint32 pos;
} TMethodPos;
typedef struct {
char *name;
uint32 pos;
} TEventPos;
typedef struct {
char *name;
char *dll_name;
TCallType call_type;
TExternalType returns;
int32 numParams;
TExternalType *params;
} TExternalFunction;
ScStack *_callStack;
ScStack *_thisStack;
ScStack *_scopeStack;
ScStack *_stack;
ScValue *_globals;
ScEngine *_engine;
int32 _currentLine;
virtual bool executeInstruction();
char *getString();
uint32 getDWORD();
double getFloat();
void cleanup();
bool create(const char *filename, byte *buffer, uint32 size, BaseScriptHolder *owner);
uint32 _iP;
void readHeader();
uint32 _bufferSize;
byte *_buffer;
Common::SeekableReadStream *_scriptStream;
ScScript(BaseGame *inGame, ScEngine *engine);
~ScScript() override;
char *_filename;
char **_symbols;
uint32 _numSymbols;
TFunctionPos *_functions;
TMethodPos *_methods;
TEventPos *_events;
uint32 _numExternals;
TExternalFunction *_externals;
uint32 _numFunctions;
uint32 _numMethods;
uint32 _numEvents;
bool _thread;
bool _methodThread;
char *_threadEvent;
BaseScriptHolder *_owner;
ScScript::TExternalFunction *getExternal(char *name);
bool externalCall(ScStack *stack, ScStack *thisStack, ScScript::TExternalFunction *function);
private:
bool initScript();
bool initTables();
virtual void preInstHook(uint32 inst);
virtual void postInstHook(uint32 inst);
#ifdef ENABLE_FOXTAIL
TOpcodesType _opcodesType;
void initOpcodesType();
uint32 decodeAltOpcodes(uint32 inst);
#endif
bool _enableFloatCompareWA{};
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,644 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/scriptables/script_engine.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/utils/utils.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
IMPLEMENT_PERSISTENT(ScEngine, true)
#define COMPILER_DLL "dcscomp.dll"
//////////////////////////////////////////////////////////////////////////
ScEngine::ScEngine(BaseGame *inGame) : BaseClass(inGame) {
_game->LOG(0, "Initializing scripting engine...");
if (_compilerAvailable) {
_game->LOG(0, " Script compiler bound successfuly");
} else {
_game->LOG(0, " Script compiler is NOT available");
}
_globals = new ScValue(_game);
// register 'Game' as global variable
if (!_globals->propExists("Game")) {
ScValue val(_game);
val.setNative(_game, true);
_globals->setProp("Game", &val);
}
// register 'Math' as global variable
if (!_globals->propExists("Math")) {
ScValue val(_game);
val.setNative(_game->_mathClass, true);
_globals->setProp("Math", &val);
}
// register 'Directory' as global variable
if (!_globals->propExists("Directory")) {
ScValue val(_game);
val.setNative(_game->_directoryClass, true);
_globals->setProp("Directory", &val);
}
// prepare script cache
for (int i = 0; i < MAX_CACHED_SCRIPTS; i++) {
_cachedScripts[i] = nullptr;
}
_currentScript = nullptr;
_isProfiling = false;
_profilingStartTime = 0;
//enableProfiling();
}
//////////////////////////////////////////////////////////////////////////
ScEngine::~ScEngine() {
_game->LOG(0, "Shutting down scripting engine");
disableProfiling();
cleanup();
}
//////////////////////////////////////////////////////////////////////////
bool ScEngine::cleanup() {
for (int32 i = 0; i < _scripts.getSize(); i++) {
if (!_scripts[i]->_thread && _scripts[i]->_owner) {
_scripts[i]->_owner->removeScript(_scripts[i]);
}
delete _scripts[i];
_scripts.removeAt(i);
i--;
}
_scripts.removeAll();
SAFE_DELETE(_globals);
emptyScriptCache();
_currentScript = nullptr; // ref only
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
byte *ScEngine::loadFile(void *data, char *filename, uint32 *size) {
BaseGame *game = (BaseGame *)data;
return game->_fileManager->readWholeFile(filename, size);
}
//////////////////////////////////////////////////////////////////////////
void ScEngine::closeFile(void *data, byte *buffer) {
delete[] buffer;
}
//////////////////////////////////////////////////////////////////////////
void ScEngine::parseElement(void *data, int line, int type, void *elementData) {
}
//////////////////////////////////////////////////////////////////////////
ScScript *ScEngine::runScript(const char *filename, BaseScriptHolder *owner) {
byte *compBuffer;
uint32 compSize;
// get script from cache
compBuffer = getCompiledScript(filename, &compSize);
if (!compBuffer) {
return nullptr;
}
// add new script
#if EXTENDED_DEBUGGER_ENABLED
DebuggableScEngine* debuggableEngine;
debuggableEngine = dynamic_cast<DebuggableScEngine*>(this);
// TODO: Not pretty
assert(debuggableEngine);
ScScript *script = new DebuggableScript(_game, debuggableEngine);
#else
ScScript *script = new ScScript(_game, this);
#endif
bool ret = script->create(filename, compBuffer, compSize, owner);
if (DID_FAIL(ret)) {
_game->LOG(ret, "Error running script '%s'...", filename);
delete script;
return nullptr;
} else {
// publish the "self" pseudo-variable
ScValue val(_game);
if (owner) {
val.setNative(owner, true);
} else {
val.setNULL();
}
script->_globals->setProp("self", &val);
script->_globals->setProp("this", &val);
_scripts.add(script);
return script;
}
}
//////////////////////////////////////////////////////////////////////////
bool ScEngine::isRunningScript(const char *filename) {
for (int32 i = 0; i < _scripts.getSize(); i++) {
if (strcmp(_scripts[i]->_filename, filename) == 0) {
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
byte *ScEngine::getCompiledScript(const char *filename, uint32 *outSize, bool ignoreCache) {
// is script in cache?
if (!ignoreCache) {
for (int i = 0; i < MAX_CACHED_SCRIPTS; i++) {
if (_cachedScripts[i] && scumm_stricmp(_cachedScripts[i]->_filename, filename) == 0) {
_cachedScripts[i]->_timestamp = BasePlatform::getTime();
*outSize = _cachedScripts[i]->_size;
return _cachedScripts[i]->_buffer;
}
}
}
// nope, load it
byte *compBuffer;
uint32 compSize;
uint32 size;
byte *buffer = _game->_fileManager->readWholeFile(filename, &size);
if (!buffer) {
_game->LOG(0, "ScEngine::getCompiledScript - error opening script '%s'", filename);
return nullptr;
}
// needs to be compiled?
if (READ_LE_UINT32(buffer) == SCRIPT_MAGIC) {
compBuffer = buffer;
compSize = size;
} else {
if (!_compilerAvailable) {
_game->LOG(0, "ScEngine::getCompiledScript - script '%s' needs to be compiled but compiler is not available", filename);
delete[] buffer;
return nullptr;
}
// This code will never be called, since _compilerAvailable is const false.
// It's only here in the event someone would want to reinclude the compiler.
error("Script needs compilation, ScummVM does not contain a WME compiler");
}
byte *ret = nullptr;
// add script to cache
CScCachedScript *cachedScript = new CScCachedScript(filename, compBuffer, compSize);
if (cachedScript) {
int index = 0;
uint32 minTime = BasePlatform::getTime();
for (int i = 0; i < MAX_CACHED_SCRIPTS; i++) {
if (_cachedScripts[i] == nullptr) {
index = i;
break;
} else if (_cachedScripts[i]->_timestamp <= minTime) {
minTime = _cachedScripts[i]->_timestamp;
index = i;
}
}
if (_cachedScripts[index] != nullptr) {
delete _cachedScripts[index];
}
_cachedScripts[index] = cachedScript;
ret = cachedScript->_buffer;
*outSize = cachedScript->_size;
}
// cleanup
delete[] buffer;
return ret;
}
//////////////////////////////////////////////////////////////////////////
bool ScEngine::tick() {
if (_scripts.getSize() == 0) {
return STATUS_OK;
}
// resolve waiting scripts
for (int32 i = 0; i < _scripts.getSize(); i++) {
switch (_scripts[i]->_state) {
case SCRIPT_WAITING: {
/*
bool obj_found=false;
for(int j=0; j<_game->_regObjects.size(); j++)
{
if (_game->_regObjects[j] == _scripts[i]->_waitObject)
{
if (_game->_regObjects[j]->IsReady()) _scripts[i]->Run();
obj_found = true;
break;
}
}
if (!obj_found) _scripts[i]->finish(); // _waitObject no longer exists
*/
if (_game->validObject(_scripts[i]->_waitObject)) {
if (_scripts[i]->_waitObject->isReady()) {
_scripts[i]->run();
}
} else {
_scripts[i]->finish();
}
break;
}
case SCRIPT_SLEEPING: {
if (_scripts[i]->_waitFrozen) {
if (_scripts[i]->_waitTime <= BasePlatform::getTime()) {
_scripts[i]->run();
}
} else {
if (_scripts[i]->_waitTime <= _game->_timer) {
_scripts[i]->run();
}
}
break;
}
case SCRIPT_WAITING_SCRIPT: {
if (!isValidScript(_scripts[i]->_waitScript) || _scripts[i]->_waitScript->_state == SCRIPT_ERROR) {
// fake return value
_scripts[i]->_stack->pushNULL();
_scripts[i]->_waitScript = nullptr;
_scripts[i]->run();
} else {
if (_scripts[i]->_waitScript->_state == SCRIPT_THREAD_FINISHED) {
// copy return value
_scripts[i]->_stack->push(_scripts[i]->_waitScript->_stack->pop());
_scripts[i]->run();
_scripts[i]->_waitScript->finish();
_scripts[i]->_waitScript = nullptr;
}
}
break;
}
default:
break;
} // switch
} // for each script
// execute scripts
for (int32 i = 0; i < _scripts.getSize(); i++) {
// skip paused scripts
if (_scripts[i]->_state == SCRIPT_PAUSED) {
continue;
}
// time sliced script
if (_scripts[i]->_timeSlice > 0) {
uint32 startTime = BasePlatform::getTime();
while (_scripts[i]->_state == SCRIPT_RUNNING && BasePlatform::getTime() - startTime < _scripts[i]->_timeSlice) {
_currentScript = _scripts[i];
_scripts[i]->executeInstruction();
}
if (_isProfiling && _scripts[i]->_filename && _scripts[i]->_filename[0]) {
addScriptTime(_scripts[i]->_filename, BasePlatform::getTime() - startTime);
}
}
// normal script
else {
uint32 startTime = 0;
bool isProfiling = _isProfiling;
if (isProfiling) {
startTime = BasePlatform::getTime();
}
while (_scripts[i]->_state == SCRIPT_RUNNING) {
_currentScript = _scripts[i];
_scripts[i]->executeInstruction();
}
if (isProfiling && _scripts[i]->_filename && _scripts[i]->_filename[0]) {
addScriptTime(_scripts[i]->_filename, BasePlatform::getTime() - startTime);
}
}
_currentScript = nullptr;
}
removeFinishedScripts();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool ScEngine::tickUnbreakable() {
ScScript *oldScript = _currentScript;
// execute unbreakable scripts
for (int32 i = 0; i < _scripts.getSize(); i++) {
if (!_scripts[i]->_unbreakable) {
continue;
}
while (_scripts[i]->_state == SCRIPT_RUNNING) {
_currentScript = _scripts[i];
_scripts[i]->executeInstruction();
}
_scripts[i]->finish();
_currentScript = oldScript;
}
// NB: Don't remove finished scripts here since we could be recursively
// executing scripts. Doing so could invalidate the outer iteration in
// ::tick() over _scripts.
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool ScEngine::removeFinishedScripts() {
// remove finished scripts
for (int32 i = 0; i < _scripts.getSize(); i++) {
if (_scripts[i]->_state == SCRIPT_FINISHED || _scripts[i]->_state == SCRIPT_ERROR) {
if (!_scripts[i]->_thread && _scripts[i]->_owner) {
_scripts[i]->_owner->removeScript(_scripts[i]);
}
delete _scripts[i];
_scripts.removeAt(i);
i--;
}
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
int ScEngine::getNumScripts(int *running, int *waiting, int *persistent) {
int numRunning = 0, numWaiting = 0, numPersistent = 0, numTotal = 0;
for (int32 i = 0; i < _scripts.getSize(); i++) {
if (_scripts[i]->_state == SCRIPT_FINISHED) {
continue;
}
switch (_scripts[i]->_state) {
case SCRIPT_RUNNING:
case SCRIPT_SLEEPING:
case SCRIPT_PAUSED:
numRunning++;
break;
case SCRIPT_WAITING:
numWaiting++;
break;
case SCRIPT_PERSISTENT:
numPersistent++;
break;
default:
break;
}
numTotal++;
}
if (running) {
*running = numRunning;
}
if (waiting) {
*waiting = numWaiting;
}
if (persistent) {
*persistent = numPersistent;
}
return numTotal;
}
//////////////////////////////////////////////////////////////////////////
bool ScEngine::emptyScriptCache() {
for (int i = 0; i < MAX_CACHED_SCRIPTS; i++) {
if (_cachedScripts[i]) {
SAFE_DELETE(_cachedScripts[i]);
}
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool ScEngine::resetObject(BaseObject *object) {
// terminate all scripts waiting for this object
for (int32 i = 0; i < _scripts.getSize(); i++) {
if (_scripts[i]->_state == SCRIPT_WAITING && _scripts[i]->_waitObject == object) {
if (!_game->_compatKillMethodThreads) {
resetScript(_scripts[i]);
}
bool isThread = _scripts[i]->_methodThread || _scripts[i]->_thread;
_scripts[i]->finish(!isThread); // 1.9b1 - top-level script kills its threads as well
}
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool ScEngine::resetScript(ScScript *script) {
// terminate all scripts waiting for this script
for (int32 i = 0; i < _scripts.getSize(); i++) {
if (_scripts[i]->_state == SCRIPT_WAITING_SCRIPT && _scripts[i]->_waitScript == script) {
_scripts[i]->finish();
}
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool ScEngine::persist(BasePersistenceManager *persistMgr) {
if (!persistMgr->getIsSaving()) {
cleanup();
}
persistMgr->transferPtr(TMEMBER_PTR(_game));
persistMgr->transferPtr(TMEMBER_PTR(_currentScript));
persistMgr->transferPtr(TMEMBER_PTR(_globals));
_scripts.persist(persistMgr);
// initialise to defaults
if (!persistMgr->getIsSaving()) {
_isProfiling = false;
_profilingStartTime = 0;
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
void ScEngine::editorCleanup() {
for (int32 i = 0; i < _scripts.getSize(); i++) {
if (_scripts[i]->_owner == nullptr && (_scripts[i]->_state == SCRIPT_FINISHED || _scripts[i]->_state == SCRIPT_ERROR)) {
delete _scripts[i];
_scripts.removeAt(i);
i--;
}
}
}
//////////////////////////////////////////////////////////////////////////
bool ScEngine::pauseAll() {
for (int32 i = 0; i < _scripts.getSize(); i++) {
if (_scripts[i] != _currentScript) {
_scripts[i]->pause();
}
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool ScEngine::resumeAll() {
for (int32 i = 0; i < _scripts.getSize(); i++) {
_scripts[i]->resume();
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool ScEngine::isValidScript(ScScript *script) {
for (int32 i = 0; i < _scripts.getSize(); i++) {
if (_scripts[i] == script) {
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
bool ScEngine::clearGlobals(bool includingNatives) {
_globals->cleanProps(includingNatives);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
void ScEngine::addScriptTime(const char *filename, uint32 time) {
if (!_isProfiling) {
return;
}
AnsiString fileName = filename;
fileName.toLowercase();
_scriptTimes[fileName] += time;
}
//////////////////////////////////////////////////////////////////////////
void ScEngine::enableProfiling() {
if (_isProfiling) {
return;
}
// destroy old data, if any
_scriptTimes.clear();
_profilingStartTime = BasePlatform::getTime();
_isProfiling = true;
}
//////////////////////////////////////////////////////////////////////////
void ScEngine::disableProfiling() {
if (!_isProfiling) {
return;
}
dumpStats();
_isProfiling = false;
}
//////////////////////////////////////////////////////////////////////////
void ScEngine::dumpStats() {
error("DumpStats not ported to ScummVM yet");
/* uint32 totalTime = BasePlatform::getTime() - _profilingStartTime;
typedef std::vector <std::pair<uint32, std::string> > TimeVector;
TimeVector times;
ScriptTimes::iterator it;
for (it = _scriptTimes.begin(); it != _scriptTimes.end(); ++it) {
times.push_back(std::pair<uint32, std::string> (it->_value, it->_key));
}
std::sort(times.begin(), times.end());
TimeVector::reverse_iterator tit;
_game->LOG(0, "***** Script profiling information: *****");
_game->LOG(0, " %-40s %fs", "Total execution time", (float)totalTime / 1000);
for (tit = times.rbegin(); tit != times.rend(); ++tit) {
_game->LOG(0, " %-40s %fs (%f%%)", tit->second.c_str(), (float)tit->first / 1000, (float)tit->first / (float)totalTime * 100);
}*/
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,126 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_SCENGINE_H
#define WINTERMUTE_SCENGINE_H
#include "engines/wintermute/persistent.h"
#include "engines/wintermute/coll_templ.h"
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/platform_osystem.h"
namespace Wintermute {
#define MAX_CACHED_SCRIPTS 20
class ScScript;
class ScValue;
class BaseObject;
class BaseScriptHolder;
class ScEngine : public BaseClass {
public:
class CScCachedScript {
public:
CScCachedScript(const char *filename, byte *buffer, uint32 size) {
_timestamp = BasePlatform::getTime();
_buffer = new byte[size];
if (_buffer) {
memcpy(_buffer, buffer, size);
}
_size = size;
size_t filenameSize = strlen(filename) + 1;
_filename = new char[filenameSize];
Common::strcpy_s(_filename, filenameSize, filename);
};
~CScCachedScript() {
if (_buffer) {
delete[] _buffer;
}
if (_filename)
delete[] _filename;
};
uint32 _timestamp;
byte *_buffer;
uint32 _size;
char *_filename;
};
public:
bool clearGlobals(bool includingNatives = false);
bool tickUnbreakable();
bool removeFinishedScripts();
bool isValidScript(ScScript *script);
ScScript *_currentScript;
bool resumeAll();
bool pauseAll();
void editorCleanup();
bool resetObject(BaseObject *object);
bool resetScript(ScScript *script);
bool emptyScriptCache();
byte *getCompiledScript(const char *filename, uint32 *outSize, bool ignoreCache = false);
DECLARE_PERSISTENT(ScEngine, BaseClass)
bool cleanup();
int getNumScripts(int *running = nullptr, int *waiting = nullptr, int *persistent = nullptr);
bool tick();
ScValue *_globals;
ScScript *runScript(const char *filename, BaseScriptHolder *owner = nullptr);
bool isRunningScript(const char *filename);
static const bool _compilerAvailable = false;
ScEngine(BaseGame *inGame);
~ScEngine() override;
static byte *loadFile(void *data, char *filename, uint32 *size);
static void closeFile(void *data, byte *buffer);
static void parseElement(void *data, int line, int type, void *elementData);
BaseArray<ScScript *> _scripts;
void enableProfiling();
void disableProfiling();
bool isProfiling() {
return _isProfiling;
}
void addScriptTime(const char *filename, uint32 time);
void dumpStats();
private:
CScCachedScript *_cachedScripts[MAX_CACHED_SCRIPTS];
bool _isProfiling;
uint32 _profilingStartTime;
typedef Common::HashMap<Common::String, uint32> ScriptTimes;
ScriptTimes _scriptTimes;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,278 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/persistent.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/system/sys_instance.h"
#include "engines/wintermute/base/scriptables/script_ext_array.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
IMPLEMENT_PERSISTENT(SXArray, false)
BaseScriptable *makeSXArray(BaseGame *inGame, ScStack *stack) {
return new SXArray(inGame, stack);
}
//////////////////////////////////////////////////////////////////////////
SXArray::SXArray(BaseGame *inGame, ScStack *stack) : BaseScriptable(inGame) {
_length = 0;
_values = new ScValue(_game);
int numParams = stack->pop()->getInt(0);
if (numParams == 1) {
_length = stack->pop()->getInt(0);
} else if (numParams > 1) {
_length = numParams;
char paramName[20];
for (int i = 0; i < numParams; i++) {
Common::sprintf_s(paramName, "%d", i);
_values->setProp(paramName, stack->pop());
}
}
}
//////////////////////////////////////////////////////////////////////////
SXArray::SXArray(BaseGame *inGame) : BaseScriptable(inGame) {
_length = 0;
_values = new ScValue(_game);
}
//////////////////////////////////////////////////////////////////////////
SXArray::~SXArray() {
SAFE_DELETE(_values);
}
//////////////////////////////////////////////////////////////////////////
const char *SXArray::scToString() {
static char dummy[32768];
dummy[0] = '\0';
char propName[20];
for (int i = 0; i < _length; i++) {
Common::sprintf_s(propName, "%d", i);
ScValue *val = _values->getProp(propName);
if (val) {
if (strlen(dummy) + strlen(val->getString()) < 32768) {
Common::strcat_s(dummy, val->getString());
}
}
if (i < _length - 1 && strlen(dummy) + 1 < 32768) {
Common::strcat_s(dummy, ",");
}
}
return dummy;
}
//////////////////////////////////////////////////////////////////////////
bool SXArray::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
//////////////////////////////////////////////////////////////////////////
// Push
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Push") == 0) {
int numParams = stack->pop()->getInt(0);
char paramName[20];
for (int i = 0; i < numParams; i++) {
_length++;
Common::sprintf_s(paramName, "%d", _length - 1);
_values->setProp(paramName, stack->pop(), true);
}
stack->pushInt(_length);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Pop
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Pop") == 0) {
stack->correctParams(0);
if (_length > 0) {
char paramName[20];
Common::sprintf_s(paramName, "%d", _length - 1);
stack->push(_values->getProp(paramName));
_values->deleteProp(paramName);
_length--;
} else {
stack->pushNULL();
}
return STATUS_OK;
}
#ifdef ENABLE_FOXTAIL
//////////////////////////////////////////////////////////////////////////
// [FoxTail] Delete
// Removes item from array by index, shifting other elements
// Used to shuffle arrays and delete found items in various scripts
// Return value is never used
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Delete") == 0) {
stack->correctParams(1);
int shiftPoint = stack->pop()->getInt(0);
char paramNameFrom[20];
char paramNameTo[20];
for (int i = shiftPoint; i < _length - 1 ; i++) {
Common::sprintf_s(paramNameFrom, "%d", i + 1);
Common::sprintf_s(paramNameTo, "%d", i);
_values->setProp(paramNameTo, _values->getProp(paramNameFrom), false);
}
_values->deleteProp(paramNameFrom);
_length--;
stack->pushNULL();
return STATUS_OK;
}
#endif
else {
return STATUS_FAILED;
}
}
//////////////////////////////////////////////////////////////////////////
ScValue *SXArray::scGetProperty(const char *name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Type") == 0) {
_scValue->setString("array");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Length
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Length") == 0) {
_scValue->setInt(_length);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// [number]
//////////////////////////////////////////////////////////////////////////
else {
char paramName[20];
if (validNumber(name, paramName)) {
return _values->getProp(paramName);
} else {
return _scValue;
}
}
}
//////////////////////////////////////////////////////////////////////////
bool SXArray::scSetProperty(const char *name, ScValue *value) {
//////////////////////////////////////////////////////////////////////////
// Length
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Length") == 0) {
int origLength = _length;
_length = MAX(value->getInt(0), 0);
char propName[20];
if (_length < origLength) {
for (int i = _length; i < origLength; i++) {
Common::sprintf_s(propName, "%d", i);
_values->deleteProp(propName);
}
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// [number]
//////////////////////////////////////////////////////////////////////////
else {
char paramName[20];
if (validNumber(name, paramName)) {
int index = atoi(paramName);
if (index >= _length) {
_length = index + 1;
}
return _values->setProp(paramName, value);
} else {
return STATUS_FAILED;
}
}
}
//////////////////////////////////////////////////////////////////////////
bool SXArray::persist(BasePersistenceManager *persistMgr) {
BaseScriptable::persist(persistMgr);
persistMgr->transferSint32(TMEMBER(_length));
persistMgr->transferPtr(TMEMBER_PTR(_values));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool SXArray::validNumber(const char *origStr, char *outStr) {
bool isNumber = true;
for (uint32 i = 0; i < strlen(origStr); i++) {
if (!(origStr[i] >= '0' && origStr[i] <= '9')) {
isNumber = false;
break;
}
}
if (isNumber) {
int index = atoi(origStr);
Common::sprintf_s(outStr, 20, "%d", index);
return true;
} else {
return false;
}
}
//////////////////////////////////////////////////////////////////////////
bool SXArray::push(ScValue *val) {
char paramName[20];
_length++;
Common::sprintf_s(paramName, "%d", _length - 1);
_values->setProp(paramName, val, true);
return STATUS_OK;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,53 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_SXARRAY_H
#define WINTERMUTE_SXARRAY_H
#include "engines/wintermute/base/base_scriptable.h"
namespace Wintermute {
class SXArray : public BaseScriptable {
public:
bool push(ScValue *val);
bool validNumber(const char *origStr, char *outStr);
DECLARE_PERSISTENT(SXArray, BaseScriptable)
SXArray(BaseGame *inGame, ScStack *stack);
SXArray(BaseGame *inGame);
~SXArray() override;
ScValue *scGetProperty(const char *name) override;
bool scSetProperty(const char *name, ScValue *value) override;
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
const char *scToString() override;
int32 _length;
ScValue *_values;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,320 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script_ext_date.h"
namespace Wintermute {
IMPLEMENT_PERSISTENT(SXDate, false)
BaseScriptable *makeSXDate(BaseGame *inGame, ScStack *stack) {
return new SXDate(inGame, stack);
}
//////////////////////////////////////////////////////////////////////////
SXDate::SXDate(BaseGame *inGame, ScStack *stack) : BaseScriptable(inGame) {
stack->correctParams(6);
memset(&_tm, 0, sizeof(_tm));
ScValue *valYear = stack->pop();
_tm.tm_year = valYear->getInt() - 1900;
_tm.tm_mon = stack->pop()->getInt() - 1;
_tm.tm_mday = stack->pop()->getInt();
_tm.tm_hour = stack->pop()->getInt();
_tm.tm_min = stack->pop()->getInt();
_tm.tm_sec = stack->pop()->getInt();
if (valYear->isNULL()) {
g_system->getTimeAndDate(_tm);
}
}
//////////////////////////////////////////////////////////////////////////
SXDate::~SXDate() {
}
//////////////////////////////////////////////////////////////////////////
const char *SXDate::scToString() {
// TODO: Make this more stringy, and less ISO 8601-like
_strRep.format("%04d-%02d-%02d - %02d:%02d:%02d", _tm.tm_year, _tm.tm_mon, _tm.tm_mday, _tm.tm_hour, _tm.tm_min, _tm.tm_sec);
return _strRep.c_str();
//return asctime(&_tm);
}
//////////////////////////////////////////////////////////////////////////
bool SXDate::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
//////////////////////////////////////////////////////////////////////////
// GetYear
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "GetYear") == 0) {
stack->correctParams(0);
stack->pushInt(_tm.tm_year + 1900);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetMonth
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetMonth") == 0) {
stack->correctParams(0);
stack->pushInt(_tm.tm_mon + 1);
return STATUS_OK;
}
#ifdef ENABLE_FOXTAIL
//////////////////////////////////////////////////////////////////////////
// [FoxTail] GetDay
// date.GetDate() was renamed to date.GetDay() in FoxTail 1.2.896 engine
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetDay") == 0) {
stack->correctParams(0);
stack->pushInt(_tm.tm_mday);
return STATUS_OK;
}
#endif
//////////////////////////////////////////////////////////////////////////
// GetDate
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetDate") == 0) {
stack->correctParams(0);
stack->pushInt(_tm.tm_mday);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetHours
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetHours") == 0) {
stack->correctParams(0);
stack->pushInt(_tm.tm_hour);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetMinutes
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetMinutes") == 0) {
stack->correctParams(0);
stack->pushInt(_tm.tm_min);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetSeconds
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetSeconds") == 0) {
stack->correctParams(0);
stack->pushInt(_tm.tm_sec);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetWeekday
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetWeekday") == 0) {
stack->correctParams(0);
stack->pushInt(_tm.tm_wday);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// SetYear
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "SetYear") == 0) {
stack->correctParams(1);
_tm.tm_year = stack->pop()->getInt() - 1900;
stack->pushNULL();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// SetMonth
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "SetMonth") == 0) {
stack->correctParams(1);
_tm.tm_mon = stack->pop()->getInt() - 1;
stack->pushNULL();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// SetDate
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "SetDate") == 0) {
stack->correctParams(1);
_tm.tm_mday = stack->pop()->getInt();
stack->pushNULL();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// SetHours
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "SetHours") == 0) {
stack->correctParams(1);
_tm.tm_hour = stack->pop()->getInt();
stack->pushNULL();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// SetMinutes
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "SetMinutes") == 0) {
stack->correctParams(1);
_tm.tm_min = stack->pop()->getInt();
stack->pushNULL();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// SetSeconds
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "SetSeconds") == 0) {
stack->correctParams(1);
_tm.tm_sec = stack->pop()->getInt();
stack->pushNULL();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// SetCurrentTime
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "SetCurrentTime") == 0) {
stack->correctParams(0);
g_system->getTimeAndDate(_tm);
stack->pushNULL();
return STATUS_OK;
} else {
return STATUS_FAILED;
}
}
//////////////////////////////////////////////////////////////////////////
ScValue *SXDate::scGetProperty(const char *name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Type") == 0) {
_scValue->setString("date");
return _scValue;
} else {
return _scValue;
}
}
//////////////////////////////////////////////////////////////////////////
bool SXDate::scSetProperty(const char *name, ScValue *value) {
/*
//////////////////////////////////////////////////////////////////////////
// Name
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Name") == 0) {
setName(value->getString());
return STATUS_OK;
}
else*/ return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
bool SXDate::persist(BasePersistenceManager *persistMgr) {
BaseScriptable::persist(persistMgr);
int32 year = _tm.tm_year;
int32 mon = _tm.tm_mon;
int32 mday = _tm.tm_mday;
int32 hour = _tm.tm_hour;
int32 min = _tm.tm_min;
int32 sec = _tm.tm_sec;
persistMgr->transferSint32(TMEMBER(year));
persistMgr->transferSint32(TMEMBER(mon));
persistMgr->transferSint32(TMEMBER(mday));
persistMgr->transferSint32(TMEMBER(hour));
persistMgr->transferSint32(TMEMBER(min));
persistMgr->transferSint32(TMEMBER(sec));
if (persistMgr->checkVersion(1, 2, 1)) {
int32 wday = _tm.tm_wday;
persistMgr->transferSint32(TMEMBER(wday));
_tm.tm_wday = wday;
}
_tm.tm_year = year;
_tm.tm_mon = mon;
_tm.tm_mday = mday;
_tm.tm_hour = hour;
_tm.tm_min = min;
_tm.tm_sec = sec;
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
int SXDate::scCompare(BaseScriptable *value) {
TimeDate time1 = _tm;
TimeDate time2 = ((SXDate *)value)->_tm;
if (time1.tm_year < time2.tm_year) {
return -1;
} else if (time1.tm_year == time2.tm_year) {
if (time1.tm_mon < time2.tm_mon) {
return -1;
} else if (time1.tm_mon == time2.tm_mon) {
if (time1.tm_mday < time2.tm_mday) {
return -1;
} else if (time1.tm_mday == time2.tm_mday) {
if (time1.tm_hour < time2.tm_hour) {
return -1;
} else if (time1.tm_hour == time2.tm_hour) {
if (time1.tm_min < time2.tm_min) {
return -1;
} else if (time1.tm_min == time2.tm_min) {
if (time1.tm_sec < time2.tm_sec) {
return -1;
} else if (time1.tm_sec == time2.tm_sec) {
return 0; // Equal
} else {
return 1; // Sec
}
} else {
return 1; // Minute
}
} else {
return 1; // Hour
}
} else {
return 1; // Day
}
} else {
return 1; // Month
}
} else {
return 1; // Year
}
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,53 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_SXDATE_H
#define WINTERMUTE_SXDATE_H
#include "common/system.h"
#include "engines/wintermute/base/base_scriptable.h"
namespace Wintermute {
class SXDate : public BaseScriptable {
public:
int scCompare(BaseScriptable *value) override;
DECLARE_PERSISTENT(SXDate, BaseScriptable)
SXDate(BaseGame *inGame, ScStack *stack);
~SXDate() override;
ScValue *scGetProperty(const char *name) override;
bool scSetProperty(const char *name, ScValue *value) override;
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
const char *scToString() override;
TimeDate _tm;
Common::String _strRep;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,207 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/scriptables/script_ext_array.h"
#include "engines/wintermute/base/scriptables/script_ext_directory.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/persistent.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IMPLEMENT_PERSISTENT(SXDirectory, true)
BaseScriptable *makeSXDirectory(BaseGame *inGame) {
return new SXDirectory(inGame);
}
//////////////////////////////////////////////////////////////////////////
SXDirectory::SXDirectory(BaseGame *inGame) : BaseScriptable(inGame) {
}
//////////////////////////////////////////////////////////////////////////
SXDirectory::~SXDirectory() {
}
//////////////////////////////////////////////////////////////////////////
bool SXDirectory::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
//////////////////////////////////////////////////////////////////////////
// Create
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Create") == 0) {
stack->correctParams(1);
const char *dirName = stack->pop()->getString();
if (strcmp(dirName, "saves") == 0) {
// Known games that do this: alphapolaris, hamlet, lostbride, papasdaughters1, papasdaughters2, polechudes, etc
// No need to actually create anything, files will be stored at SavefileManager
stack->pushBool(true);
} else {
// No currently known games need this
warning("Directory.Create is not implemented! Returning false...");
stack->pushBool(false);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Delete
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Delete") == 0) {
stack->correctParams(1);
stack->pop()->getString();
// No currently known games need this
warning("Directory.Delete is not implemented! Returning false...");
stack->pushBool(false);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetFiles / GetDirectories
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetFiles") == 0 || strcmp(name, "GetDirectories") == 0) {
stack->correctParams(2);
const char *dirName = stack->pop()->getString();
stack->pop()->getString();
stack->pushInt(0);
BaseScriptable *array = makeSXArray(_game, stack);
if (strcmp(dirName, "saves") == 0 && strcmp(name, "GetFiles") == 0) {
// used in "Tale of The Lost Bride and A Hidden Treasure"
// returns list of saves, removing "lostbride-win-ru.saves_" prefix
Common::StringArray fnames;
BaseFileManager::getEngineInstance()->listMatchingFiles(fnames, "*");
for (uint32 i = 0; i < fnames.size(); i++) {
stack->pushString(fnames[i].c_str());
((SXArray *)array)->push(stack->pop());
}
} else if (strcmp(dirName, "X:\\FBI\\data\\scenes\\17-magic\\") == 0 && strcmp(name, "GetDirectories") == 0) {
// used in secret scene of "Art of Murder 1: FBI Confidential"
// TODO: return list of "scenes\17-magic" subfolders from data.dcp
warning("FBI\\scenes\\17-magic Directory.%s is not implemented! Returning empty array...", name);
} else if (strcmp(dirName, ".\\") == 0 && strcmp(name, "GetFiles") == 0) {
// Used in "Stroke of Fate: Operation Valkyrie" and "Stroke of Fate: Operation Bunker"
// to return list of log files to be removed.
// return empty list instead
} else {
// No currently known games need this
warning("Directory.%s is not implemented! Returning empty array...", name);
}
stack->pushNative(array, false);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetDrives
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetDrives") == 0) {
stack->correctParams(0);
// No currently known games do this
warning("Directory.GetDrives is not implemented! Returning empty array...");
stack->pushInt(0);
stack->pushNative(makeSXArray(_game, stack), false);
return STATUS_OK;
} else {
return STATUS_FAILED;
}
}
//////////////////////////////////////////////////////////////////////////
ScValue *SXDirectory::scGetProperty(const char *name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Type") == 0) {
_scValue->setString("directory");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// PathSeparator
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "PathSeparator") == 0) {
_scValue->setString("\\");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// CurrentDirectory
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "CurrentDirectory") == 0) {
_scValue->setString("."); // See also: BaseGame::scGetProperty("SaveDirectory")
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// TempDirectory
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "TempDirectory") == 0) {
_scValue->setString("temp"); // See also: BaseGame::scGetProperty("SaveDirectory")
return _scValue;
} else {
return _scValue;
}
}
//////////////////////////////////////////////////////////////////////////
bool SXDirectory::persist(BasePersistenceManager *persistMgr) {
BaseScriptable::persist(persistMgr);
return STATUS_OK;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,47 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_SXDIRECTORY_H
#define WINTERMUTE_SXDIRECTORY_H
#include "engines/wintermute/base/base_scriptable.h"
namespace Wintermute {
class SXDirectory : public BaseScriptable {
public:
DECLARE_PERSISTENT(SXDirectory, BaseScriptable)
ScValue *scGetProperty(const char *name) override;
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
SXDirectory(BaseGame *inGame);
~SXDirectory() override;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,826 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/system/sys_class_registry.h"
#include "engines/wintermute/system/sys_class.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/utils/utils.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/file/base_savefile_manager_file.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/base/scriptables/script_ext_file.h"
#include "engines/wintermute/dcgf.h"
// Note: This code is completely untested, as I have yet to find a game that uses SXFile.
namespace Wintermute {
IMPLEMENT_PERSISTENT(SXFile, false)
BaseScriptable *makeSXFile(BaseGame *inGame, ScStack *stack) {
return new SXFile(inGame, stack);
}
//////////////////////////////////////////////////////////////////////////
SXFile::SXFile(BaseGame *inGame, ScStack *stack) : BaseScriptable(inGame) {
stack->correctParams(1);
ScValue *val = stack->pop();
_filename = nullptr;
if (!val->isNULL()) {
BaseUtils::setString(&_filename, val->getString());
}
_readFile = nullptr;
_writeFile = nullptr;
_mode = 0;
_textMode = false;
}
//////////////////////////////////////////////////////////////////////////
SXFile::~SXFile() {
cleanup();
}
//////////////////////////////////////////////////////////////////////////
void SXFile::cleanup() {
SAFE_DELETE_ARRAY(_filename);
close();
}
//////////////////////////////////////////////////////////////////////////
void SXFile::close() {
if (_readFile) {
_game->_fileManager->closeFile(_readFile);
_readFile = nullptr;
}
if (_writeFile) {
_writeFile->finalize();
SAFE_DELETE(_writeFile);
}
_mode = 0;
_textMode = false;
}
//////////////////////////////////////////////////////////////////////////
const char *SXFile::scToString() {
if (_filename && _filename[0]) {
return _filename;
} else {
return "[file object]";
}
}
#define FILE_BUFFER_SIZE 32768
//////////////////////////////////////////////////////////////////////////
bool SXFile::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
//////////////////////////////////////////////////////////////////////////
// SetFilename
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "SetFilename") == 0) {
stack->correctParams(1);
const char *filename = stack->pop()->getString();
cleanup();
BaseUtils::setString(&_filename, filename);
stack->pushNULL();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// OpenAsText / OpenAsBinary
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "OpenAsText") == 0 || strcmp(name, "OpenAsBinary") == 0) {
stack->correctParams(1);
close();
_mode = stack->pop()->getInt(1);
if (_mode < 1 || _mode > 3) {
script->runtimeError("File.%s: invalid access mode. Setting read mode.", name);
_mode = 1;
}
if (_mode == 1) {
_readFile = _game->_fileManager->openFile(_filename);
if (!_readFile) {
//script->runtimeError("File.%s: Error opening file '%s' for reading.", name, _filename);
close();
} else {
_textMode = strcmp(name, "OpenAsText") == 0;
}
} else {
if (strcmp(name, "OpenAsText") == 0) {
if (_mode == 2) {
_writeFile = openForWrite(_filename, false);
} else {
_writeFile = openForAppend(_filename, false);
}
} else {
if (_mode == 2) {
_writeFile = openForWrite(_filename, true);
} else {
_writeFile = openForAppend(_filename, true);
}
}
if (!_writeFile) {
//script->runtimeError("File.%s: Error opening file '%s' for writing.", name, _filename);
close();
} else {
_textMode = strcmp(name, "OpenAsText") == 0;
}
}
if (_readFile || _writeFile) {
stack->pushBool(true);
} else {
stack->pushBool(false);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Close
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Close") == 0) {
stack->correctParams(0);
close();
stack->pushNULL();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// SetPosition
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "SetPosition") == 0) {
stack->correctParams(1);
if (_mode == 0) {
script->runtimeError("File.%s: File is not open", name);
stack->pushBool(false);
} else {
int pos = stack->pop()->getInt();
stack->pushBool(setPos(pos));
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Delete
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Delete") == 0) {
stack->correctParams(0);
close();
stack->pushBool(sfmFileRemove(_filename));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Copy
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Copy") == 0) {
stack->correctParams(2);
/* const char *dest = */ stack->pop()->getString();
/* bool overwrite = */ stack->pop()->getBool(true);
// Known game that need this:
// * Space Madness (to copy bonus wallpapers from data.dcp to /saves/ folder)
// * games by Rootfix intertainment (to save temporary screenshot as savegame screenshot)
warning("SXFile-Method: Copy not supported");
stack->pushBool(false);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// ReadLine
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "ReadLine") == 0) {
stack->correctParams(0);
if (!_textMode || !_readFile) {
script->runtimeError("File.%s: File must be open in text mode.", name);
stack->pushNULL();
return STATUS_OK;
}
uint32 bufSize = FILE_BUFFER_SIZE;
byte *buf = (byte *)malloc(bufSize);
uint32 counter = 0;
byte b;
bool foundNewLine = false;
bool ret = STATUS_FAILED;
do {
ret = _readFile->read(&b, 1);
if (ret != 1) {
break;
}
if (counter > bufSize) {
buf = (byte *)realloc(buf, bufSize + FILE_BUFFER_SIZE);
bufSize += FILE_BUFFER_SIZE;
}
if (b == '\n') {
buf[counter] = '\0';
foundNewLine = true;
break;
} else if (b == 0x0D) {
continue;
} else {
buf[counter] = b;
counter++;
}
} while (DID_SUCCEED(ret));
if (counter > bufSize) {
buf = (byte *)realloc(buf, bufSize + FILE_BUFFER_SIZE);
bufSize += FILE_BUFFER_SIZE;
}
buf[counter] = '\0';
if (!foundNewLine && counter == 0) {
stack->pushNULL();
} else {
stack->pushString((char *)buf);
}
free(buf);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// ReadText
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "ReadText") == 0) {
stack->correctParams(1);
int textLen = stack->pop()->getInt();
if (!_textMode || !_readFile) {
script->runtimeError("File.%s: File must be open in text mode.", name);
stack->pushNULL();
return STATUS_OK;
}
uint32 bufSize = FILE_BUFFER_SIZE;
byte *buf = (byte *)malloc(bufSize);
uint32 counter = 0;
byte b;
bool ret = STATUS_FAILED;
while (counter < (uint32)textLen) {
ret = _readFile->read(&b, 1);
if (ret != 1) {
break;
}
if (counter > bufSize) {
buf = (byte *)realloc(buf, bufSize + FILE_BUFFER_SIZE);
bufSize += FILE_BUFFER_SIZE;
}
if (b == 0x0D) {
continue;
} else {
buf[counter] = b;
counter++;
}
}
if (counter > bufSize) {
buf = (byte *)realloc(buf, bufSize + FILE_BUFFER_SIZE);
bufSize += FILE_BUFFER_SIZE;
}
buf[counter] = '\0';
if (textLen > 0 && counter == 0) {
stack->pushNULL();
} else {
stack->pushString((char *)buf);
}
free(buf);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// WriteLine / WriteText
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "WriteLine") == 0 || strcmp(name, "WriteText") == 0) {
stack->correctParams(1);
const char *line = stack->pop()->getString();
if (!_textMode || !_writeFile) {
script->runtimeError("File.%s: File must be open for writing in text mode.", name);
stack->pushBool(false);
return STATUS_OK;
}
Common::String writeLine;
if (strcmp(name, "WriteLine") == 0) {
writeLine = Common::String::format("%s\n", line);
} else {
writeLine = Common::String::format("%s", line);
}
_writeFile->writeString(writeLine);
stack->pushBool(true);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// ReadBool
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "ReadBool") == 0) {
stack->correctParams(0);
if (_textMode || !_readFile) {
script->runtimeError("File.%s: File must be open for reading in binary mode.", name);
stack->pushNULL();
return STATUS_OK;
}
byte val;
if (_readFile->read(&val, sizeof(byte))) {
stack->pushBool(val != 0);
} else {
stack->pushNULL();
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// ReadByte
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "ReadByte") == 0) {
stack->correctParams(0);
if (_textMode || !_readFile) {
script->runtimeError("File.%s: File must be open for reading in binary mode.", name);
stack->pushNULL();
return STATUS_OK;
}
byte val = _readFile->readByte();
if (!_readFile->err()) {
stack->pushInt(val);
} else {
stack->pushNULL();
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// ReadShort
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "ReadShort") == 0) {
stack->correctParams(0);
if (_textMode || !_readFile) {
script->runtimeError("File.%s: File must be open for reading in binary mode.", name);
stack->pushNULL();
return STATUS_OK;
}
int16 val = _readFile->readSint16LE();
if (!_readFile->err()) {
stack->pushInt(65536 + val);
} else {
stack->pushNULL();
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// ReadInt / ReadLong
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "ReadInt") == 0 || strcmp(name, "ReadLong") == 0) {
stack->correctParams(0);
if (_textMode || !_readFile) {
script->runtimeError("File.%s: File must be open for reading in binary mode.", name);
stack->pushNULL();
return STATUS_OK;
}
int32 val = _readFile->readSint32LE();
if (!_readFile->err()) {
stack->pushInt(val);
} else {
stack->pushNULL();
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// ReadFloat
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "ReadFloat") == 0) {
stack->correctParams(0);
if (_textMode || !_readFile) {
script->runtimeError("File.%s: File must be open for reading in binary mode.", name);
stack->pushNULL();
return STATUS_OK;
}
float val = _readFile->readFloatLE();
if (!_readFile->err()) {
stack->pushFloat(val);
} else {
stack->pushNULL();
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// ReadDouble
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "ReadDouble") == 0) {
stack->correctParams(0);
if (_textMode || !_readFile) {
script->runtimeError("File.%s: File must be open for reading in binary mode.", name);
stack->pushNULL();
return STATUS_OK;
}
double val = _readFile->readDoubleLE();
if (!_readFile->err()) {
stack->pushFloat(val);
} else {
stack->pushNULL();
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// ReadString
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "ReadString") == 0) {
stack->correctParams(0);
if (_textMode || !_readFile) {
script->runtimeError("File.%s: File must be open for reading in binary mode.", name);
stack->pushNULL();
return STATUS_OK;
}
uint32 size = _readFile->readUint32LE();
if (!_readFile->err()) {
byte *str = new byte[size + 1];
if (str) {
if (_readFile->read(str, size) == size) {
str[size] = '\0';
stack->pushString((char *)str);
}
delete[] str;
} else {
stack->pushNULL();
}
} else {
stack->pushNULL();
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// WriteBool
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "WriteBool") == 0) {
stack->correctParams(1);
bool val = stack->pop()->getBool();
if (_textMode || !_writeFile) {
script->runtimeError("File.%s: File must be open for writing in binary mode.", name);
stack->pushBool(false);
return STATUS_OK;
}
_writeFile->writeByte(val);
stack->pushBool(true);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// WriteByte
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "WriteByte") == 0) {
stack->correctParams(1);
byte val = stack->pop()->getInt();
if (_textMode || !_writeFile) {
script->runtimeError("File.%s: File must be open for writing in binary mode.", name);
stack->pushBool(false);
return STATUS_OK;
}
_writeFile->writeByte(val);
stack->pushBool(true);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// WriteShort
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "WriteShort") == 0) {
stack->correctParams(1);
int16 val = stack->pop()->getInt();
if (_textMode || !_writeFile) {
script->runtimeError("File.%s: File must be open for writing in binary mode.", name);
stack->pushBool(false);
return STATUS_OK;
}
_writeFile->writeSint16LE(val);
stack->pushBool(true);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// WriteInt / WriteLong
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "WriteInt") == 0 || strcmp(name, "WriteLong") == 0) {
stack->correctParams(1);
int32 val = stack->pop()->getInt();
if (_textMode || !_writeFile) {
script->runtimeError("File.%s: File must be open for writing in binary mode.", name);
stack->pushBool(false);
return STATUS_OK;
}
_writeFile->writeSint32LE(val);
stack->pushBool(true);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// WriteFloat
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "WriteFloat") == 0) {
stack->correctParams(1);
float val = stack->pop()->getFloat();
if (_textMode || !_writeFile) {
script->runtimeError("File.%s: File must be open for writing in binary mode.", name);
stack->pushBool(false);
return STATUS_OK;
}
uint32 *ptr = (uint32 *)&val;
_writeFile->writeUint32LE(*ptr);
stack->pushBool(true);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// WriteDouble
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "WriteDouble") == 0) {
stack->correctParams(1);
double val = stack->pop()->getFloat();
if (_textMode || !_writeFile) {
script->runtimeError("File.%s: File must be open for writing in binary mode.", name);
stack->pushBool(false);
return STATUS_OK;
}
_writeFile->writeDoubleLE(val);
stack->pushBool(true);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// WriteString
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "WriteString") == 0) {
stack->correctParams(1);
const char *val = stack->pop()->getString();
if (_textMode || !_writeFile) {
script->runtimeError("File.%s: File must be open for writing in binary mode.", name);
stack->pushBool(false);
return STATUS_OK;
}
uint32 size = strlen(val);
_writeFile->writeUint32LE(size);
_writeFile->writeString(val);
stack->pushBool(true);
return STATUS_OK;
} else {
return BaseScriptable::scCallMethod(script, stack, thisStack, name);
}
}
//////////////////////////////////////////////////////////////////////////
ScValue *SXFile::scGetProperty(const char *name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type (RO)
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Type") == 0) {
_scValue->setString("file");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Filename (RO)
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Filename") == 0) {
_scValue->setString(_filename);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Position (RO)
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Position") == 0) {
_scValue->setInt(getPos());
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Length (RO)
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Length") == 0) {
_scValue->setInt(getLength());
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// TextMode (RO)
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "TextMode") == 0) {
_scValue->setBool(_textMode);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// AccessMode (RO)
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "AccessMode") == 0) {
_scValue->setInt(_mode);
return _scValue;
} else {
return BaseScriptable::scGetProperty(name);
}
}
//////////////////////////////////////////////////////////////////////////
bool SXFile::scSetProperty(const char *name, ScValue *value) {
/*
//////////////////////////////////////////////////////////////////////////
// Length
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Length")==0) {
int origLength = _length;
_length = MAX(value->getInt(0), 0);
char propName[20];
if (_length < OrigLength) {
for(int i=_length; i<OrigLength; i++) {
Common::sprintf_s(PropName, "%d", i);
_values->DeleteProp(PropName);
}
}
return STATUS_OK;
}
else*/ return BaseScriptable::scSetProperty(name, value);
}
//////////////////////////////////////////////////////////////////////////
uint32 SXFile::getPos() {
if (_mode == 1 && _readFile) {
return _readFile->pos();
} else if ((_mode == 2 || _mode == 3) && _writeFile) {
error("SXFile - getPos for WriteFile not supported");
return 0;
// return ftell((FILE *)_writeFile);
} else {
return 0;
}
}
//////////////////////////////////////////////////////////////////////////
bool SXFile::setPos(uint32 pos, int whence) {
if (_mode == 1 && _readFile) {
return _readFile->seek(pos, whence);
} else if ((_mode == 2 || _mode == 3) && _writeFile) {
if (BaseEngine::instance().getGameId() != "royalmahjong") {
error("SXFile - seeking in WriteFile not supported");
}
return false;
// return fseek((FILE *)_writeFile, pos, (int)origin) == 0;
} else {
return false;
}
}
//////////////////////////////////////////////////////////////////////////
uint32 SXFile::getLength() {
if (_mode == 1 && _readFile) {
return _readFile->size();
} else if ((_mode == 2 || _mode == 3) && _writeFile) {
error("SXFile - reading length for WriteFile not supported");
return 0;
/*
uint32 currentPos = ftell((FILE *)_writeFile);
fseek((FILE *)_writeFile, 0, SEEK_END);
int ret = ftell((FILE *)_writeFile);
fseek((FILE *)_writeFile, CurrentPos, SEEK_SET);
return Ret;*/
} else {
return 0;
}
}
//////////////////////////////////////////////////////////////////////////
bool SXFile::persist(BasePersistenceManager *persistMgr) {
BaseScriptable::persist(persistMgr);
persistMgr->transferCharPtr(TMEMBER(_filename));
persistMgr->transferSint32(TMEMBER(_mode));
persistMgr->transferBool(TMEMBER(_textMode));
uint32 pos = 0;
if (persistMgr->getIsSaving()) {
pos = getPos();
persistMgr->transferUint32(TMEMBER(pos));
} else {
persistMgr->transferUint32(TMEMBER(pos));
// try to re-open file if needed
_writeFile = nullptr;
_readFile = nullptr;
if (_mode != 0) {
// open for reading
if (_mode == 1) {
_readFile = _game->_fileManager->openFile(_filename);
if (!_readFile) {
close();
}
}
// open for writing / appending
else {
if (_textMode) {
if (_mode == 2) {
_writeFile = openForWrite(_filename, false);
} else {
_writeFile = openForAppend(_filename, false);
}
} else {
if (_mode == 2) {
_writeFile = openForWrite(_filename, true);
} else {
_writeFile = openForAppend(_filename, true);
}
}
if (_writeFile) {
close();
}
}
setPos(pos);
}
}
return STATUS_OK;
}
Common::WriteStream *SXFile::openForWrite(const Common::String &filename, bool binary) {
return BaseFileManager::getEngineInstance()->openFileForWrite(_filename);
}
// Should replace fopen(..., "ab+") and fopen(..., "a+")
Common::WriteStream *SXFile::openForAppend(const Common::String &filename, bool binary) {
warning("SXFile::openForAppend - WriteFiles with limited support as non-append mode");
return BaseFileManager::getEngineInstance()->openFileForWrite(_filename);
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,65 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTES_SXFILE_H
#define WINTERMUTES_SXFILE_H
#include "engines/wintermute/base/base_scriptable.h"
#include "common/stream.h"
namespace Wintermute {
class SXFile : public BaseScriptable {
public:
DECLARE_PERSISTENT(SXFile, BaseScriptable)
ScValue *scGetProperty(const char *name) override;
bool scSetProperty(const char *name, ScValue *value) override;
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
const char *scToString() override;
SXFile(BaseGame *inGame, ScStack *stack);
~SXFile() override;
private:
Common::SeekableReadStream *_readFile;
Common::WriteStream *_writeFile;
int32 _mode; // 0..none, 1..read, 2..write, 3..append
bool _textMode;
void close();
void cleanup();
uint32 getPos();
uint32 getLength();
bool setPos(uint32 pos, int whence = SEEK_SET);
char *_filename;
Common::WriteStream *openForWrite(const Common::String &filename, bool binary);
Common::WriteStream *openForAppend(const Common::String &filename, bool binary);
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,290 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/scriptables/script_ext_math.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/persistent.h"
#include "math/utils.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IMPLEMENT_PERSISTENT(SXMath, true)
BaseScriptable *makeSXMath(BaseGame *inGame) {
return new SXMath(inGame);
}
//////////////////////////////////////////////////////////////////////////
SXMath::SXMath(BaseGame *inGame) : BaseScriptable(inGame) {
}
//////////////////////////////////////////////////////////////////////////
SXMath::~SXMath() {
}
//////////////////////////////////////////////////////////////////////////
bool SXMath::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
//////////////////////////////////////////////////////////////////////////
// Abs
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Abs") == 0) {
stack->correctParams(1);
stack->pushFloat(fabs(stack->pop()->getFloat()));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Acos
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Acos") == 0) {
stack->correctParams(1);
stack->pushFloat(acos(stack->pop()->getFloat()));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Asin
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Asin") == 0) {
stack->correctParams(1);
stack->pushFloat(asin(stack->pop()->getFloat()));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Atan
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Atan") == 0) {
stack->correctParams(1);
stack->pushFloat(atan(stack->pop()->getFloat()));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Atan2
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Atan2") == 0) {
stack->correctParams(2);
double y = stack->pop()->getFloat();
double x = stack->pop()->getFloat();
stack->pushFloat(atan2(y, x));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Ceil
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Ceil") == 0) {
stack->correctParams(1);
stack->pushFloat(ceil(stack->pop()->getFloat()));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Cos
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Cos") == 0) {
stack->correctParams(1);
stack->pushFloat(cos(degreeToRadian(stack->pop()->getFloat())));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Cosh
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Cosh") == 0) {
stack->correctParams(1);
stack->pushFloat(cosh(degreeToRadian(stack->pop()->getFloat())));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Exp
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Exp") == 0) {
stack->correctParams(1);
stack->pushFloat(exp(stack->pop()->getFloat()));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Floor
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Floor") == 0) {
stack->correctParams(1);
stack->pushFloat(floor(stack->pop()->getFloat()));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Log
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Log") == 0) {
stack->correctParams(1);
stack->pushFloat(log(stack->pop()->getFloat()));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Log10
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Log10") == 0) {
stack->correctParams(1);
stack->pushFloat(log10(stack->pop()->getFloat()));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Pow
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Pow") == 0) {
stack->correctParams(2);
double x = stack->pop()->getFloat();
double y = stack->pop()->getFloat();
stack->pushFloat(pow(x, y));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Sin
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Sin") == 0) {
stack->correctParams(1);
stack->pushFloat(sin(degreeToRadian(stack->pop()->getFloat())));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Sinh
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Sinh") == 0) {
stack->correctParams(1);
stack->pushFloat(sinh(degreeToRadian(stack->pop()->getFloat())));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Tan
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Tan") == 0) {
stack->correctParams(1);
stack->pushFloat(tan(degreeToRadian(stack->pop()->getFloat())));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Tanh
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Tanh") == 0) {
stack->correctParams(1);
stack->pushFloat(tanh(degreeToRadian(stack->pop()->getFloat())));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Sqrt
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Sqrt") == 0) {
stack->correctParams(1);
stack->pushFloat(sqrt(stack->pop()->getFloat()));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// DegToRad
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "DegToRad") == 0) {
stack->correctParams(1);
stack->pushFloat(degreeToRadian(stack->pop()->getFloat()));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// RadToDeg
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "RadToDeg") == 0) {
stack->correctParams(1);
stack->pushFloat(radianToDegree(stack->pop()->getFloat()));
return STATUS_OK;
} else {
return STATUS_FAILED;
}
}
//////////////////////////////////////////////////////////////////////////
ScValue *SXMath::scGetProperty(const char *name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Type") == 0) {
_scValue->setString("math");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// PI
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "PI") == 0) {
_scValue->setFloat(M_PI);
return _scValue;
} else {
return _scValue;
}
}
//////////////////////////////////////////////////////////////////////////
double SXMath::degreeToRadian(double value) {
return value * (M_PI / 180.0f);
}
//////////////////////////////////////////////////////////////////////////
double SXMath::radianToDegree(double value) {
return value * (180.0f / M_PI);
}
//////////////////////////////////////////////////////////////////////////
bool SXMath::persist(BasePersistenceManager *persistMgr) {
BaseScriptable::persist(persistMgr);
return STATUS_OK;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,52 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_SXMATH_H
#define WINTERMUTE_SXMATH_H
#include "engines/wintermute/base/base_scriptable.h"
namespace Wintermute {
class SXMath : public BaseScriptable {
public:
DECLARE_PERSISTENT(SXMath, BaseScriptable)
SXMath(BaseGame *inGame);
~SXMath() override;
ScValue *scGetProperty(const char *name) override;
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
private:
double degreeToRadian(double value);
double radianToDegree(double value);
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,529 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_scriptable.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script_ext_mem_buffer.h"
#include "common/file.h"
namespace Wintermute {
IMPLEMENT_PERSISTENT(SXMemBuffer, false)
BaseScriptable *makeSXMemBuffer(BaseGame *inGame, ScStack *stack) {
return new SXMemBuffer(inGame, stack);
}
//////////////////////////////////////////////////////////////////////////
SXMemBuffer::SXMemBuffer(BaseGame *inGame, ScStack *stack) : BaseScriptable(inGame) {
stack->correctParams(1);
_buffer = nullptr;
_size = 0;
int newSize = stack->pop()->getInt();
resize(MAX(0, newSize));
}
//////////////////////////////////////////////////////////////////////////
SXMemBuffer::SXMemBuffer(BaseGame *inGame, void *buffer) : BaseScriptable(inGame) {
_size = 0;
_buffer = buffer;
}
//////////////////////////////////////////////////////////////////////////
SXMemBuffer::~SXMemBuffer() {
cleanup();
}
//////////////////////////////////////////////////////////////////////////
void *SXMemBuffer::scToMemBuffer() {
return _buffer;
}
//////////////////////////////////////////////////////////////////////////
void SXMemBuffer::cleanup() {
if (_size) {
free(_buffer);
}
_buffer = nullptr;
_size = 0;
}
//////////////////////////////////////////////////////////////////////////
bool SXMemBuffer::resize(int newSize) {
int oldSize = _size;
if (_size == 0) {
_buffer = malloc(newSize);
if (_buffer) {
_size = newSize;
}
} else {
void *newBuf = realloc(_buffer, newSize);
if (!newBuf) {
if (newSize == 0) {
_buffer = newBuf;
_size = newSize;
} else {
return STATUS_FAILED;
}
} else {
_buffer = newBuf;
_size = newSize;
}
}
if (_buffer && _size > oldSize) {
memset((byte *)_buffer + oldSize, 0, _size - oldSize);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool SXMemBuffer::checkBounds(ScScript *script, int start, int length) {
if (_buffer == nullptr) {
script->runtimeError("Cannot use Set/Get methods on an uninitialized memory buffer");
return false;
}
if (_size == 0) {
return true;
}
if (start < 0 || length == 0 || start + length > _size) {
script->runtimeError("Set/Get method call is out of bounds");
return false;
} else {
return true;
}
}
//////////////////////////////////////////////////////////////////////////
const char *SXMemBuffer::scToString() {
return "[membuffer object]";
}
//////////////////////////////////////////////////////////////////////////
bool SXMemBuffer::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
//////////////////////////////////////////////////////////////////////////
// SetSize
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "SetSize") == 0) {
stack->correctParams(1);
int newSize = stack->pop()->getInt();
newSize = MAX(0, newSize);
if (DID_SUCCEED(resize(newSize))) {
stack->pushBool(true);
} else {
stack->pushBool(false);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetBool
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetBool") == 0) {
stack->correctParams(1);
int start = stack->pop()->getInt();
if (!checkBounds(script, start, sizeof(byte))) {
stack->pushNULL();
} else {
stack->pushBool(*((byte *)_buffer + start) != 0);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetByte
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetByte") == 0) {
stack->correctParams(1);
int start = stack->pop()->getInt();
if (!checkBounds(script, start, sizeof(byte))) {
stack->pushNULL();
} else {
stack->pushInt(*(byte *)((byte *)_buffer + start));
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetShort
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetShort") == 0) {
stack->correctParams(1);
int start = stack->pop()->getInt();
if (!checkBounds(script, start, sizeof(short))) {
stack->pushNULL();
} else {
stack->pushInt(65536 + * (short *)((byte *)_buffer + start));
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetInt / GetLong
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetInt") == 0 || strcmp(name, "GetLong") == 0) {
stack->correctParams(1);
int start = stack->pop()->getInt();
if (!checkBounds(script, start, sizeof(int))) {
stack->pushNULL();
} else {
stack->pushInt(*(int *)((byte *)_buffer + start));
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetFloat
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetFloat") == 0) {
stack->correctParams(1);
int start = stack->pop()->getInt();
if (!checkBounds(script, start, sizeof(float))) {
stack->pushNULL();
} else {
stack->pushFloat(*(float *)((byte *)_buffer + start));
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetDouble
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetDouble") == 0) {
stack->correctParams(1);
int start = stack->pop()->getInt();
if (!checkBounds(script, start, sizeof(double))) {
stack->pushNULL();
} else {
stack->pushFloat(*(double *)((byte *)_buffer + start));
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetString
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetString") == 0) {
stack->correctParams(2);
int start = stack->pop()->getInt();
int length = stack->pop()->getInt();
// find end of string
if (length == 0 && start >= 0 && start < _size) {
for (int i = start; i < _size; i++) {
if (((char *)_buffer)[i] == '\0') {
length = i - start;
break;
}
}
}
if (!checkBounds(script, start, length)) {
stack->pushNULL();
} else {
char *str = new char[length + 1];
strncpy(str, (const char *)_buffer + start, length);
str[length] = '\0';
stack->pushString(str);
delete[] str;
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetPointer
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetPointer") == 0) {
stack->correctParams(1);
int start = stack->pop()->getInt();
if (!checkBounds(script, start, sizeof(void *))) {
stack->pushNULL();
} else {
void *pointer = *(void **)((byte *)_buffer + start);
SXMemBuffer *buf = new SXMemBuffer(_game, pointer);
stack->pushNative(buf, false);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// SetBool
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "SetBool") == 0) {
stack->correctParams(2);
int start = stack->pop()->getInt();
bool val = stack->pop()->getBool();
if (!checkBounds(script, start, sizeof(byte))) {
stack->pushBool(false);
} else {
*((byte *)_buffer + start) = (byte)val;
stack->pushBool(true);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// SetByte
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "SetByte") == 0) {
stack->correctParams(2);
int start = stack->pop()->getInt();
byte val = (byte)stack->pop()->getInt();
if (!checkBounds(script, start, sizeof(byte))) {
stack->pushBool(false);
} else {
*(byte *)((byte *)_buffer + start) = val;
stack->pushBool(true);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// SetShort
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "SetShort") == 0) {
stack->correctParams(2);
int start = stack->pop()->getInt();
short val = (short)stack->pop()->getInt();
if (!checkBounds(script, start, sizeof(short))) {
stack->pushBool(false);
} else {
*(short *)((byte *)_buffer + start) = val;
stack->pushBool(true);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// SetInt / SetLong
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "SetInt") == 0 || strcmp(name, "SetLong") == 0) {
stack->correctParams(2);
int start = stack->pop()->getInt();
int val = stack->pop()->getInt();
if (!checkBounds(script, start, sizeof(int))) {
stack->pushBool(false);
} else {
*(int *)((byte *)_buffer + start) = val;
stack->pushBool(true);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// SetFloat
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "SetFloat") == 0) {
stack->correctParams(2);
int start = stack->pop()->getInt();
float val = (float)stack->pop()->getFloat();
if (!checkBounds(script, start, sizeof(float))) {
stack->pushBool(false);
} else {
*(float *)((byte *)_buffer + start) = val;
stack->pushBool(true);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// SetDouble
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "SetDouble") == 0) {
stack->correctParams(2);
int start = stack->pop()->getInt();
double val = stack->pop()->getFloat();
if (!checkBounds(script, start, sizeof(double))) {
stack->pushBool(false);
} else {
*(double *)((byte *)_buffer + start) = val;
stack->pushBool(true);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// SetString
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "SetString") == 0) {
stack->correctParams(2);
int start = stack->pop()->getInt();
const char *val = stack->pop()->getString();
if (!checkBounds(script, start, strlen(val) + 1)) {
stack->pushBool(false);
} else {
memcpy((byte *)_buffer + start, val, strlen(val) + 1);
stack->pushBool(true);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// SetPointer
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "SetPointer") == 0) {
stack->correctParams(2);
int start = stack->pop()->getInt();
/* ScValue *val = */ stack->pop();
if (!checkBounds(script, start, sizeof(void *))) {
stack->pushBool(false);
} else {
/*
int pointer = (int)Val->getMemBuffer();
memcpy((byte *)_buffer+Start, &Pointer, sizeof(void*));
stack->pushBool(true);
*/
// TODO: fix
debug(3, "SXMemBuffer::ScCallMethod - SetPointer Bounds FIXME");
stack->pushBool(false);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// DEBUG_Dump
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "DEBUG_Dump") == 0) {
stack->correctParams(0);
if (_buffer && _size) {
warning("SXMemBuffer::ScCallMethod - DEBUG_Dump");
Common::DumpFile f;
f.open("buffer.bin");
f.write(_buffer, _size);
f.close();
}
stack->pushNULL();
return STATUS_OK;
} else {
return STATUS_FAILED;
}
}
//////////////////////////////////////////////////////////////////////////
ScValue *SXMemBuffer::scGetProperty(const char *name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type (RO)
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Type") == 0) {
_scValue->setString("membuffer");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Size (RO)
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Size") == 0) {
_scValue->setInt(_size);
return _scValue;
} else {
return BaseScriptable::scGetProperty(name);
}
}
//////////////////////////////////////////////////////////////////////////
bool SXMemBuffer::scSetProperty(const char *name, ScValue *value) {
/*
//////////////////////////////////////////////////////////////////////////
// Length
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Length")==0) {
int origLength = _length;
_length = MAX(value->getInt(0), 0);
char propName[20];
if (_length < origLength) {
for(int i=_length; i < origLength; i++) {
Common::sprintf_s(propName, "%d", i);
_values->DeleteProp(propName);
}
}
return STATUS_OK;
}
else*/ return BaseScriptable::scSetProperty(name, value);
}
//////////////////////////////////////////////////////////////////////////
bool SXMemBuffer::persist(BasePersistenceManager *persistMgr) {
BaseScriptable::persist(persistMgr);
persistMgr->transferSint32(TMEMBER(_size));
if (persistMgr->getIsSaving()) {
if (_size > 0) {
persistMgr->putBytes((byte *)_buffer, _size);
}
} else {
if (_size > 0) {
_buffer = malloc(_size);
persistMgr->getBytes((byte *)_buffer, _size);
} else {
_buffer = nullptr;
}
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
int SXMemBuffer::scCompare(BaseScriptable *val) {
if (_buffer == val->scToMemBuffer()) {
return 0;
} else {
return 1;
}
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,59 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_SXMEMBUFFER_H
#define WINTERMUTE_SXMEMBUFFER_H
#include "engines/wintermute/base/base_scriptable.h"
namespace Wintermute {
class SXMemBuffer : public BaseScriptable {
public:
int scCompare(BaseScriptable *val) override;
DECLARE_PERSISTENT(SXMemBuffer, BaseScriptable)
ScValue *scGetProperty(const char *name) override;
bool scSetProperty(const char *name, ScValue *value) override;
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
const char *scToString() override;
SXMemBuffer(BaseGame *inGame, ScStack *stack);
SXMemBuffer(BaseGame *inGame, void *buffer);
~SXMemBuffer() override;
void *scToMemBuffer() override;
int32 _size;
private:
bool resize(int newSize);
void *_buffer;
void cleanup();
bool checkBounds(ScScript *script, int start, int length);
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,66 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/scriptables/script_ext_object.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IMPLEMENT_PERSISTENT(SXObject, false)
BaseScriptable *makeSXObject(BaseGame *inGame, ScStack *stack) {
return new SXObject(inGame, stack);
}
//////////////////////////////////////////////////////////////////////////
SXObject::SXObject(BaseGame *inGame, ScStack *stack) : BaseObject(inGame) {
int numParams = stack->pop()->getInt(0);
for (int i = 0; i < numParams; i++) {
addScript(stack->pop()->getString());
}
}
//////////////////////////////////////////////////////////////////////////
SXObject::~SXObject() {
}
//////////////////////////////////////////////////////////////////////////
bool SXObject::persist(BasePersistenceManager *persistMgr) {
BaseObject::persist(persistMgr);
return STATUS_OK;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,45 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_SXOBJECT_H
#define WINTERMUTE_SXOBJECT_H
#include "engines/wintermute/base/base_object.h"
namespace Wintermute {
class SXObject : public BaseObject {
public:
DECLARE_PERSISTENT(SXObject, BaseObject)
SXObject(BaseGame *inGame, ScStack *stack);
~SXObject() override;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,443 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/utils/utils.h"
#include "engines/wintermute/base/scriptables/script_ext_string.h"
#include "engines/wintermute/base/scriptables/script_ext_array.h"
#include "engines/wintermute/utils/string_util.h"
#include "engines/wintermute/dcgf.h"
#include "common/str.h"
#include "common/tokenizer.h"
namespace Wintermute {
IMPLEMENT_PERSISTENT(SXString, false)
BaseScriptable *makeSXString(BaseGame *inGame, ScStack *stack) {
return new SXString(inGame, stack);
}
//////////////////////////////////////////////////////////////////////////
SXString::SXString(BaseGame *inGame, ScStack *stack) : BaseScriptable(inGame) {
_string = nullptr;
_capacity = 0;
stack->correctParams(1);
ScValue *val = stack->pop();
if (val->isInt()) {
_capacity = MAX(0, val->getInt());
if (_capacity > 0) {
_string = new char[_capacity]();
memset(_string, 0, _capacity);
}
} else {
setStringVal(val->getString());
}
if (_capacity == 0) {
setStringVal("");
}
}
//////////////////////////////////////////////////////////////////////////
SXString::~SXString() {
if (_string) {
delete[] _string;
}
}
//////////////////////////////////////////////////////////////////////////
void SXString::setStringVal(const char *val) {
int len = strlen(val);
if (len >= _capacity) {
_capacity = len + 1;
SAFE_DELETE_ARRAY(_string);
_string = new char[_capacity]();
memset(_string, 0, _capacity);
}
Common::strcpy_s(_string, _capacity, val);
}
//////////////////////////////////////////////////////////////////////////
const char *SXString::scToString() {
if (_string) {
return _string;
} else {
return "[null string]";
}
}
//////////////////////////////////////////////////////////////////////////
void SXString::scSetString(const char *val) {
setStringVal(val);
}
//////////////////////////////////////////////////////////////////////////
bool SXString::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
//////////////////////////////////////////////////////////////////////////
// Substring
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Substring") == 0) {
stack->correctParams(2);
int start = stack->pop()->getInt();
int end = stack->pop()->getInt();
if (end < start) {
BaseUtils::swap(&start, &end);
}
//try {
WideString str;
if (_game->_textEncoding == TEXT_UTF8) {
str = StringUtil::utf8ToWide(_string);
} else {
str = StringUtil::ansiToWide(_string);
}
WideString subStr = str.substr(start, end - start + 1);
if (_game->_textEncoding == TEXT_UTF8) {
stack->pushString(StringUtil::wideToUtf8(subStr).c_str());
} else {
stack->pushString(StringUtil::wideToAnsi(subStr).c_str());
}
// } catch (std::exception &) {
// stack->pushNULL();
// }
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Substr
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Substr") == 0) {
stack->correctParams(2);
int start = stack->pop()->getInt();
ScValue *val = stack->pop();
int len = val->getInt();
if (!val->isNULL() && len <= 0) {
stack->pushString("");
return STATUS_OK;
}
if (val->isNULL()) {
len = strlen(_string) - start;
}
// try {
WideString str;
if (_game->_textEncoding == TEXT_UTF8) {
str = StringUtil::utf8ToWide(_string);
} else {
str = StringUtil::ansiToWide(_string);
}
WideString subStr = str.substr(start, len);
if (_game->_textEncoding == TEXT_UTF8) {
stack->pushString(StringUtil::wideToUtf8(subStr).c_str());
} else {
stack->pushString(StringUtil::wideToAnsi(subStr).c_str());
}
// } catch (std::exception &) {
// stack->pushNULL();
// }
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// ToUpperCase
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "ToUpperCase") == 0) {
stack->correctParams(0);
WideString str;
if (_game->_textEncoding == TEXT_UTF8) {
str = StringUtil::utf8ToWide(_string);
} else {
str = StringUtil::ansiToWide(_string);
}
str.toUppercase();
if (_game->_textEncoding == TEXT_UTF8) {
stack->pushString(StringUtil::wideToUtf8(str).c_str());
} else {
stack->pushString(StringUtil::wideToAnsi(str).c_str());
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// ToLowerCase
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "ToLowerCase") == 0) {
stack->correctParams(0);
WideString str;
if (_game->_textEncoding == TEXT_UTF8) {
str = StringUtil::utf8ToWide(_string);
} else {
str = StringUtil::ansiToWide(_string);
}
str.toLowercase();
if (_game->_textEncoding == TEXT_UTF8) {
stack->pushString(StringUtil::wideToUtf8(str).c_str());
} else {
stack->pushString(StringUtil::wideToAnsi(str).c_str());
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// IndexOf
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "IndexOf") == 0) {
stack->correctParams(2);
const char *strToFind = stack->pop()->getString();
int index = stack->pop()->getInt();
WideString str;
if (_game->_textEncoding == TEXT_UTF8) {
str = StringUtil::utf8ToWide(_string);
} else {
str = StringUtil::ansiToWide(_string);
}
WideString toFind;
if (_game->_textEncoding == TEXT_UTF8) {
toFind = StringUtil::utf8ToWide(strToFind);
} else {
toFind = StringUtil::ansiToWide(strToFind);
}
int indexOf = StringUtil::indexOf(str, toFind, index);
stack->pushInt(indexOf);
return STATUS_OK;
}
#ifdef ENABLE_HEROCRAFT
//////////////////////////////////////////////////////////////////////////
// [HeroCraft] GetCharCode
// Returns integer value of char at given position
// Used at "Pole Chudes" only
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetCharCode") == 0) {
stack->correctParams(1);
int index = stack->pop()->getInt();
int result = 0;
if (strlen(_string) > (uint32)index) {
result = _string[index];
}
stack->pushInt(result);
return STATUS_OK;
}
#endif
//////////////////////////////////////////////////////////////////////////
// Split
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Split") == 0) {
stack->correctParams(1);
ScValue *val = stack->pop();
char separators[MAX_PATH_LENGTH] = ",";
if (!val->isNULL()) {
Common::strlcpy(separators, val->getString(), MAX_PATH_LENGTH);
}
SXArray *array = new SXArray(_game);
if (!array) {
stack->pushNULL();
return STATUS_OK;
}
WideString str;
if (_game->_textEncoding == TEXT_UTF8) {
str = StringUtil::utf8ToWide(_string);
} else {
str = StringUtil::ansiToWide(_string);
}
WideString delims;
if (_game->_textEncoding == TEXT_UTF8) {
delims = StringUtil::utf8ToWide(separators);
} else {
delims = StringUtil::ansiToWide(separators);
}
Common::Array<WideString> parts;
uint32 start = 0;
for(uint32 i = 0; i < str.size() + 1; i++) {
// The [] operator doesn't allow access to the zero code terminator
// (bug #6531)
uint32 ch = (i == str.size()) ? '\0' : str[i];
if (ch =='\0' || delims.contains(ch)) {
if (i != start) {
parts.push_back(str.substr(start, i - start));
} else {
parts.push_back(WideString());
}
start = i + 1;
}
}
for (Common::Array<WideString>::iterator it = parts.begin(); it != parts.end(); ++it) {
WideString &part = (*it);
if (_game->_textEncoding == TEXT_UTF8) {
val = new ScValue(_game, StringUtil::wideToUtf8(part).c_str());
} else {
val = new ScValue(_game, StringUtil::wideToAnsi(part).c_str());
}
array->push(val);
SAFE_DELETE(val);
}
stack->pushNative(array, false);
return STATUS_OK;
} else {
return STATUS_FAILED;
}
}
//////////////////////////////////////////////////////////////////////////
ScValue *SXString::scGetProperty(const char *name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type (RO)
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Type") == 0) {
_scValue->setString("string");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Length (RO)
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Length") == 0) {
if (_game->_textEncoding == TEXT_UTF8) {
WideString wstr = StringUtil::utf8ToWide(_string);
_scValue->setInt(wstr.size());
} else {
_scValue->setInt(strlen(_string));
}
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Capacity
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Capacity") == 0) {
_scValue->setInt(_capacity);
return _scValue;
} else {
return _scValue;
}
}
//////////////////////////////////////////////////////////////////////////
bool SXString::scSetProperty(const char *name, ScValue *value) {
//////////////////////////////////////////////////////////////////////////
// Capacity
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Capacity") == 0) {
int32 newCap = (uint32)value->getInt();
if (newCap < (int32)(strlen(_string) + 1)) {
_game->LOG(0, "Warning: cannot lower string capacity");
} else if (newCap != _capacity) {
char *newStr = new char[newCap]();
if (newStr) {
Common::strcpy_s(newStr, newCap, _string);
SAFE_DELETE_ARRAY(_string);
_string = newStr;
_capacity = newCap;
}
}
return STATUS_OK;
} else {
return STATUS_FAILED;
}
}
//////////////////////////////////////////////////////////////////////////
bool SXString::persist(BasePersistenceManager *persistMgr) {
BaseScriptable::persist(persistMgr);
persistMgr->transferSint32(TMEMBER(_capacity));
if (persistMgr->getIsSaving()) {
if (_capacity > 0) {
persistMgr->putBytes((byte *)_string, _capacity);
}
} else {
if (_capacity > 0) {
_string = new char[_capacity];
persistMgr->getBytes((byte *)_string, _capacity);
} else {
_string = nullptr;
}
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
int SXString::scCompare(BaseScriptable *val) {
return strcmp(_string, ((SXString *)val)->_string);
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,54 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_SXSTRING_H
#define WINTERMUTE_SXSTRING_H
#include "engines/wintermute/base/base_scriptable.h"
namespace Wintermute {
class SXString : public BaseScriptable {
public:
int scCompare(BaseScriptable *val) override;
DECLARE_PERSISTENT(SXString, BaseScriptable)
ScValue *scGetProperty(const char *name) override;
bool scSetProperty(const char *name, ScValue *value) override;
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
void scSetString(const char *val) override;
const char *scToString() override;
void setStringVal(const char *val);
char *_string;
SXString(BaseGame *inGame, ScStack *stack);
~SXString() override;
int32 _capacity;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,135 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_SCOPCODES_H
#define WINTERMUTE_SCOPCODES_H
namespace Wintermute {
const uint32 foxtail_1_2_896_mapping[] = {
II_CMP_LE,
II_JMP,
II_POP_REG1,
II_PUSH_BOOL,
II_MODULO,
II_POP_EMPTY,
II_CALL_BY_EXP,
II_CMP_L,
II_PUSH_FLOAT,
II_NOT,
II_PUSH_THIS,
II_PUSH_BY_EXP,
II_PUSH_THIS_FROM_STACK,
II_CMP_G,
II_DEF_GLOB_VAR,
II_PUSH_STRING,
II_PUSH_REG1,
II_DEF_VAR,
II_PUSH_VAR_THIS,
II_RET_EVENT,
II_PUSH_VAR_REF,
II_CMP_NE,
II_DBG_LINE,
II_OR,
II_POP_VAR,
II_AND,
II_EXTERNAL_CALL,
II_CORRECT_STACK,
II_RET,
II_DIV,
II_PUSH_VAR,
II_SUB,
II_CALL,
II_CREATE_OBJECT,
II_MUL,
II_POP_BY_EXP,
II_DEF_CONST_VAR,
II_PUSH_NULL,
II_JMP_FALSE,
II_ADD,
II_CMP_GE,
II_CMP_STRICT_EQ,
II_CMP_STRICT_NE,
II_PUSH_INT,
II_CMP_EQ,
II_POP_THIS,
II_SCOPE
};
const uint32 foxtail_1_2_902_mapping[] = {
II_CMP_L,
II_CALL,
II_DEF_GLOB_VAR,
II_DBG_LINE,
II_JMP_FALSE,
II_CMP_STRICT_EQ,
II_PUSH_FLOAT,
II_CALL_BY_EXP,
II_MODULO,
II_PUSH_THIS,
II_CMP_GE,
II_PUSH_BOOL,
II_PUSH_VAR,
II_PUSH_VAR_REF,
II_POP_BY_EXP,
II_CMP_STRICT_NE,
II_RET_EVENT,
II_PUSH_BY_EXP,
II_CORRECT_STACK,
II_POP_VAR,
II_CMP_G,
II_PUSH_THIS_FROM_STACK,
II_JMP,
II_AND,
II_CREATE_OBJECT,
II_POP_REG1,
II_PUSH_STRING,
II_POP_EMPTY,
II_DIV,
II_ADD,
II_RET,
II_EXTERNAL_CALL,
II_NOT,
II_OR,
II_SUB,
II_PUSH_INT,
II_DEF_VAR,
II_SCOPE,
II_CMP_EQ,
II_MUL,
II_POP_THIS,
II_CMP_LE,
II_PUSH_REG1,
II_DEF_CONST_VAR,
II_PUSH_NULL,
II_CMP_NE,
II_PUSH_VAR_THIS
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,191 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/base_game.h"
namespace Wintermute {
IMPLEMENT_PERSISTENT(ScStack, false)
//////////////////////////////////////////////////////////////////////////
ScStack::ScStack(BaseGame *inGame) : BaseClass(inGame) {
_sP = -1;
}
//////////////////////////////////////////////////////////////////////////
ScStack::~ScStack() {
//_game->LOG(0, "STAT: Stack size: %d, SP=%d", _values.getSize(), _sP);
for (int32 i = 0; i < _values.getSize(); i++) {
delete _values[i];
}
_values.removeAll();
}
//////////////////////////////////////////////////////////////////////////
ScValue *ScStack::pop() {
if (_sP < 0) {
_game->LOG(0, "Fatal: Stack underflow");
return nullptr;
}
return _values[_sP--];
}
//////////////////////////////////////////////////////////////////////////
void ScStack::push(ScValue *val) {
_sP++;
if (_sP < _values.getSize()) {
_values[_sP]->cleanup();
_values[_sP]->copy(val);
} else {
ScValue *copyVal = new ScValue(_game);
copyVal->copy(val);
_values.add(copyVal);
}
}
//////////////////////////////////////////////////////////////////////////
ScValue *ScStack::getPushValue() {
_sP++;
if (_sP >= _values.getSize()) {
ScValue *val = new ScValue(_game);
_values.add(val);
}
_values[_sP]->cleanup();
return _values[_sP];
}
//////////////////////////////////////////////////////////////////////////
ScValue *ScStack::getTop() {
if (_sP < 0 || _sP >= _values.getSize()) {
return nullptr;
} else {
return _values[_sP];
}
}
//////////////////////////////////////////////////////////////////////////
ScValue *ScStack::getAt(int index) {
index = _sP - index;
if (index < 0 || index >= _values.getSize()) {
return nullptr;
} else {
return _values[index];
}
}
//////////////////////////////////////////////////////////////////////////
void ScStack::correctParams(uint32 expectedParams) {
uint32 numParams = (uint32)pop()->getInt();
if (expectedParams < numParams) { // too many params
while (expectedParams < numParams) {
//pop();
delete _values[_sP - expectedParams];
_values.removeAt(_sP - expectedParams);
numParams--;
_sP--;
}
} else if (expectedParams > numParams) { // need more params
while (expectedParams > numParams) {
//push(nullVal);
ScValue *nullVal = new ScValue(_game);
nullVal->setNULL();
_values.insertAt(_sP - numParams + 1, nullVal);
numParams++;
_sP++;
if (_values.getSize() > _sP + 1) {
delete _values[_values.getSize() - 1];
_values.removeAt(_values.getSize() - 1);
}
}
}
}
//////////////////////////////////////////////////////////////////////////
void ScStack::pushNULL() {
getPushValue()->setNULL();
}
//////////////////////////////////////////////////////////////////////////
void ScStack::pushInt(int val) {
getPushValue()->setInt(val);
}
//////////////////////////////////////////////////////////////////////////
void ScStack::pushFloat(double val) {
getPushValue()->setFloat(val);
}
//////////////////////////////////////////////////////////////////////////
void ScStack::pushBool(bool val) {
getPushValue()->setBool(val);
}
//////////////////////////////////////////////////////////////////////////
void ScStack::pushString(const char *val) {
getPushValue()->setString(val);
}
//////////////////////////////////////////////////////////////////////////
void ScStack::pushNative(BaseScriptable *val, bool persistent) {
getPushValue()->setNative(val, persistent);
}
//////////////////////////////////////////////////////////////////////////
bool ScStack::persist(BasePersistenceManager *persistMgr) {
persistMgr->transferPtr(TMEMBER_PTR(_game));
persistMgr->transferSint32(TMEMBER(_sP));
_values.persist(persistMgr);
return STATUS_OK;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,65 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_SCSTACK_H
#define WINTERMUTE_SCSTACK_H
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/coll_templ.h"
#include "engines/wintermute/persistent.h"
namespace Wintermute {
class ScValue;
class BaseScriptable;
class ScStack : public BaseClass {
public:
ScValue *getAt(int index);
ScValue *getPushValue();
DECLARE_PERSISTENT(ScStack, BaseClass)
void pushNative(BaseScriptable *val, bool persistent);
void pushString(const char *val);
void pushBool(bool val);
void pushInt(int val);
void pushFloat(double val);
void pushNULL();
void correctParams(uint32 expectedParams);
ScValue *getTop();
void push(ScValue *val);
ScValue *pop();
ScStack(BaseGame *inGame);
~ScStack() override;
BaseArray<ScValue *> _values;
int32 _sP;
};
} // End of namespace Wintermute
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,110 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_SCVALUE_H
#define WINTERMUTE_SCVALUE_H
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/persistent.h"
#include "engines/wintermute/base/scriptables/dcscript.h" // Added by ClassView
#include "common/str.h"
namespace Wintermute {
class ScScript;
class BaseScriptable;
class ScValue : public BaseClass {
public:
static int compare(ScValue *val1, ScValue *val2, bool enableFloatCompareWA);
static int compareStrict(ScValue *val1, ScValue *val2, bool enableFloatCompareWA);
TValType getTypeTolerant();
void cleanup(bool ignoreNatives = false);
DECLARE_PERSISTENT(ScValue, BaseClass)
bool _isConstVar;
bool saveAsText(BaseDynamicBuffer *buffer, int indent) override;
void setValue(ScValue *val);
bool _persistent;
bool propExists(const char *name);
void copy(ScValue *orig, bool copyWhole = false);
void setStringVal(const char *val);
TValType getType();
bool getBool(bool defaultVal = false);
int getInt(int defaultVal = 0);
double getFloat(double defaultVal = 0.0f);
const char *getString();
void *getMemBuffer();
BaseScriptable *getNative();
bool deleteProp(const char *name);
void deleteProps();
void cleanProps(bool includingNatives);
void setBool(bool val);
void setInt(int val);
void setFloat(double val);
void setString(const char *val);
void setString(const Common::String &val);
void setNULL();
void setNative(BaseScriptable *val, bool persistent = false);
void setObject();
void setReference(ScValue *val);
bool isNULL();
bool isNative();
bool isString();
bool isBool();
bool isFloat();
bool isInt();
bool isObject();
bool setProp(const char *name, ScValue *val, bool copyWhole = false, bool setAsConst = false);
ScValue *getProp(const char *name);
BaseScriptable *_valNative;
ScValue *_valRef;
bool _valBool;
int32 _valInt;
double _valFloat;
char *_valString;
TValType _type;
ScValue(BaseGame *inGame);
ScValue(BaseGame *inGame, bool val);
ScValue(BaseGame *inGame, int32 val);
ScValue(BaseGame *inGame, double val);
ScValue(BaseGame *inGame, const char *val);
~ScValue() override;
Common::HashMap<Common::String, ScValue *> _valObject;
Common::HashMap<Common::String, ScValue *>::iterator _valIter;
bool setProperty(const char *propName, int32 value);
bool setProperty(const char *propName, const char *value);
bool setProperty(const char *propName, double value);
bool setProperty(const char *propName, bool value);
bool setProperty(const char *propName);
};
} // End of namespace Wintermute
#endif