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

2
engines/sludge/POTFILES Normal file
View File

@@ -0,0 +1,2 @@
engines/sludge/event.cpp
engines/sludge/keymapper_tables.h

536
engines/sludge/backdrop.cpp Normal file
View File

@@ -0,0 +1,536 @@
/* 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 "image/png.h"
#include "sludge/event.h"
#include "sludge/fileset.h"
#include "sludge/graphics.h"
#include "sludge/imgloader.h"
#include "sludge/newfatal.h"
#include "sludge/speech.h"
#include "sludge/statusba.h"
#include "sludge/sludge.h"
#include "sludge/sludger.h"
#include "sludge/variable.h"
#include "sludge/version.h"
#include "sludge/zbuffer.h"
namespace Sludge {
void GraphicsManager::killParallax() {
if (!_parallaxLayers)
return;
for (ParallaxLayers::iterator it = _parallaxLayers->begin(); it != _parallaxLayers->end(); ++it) {
(*it)->surface.free();
delete (*it);
(*it) = nullptr;
}
_parallaxLayers->clear();
delete _parallaxLayers;
_parallaxLayers = nullptr;
}
bool GraphicsManager::loadParallax(uint16 v, uint16 fracX, uint16 fracY) {
if (!_parallaxLayers)
_parallaxLayers = new ParallaxLayers;
setResourceForFatal(v);
if (!g_sludge->_resMan->openFileFromNum(v))
return fatal("Can't open parallax image");
ParallaxLayer *nP = new ParallaxLayer;
if (!checkNew(nP))
return false;
_parallaxLayers->push_back(nP);
if (!ImgLoader::loadImage(v, "parallax", g_sludge->_resMan->getData(), &nP->surface, 0))
return false;
nP->fileNum = v;
nP->fractionX = fracX;
nP->fractionY = fracY;
// 65535 is the value of AUTOFIT constant in Sludge
if (fracX == 65535) {
nP->wrapS = false;
if (nP->surface.w < (int16)_winWidth) {
fatal("For AUTOFIT parallax backgrounds, the image must be at least as wide as the game window/screen.");
return false;
}
} else {
nP->wrapS = true;
}
if (fracY == 65535) {
nP->wrapT = false;
if (nP->surface.h < (int16)_winHeight) {
fatal("For AUTOFIT parallax backgrounds, the image must be at least as tall as the game window/screen.");
return false;
}
} else {
nP->wrapT = true;
}
g_sludge->_resMan->finishAccess();
setResourceForFatal(-1);
return true;
}
void GraphicsManager::drawParallax() {
if (!_parallaxLayers || _parallaxLayers->empty())
return;
// display parallax from bottom to top
for (ParallaxLayers::iterator it = _parallaxLayers->begin(); it != _parallaxLayers->end(); ++it) {
ParallaxLayer *p = *it;
p->cameraX = sortOutPCamera(_cameraX, p->fractionX, (int)(_sceneWidth - (float)_winWidth / _cameraZoom), (int)(p->surface.w - (float)_winWidth / _cameraZoom));
p->cameraY = sortOutPCamera(_cameraY, p->fractionY, (int)(_sceneHeight - (float)_winHeight / _cameraZoom), (int)(p->surface.h - (float)_winHeight / _cameraZoom));
uint w = p->wrapS ? _sceneWidth : p->surface.w;
uint h = p->wrapT ? _sceneHeight : p->surface.h;
debugC(1, kSludgeDebugGraphics, "drawParallax(): camX: %d camY: %d dims: %d x %d sceneDims: %d x %d winDims: %d x %d surf: %d x %d", p->cameraX, p->cameraY, w, h, _sceneWidth, _sceneHeight, _winWidth, _winHeight, p->surface.w, p->surface.h);
Graphics::ManagedSurface tmp;
tmp.copyFrom(p->surface);
for (uint y = 0; y < _sceneHeight; y += p->surface.h) {
for (uint x = 0; x < _sceneWidth; x += p->surface.w) {
tmp.blendBlitTo(_renderSurface, x - p->cameraX, y - p->cameraY);
debugC(3, kSludgeDebugGraphics, "drawParallax(): blit to: %d, %d", x - p->cameraX, y - p->cameraY);
}
}
}
}
void GraphicsManager::saveParallax(Common::WriteStream *stream) {
if (!_parallaxLayers)
return;
ParallaxLayers::iterator it;
for (it = _parallaxLayers->begin(); it != _parallaxLayers->end(); ++it) {
stream->writeByte(1);
stream->writeUint16BE((*it)->fileNum);
stream->writeUint16BE((*it)->fractionX);
stream->writeUint16BE((*it)->fractionY);
}
}
void GraphicsManager::nosnapshot() {
if (_snapshotSurface.getPixels())
_snapshotSurface.free();
}
void GraphicsManager::saveSnapshot(Common::WriteStream *stream) {
if (_snapshotSurface.getPixels()) {
stream->writeByte(1); // 1 for snapshot follows
Image::writePNG(*stream, _snapshotSurface);
} else {
stream->writeByte(0);
}
}
bool GraphicsManager::snapshot() {
nosnapshot();
if (!freeze())
return false;
// draw snapshot to rendersurface
displayBase();
_vm->_speechMan->display();
g_sludge->_statusBar->draw();
// copy backdrop to snapshot
_snapshotSurface.copyFrom(_renderSurface);
unfreeze(false);
return true;
}
bool GraphicsManager::restoreSnapshot(Common::SeekableReadStream *stream) {
if (!(ImgLoader::loadImage(-1, NULL, stream, &_snapshotSurface))) {
return false;
}
return true;
}
void GraphicsManager::killBackDrop() {
if (_backdropSurface.getPixels())
_backdropSurface.free();
_backdropExists = false;
}
void GraphicsManager::killLightMap() {
if (_lightMap.getPixels()) {
_lightMap.free();
}
_lightMapNumber = 0;
}
bool GraphicsManager::reserveBackdrop() {
_cameraX = 0;
_cameraY = 0;
_vm->_evtMan->mouseX() = (int)((float)_vm->_evtMan->mouseX() * _cameraZoom);
_vm->_evtMan->mouseY() = (int)((float)_vm->_evtMan->mouseY() * _cameraZoom);
_cameraZoom = 1.0;
_vm->_evtMan->mouseX() = (int)((float)_vm->_evtMan->mouseX() / _cameraZoom);
_vm->_evtMan->mouseY() = (int)((float)_vm->_evtMan->mouseY() / _cameraZoom);
_backdropSurface.create(_sceneWidth, _sceneHeight, *_vm->getScreenPixelFormat());
return true;
}
void GraphicsManager::killAllBackDrop() {
killLightMap();
killBackDrop();
g_sludge->_gfxMan->killParallax();
killZBuffer();
}
bool GraphicsManager::resizeBackdrop(int x, int y) {
debugC(1, kSludgeDebugGraphics, "Load HSI");
_sceneWidth = x;
_sceneHeight = y;
return reserveBackdrop();
}
bool GraphicsManager::killResizeBackdrop(int x, int y) {
killAllBackDrop();
return resizeBackdrop(x, y);
}
void GraphicsManager::loadBackDrop(int fileNum, int x, int y) {
debugC(1, kSludgeDebugGraphics, "Load back drop of num %i at position %i, %i", fileNum, x, y);
setResourceForFatal(fileNum);
if (!g_sludge->_resMan->openFileFromNum(fileNum)) {
fatal("Can't load overlay image");
return;
}
if (!loadHSI(fileNum, g_sludge->_resMan->getData(), x, y, false)) {
Common::String mess = Common::String::format("Can't paste overlay image outside scene dimensions\n\nX = %i\nY = %i\nWidth = %i\nHeight = %i", x, y, _sceneWidth, _sceneHeight);
fatal(mess);
}
g_sludge->_resMan->finishAccess();
setResourceForFatal(-1);
// reset zBuffer
if (_zBuffer->originalNum >= 0) {
setZBuffer(_zBuffer->originalNum);
}
}
void GraphicsManager::mixBackDrop(int fileNum, int x, int y) {
debugC(1, kSludgeDebugGraphics, "Mix back drop of num %i at position %i, %i", fileNum, x, y);
setResourceForFatal(fileNum);
if (!g_sludge->_resMan->openFileFromNum(fileNum)) {
fatal("Can't load overlay image");
return;
}
if (!mixHSI(fileNum, g_sludge->_resMan->getData(), x, y)) {
fatal("Can't paste overlay image outside screen dimensions");
}
g_sludge->_resMan->finishAccess();
setResourceForFatal(-1);
}
void GraphicsManager::blankScreen(int x1, int y1, int x2, int y2) {
// in case of no backdrop added at all, create it
if (!_backdropSurface.getPixels()) {
_backdropSurface.create(_winWidth, _winHeight, _renderSurface.format);
}
if (y1 < 0)
y1 = 0;
if (x1 < 0)
x1 = 0;
if (x2 > (int)_sceneWidth)
x2 = (int)_sceneWidth;
if (y2 > (int)_sceneHeight)
y2 = (int)_sceneHeight;
_backdropSurface.fillRect(Common::Rect(x1, y1, x2, y2), _currentBlankColour);
// reset zBuffer
if (_zBuffer->originalNum >= 0) {
setZBuffer(_zBuffer->originalNum);
}
}
void GraphicsManager::blankAllScreen() {
blankScreen(0, 0, _sceneWidth, _sceneHeight);
}
// This function is very useful for scrolling credits, but very little else
void GraphicsManager::hardScroll(int distance) {
// scroll 0 distance, return
if (!distance)
return;
// blank screen
blankAllScreen();
// scroll more than backdrop height, screen stay blank
if (ABS(distance) >= (int)_sceneHeight) {
return;
}
// copy part of the backdrop to it
if (distance > 0) {
_backdropSurface.copyRectToSurface(_origBackdropSurface, 0, 0,
Common::Rect(0, distance, _backdropSurface.w, _backdropSurface.h));
} else {
_backdropSurface.copyRectToSurface(_origBackdropSurface, 0, -distance,
Common::Rect(0, 0, _backdropSurface.w, _backdropSurface.h + distance));
}
}
void GraphicsManager::drawLine(uint x1, uint y1, uint x2, uint y2) {
_backdropSurface.drawLine(x1, y1, x2, y2, _backdropSurface.format.ARGBToColor(255, 0, 0, 0));
}
void GraphicsManager::drawVerticalLine(uint x, uint y1, uint y2) {
drawLine(x, y1, x, y2);
}
void GraphicsManager::drawHorizontalLine(uint x1, uint y, uint x2) {
drawLine(x1, y, x2, y);
}
void GraphicsManager::darkScreen() {
Graphics::ManagedSurface tmp;
tmp.copyFrom(_backdropSurface);
tmp.blendBlitTo(_backdropSurface, 0, 0, Graphics::FLIP_NONE, nullptr, MS_ARGB(255 >> 1, 0, 0, 0));
// reset zBuffer
if (_zBuffer->originalNum >= 0) {
setZBuffer(_zBuffer->originalNum);
}
}
void GraphicsManager::drawBackDrop() {
// TODO: apply lightmap shader
drawParallax();
if (!_backdropExists && !_backdropSurface.getPixels())
return;
// draw backdrop
Graphics::ManagedSurface tmp;
tmp.copyFrom(_backdropSurface);
tmp.blendBlitTo(_renderSurface, -_cameraX, -_cameraY);
}
bool GraphicsManager::loadLightMap(int v) {
setResourceForFatal(v);
if (!g_sludge->_resMan->openFileFromNum(v))
return fatal("Can't open light map.");
killLightMap();
_lightMapNumber = v;
_lightMap.create(_sceneWidth, _sceneWidth, *_vm->getScreenPixelFormat());
Graphics::ManagedSurface tmp;
if (!ImgLoader::loadImage(v, "lightmap", g_sludge->_resMan->getData(), tmp.surfacePtr()))
return false;
if (tmp.w != (int16)_sceneWidth || tmp.h != (int16)_sceneHeight) {
if (_lightMapMode == LIGHTMAPMODE_HOTSPOT) {
return fatal("Light map width and height don't match scene width and height. That is required for lightmaps in HOTSPOT mode.");
} else if (_lightMapMode == LIGHTMAPMODE_PIXEL) {
tmp.blendBlitTo(_lightMap, 0, 0, Graphics::FLIP_NONE, nullptr, MS_ARGB((uint)255, (uint)255, (uint)255, (uint)255), (int)_sceneWidth, (int)_sceneHeight);
} else {
_lightMap.copyFrom(tmp);
}
} else {
_lightMap.copyFrom(tmp);
}
tmp.free();
g_sludge->_resMan->finishAccess();
setResourceForFatal(-1);
return true;
}
void GraphicsManager::saveLightMap(Common::WriteStream *stream) {
if (_lightMap.getPixels()) {
stream->writeByte(1);
stream->writeUint16BE(_lightMapNumber);
} else {
stream->writeByte(0);
}
stream->writeByte(_lightMapMode);
stream->writeByte(_fadeMode);
}
bool GraphicsManager::loadLightMap(int ssgVersion, Common::SeekableReadStream *stream) {
if (stream->readByte()) {
if (!loadLightMap(stream->readUint16BE()))
return false;
}
if (ssgVersion >= VERSION(1, 4)) {
_lightMapMode = stream->readByte() % 3;
}
_fadeMode = stream->readByte();
return true;
}
bool GraphicsManager::loadHSI(int num, Common::SeekableReadStream *stream, int x, int y, bool reserve) {
debugC(1, kSludgeDebugGraphics, "Load HSI");
if (reserve) {
killAllBackDrop(); // kill all
}
Graphics::Surface tmp;
if (!ImgLoader::loadImage(num, "hsi", stream, &tmp, (int)reserve))
return false;
uint realPicWidth = tmp.w;
uint realPicHeight = tmp.h;
// resize backdrop
if (reserve) {
if (!resizeBackdrop(realPicWidth, realPicHeight)) {
tmp.free();
return false;
}
}
if (x == IN_THE_CENTRE)
x = (_sceneWidth - realPicWidth) >> 1;
if (y == IN_THE_CENTRE)
y = (_sceneHeight - realPicHeight) >> 1;
if (x < 0 || x + realPicWidth > _sceneWidth || y < 0 || y + realPicHeight > _sceneHeight) {
debugC(0, kSludgeDebugGraphics, "Illegal back drop size");
tmp.free();
return false;
}
if (!_backdropExists)
_backdropSurface.fillRect(Common::Rect(x, y, x + tmp.w, y + tmp.h), _renderSurface.format.ARGBToColor(0, 0, 0, 0));
// copy surface loaded to backdrop
Graphics::ManagedSurface tmp_trans;
tmp_trans.copyFrom(tmp);
tmp_trans.blendBlitTo(_backdropSurface, x, y);
tmp.free();
_origBackdropSurface.copyFrom(_backdropSurface);
_backdropExists = true;
return true;
}
bool GraphicsManager::mixHSI(int num, Common::SeekableReadStream *stream, int x, int y) {
debugC(1, kSludgeDebugGraphics, "Load mixHSI");
Graphics::Surface mixSurface;
if (!ImgLoader::loadImage(num, "mixhsi", stream, &mixSurface, 0))
return false;
uint realPicWidth = mixSurface.w;
uint realPicHeight = mixSurface.h;
if (x == IN_THE_CENTRE)
x = (_sceneWidth - realPicWidth) >> 1;
if (y == IN_THE_CENTRE)
y = (_sceneHeight - realPicHeight) >> 1;
if (x < 0 || x + realPicWidth > _sceneWidth || y < 0 || y + realPicHeight > _sceneHeight) {
mixSurface.free();
return false;
}
Graphics::ManagedSurface tmp;
tmp.copyFrom(mixSurface);
tmp.blendBlitTo(_backdropSurface, x, y, Graphics::FLIP_NONE, nullptr, MS_ARGB(255 >> 1, 255, 255, 255));
mixSurface.free();
return true;
}
void GraphicsManager::saveHSI(Common::WriteStream *stream) {
Image::writePNG(*stream, _backdropSurface);
}
void GraphicsManager::saveBackdrop(Common::WriteStream *stream) {
stream->writeUint16BE(_cameraX);
stream->writeUint16BE(_cameraY);
stream->writeFloatLE(_cameraZoom);
stream->writeByte(_brightnessLevel);
saveHSI(stream);
}
void GraphicsManager::loadBackdrop(int ssgVersion, Common::SeekableReadStream *stream) {
int cameraX = stream->readUint16BE();
int cameraY = stream->readUint16BE();
float cameraZoom;
if (ssgVersion >= VERSION(2, 0)) {
cameraZoom = stream->readFloatLE();
} else {
cameraZoom = 1.0;
}
_brightnessLevel = stream->readByte();
loadHSI(-1, stream, 0, 0, true);
_cameraX = cameraX;
_cameraY = cameraY;
_cameraZoom = cameraZoom;
}
bool GraphicsManager::getRGBIntoStack(uint x, uint y, StackHandler *sH) {
if (x >= _sceneWidth || y >= _sceneHeight) {
return fatal("Co-ordinates are outside current scene!");
}
Variable newValue;
newValue.varType = SVT_NULL;
byte *target = (byte *)_renderSurface.getBasePtr(x, y);
newValue.setVariable(SVT_INT, target[1]);
if (!addVarToStackQuick(newValue, sH->first)) return false;
sH->last = sH->first;
newValue.setVariable(SVT_INT, target[2]);
if (!addVarToStackQuick(newValue, sH->first)) return false;
newValue.setVariable(SVT_INT, target[3]);
if (!addVarToStackQuick(newValue, sH->first)) return false;
return true;
}
} // End of namespace Sludge

View File

@@ -0,0 +1,351 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/debug.h"
#include "common/file.h"
#include "sludge/graphics.h"
#include "sludge/newfatal.h"
#include "sludge/variable.h"
namespace Sludge {
#if 0
// Raised
static int s_matrixEffectDivide = 2;
static int s_matrixEffectWidth = 3;
static int s_matrixEffectHeight = 3;
static int s_matrixEffectData[9] = {0, 0, 0, 0, -1, 0, 0, 0, 2};
static int s_matrixEffectBase = 0;
#elif 0
// Stay put
static int s_matrixEffectDivide = 1;
static int s_matrixEffectWidth = 3;
static int s_matrixEffectHeight = 3;
static int s_matrixEffectData[9] = {0, 0, 0, 0, 1, 0, 0, 0, 0};
static int s_matrixEffectBase = 0;
#elif 0
// Brighten
static int s_matrixEffectDivide = 9;
static int s_matrixEffectWidth = 1;
static int s_matrixEffectHeight = 1;
static int s_matrixEffectData[9] = {10};
static int s_matrixEffectBase = 15;
#elif 0
// Raised up/left
static int s_matrixEffectDivide = 4;
static int s_matrixEffectWidth = 3;
static int s_matrixEffectHeight = 3;
static int s_matrixEffectData[9] = {-2, -1, 0, -1, 1, 1, 0, 1, 2};
static int s_matrixEffectBase = 16;
#elif 0
// Standard emboss
static int s_matrixEffectDivide = 2;
static int s_matrixEffectWidth = 3;
static int s_matrixEffectHeight = 3;
static int s_matrixEffectData[9] = {-1, 0, 0, 0, 0, 0, 0, 0, 1};
static int s_matrixEffectBase = 128;
#elif 0
// Horizontal blur
static int s_matrixEffectDivide = 11;
static int s_matrixEffectWidth = 5;
static int s_matrixEffectHeight = 1;
static int s_matrixEffectData[9] = {1, 3, 3, 3, 1};
static int s_matrixEffectBase = 0;
#elif 0
// Double vision
static int s_matrixEffectDivide = 6;
static int s_matrixEffectWidth = 13;
static int s_matrixEffectHeight = 2;
static int s_matrixEffectData[26] = {2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3};
static int s_matrixEffectBase = 0;
#elif 0
// Negative
static int s_matrixEffectDivide = 1;
static int s_matrixEffectWidth = 1;
static int s_matrixEffectHeight = 1;
static int s_matrixEffectData[9] = {-1};
static int s_matrixEffectBase = 255;
#elif 0
// Fog
static int s_matrixEffectDivide = 4;
static int s_matrixEffectWidth = 1;
static int s_matrixEffectHeight = 1;
static int s_matrixEffectData[9] = {3};
static int s_matrixEffectBase = 45;
#elif 0
// Blur
static int s_matrixEffectDivide = 14;
static int s_matrixEffectWidth = 3;
static int s_matrixEffectHeight = 3;
static int s_matrixEffectData[9] = {1, 2, 1, 2, 2, 2, 1, 2, 1};
static int s_matrixEffectBase = 0;
#else
static int s_matrixEffectDivide = 0;
static int s_matrixEffectWidth = 0;
static int s_matrixEffectHeight = 0;
static int *s_matrixEffectData = NULL;
static int s_matrixEffectBase = 0;
#endif
void GraphicsManager::blur_saveSettings(Common::WriteStream *stream) {
if (s_matrixEffectData) {
stream->writeUint32LE(s_matrixEffectDivide);
stream->writeUint32LE(s_matrixEffectWidth);
stream->writeUint32LE(s_matrixEffectHeight);
stream->writeUint32LE(s_matrixEffectBase);
stream->write(s_matrixEffectData, sizeof(int) * s_matrixEffectWidth * s_matrixEffectHeight);
} else {
stream->writeUint32LE(0);
stream->writeUint32LE(0);
stream->writeUint32LE(0);
stream->writeUint32LE(0);
}
}
static int *blur_allocateMemoryForEffect() {
free(s_matrixEffectData);
s_matrixEffectData = NULL;
if (s_matrixEffectWidth && s_matrixEffectHeight) {
s_matrixEffectData = (int *)malloc(sizeof(int) * s_matrixEffectHeight * s_matrixEffectWidth);
checkNew(s_matrixEffectData);
}
return s_matrixEffectData;
}
void GraphicsManager::blur_loadSettings(Common::SeekableReadStream *stream) {
s_matrixEffectDivide = stream->readUint32LE();
s_matrixEffectWidth = stream->readUint32LE();
s_matrixEffectHeight = stream->readUint32LE();
s_matrixEffectBase = stream->readUint32LE();
if (blur_allocateMemoryForEffect()) {
uint bytes_read = stream->read(s_matrixEffectData, sizeof(int) * s_matrixEffectWidth * s_matrixEffectHeight);
if (bytes_read != sizeof(int) * s_matrixEffectWidth * s_matrixEffectHeight && stream->err()) {
debug("Reading error in blur_loadSettings.");
}
} else {
stream->seek(sizeof(int) * s_matrixEffectWidth * s_matrixEffectHeight, SEEK_CUR);
}
}
bool GraphicsManager::blur_createSettings(int numParams, VariableStack *&stack) {
bool createNullThing = true;
Common::String error = "";
if (numParams >= 3) {
// PARAMETERS: base, divide, stack (, stack (, stack...))
int height = numParams - 2;
int width = 0;
VariableStack *justToCheckSizes = stack;
for (int a = 0; a < height; a++) {
if (justToCheckSizes->thisVar.varType != SVT_STACK) {
error = "Third and subsequent parameters in setBackgroundEffect should be arrays";
break;
} else {
int w = justToCheckSizes->thisVar.varData.theStack->getStackSize();
if (a) {
if (w != width) {
error = "Arrays in setBackgroundEffect must be the same size";
break;
}
if (w < width) {
width = w;
}
} else {
width = w;
}
}
}
if (width == 0 && error.empty()) {
error = "Empty arrays found in setBackgroundEffect parameters";
}
if (error.empty()) {
s_matrixEffectWidth = width;
s_matrixEffectHeight = height;
if (blur_allocateMemoryForEffect()) {
for (int y = height - 1; y >= 0; y--) {
VariableStack *eachNumber = stack->thisVar.varData.theStack->first;
if (error.empty()) {
for (int x = 0; x < width; x++) {
int arraySlot = x + (y * width);
// s_matrixEffectData[arraySlot] = (rand() % 4);
if (!eachNumber->thisVar.getValueType(s_matrixEffectData[arraySlot], SVT_INT)) {
error = "";
break;
}
eachNumber = eachNumber->next;
}
trimStack(stack);
}
}
if (error.empty() && !stack->thisVar.getValueType(s_matrixEffectDivide, SVT_INT))
error = "";
trimStack(stack);
if (error.empty() && !stack->thisVar.getValueType(s_matrixEffectBase, SVT_INT))
error = "";
trimStack(stack);
if (error.empty()) {
if (s_matrixEffectDivide) {
createNullThing = false;
} else {
error = "Second parameter of setBackgroundEffect (the 'divide' value) should not be 0!";
}
}
} else {
error = "Couldn't allocate memory for effect";
}
}
} else {
if (numParams) {
error = "setBackgroundEffect should either have 0 parameters or more than 2";
}
}
if (createNullThing) {
s_matrixEffectDivide = 0;
s_matrixEffectWidth = 0;
s_matrixEffectHeight = 0;
s_matrixEffectBase = 0;
delete s_matrixEffectData;
s_matrixEffectData = NULL;
}
if (!error.empty()) {
fatal(error);
}
return !createNullThing;
}
static inline void blur_createSourceLine(byte *createLine, byte *fromLine, int overlapOnLeft, int width) {
int miniX;
memcpy(createLine + overlapOnLeft * 4, fromLine, width * 4);
for (miniX = 0; miniX < overlapOnLeft; miniX++) {
createLine[miniX * 4] = fromLine[1];
createLine[miniX * 4 + 1] = fromLine[2];
createLine[miniX * 4 + 2] = fromLine[3];
}
for (miniX = width + overlapOnLeft; miniX < width + s_matrixEffectWidth - 1; miniX++) {
createLine[miniX * 4] = fromLine[width * 4 - 3];
createLine[miniX * 4 + 1] = fromLine[width * 4 - 2];
createLine[miniX * 4 + 2] = fromLine[width * 4 - 1];
}
}
bool GraphicsManager::blurScreen() {
if (s_matrixEffectWidth && s_matrixEffectHeight && s_matrixEffectDivide && s_matrixEffectData) {
byte *thisLine;
int y, x;
bool ok = true;
int overlapOnLeft = s_matrixEffectWidth / 2;
int overlapAbove = s_matrixEffectHeight / 2;
byte **sourceLine = new byte *[s_matrixEffectHeight];
if (!checkNew(sourceLine))
return false;
for (y = 0; y < s_matrixEffectHeight; y++) {
sourceLine[y] = new byte[(s_matrixEffectWidth - 1 + _sceneWidth) * 4];
ok &= (sourceLine[y] != NULL);
}
if (ok) {
for (y = 0; y < s_matrixEffectHeight; y++) {
int miniY = CLIP<int>(y - overlapAbove - 1, 0, _sceneHeight - 1);
blur_createSourceLine(sourceLine[y], (byte *)_backdropSurface.getBasePtr(0, miniY), overlapOnLeft, _sceneWidth);
}
for (y = 0; y < (int)_sceneHeight; y++) {
thisLine = (byte *)_backdropSurface.getBasePtr(0, y);
//-------------------------
// Scroll source lines
//-------------------------
byte *tempLine = sourceLine[0];
for (int miniY = 0; miniY < s_matrixEffectHeight - 1; miniY++) {
sourceLine[miniY] = sourceLine[miniY + 1];
}
sourceLine[s_matrixEffectHeight - 1] = tempLine;
{
int h = s_matrixEffectHeight - 1;
int miniY = CLIP<int>(y + (s_matrixEffectHeight - overlapAbove - 1), 0, _sceneHeight - 1);
blur_createSourceLine(sourceLine[h], (byte *)_backdropSurface.getBasePtr(0, miniY), overlapOnLeft, _sceneWidth);
}
for (x = 0; x < (int)_sceneWidth; x++) {
int totalRed = 0;
int totalGreen = 0;
int totalBlue = 0;
int *matrixElement = s_matrixEffectData;
for (int miniY = 0; miniY < s_matrixEffectHeight; ++miniY) {
byte *pixel = &sourceLine[miniY][x * 4];
for (int miniX = 0; miniX < s_matrixEffectWidth; ++miniX) {
totalRed += pixel[1] **matrixElement;
totalGreen += pixel[2] **matrixElement;
totalBlue += pixel[3] **matrixElement;
++matrixElement;
pixel += 4;
}
}
totalRed = (totalRed + s_matrixEffectDivide / 2) / s_matrixEffectDivide + s_matrixEffectBase;
totalRed = (totalRed < 0) ? 0 : ((totalRed > 255) ? 255 : totalRed);
totalGreen = (totalGreen + s_matrixEffectDivide / 2) / s_matrixEffectDivide + s_matrixEffectBase;
totalGreen = (totalGreen < 0) ? 0 : ((totalGreen > 255) ? 255 : totalGreen);
totalBlue = (totalBlue + s_matrixEffectDivide / 2) / s_matrixEffectDivide + s_matrixEffectBase;
totalBlue = (totalBlue < 0) ? 0 : ((totalBlue > 255) ? 255 : totalBlue);
// *thisLine = totalAlpha;
++thisLine;
*thisLine = totalRed;
++thisLine;
*thisLine = totalGreen;
++thisLine;
*thisLine = totalBlue;
++thisLine;
}
}
}
for (y = 0; y < s_matrixEffectHeight; y++) {
delete[] sourceLine[y];
}
delete[] sourceLine;
sourceLine = NULL;
return true;
}
return false;
}
} // End of namespace Sludge

2653
engines/sludge/builtin.cpp Normal file

File diff suppressed because it is too large Load Diff

46
engines/sludge/builtin.h Normal file
View File

@@ -0,0 +1,46 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef SLUDGE_BUILTIN_H
#define SLUDGE_BUILTIN_H
#include "common/str.h"
namespace Sludge {
struct LoadedFunction;
enum BuiltReturn {
BR_KEEP_AND_PAUSE,
BR_ERROR,
BR_CONTINUE,
BR_PAUSE,
BR_CALLAFUNC,
BR_ALREADY_GONE
};
bool failSecurityCheck(const Common::String &fn);
BuiltReturn callBuiltIn(int whichFunc, int numParams, LoadedFunction *fun);
const char *getBuiltInName(int num);
} // End of namespace Sludge
#endif

View File

@@ -0,0 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
add_engine sludge "Sludge" yes "" "" "16bit png" "vpx universaltracker"

View File

@@ -0,0 +1,4 @@
begin_section("SLUDGE");
add_person("Eugene Sandulenko", "sev", "");
add_person("Simei Yin", "yinsimei", "GSoC Student");
end_section();

75
engines/sludge/csludge.h Normal file
View File

@@ -0,0 +1,75 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef SLUDGE_CSLUDGE_H
#define SLUDGE_CSLUDGE_H
namespace Sludge {
enum SludgeCommand {
SLU_UNKNOWN,
SLU_RETURN,
SLU_BRANCH,
SLU_BR_ZERO,
SLU_SET_GLOBAL,
SLU_SET_LOCAL,
SLU_LOAD_GLOBAL,
SLU_LOAD_LOCAL,
SLU_PLUS,
SLU_MINUS,
SLU_MULT,
SLU_DIVIDE,
SLU_AND,
SLU_OR,
SLU_EQUALS,
SLU_NOT_EQ,
SLU_MODULUS,
SLU_LOAD_VALUE,
SLU_LOAD_BUILT,
SLU_LOAD_FUNC,
SLU_CALLIT,
SLU_LOAD_STRING,
SLU_LOAD_FILE, /*SLU_LOAD_SCENE,*/
SLU_LOAD_OBJTYPE,
SLU_NOT,
SLU_LOAD_NULL,
SLU_STACK_PUSH,
SLU_LESSTHAN,
SLU_MORETHAN,
SLU_NEGATIVE,
SLU_UNREG,
SLU_LESS_EQUAL,
SLU_MORE_EQUAL,
SLU_INCREMENT_LOCAL,
SLU_DECREMENT_LOCAL,
SLU_INCREMENT_GLOBAL,
SLU_DECREMENT_GLOBAL,
SLU_INDEXSET,
SLU_INDEXGET,
SLU_INCREMENT_INDEX,
SLU_DECREMENT_INDEX,
SLU_QUICK_PUSH,
numSludgeCommands
};
} // End of namespace Sludge
#endif

142
engines/sludge/cursors.cpp Normal file
View File

@@ -0,0 +1,142 @@
/* 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/system.h"
#include "sludge/cursors.h"
#include "sludge/event.h"
#include "sludge/graphics.h"
#include "sludge/freeze.h"
#include "sludge/newfatal.h"
#include "sludge/people.h"
#include "sludge/sludge.h"
#include "sludge/sludger.h"
namespace Sludge {
CursorManager::CursorManager(SludgeEngine *vm) {
_vm = vm;
init();
}
CursorManager::~CursorManager() {
kill();
}
void CursorManager::init() {
_mouseCursorAnim = new PersonaAnimation();
_mouseCursorFrameNum = 0;
_mouseCursorCountUp = 0;
}
void CursorManager::kill() {
if (_mouseCursorAnim) {
delete _mouseCursorAnim;
_mouseCursorAnim = nullptr;
}
_mouseCursorAnim = nullptr;
}
void CursorManager::pickAnimCursor(PersonaAnimation *pp) {
if (_mouseCursorAnim) {
delete _mouseCursorAnim;
_mouseCursorAnim = nullptr;
}
_mouseCursorAnim = pp;
_mouseCursorFrameNum = 0;
_mouseCursorCountUp = 0;
}
void CursorManager::displayCursor() {
if (_mouseCursorAnim && _mouseCursorAnim->numFrames) {
int spriteNum = _mouseCursorAnim->frames[_mouseCursorFrameNum].frameNum;
int flipMe = 0;
if (spriteNum < 0) {
spriteNum = -spriteNum;
flipMe = 1;
if (spriteNum >= _mouseCursorAnim->theSprites->bank.total)
spriteNum = 0;
} else {
if (spriteNum >= _mouseCursorAnim->theSprites->bank.total)
flipMe = 2;
}
if (flipMe != 2) {
if (flipMe) {
_vm->_gfxMan->flipFontSprite(
_vm->_evtMan->mouseX(), _vm->_evtMan->mouseY(),
_mouseCursorAnim->theSprites->bank.sprites[spriteNum],
_mouseCursorAnim->theSprites->bank.myPalette /* ( spritePalette&) NULL*/);
} else {
_vm->_gfxMan->fontSprite(
_vm->_evtMan->mouseX(), _vm->_evtMan->mouseY(),
_mouseCursorAnim->theSprites->bank.sprites[spriteNum],
_mouseCursorAnim->theSprites->bank.myPalette /* ( spritePalette&) NULL*/);
}
}
if (++_mouseCursorCountUp >= _mouseCursorAnim->frames[_mouseCursorFrameNum].howMany) {
_mouseCursorCountUp = 0;
_mouseCursorFrameNum++;
_mouseCursorFrameNum %= _mouseCursorAnim->numFrames;
}
}
}
void CursorManager::pasteCursor(int x, int y, PersonaAnimation *c) {
if (c->numFrames)
_vm->_gfxMan->pasteSpriteToBackDrop(x, y, c->theSprites->bank.sprites[c->frames[0].frameNum], c->theSprites->bank.myPalette);
}
void CursorManager::freeze(FrozenStuffStruct *frozenStuff) {
frozenStuff->mouseCursorAnim = _mouseCursorAnim;
frozenStuff->mouseCursorFrameNum = _mouseCursorFrameNum;
_mouseCursorAnim = new PersonaAnimation();
_mouseCursorFrameNum = 0;
}
void CursorManager::resotre(FrozenStuffStruct *frozenStuff) {
if (_mouseCursorAnim) {
delete _mouseCursorAnim;
_mouseCursorAnim = nullptr;
}
_mouseCursorAnim = frozenStuff->mouseCursorAnim;
_mouseCursorFrameNum = frozenStuff->mouseCursorFrameNum;
}
void CursorManager::saveCursor(Common::WriteStream *stream) {
_mouseCursorAnim->save(stream);
stream->writeUint16BE(_mouseCursorFrameNum);
}
bool CursorManager::loadCursor(Common::SeekableReadStream *stream) {
_mouseCursorAnim = new PersonaAnimation;
if (!checkNew(_mouseCursorAnim))
return false;
if (!_mouseCursorAnim->load(stream))
return false;
_mouseCursorFrameNum = stream->readUint16BE();
return true;
}
} // End of namespace Sludge

67
engines/sludge/cursors.h Normal file
View File

@@ -0,0 +1,67 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef SLUDGE_CURSORS_H
#define SLUDGE_CURSORS_H
namespace Common {
class SeekableReadStream;
class WriteStream;
}
namespace Sludge {
class SludgeEngine;
struct FrozenStuffStruct;
class CursorManager {
public:
CursorManager(SludgeEngine *vm);
virtual ~CursorManager();
void init();
void kill();
// cursor
void pickAnimCursor(struct PersonaAnimation *pp);
void displayCursor();
void pasteCursor(int x, int y, struct PersonaAnimation *c);
// freeze
void freeze(FrozenStuffStruct *frozenStuff);
void resotre(FrozenStuffStruct *frozenStuff);
// load & save
void saveCursor(Common::WriteStream *stream);
bool loadCursor(Common::SeekableReadStream *stream);
private:
SludgeEngine *_vm;
PersonaAnimation *_mouseCursorAnim;
int _mouseCursorFrameNum;
int _mouseCursorCountUp;
};
} // End of namespace Sludge
#endif

View File

@@ -0,0 +1,62 @@
/* 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 "sludge/debugger.h"
#include "sludge/sludge.h"
#include "sludge/fileset.h"
namespace Sludge {
Debugger::Debugger(SludgeEngine *vm) : GUI::Debugger(), _vm(vm) {
registerCmd("listResources", WRAP_METHOD(Debugger, Cmd_ListResources));
registerCmd("dumpResource", WRAP_METHOD(Debugger, Cmd_DumpResource));
}
bool Debugger::Cmd_ListResources(int argc, const char **argv) {
if (argc != 1 && argc != 2) {
debugPrintf("Usage: %s\n", argv[0]);
return true;
}
for (int i = 0; i < _vm->_resMan->getResourceNameCount(); i++) {
const Common::String name = _vm->_resMan->resourceNameFromNum(i);
if (argc == 1 || name.matchString(argv[1]))
debugPrintf(" - %s\n", name.c_str());
}
return true;
}
bool Debugger::Cmd_DumpResource(int argc, const char **argv) {
if (argc != 2) {
debugPrintf("Usage: %s\n", argv[0]);
return true;
}
if (_vm->_resMan->dumpFileFromName(argv[1])) {
debugPrintf("Success\n");
} else {
debugPrintf("Failure\n");
}
return true;
}
} // End of namespace Sludge

46
engines/sludge/debugger.h Normal file
View File

@@ -0,0 +1,46 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef SLUDGE_DEBUGGER_H
#define SLUDGE_DEBUGGER_H
#include "gui/debugger.h"
namespace Sludge {
class SludgeEngine;
class Debugger : public GUI::Debugger {
private:
SludgeEngine *_vm;
public:
Debugger(SludgeEngine *vm);
~Debugger() override {}
protected:
bool Cmd_ListResources(int argc, const char **argv);
bool Cmd_DumpResource(int argc, const char **argv);
};
} // End of namespace Sludge
#endif

View File

@@ -0,0 +1,143 @@
/* 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/file.h"
#include "engines/advancedDetector.h"
#include "sludge/detection.h"
#include "sludge/sludge.h"
static const DebugChannelDef debugFlagList[] = {
{Sludge::kSludgeDebugFatal, "script", "Script debug level"},
{Sludge::kSludgeDebugDataLoad, "loading", "Data loading debug level"},
{Sludge::kSludgeDebugStackMachine, "stack", "Stack Machine debug level"},
{Sludge::kSludgeDebugBuiltin, "builtin", "Built-in debug level"},
{Sludge::kSludgeDebugGraphics, "graphics", "Graphics debug level"},
{Sludge::kSludgeDebugZBuffer, "zBuffer", "ZBuffer debug level"},
{Sludge::kSludgeDebugSound, "sound", "Sound debug level"},
DEBUG_CHANNEL_END
};
#include "sludge/detection_tables.h"
static Sludge::SludgeGameDescription s_fallbackDesc =
{
{
"",
"",
AD_ENTRY1(0, 0), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor
Common::UNK_LANG,
Common::kPlatformWindows,
ADGF_NO_FLAGS,
GUIO1(GUIO_NOMIDI)
},
0
};
static char s_fallbackFileNameBuffer[51];
class SludgeMetaEngineDetection : public AdvancedMetaEngineDetection<Sludge::SludgeGameDescription> {
public:
SludgeMetaEngineDetection() : AdvancedMetaEngineDetection(Sludge::gameDescriptions, Sludge::sludgeGames) {
_maxScanDepth = 1;
}
const char *getName() const override {
return "sludge";
}
const char *getEngineName() const override {
return "Sludge";
}
const char *getOriginalCopyright() const override {
return "Sludge (C) 2000-2014 Hungry Software and contributors";
}
const DebugChannelDef *getDebugChannels() const override {
return debugFlagList;
}
// for fall back detection
ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist, ADDetectedGameExtraInfo **extra) const override;
};
ADDetectedGame SludgeMetaEngineDetection::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist, ADDetectedGameExtraInfo **extra) const {
// reset fallback description
s_fallbackDesc.desc.gameId = "sludge";
s_fallbackDesc.desc.extra = "";
s_fallbackDesc.desc.language = Common::EN_ANY;
s_fallbackDesc.desc.flags = ADGF_UNSTABLE;
s_fallbackDesc.desc.platform = Common::kPlatformUnknown;
s_fallbackDesc.desc.guiOptions = GUIO1(GUIO_NOMIDI);
s_fallbackDesc.languageID = 0;
for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
if (file->isDirectory())
continue;
Common::Path fileName = file->getPathInArchive();
fileName.toLowercase();
if (!(fileName.baseName().hasSuffix(".slg") || fileName == "gamedata"))
continue;
Common::File f;
if (!f.open(*file))
continue;
bool headerBad = false;
if (f.readByte() != 'S')
headerBad = true;
if (f.readByte() != 'L')
headerBad = true;
if (f.readByte() != 'U')
headerBad = true;
if (f.readByte() != 'D')
headerBad = true;
if (f.readByte() != 'G')
headerBad = true;
if (f.readByte() != 'E')
headerBad = true;
if (headerBad) {
continue;
}
strncpy(s_fallbackFileNameBuffer, fileName.toString('/').c_str(), 50);
s_fallbackFileNameBuffer[50] = '\0';
s_fallbackDesc.desc.filesDescriptions[0].fileName = s_fallbackFileNameBuffer;
ADDetectedGame game;
game.desc = &s_fallbackDesc.desc;
FileProperties tmp;
if (getFileProperties(allFiles, kMD5Head, fileName, tmp)) {
game.hasUnknownFiles = true;
game.matchedFiles[fileName] = tmp;
}
return game;
}
return ADDetectedGame();
}
REGISTER_PLUGIN_STATIC(SLUDGE_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, SludgeMetaEngineDetection);

View File

@@ -0,0 +1,36 @@
/* 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 SLUDGE_DETECTION_H
#define SLUDGE_DETECTION_H
namespace Sludge {
struct SludgeGameDescription {
AD_GAME_DESCRIPTION_HELPERS(desc);
ADGameDescription desc;
uint languageID;
};
} // End of namespace Sludge
#endif // SLUDGE_DETECTION_H

View File

@@ -0,0 +1,173 @@
/* 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/>.
*
*/
namespace Sludge {
static const PlainGameDescriptor sludgeGames[] = {
{ "sludge", "Sludge Game" },
{ "welcome", "Welcome Example" },
{ "verbcoin", "Verb Coin" },
{ "verbcoin2", "Verb Coin 2"},
{ "parallax", "Parallax Demo" },
{ "robinsrescue", "Robin's Rescue" },
{ "outoforder", "Out Of Order" },
{ "frasse", "Frasse and the Peas of Kejick" },
{ "interview", "The Interview" },
{ "life", "Life Flashes By" },
{ "tgttpoacs", "The Game That Takes Place on a Cruise Ship" },
{ "mandy", "Mandy Christmas Adventure" },
{ "cubert", "Cubert Badbone, P.I." },
{ "gjgagsas", "The Game Jam Game About Games, Secrets and Stuff" },
{ "tsotc", "The Secret of Tremendous Corporation" },
{ "nsc", "Nathan's Second Chance" },
{ "atw", "Above The Waves" },
{ "leptonsquest", "Lepton's Quest" },
{ "otto", "Otto Experiment" },
{ 0, 0 }
};
#define GAME1l(t, e, f1, m1, s1, lang, pl, langId) { { t, e, AD_ENTRY1s(f1, m1, s1), lang, pl, ADGF_NO_FLAGS, GUIO1(GUIO_NOMIDI) }, langId }
#define GAME1(t, e, f1, m1, s1) GAME1l(t, e, f1, m1, s1, Common::EN_ANY, Common::kPlatformUnknown, 0)
#define GAME2l(t, e, f1, m1, s1, f2, m2, s2, lang, pl, langId) { { t, e, AD_ENTRY2s(f1, m1, s1, f2, m2, s2), lang, pl, ADGF_NO_FLAGS, GUIO1(GUIO_NOMIDI) }, langId }
#define GAME2(t, e, f1, m1, s1, f2, m2, s2) GAME2l(t, e, f1, m1, s1, f2, m2, s2, Common::EN_ANY, Common::kPlatformUnknown, 0)
static const SludgeGameDescription gameDescriptions[] = {
GAME1("welcome", "", "Welcome.slg", "50445503761cf6684fe3270d0860a4c3", 51736),
GAME1("verbcoin", "", "Verb Coin.slg", "e39ec315dcbf3a1137481f0a5fe1617d", 980270),
GAME1l("verbcoin", "", "Verb Coin.slg", "e39ec315dcbf3a1137481f0a5fe1617d", 980270, Common::DE_DEU, Common::kPlatformUnknown, 1),
GAME1("verbcoin2", "", "Verb Coin.slg", "483b315990309c718617c7c47fa132d8", 1067575),
GAME1l("verbcoin2", "", "Verb Coin.slg", "483b315990309c718617c7c47fa132d8", 1067575, Common::DE_DEU, Common::kPlatformUnknown, 1),
GAME1("parallax", "", "Parallax_demo.slg", "daae3f75c6695bed47e5e633cd406a47", 65881),
GAME1("robinsrescue", "", "robins_rescue.slg", "16cbf2bf916ed89f9c1b14fab133cf96", 14413769),
GAME1("robinsrescue", "v1.0", "Gamedata.slg", "16cbf2bf916ed89f9c1b14fab133cf96", 14413754),
GAME1l("robinsrescue", "v1.0", "Gamedata.slg", "16cbf2bf916ed89f9c1b14fab133cf96", 14413754, Common::EN_ANY, Common::kPlatformLinux, 0),
GAME2l("outoforder", "v1.0", "gamedata", "4d72dbad0ff170169cd7e4e7e389a90d", 21122647,
"out-of-order.xpm", "407086751ac167884c6585c4cad5b664", 2601,
Common::EN_ANY, Common::kPlatformLinux, 0),
GAME2l("outoforder", "v1.0", "gamedata", "4d72dbad0ff170169cd7e4e7e389a90d", 21122647, // 2003-02-08
"Out Of Order.exe", "064d221103ca4bb7f187432b69c70efd", 68096,
Common::EN_ANY, Common::kPlatformWindows, 0),
GAME2l("outoforder", "v1.0", "gamedata", "4d72dbad0ff170169cd7e4e7e389a90d", 21122647, // 2003-06-05
"Out Of Order.exe", "ebc386dd0cb77df68dd12d72742eb310", 68608,
Common::EN_ANY, Common::kPlatformWindows, 0),
GAME2("frasse", "v1.03", "gamedata", "5a985d772f9909a8cc98e1e9edf0875d", 38186227,
"frasse.exe", "7016ef8ab67133a1d6fce20b8b70cd1d", 83968),
GAME2("frasse", "v1.04", "gamedata", "13934872c16391de3ddd6644e3bfcd15", 38154596,
"frasse.exe", "7016ef8ab67133a1d6fce20b8b70cd1d", 83968),
GAME1l("frasse", "v2.02", "Gamedata.slg", "25e4a63ae10f69f5032c58ad2fd51fac", 88582783, Common::EN_ANY, Common::kPlatformMacintosh, 0),
GAME1l("frasse", "v2.03", "Gamedata.slg", "e4eb4eca6117bb9b77870bb74af453b4", 88582819, Common::EN_ANY, Common::kPlatformWindows, 0),
GAME2("interview", "", "gamedata", "6ca8f6e44f30d09bd68e008be4c20e8d", 2570140,
"interview.exe", "7974f71566c423c3a344862dcbb827dd", 83968),
GAME1("life", "", "LifeFlashesBy.slg", "a471759e071e5d2c0e8e6887607df778", 163794266),
GAME2("life", "", "gamedata", "a471759e071e5d2c0e8e6887607df778", 163794266,
"sludge.bmp", "69db99963fb7e93af6d48dfd7f4246ee", 13846),
GAME2("life", "", "gamedata", "a471759e071e5d2c0e8e6887607df778", 163794266,
"Life Flashes By.exe", "d33c957eefa85defde8b8c29a0bb5a9b", 972800),
GAME2l("tgttpoacs", "", "gamedata", "d5ec4d7d8440f7744335d25d25e1e943", 40368,
"gert.ico", "b76b5b38e8d5cd6843636085947bfd29", 3638,
Common::EN_ANY, Common::kPlatformWindows, 0),
GAME1l("tgttpoacs", "", "tgttpoacs.dat", "e61d3d050793689d55487d3ad01b6693", 23817174, Common::EN_ANY, Common::kPlatformLinux, 0),
GAME2l("mandy", "v1.2", "data", "df4a0c113b93b89ff2fe7991fb018bae", 7099447,
"Mandy.exe", "596478e1a7b4445fc0bd7f5ec2696125", 71168,
Common::SK_SVK, Common::kPlatformWindows, 0),
GAME2l("mandy", "v1.2", "data", "df4a0c113b93b89ff2fe7991fb018bae", 7099447,
"Mandy.exe", "596478e1a7b4445fc0bd7f5ec2696125", 71168,
Common::EN_ANY, Common::kPlatformWindows, 1),
GAME2l("mandy", "v1.3", "data", "b732ffe04367c787c6ce70fbcb7aa6aa", 7100976,
"Mandy.exe", "596478e1a7b4445fc0bd7f5ec2696125", 71168,
Common::SK_SVK, Common::kPlatformWindows, 0),
GAME2l("mandy", "v1.3", "data", "b732ffe04367c787c6ce70fbcb7aa6aa", 7100976,
"Mandy.exe", "596478e1a7b4445fc0bd7f5ec2696125", 71168,
Common::EN_ANY, Common::kPlatformWindows, 1),
GAME2l("mandy", "v1.3", "data", "b732ffe04367c787c6ce70fbcb7aa6aa", 7100976,
"Mandy.exe", "596478e1a7b4445fc0bd7f5ec2696125", 71168,
Common::IT_ITA, Common::kPlatformWindows, 2),
GAME2l("mandy", "v1.4", "data", "705f6ca5f5da0c40c1f547231dd5139f", 7141292,
"Mandy.exe", "7016ef8ab67133a1d6fce20b8b70cd1d", 83968,
Common::SK_SVK, Common::kPlatformWindows, 0),
GAME2l("mandy", "v1.4", "data", "705f6ca5f5da0c40c1f547231dd5139f", 7141292,
"Mandy.exe", "7016ef8ab67133a1d6fce20b8b70cd1d", 83968,
Common::EN_ANY, Common::kPlatformWindows, 1),
GAME2l("mandy", "v1.4", "data", "705f6ca5f5da0c40c1f547231dd5139f", 7141292,
"Mandy.exe", "7016ef8ab67133a1d6fce20b8b70cd1d", 83968,
Common::IT_ITA, Common::kPlatformWindows, 2),
GAME2l("mandy", "v1.4", "data", "705f6ca5f5da0c40c1f547231dd5139f", 7141292,
"Mandy.exe", "7016ef8ab67133a1d6fce20b8b70cd1d", 83968,
Common::PL_POL, Common::kPlatformWindows, 3),
// August 4, 2002
GAME2l("cubert", "v1.1", "Gamedata", "dfb7f8012a29631349a14351ba1cfd49", 27303861,
"Cubert.exe", "055b5b5c30265ba32e4235b012eb90bb", 64000,
Common::EN_ANY, Common::kPlatformWindows, 0),
// June 11, 2003
GAME2l("cubert", "v1.1", "Gamedata", "dfb7f8012a29631349a14351ba1cfd49", 27303861,
"Cubert Badbone.exe", "055b5b5c30265ba32e4235b012eb90bb", 64000,
Common::EN_ANY, Common::kPlatformWindows, 0),
// August 16, 2002
GAME2l("cubert", "v1.2", "Gamedata", "245b043e4b2ade16f56118f8d98fb940", 27304149,
"Cubert.exe", "055b5b5c30265ba32e4235b012eb90bb", 64000,
Common::EN_ANY, Common::kPlatformWindows, 0),
// September 5, 2002
GAME2l("cubert", "v1.25", "gamedata", "d1d9b27d0c43a37952c1bef7bc848623", 27306453,
"Cubert.exe", "acc9fb7b4be7e7824a003c88942d778d", 67072,
Common::EN_ANY, Common::kPlatformWindows, 0),
// Mar 9, 2004
GAME1l("cubert", "", "cubert.dat", "cabc424d4e39ecdba4b0afd4033b5ea8", 19696514, Common::EN_ANY, Common::kPlatformWindows, 0),
GAME1l("cubert", "", "cubert.dat", "cabc424d4e39ecdba4b0afd4033b5ea8", 19696514, Common::IT_ITA, Common::kPlatformWindows, 1),
GAME1l("cubert", "", "cubert.dat", "cabc424d4e39ecdba4b0afd4033b5ea8", 19696514, Common::SV_SWE, Common::kPlatformWindows, 2),
GAME1l("cubert", "", "cubert.dat", "cabc424d4e39ecdba4b0afd4033b5ea8", 19696514, Common::DE_DEU, Common::kPlatformWindows, 3),
// Dec 15, 2005
GAME1l("cubert", "", "cubert.dat", "e70050692a0ab96e8753109793157ccd", 19677815, Common::EN_ANY, Common::kPlatformWindows, 0),
GAME1l("cubert", "", "cubert.dat", "e70050692a0ab96e8753109793157ccd", 19677815, Common::IT_ITA, Common::kPlatformWindows, 1),
GAME1l("cubert", "", "cubert.dat", "e70050692a0ab96e8753109793157ccd", 19677815, Common::SV_SWE, Common::kPlatformWindows, 2),
GAME1l("cubert", "", "cubert.dat", "e70050692a0ab96e8753109793157ccd", 19677815, Common::DE_DEU, Common::kPlatformWindows, 3),
GAME1("nsc", "v1.03", "gamedata.slg", "57f318cc09e93a1e0685b790a956ebdc", 12733871),
GAME2l("nsc", "v1.03", "gamedata", "57f318cc09e93a1e0685b790a956ebdc", 12733871,
"Nathan's Second Chance.exe", "9bb4492fc7f7fc38bc1772bb9f15f787", 71680,
Common::EN_ANY, Common::kPlatformWindows, 0),
GAME1("gjgagsas", "", "gamedata.slg", "f438946f2ee79d52918f44c4a67eb37b", 27527984),
GAME1("tsotc", "v6", "gamedata.slg", "7d677e79fb842df00c4602864da13829", 34740918),
GAME1("atw", "", "atw.slg", "41ae22ac9fa5051e0499468a9fbe600e", 27808575),
GAME1l("leptonsquest", "", "game.slg", "763d4020dcd55a4af4c01664f79584da", 71233234, Common::EN_ANY, Common::kPlatformWindows, 0),
GAME1l("leptonsquest", "", "Gamedata.slg", "763d4020dcd55a4af4c01664f79584da", 71233239, Common::EN_ANY, Common::kPlatformMacintosh, 0),
GAME1l("leptonsquest", "", "LeptonsQuest.slg", "763d4020dcd55a4af4c01664f79584da", 71233239, Common::EN_ANY, Common::kPlatformLinux, 0),
GAME1("otto", "", "gamedata", "c93b1bd849cdb6a23fb8eb389f5c1955", 154427),
{ AD_TABLE_END_MARKER, 0 }
};
} // End of namespace Wage

75
engines/sludge/errors.h Normal file
View File

@@ -0,0 +1,75 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef SLUDGE_ERRRORS_H
#define SLUDGE_ERRRORS_H
namespace Sludge {
#define _NO_MEMORY_GENERAL_ "\n\nTry closing down any programs you don't really need running (or freeing up a bit of disk space, which will give you more virtual memory - that should help too)."
//---------------------------------------
// Fatal errors
//---------------------------------------
#define ERROR_VERSION_TOO_LOW_1 "This SLUDGE file requires a more recent version of the SLUDGE engine"
#define ERROR_VERSION_TOO_LOW_2 "(it was created for v%i.%i).\n\nVisit http://opensludge.github.io/ to download the most recent version."
#define ERROR_VERSION_TOO_HIGH_1 "This SLUDGE file was created for an older version of the SLUDGE engine"
#define ERROR_VERSION_TOO_HIGH_2 "(v%i.%i).\n\nPlease contact the author of this game to obtain a version compatible with your SLUDGE engine (v" TEXT_VERSION ")."
#define ERROR_BAD_HEADER "Bad header information... this isn't a valid SLUDGE game"
#define ERROR_HACKER "What have you been up to? Think we're a hacker, do we? Nice try."
#define ERROR_GAME_LOAD_NO "This isn't a SLUDGE saved game!\n"
#define ERROR_GAME_LOAD_WRONG "Can't load this saved game! It was either created by...\n\n (a) a different SLUDGE game to the one which you're playing, or...\n (b) a different (newer or older) version of the same game.\n\nFilename"
#define ERROR_GAME_SAVE_FROZEN "Can't save games while I'm frozen"
#define ERROR_GAME_LOAD_CORRUPT "This saved game appears to be corrupted"
#define ERROR_NON_EMPTY_STACK "Returning from function with non-empty stack"
#define ERROR_UNKNOWN_MCODE "Unknown SLUDGE machine code"
#define ERROR_CALL_NONFUNCTION "Call of non-function"
#define ERROR_INCDEC_UNKNOWN "Tried to increment/decrement index of an undefined variable"
#define ERROR_INDEX_EMPTY "Tried to index an empty stack"
#define ERROR_INDEX_NONSTACK "Tried to index a non-stack variable"
#define ERROR_NOSTACK "Corrupt file - no stack"
#define ERROR_UNKNOWN_CODE "Unimplemented internal SLUDGE command code."
#define ERROR_OUT_OF_MEMORY "Out of memory!" _NO_MEMORY_GENERAL_
#define ERROR_MUSIC_MEMORY_LOW "Your computer doesn't have enough memory available to load a music resource that needs playing." _NO_MEMORY_GENERAL_
#define ERROR_SOUND_MEMORY_LOW "Your computer doesn't have enough memory available to load a sound resource that needs playing." _NO_MEMORY_GENERAL_
#define ERROR_MUSIC_UNKNOWN "I can't understand a piece of music which I've been told to play!\n\n" \
"Maybe it's stored in a format that SLUDGE doesn't know about... " \
"make sure you've got a recent version of the SLUDGE engine from http://opensludge.github.io/. " \
"Failing that, maybe the resource in question isn't a valid music format at all... in which case, contact the game's author and tell them what's happened."
#define ERROR_SOUND_UNKNOWN "I can't understand a sample which I've been told to play!\nMake sure you've got the latest SLUDGE engine from http://opensludge.github.io/. Failing that, maybe the resource in question isn't a valid sound at all... in which case, contact the game's author and tell them what's happened."
#define ERROR_MUSIC_ODDNESS "I can't load a music resource I've been told to play. Sorry."
#define ERROR_SOUND_ODDNESS "I can't load a sound resource I've been told to play. Sorry."
#define ERROR_MOVIE_ODDNESS "I can't load a music resource I've been told to play. Sorry."
//---------------------------------------
// Startup warnings
//---------------------------------------
#define WARNING_BASS_WRONG_VERSION "Incompatible version of BASS.DLL found!"
#define WARNING_BASS_FAIL "Can't initialise sound engine."
} // End of namespace Sludge
#endif

359
engines/sludge/event.cpp Normal file
View File

@@ -0,0 +1,359 @@
/* 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/events.h"
#include "common/system.h"
#include "common/translation.h"
#include "gui/message.h"
#include "sludge/event.h"
#include "sludge/fileset.h"
#include "sludge/graphics.h"
#include "sludge/freeze.h"
#include "sludge/function.h"
#include "sludge/movie.h"
#include "sludge/newfatal.h"
#include "sludge/objtypes.h"
#include "sludge/region.h"
#include "sludge/sludge.h"
#include "sludge/sludger.h"
namespace Sludge {
extern VariableStack *noStack;
EventManager::EventManager(SludgeEngine *vm) {
_vm = vm;
_currentEvents = new EventHandlers;
init();
}
EventManager::~EventManager() {
kill();
if (_currentEvents) {
delete _currentEvents;
_currentEvents = nullptr;
}
}
void EventManager::init() {
_weAreDoneSoQuit = 0;
_reallyWantToQuit = false;
_input.leftClick = _input.rightClick = _input.justMoved = _input.leftRelease = _input.rightRelease = false;
_input.keyPressed = 0;
for (uint i = 0; i < EVENT_FUNC_NB; ++i) {
_currentEvents->func[i] = 0;
}
}
void EventManager::kill() {
}
void EventManager::checkInput() {
float cameraZoom = _vm->_gfxMan->getCamZoom();
//static bool fakeRightclick = false;
Common::Event event;
/* Check for events */
while (g_system->getEventManager()->pollEvent(event)) {
switch (event.type) {
#if 0
case SDL_VIDEORESIZE:
realWinWidth = event.resize.w;
realWinHeight = event.resize.h;
setGraphicsWindow(false, true, true);
break;
#endif
case Common::EVENT_MOUSEMOVE:
_input.justMoved = true;
_input.mouseX = event.mouse.x * cameraZoom;
_input.mouseY = event.mouse.y * cameraZoom;
break;
case Common::EVENT_LBUTTONDOWN:
if (g_system->getEventManager()->getModifierState() & Common::KBD_CTRL) {
_input.rightClick = true;
//fakeRightclick = true;
} else {
_input.leftClick = true;
//fakeRightclick = false;
}
_input.mouseX = event.mouse.x * cameraZoom;
_input.mouseY = event.mouse.y * cameraZoom;
break;
case Common::EVENT_RBUTTONDOWN:
_input.rightClick = true;
_input.mouseX = event.mouse.x * cameraZoom;
_input.mouseY = event.mouse.y * cameraZoom;
break;
case Common::EVENT_LBUTTONUP:
_input.leftRelease = true;
_input.mouseX = event.mouse.x * cameraZoom;
_input.mouseY = event.mouse.y * cameraZoom;
break;
case Common::EVENT_RBUTTONUP:
_input.rightRelease = true;
_input.mouseX = event.mouse.x * cameraZoom;
_input.mouseY = event.mouse.y * cameraZoom;
break;
case Common::EVENT_KEYDOWN:
switch (event.kbd.keycode) {
case Common::KEYCODE_BACKSPACE:
// fall through
case Common::KEYCODE_DELETE:
_input.keyPressed = Common::KEYCODE_DELETE;
break;
default:
_input.keyPressed = event.kbd.keycode;
break;
}
break;
case Common::EVENT_QUIT:
case Common::EVENT_RETURN_TO_LAUNCHER: {
if (!_weAreDoneSoQuit) {
g_system->getEventManager()->resetQuit();
g_system->getEventManager()->resetReturnToLauncher();
GUI::MessageDialog dialog(_(g_sludge->_resMan->getNumberedString(2)), _("Yes"), _("No"));
if (dialog.runModal() == GUI::kMessageOK) {
_weAreDoneSoQuit = 1;
g_system->getEventManager()->pushEvent(event);
}
}
break;
}
default:
break;
}
}
}
bool EventManager::handleInput() {
if (!_vm->_regionMan->getOverRegion())
_vm->_regionMan->updateOverRegion();
if (_input.justMoved) {
if (_currentEvents->func[kMoveMouse]) {
if (!startNewFunctionNum(_currentEvents->func[kMoveMouse], 0, nullptr, noStack))
return false;
}
}
_input.justMoved = false;
if (_vm-> _regionMan->isRegionChanged()&& _currentEvents->func[kFocus]) {
VariableStack *tempStack = new VariableStack;
if (!checkNew(tempStack))
return false;
ScreenRegion *overRegion = _vm->_regionMan->getOverRegion();
if (overRegion) {
tempStack->thisVar.setVariable(SVT_OBJTYPE, overRegion->thisType->objectNum);
} else {
tempStack->thisVar.setVariable(SVT_INT, 0);
}
tempStack->next = nullptr;
if (!startNewFunctionNum(_currentEvents->func[kFocus], 1, nullptr, tempStack))
return false;
}
if (_input.leftRelease && _currentEvents->func[kLeftMouseUp]) {
if (!startNewFunctionNum(_currentEvents->func[kLeftMouseUp], 0, nullptr, noStack))
return false;
}
if (_input.rightRelease && _currentEvents->func[kRightMouseUp]) {
if (!startNewFunctionNum(_currentEvents->func[kRightMouseUp], 0, nullptr, noStack))
return false;
}
if (_input.leftClick && _currentEvents->func[kLeftMouse])
if (!startNewFunctionNum(_currentEvents->func[kLeftMouse], 0, nullptr, noStack))
return false;
if (_input.rightClick && _currentEvents->func[kRightMouse]) {
if (!startNewFunctionNum(_currentEvents->func[kRightMouse], 0, nullptr, noStack))
return false;
}
if (_input.keyPressed && _currentEvents->func[kSpace]) {
Common::String tempString = "";
switch (_input.keyPressed) {
case Common::KEYCODE_DELETE:
tempString = "BACKSPACE";
break;
case Common::KEYCODE_TAB:
tempString = "TAB";
break;
case Common::KEYCODE_RETURN:
tempString = "ENTER";
break;
case Common::KEYCODE_ESCAPE:
tempString = "ESCAPE";
break;
/*
case 1112: tempString = copyString ("ALT+F1"); break;
case 1113: tempString = copyString ("ALT+F2"); break;
case 1114: tempString = copyString ("ALT+F3"); break;
case 1115: tempString = copyString ("ALT+F4"); break;
case 1116: tempString = copyString ("ALT+F5"); break;
case 1117: tempString = copyString ("ALT+F6"); break;
case 1118: tempString = copyString ("ALT+F7"); break;
case 1119: tempString = copyString ("ALT+F8"); break;
case 1120: tempString = copyString ("ALT+F9"); break;
case 1121: tempString = copyString ("ALT+F10"); break;
case 1122: tempString = copyString ("ALT+F11"); break;
case 1123: tempString = copyString ("ALT+F12"); break;
case 2019: tempString = copyString ("PAUSE"); break;
*/
case Common::KEYCODE_PAGEUP:
tempString = "PAGE UP";
break;
case Common::KEYCODE_PAGEDOWN:
tempString = "PAGE DOWN";
break;
case Common::KEYCODE_END:
tempString = "END";
break;
case Common::KEYCODE_HOME:
tempString = "HOME";
break;
case Common::KEYCODE_LEFT:
tempString = "LEFT";
break;
case Common::KEYCODE_UP:
tempString = "UP";
break;
case Common::KEYCODE_RIGHT:
tempString = "RIGHT";
break;
case Common::KEYCODE_DOWN:
tempString = "DOWN";
break;
/*
case 2045: tempString = copyString ("INSERT"); break;
case 2046: tempString = copyString ("DELETE"); break;
*/
case Common::KEYCODE_F1:
tempString = "F1";
break;
case Common::KEYCODE_F2:
tempString = "F2";
break;
case Common::KEYCODE_F3:
tempString = "F3";
break;
case Common::KEYCODE_F4:
tempString = "F4";
break;
case Common::KEYCODE_F5:
tempString = "F5";
break;
case Common::KEYCODE_F6:
tempString = "F6";
break;
case Common::KEYCODE_F7:
tempString = "F7";
break;
case Common::KEYCODE_F8:
tempString = "F8";
break;
case Common::KEYCODE_F9:
tempString = "F9";
break;
case Common::KEYCODE_F10:
tempString = "F10";
break;
case Common::KEYCODE_F11:
tempString = "F11";
break;
case Common::KEYCODE_F12:
tempString = "F12";
break;
default:
if (_input.keyPressed >= 256) {
char tmp[7] = "ABCDEF";
Common::sprintf_s(tmp, "%i", _input.keyPressed);
tempString = tmp;
//}
} else {
char tmp[2] = " ";
tmp[0] = _input.keyPressed;
tempString = tmp;
}
}
if (!tempString.empty()) {
if (isMoviePlaying())
stopMovie();
VariableStack *tempStack = new VariableStack;
if (!checkNew(tempStack))
return false;
tempStack->thisVar.makeTextVar(tempString);
tempStack->next = nullptr;
if (!startNewFunctionNum(_currentEvents->func[kSpace], 1, nullptr, tempStack))
return false;
}
}
_input.rightClick = false;
_input.leftClick = false;
_input.rightRelease = false;
_input.leftRelease = false;
_input.keyPressed = 0;
_vm->_regionMan->updateLastRegion();
return true;
}
void EventManager::loadHandlers(Common::SeekableReadStream *stream) {
for (uint i = 0; i < EVENT_FUNC_NB; ++i) {
_currentEvents->func[i] = stream->readUint16BE();
}
}
void EventManager::saveHandlers(Common::WriteStream *stream) {
for (uint i = 0; i < EVENT_FUNC_NB; ++i) {
stream->writeUint16BE(_currentEvents->func[i]);
}
}
bool EventManager::freeze(FrozenStuffStruct *frozenStuff) {
frozenStuff->currentEvents = _currentEvents;
_currentEvents = new EventHandlers;
if (!checkNew(_currentEvents))
return false;
for (uint i = 0; i < EVENT_FUNC_NB; ++i) {
_currentEvents->func[i] = 0;
}
return true;
}
void EventManager::restore(FrozenStuffStruct *frozenStuff) {
delete _currentEvents;
_currentEvents = frozenStuff->currentEvents;
}
} /* namespace Sludge */

97
engines/sludge/event.h Normal file
View File

@@ -0,0 +1,97 @@
/* 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 SLUDGE_EVENT_H
#define SLUDGE_EVENT_H
namespace Common {
class SeekableReadStream;
class WriteStream;
}
namespace Sludge {
struct FrozenStuffStruct;
struct InputType {
bool leftClick, rightClick, justMoved, leftRelease, rightRelease;
int mouseX, mouseY, keyPressed;
};
enum EventFunctions {
kLeftMouse,
kLeftMouseUp,
kRightMouse,
kRightMouseUp,
kMoveMouse,
kFocus,
kSpace,
EVENT_FUNC_NB
};
struct EventHandlers {
int func[EVENT_FUNC_NB];
};
class SludgeEngine;
class EventManager {
public:
EventManager(SludgeEngine *vm);
virtual ~EventManager();
void init();
void kill();
// Input
void checkInput();
bool handleInput();
int mouseX() const { return _input.mouseX; }
int mouseY() const { return _input.mouseY; }
int &mouseX() { return _input.mouseX; }
int &mouseY() { return _input.mouseY; }
// Events
void setEventFunction(EventFunctions event, int funcNum) { _currentEvents->func[event] = funcNum; };
void loadHandlers(Common::SeekableReadStream *stream);
void saveHandlers(Common::WriteStream *stream);
bool freeze(FrozenStuffStruct *frozenStuff);
void restore(FrozenStuffStruct *frozenStuff);
// Quit
void startGame() { _weAreDoneSoQuit = false; }
void quitGame() { _weAreDoneSoQuit = true; /* _reallyWantToQuit = true; */ }
bool quit() { return _weAreDoneSoQuit; }
private:
SludgeEngine *_vm;
InputType _input;
int _weAreDoneSoQuit;
bool _reallyWantToQuit;
EventHandlers *_currentEvents;
};
} /* namespace Sludge */
#endif /* ENGINES_SLUDGE_EVENT_H_ */

344
engines/sludge/fileset.cpp Normal file
View File

@@ -0,0 +1,344 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/debug.h"
#include "sludge/fileset.h"
#include "sludge/moreio.h"
#include "sludge/newfatal.h"
#include "sludge/sludge.h"
#include "sludge/version.h"
namespace Sludge {
ResourceManager::ResourceManager() {
init();
}
ResourceManager::~ResourceManager() {
kill();
}
void ResourceManager::init() {
_sliceBusy = true;
_bigDataFile = nullptr;
_startOfDataIndex = 0;
_startOfTextIndex = 0;
_startOfSubIndex = 0;
_startOfObjectIndex = 0;
_startIndex = 0;
_allResourceNames.clear();
}
void ResourceManager::kill() {
if (_bigDataFile) {
delete _bigDataFile;
_bigDataFile = nullptr;
}
_allResourceNames.clear();
}
bool ResourceManager::openSubSlice(int num) {
if (_sliceBusy) {
fatal("Can't read from data file", "I'm already reading something");
return false;
}
_bigDataFile->seek(_startOfSubIndex + (num << 2), 0);
_bigDataFile->seek(_bigDataFile->readUint32LE(), 0);
return _sliceBusy = true;
}
bool ResourceManager::openObjectSlice(int num) {
if (_sliceBusy) {
fatal("Can't read from data file", "I'm already reading something");
return false;
}
_bigDataFile->seek(_startOfObjectIndex + (num << 2), 0);
_bigDataFile->seek(_bigDataFile->readUint32LE(), 0);
return _sliceBusy = true;
}
uint ResourceManager::openFileFromNum(int num) {
if (_sliceBusy) {
fatal("Can't read from data file", "I'm already reading something");
return 0;
}
_bigDataFile->seek(_startOfDataIndex + (num << 2), 0);
_bigDataFile->seek(_bigDataFile->readUint32LE(), 1);
_sliceBusy = true;
return _bigDataFile->readUint32LE();
}
uint32 ResourceManager::_cp1250ToUTF32[128] = {
/* 0x80 */
0x20ac, 0xfffd, 0x201a, 0xfffd, 0x201e, 0x2026, 0x2020, 0x2021,
0xfffd, 0x2030, 0x0160, 0x2039, 0x015a, 0x0164, 0x017d, 0x0179,
/* 0x90 */
0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
0xfffd, 0x2122, 0x0161, 0x203a, 0x015b, 0x0165, 0x017e, 0x017a,
/* 0xa0 */
0x00a0, 0x02c7, 0x02d8, 0x0141, 0x00a4, 0x0104, 0x00a6, 0x00a7,
0x00a8, 0x00a9, 0x015e, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x017b,
/* 0xb0 */
0x00b0, 0x00b1, 0x02db, 0x0142, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
0x00b8, 0x0105, 0x015f, 0x00bb, 0x013d, 0x02dd, 0x013e, 0x017c,
/* 0xc0 */
0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7,
0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e,
/* 0xd0 */
0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7,
0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df,
/* 0xe0 */
0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7,
0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f,
/* 0xf0 */
0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7,
0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9,
};
// Converts a string from ISO8859-2 or CP1250 to UTF8.
// This is needed for old games.
Common::String ResourceManager::convertString(const Common::String &s) {
Common::String res;
Common::U32String tmp;
// Convert CP1250 to UTF32
for (uint i = 0; i < s.size(); ++i) {
const byte c = s[i];
if (c < 0x80) {
tmp += c;
} else {
uint32 utf32 = _cp1250ToUTF32[c - 0x80];
if (utf32) {
tmp += utf32;
} else {
// It's an invalid CP1250 character...
return s;
}
}
}
// Convert UTF32 to UTF8
for (uint i = 0; i < tmp.size(); ++i) {
uint32 wc = tmp[i];
int count;
if (wc < 0x80)
count = 1;
else if (wc < 0x800)
count = 2;
else if (wc < 0x10000) {
if (wc < 0xd800 || wc >= 0xe000) {
count = 3;
} else {
// It's an invalid UTF32 character...
return s;
}
} else if (wc < 0x110000) {
count = 4;
} else {
// It's an invalid UTF32 character...
return s;
}
Common::String r = "";
switch (count) {
case 4:
r = (char)(0x80 | (wc & 0x3f)) + r;
wc = wc >> 6;
wc |= 0x10000;
// falls through
case 3:
r = (char)(0x80 | (wc & 0x3f)) + r;
wc = wc >> 6;
wc |= 0x800;
// falls through
case 2:
r = (char)(0x80 | (wc & 0x3f)) + r;
wc = wc >> 6;
wc |= 0xc0;
// falls through
case 1:
r = wc + r;
break;
default:
break;
}
res += r;
}
return res;
}
Common::String ResourceManager::getNumberedString(int value) {
uint32 pos = _bigDataFile->pos();
_bigDataFile->seek((value << 2) + _startOfTextIndex, 0);
value = _bigDataFile->readUint32LE();
_bigDataFile->seek(value, 0);
Common::String s = readString(_bigDataFile);
if (gameVersion < VERSION(2, 2)) {
// This is an older game - We need to convert the string to UTF-8
s = convertString(s);
}
if (_sliceBusy)
_bigDataFile->seek(pos);
return s;
}
bool ResourceManager::startAccess() {
int wasBusy = _sliceBusy;
_sliceBusy = true;
return wasBusy;
}
void ResourceManager::finishAccess() {
_sliceBusy = false;
}
void ResourceManager::dumpFile(int num, const char *pattern) {
if (!g_sludge->_dumpScripts)
return;
Common::DumpFile dumpFile;
dumpFile.open(Common::Path("dumps/").appendComponent(Common::String::format(pattern, num)));
uint32 pos = _bigDataFile->pos();
_bigDataFile->seek(_startOfDataIndex + (num << 2), 0);
_bigDataFile->seek(_bigDataFile->readUint32LE(), 1);
uint fsize = _bigDataFile->readUint32LE();
byte *data = (byte *)malloc(fsize);
_bigDataFile->read(data, fsize);
dumpFile.write(data, fsize);
dumpFile.close();
free(data);
_bigDataFile->seek(pos);
}
bool ResourceManager::dumpFileFromName(const char *name) {
int num = -1;
for (int i = 0; i < getResourceNameCount(); i++) {
if (name != resourceNameFromNum(i))
continue;
num = i;
break;
}
if (num < 0)
return false;
Common::DumpFile dumpFile;
dumpFile.open(Common::Path("dumps/").append(name), true);
uint32 pos = _bigDataFile->pos();
_bigDataFile->seek(_startOfDataIndex + (num << 2), 0);
_bigDataFile->seek(_bigDataFile->readUint32LE(), 1);
uint fsize = _bigDataFile->readUint32LE();
byte *data = (byte *)malloc(fsize);
_bigDataFile->read(data, fsize);
dumpFile.write(data, fsize);
dumpFile.close();
free(data);
_bigDataFile->seek(pos);
return true;
}
void ResourceManager::readResourceNames(Common::SeekableReadStream *readStream) {
int numResourceNames = readStream->readUint16BE();
debugC(2, kSludgeDebugDataLoad, "numResourceNames %i", numResourceNames);
_allResourceNames.reserve(numResourceNames);
for (int fn = 0; fn < numResourceNames; fn++) {
_allResourceNames.push_back(readString(readStream));
debugC(2, kSludgeDebugDataLoad, "Resource %i: %s", fn, _allResourceNames[fn].c_str());
}
}
const Common::String ResourceManager::resourceNameFromNum(int i) {
if (i == -1)
return "";
if (_allResourceNames.empty())
return "RESOURCE";
if (i < (int)_allResourceNames.size())
return _allResourceNames[i];
return "Unknown resource";
}
void ResourceManager::setData(Common::File *fp) {
_bigDataFile = fp;
_startIndex = fp->pos();
}
void ResourceManager::setFileIndices(uint numLanguages, uint skipBefore) {
_bigDataFile->seek(_startIndex, SEEK_SET);
_sliceBusy = false;
if (skipBefore > numLanguages) {
warning("Not a valid language ID! Using default instead.");
skipBefore = 0;
}
// STRINGS
int skipAfter = numLanguages - skipBefore;
while (skipBefore) {
_bigDataFile->seek(_bigDataFile->readUint32LE(), SEEK_SET);
skipBefore--;
}
_startOfTextIndex = _bigDataFile->pos() + 4;
debugC(2, kSludgeDebugDataLoad, "startOfTextIndex: %i", _startOfTextIndex);
_bigDataFile->seek(_bigDataFile->readUint32LE(), SEEK_SET);
while (skipAfter) {
_bigDataFile->seek(_bigDataFile->readUint32LE(), SEEK_SET);
skipAfter--;
}
_startOfSubIndex = _bigDataFile->pos() + 4;
_bigDataFile->seek(_bigDataFile->readUint32LE(), SEEK_CUR);
debugC(2, kSludgeDebugDataLoad, "startOfSubIndex: %i", _startOfSubIndex);
_startOfObjectIndex = _bigDataFile->pos() + 4;
_bigDataFile->seek(_bigDataFile->readUint32LE(), SEEK_CUR);
debugC(2, kSludgeDebugDataLoad, "startOfObjectIndex: %i", _startOfObjectIndex);
// Remember that the data section starts here
_startOfDataIndex = _bigDataFile->pos();
debugC(2, kSludgeDebugDataLoad, "startOfDataIndex: %i", _startOfDataIndex);
}
} // End of namespace Sludge

74
engines/sludge/fileset.h Normal file
View File

@@ -0,0 +1,74 @@
/* 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 SLUDGE_FILESET_H
#define SLUDGE_FILESET_H
#include "common/file.h"
namespace Sludge {
class ResourceManager {
public:
ResourceManager();
~ResourceManager();
void init();
void kill();
void setData(Common::File *readStream);
void setFileIndices(uint, uint);
Common::SeekableReadStream *getData() { return _bigDataFile; }
uint openFileFromNum(int num);
bool openSubSlice(int num);
bool openObjectSlice(int num);
Common::String getNumberedString(int value);
// Access control flag
bool startAccess();
void finishAccess();
// Resource names
void readResourceNames(Common::SeekableReadStream *readStream);
const Common::String resourceNameFromNum(int i);
bool hasResourceNames() const { return !_allResourceNames.empty(); }
int getResourceNameCount() const { return _allResourceNames.size(); }
void dumpFile(int num, const char *pattern);
bool dumpFileFromName(const char *name);
private:
bool _sliceBusy;
Common::File *_bigDataFile;
uint32 _startOfDataIndex, _startOfTextIndex, _startOfSubIndex, _startOfObjectIndex;
int32 _startIndex;
Common::Array<Common::String> _allResourceNames;
private:
static uint32 _cp1250ToUTF32[128];
Common::String convertString(const Common::String &s);
};
} // End of namespace Sludge
#endif

447
engines/sludge/floor.cpp Normal file
View File

@@ -0,0 +1,447 @@
/* 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 "sludge/fileset.h"
#include "sludge/floor.h"
#include "sludge/graphics.h"
#include "sludge/newfatal.h"
#include "sludge/people.h"
#include "sludge/sludge.h"
#define ANGLEFIX (180.0 / 3.14157)
namespace Sludge {
FloorManager::FloorManager(SludgeEngine *vm) {
_vm = vm;
_currentFloor = nullptr;
}
FloorManager::~FloorManager() {
kill();
}
bool FloorManager::pointInFloorPolygon(FloorPolygon &floorPoly, int x, int y) {
int i = 0, j, c = 0;
float xp_i, yp_i;
float xp_j, yp_j;
for (j = floorPoly.numVertices - 1; i < floorPoly.numVertices; j = i++) {
xp_i = _currentFloor->vertex[floorPoly.vertexID[i]].x;
yp_i = _currentFloor->vertex[floorPoly.vertexID[i]].y;
xp_j = _currentFloor->vertex[floorPoly.vertexID[j]].x;
yp_j = _currentFloor->vertex[floorPoly.vertexID[j]].y;
if ((((yp_i <= y) && (y < yp_j)) || ((yp_j <= y) && (y < yp_i))) && (x < (xp_j - xp_i) * (y - yp_i) / (yp_j - yp_i) + xp_i)) {
c = !c;
}
}
return c;
}
bool FloorManager::getMatchingCorners(FloorPolygon &a, FloorPolygon &b, int &cornerA, int &cornerB) {
int sharedVertices = 0;
int i, j;
for (i = 0; i < a.numVertices; i++) {
for (j = 0; j < b.numVertices; j++) {
if (a.vertexID[i] == b.vertexID[j]) {
if (sharedVertices++) {
cornerB = a.vertexID[i];
return true;
} else {
cornerA = a.vertexID[i];
}
}
}
}
return false;
}
bool FloorManager::polysShareSide(FloorPolygon &a, FloorPolygon &b) {
int sharedVertices = 0;
int i, j;
for (i = 0; i < a.numVertices; i++) {
for (j = 0; j < b.numVertices; j++) {
if (a.vertexID[i] == b.vertexID[j]) {
if (sharedVertices++)
return true;
}
}
}
return false;
}
bool FloorManager::init() {
_currentFloor = new Floor;
if (!checkNew(_currentFloor))
return false;
_currentFloor->numPolygons = 0;
_currentFloor->polygon = nullptr;
_currentFloor->vertex = nullptr;
_currentFloor->matrix = nullptr;
return true;
}
void FloorManager::setFloorNull() {
if (_currentFloor) {
for (int i = 0; i < _currentFloor->numPolygons; i++) {
delete[] _currentFloor->polygon[i].vertexID;
delete[] _currentFloor->matrix[i];
}
_currentFloor->numPolygons = 0;
delete[] _currentFloor->polygon;
_currentFloor->polygon = nullptr;
delete[] _currentFloor->vertex;
_currentFloor->vertex = nullptr;
delete[] _currentFloor->matrix;
_currentFloor->matrix = nullptr;
}
}
void FloorManager::kill() {
setFloorNull();
if (_currentFloor) {
delete _currentFloor;
_currentFloor = nullptr;
}
}
bool FloorManager::setFloor(int fileNum) {
int i, j;
setFloorNull();
setResourceForFatal(fileNum);
if (!g_sludge->_resMan->openFileFromNum(fileNum))
return false;
g_sludge->_resMan->dumpFile(fileNum, "floor%04d.flo.comp");
// Find out how many polygons there are and reserve memory
_currentFloor->originalNum = fileNum;
_currentFloor->numPolygons = g_sludge->_resMan->getData()->readByte();
_currentFloor->polygon = new FloorPolygon[_currentFloor->numPolygons];
if (!checkNew(_currentFloor->polygon))
return false;
// Read in each polygon
for (i = 0; i < _currentFloor->numPolygons; i++) {
// Find out how many vertex IDs there are and reserve memory
_currentFloor->polygon[i].numVertices = g_sludge->_resMan->getData()->readByte();
_currentFloor->polygon[i].vertexID = new int[_currentFloor->polygon[i].numVertices];
if (!checkNew(_currentFloor->polygon[i].vertexID))
return false;
// Read in each vertex ID
for (j = 0; j < _currentFloor->polygon[i].numVertices; j++) {
_currentFloor->polygon[i].vertexID[j] = g_sludge->_resMan->getData()->readUint16BE();
}
}
// Find out how many vertices there are and reserve memory
i = g_sludge->_resMan->getData()->readUint16BE();
_currentFloor->vertex = new Common::Point[i];
if (!checkNew(_currentFloor->vertex))
return false;
for (j = 0; j < i; j++) {
_currentFloor->vertex[j].x = g_sludge->_resMan->getData()->readUint16BE();
_currentFloor->vertex[j].y = g_sludge->_resMan->getData()->readUint16BE();
}
g_sludge->_resMan->finishAccess();
dumpFloor(fileNum);
// Now build the movement martix
_currentFloor->matrix = new int *[_currentFloor->numPolygons];
if (!checkNew(_currentFloor->matrix))
return false;
int **distanceMatrix = new int *[_currentFloor->numPolygons];
if (!checkNew(distanceMatrix))
return false;
for (i = 0; i < _currentFloor->numPolygons; i++) {
_currentFloor->matrix[i] = new int[_currentFloor->numPolygons];
distanceMatrix[i] = new int[_currentFloor->numPolygons];
if (!checkNew(_currentFloor->matrix[i]))
return false;
for (j = 0; j < _currentFloor->numPolygons; j++) {
_currentFloor->matrix[i][j] = -1;
distanceMatrix[i][j] = 10000;
}
}
for (i = 0; i < _currentFloor->numPolygons; i++) {
for (j = 0; j < _currentFloor->numPolygons; j++) {
if (i != j) {
if (polysShareSide(_currentFloor->polygon[i], _currentFloor->polygon[j])) {
_currentFloor->matrix[i][j] = j;
distanceMatrix[i][j] = 1;
}
} else {
_currentFloor->matrix[i][j] = -2;
distanceMatrix[i][j] = 0;
}
}
}
bool madeChange;
int lookForDistance = 0;
do {
lookForDistance++;
madeChange = false;
for (i = 0; i < _currentFloor->numPolygons; i++) {
for (j = 0; j < _currentFloor->numPolygons; j++) {
if (_currentFloor->matrix[i][j] == -1) {
// OK, so we don't know how to get from i to j...
for (int d = 0; d < _currentFloor->numPolygons; d++) {
if (d != i && d != j) {
if (_currentFloor->matrix[i][d] == d && _currentFloor->matrix[d][j] >= 0 && distanceMatrix[d][j] <= lookForDistance) {
_currentFloor->matrix[i][j] = d;
distanceMatrix[i][j] = lookForDistance + 1;
madeChange = true;
}
}
}
}
}
}
} while (madeChange);
for (i = 0; i < _currentFloor->numPolygons; i++) {
delete[] distanceMatrix[i];
}
delete []distanceMatrix;
distanceMatrix = nullptr;
setResourceForFatal(-1);
return true;
}
void FloorManager::dumpFloor(int fileNum) {
if (!g_sludge->_dumpScripts)
return;
Common::DumpFile dumpFile;
dumpFile.open(Common::Path(Common::String::format("dumps/floor%04d.flo", fileNum)));
for (int i = 0; i < _currentFloor->numPolygons; i++) {
int nV = _currentFloor->polygon[i].numVertices;
if (nV > 1) {
int vert = _currentFloor->polygon[i].vertexID[0];
dumpFile.writeString(Common::String::format("* %d, %d", _currentFloor->vertex[vert].x, _currentFloor->vertex[vert].y));
for (int j = 1; j < nV; j++) {
vert = _currentFloor->polygon[i].vertexID[j];
dumpFile.writeString(Common::String::format("; %d, %d", _currentFloor->vertex[vert].x, _currentFloor->vertex[vert].y));
}
dumpFile.writeString("\n");
}
}
dumpFile.close();
}
void FloorManager::drawFloor() {
int i, j, nV;
for (i = 0; i < _currentFloor->numPolygons; i++) {
nV = _currentFloor->polygon[i].numVertices;
if (nV > 1) {
for (j = 1; j < nV; j++) {
g_sludge->_gfxMan->drawLine(_currentFloor->vertex[_currentFloor->polygon[i].vertexID[j - 1]].x, _currentFloor->vertex[_currentFloor->polygon[i].vertexID[j - 1]].y,
_currentFloor->vertex[_currentFloor->polygon[i].vertexID[j]].x, _currentFloor->vertex[_currentFloor->polygon[i].vertexID[j]].y);
}
g_sludge->_gfxMan->drawLine(_currentFloor->vertex[_currentFloor->polygon[i].vertexID[0]].x, _currentFloor->vertex[_currentFloor->polygon[i].vertexID[0]].y,
_currentFloor->vertex[_currentFloor->polygon[i].vertexID[nV - 1]].x, _currentFloor->vertex[_currentFloor->polygon[i].vertexID[nV - 1]].y);
}
}
}
int FloorManager::inFloor(int x, int y) {
int i, r = -1;
for (i = 0; i < _currentFloor->numPolygons; i++)
if (pointInFloorPolygon(_currentFloor->polygon[i], x, y))
r = i;
return r;
}
bool FloorManager::closestPointOnLine(int &closestX, int &closestY, int x1, int y1, int x2, int y2, int xP, int yP) {
int xDiff = x2 - x1;
int yDiff = y2 - y1;
double m = xDiff * (xP - x1) + yDiff * (yP - y1);
m /= (xDiff * xDiff) + (yDiff * yDiff);
if (m < 0) {
closestX = x1;
closestY = y1;
} else if (m > 1) {
closestX = x2;
closestY = y2;
} else {
closestX = x1 + m * xDiff;
closestY = y1 + m * yDiff;
return true;
}
return false;
}
bool FloorManager::handleClosestPoint(int &setX, int &setY, int &setPoly) {
int gotX = 320, gotY = 200, gotPoly = -1, i, j, xTest1, yTest1, xTest2, yTest2, closestX, closestY, oldJ, currentDistance = 0xFFFFF, thisDistance;
for (i = 0; i < _currentFloor->numPolygons; i++) {
oldJ = _currentFloor->polygon[i].numVertices - 1;
for (j = 0; j < _currentFloor->polygon[i].numVertices; j++) {
xTest1 = _currentFloor->vertex[_currentFloor->polygon[i].vertexID[j]].x;
yTest1 = _currentFloor->vertex[_currentFloor->polygon[i].vertexID[j]].y;
xTest2 = _currentFloor->vertex[_currentFloor->polygon[i].vertexID[oldJ]].x;
yTest2 = _currentFloor->vertex[_currentFloor->polygon[i].vertexID[oldJ]].y;
closestPointOnLine(closestX, closestY, xTest1, yTest1, xTest2, yTest2, setX, setY);
xTest1 = setX - closestX;
yTest1 = setY - closestY;
thisDistance = xTest1 * xTest1 + yTest1 * yTest1;
if (thisDistance < currentDistance) {
currentDistance = thisDistance;
gotX = closestX;
gotY = closestY;
gotPoly = i;
}
oldJ = j;
}
}
if (gotPoly == -1)
return false;
setX = gotX;
setY = gotY;
setPoly = gotPoly;
return true;
}
bool FloorManager::doBorderStuff(OnScreenPerson *moveMe) {
if (moveMe->inPoly == moveMe->walkToPoly) {
moveMe->inPoly = -1;
moveMe->thisStepX = moveMe->walkToX;
moveMe->thisStepY = moveMe->walkToY;
} else {
// The section in which we need to be next...
int newPoly = _currentFloor->matrix[moveMe->inPoly][moveMe->walkToPoly];
if (newPoly == -1)
return false;
// Grab the index of the second matching corner...
int ID, ID2;
if (!getMatchingCorners(_currentFloor->polygon[moveMe->inPoly], _currentFloor->polygon[newPoly], ID, ID2))
return fatal("Not a valid floor plan!");
// Remember that we're walking to the new polygon...
moveMe->inPoly = newPoly;
// Calculate the destination position on the coincidantal line...
int x1 = moveMe->x, y1 = moveMe->y;
int x2 = moveMe->walkToX, y2 = moveMe->walkToY;
int x3 = _currentFloor->vertex[ID].x, y3 = _currentFloor->vertex[ID].y;
int x4 = _currentFloor->vertex[ID2].x, y4 = _currentFloor->vertex[ID2].y;
int xAB = x1 - x2;
int yAB = y1 - y2;
int xCD = x4 - x3;
int yCD = y4 - y3;
double m = (yAB * (x3 - x1) - xAB * (y3 - y1));
m /= ((xAB * yCD) - (yAB * xCD));
if (m > 0 && m < 1) {
moveMe->thisStepX = x3 + m * xCD;
moveMe->thisStepY = y3 + m * yCD;
} else {
int dx13 = x1 - x3, dx14 = x1 - x4, dx23 = x2 - x3, dx24 = x2 - x4;
int dy13 = y1 - y3, dy14 = y1 - y4, dy23 = y2 - y3, dy24 = y2 - y4;
dx13 *= dx13;
dx14 *= dx14;
dx23 *= dx23;
dx24 *= dx24;
dy13 *= dy13;
dy14 *= dy14;
dy23 *= dy23;
dy24 *= dy24;
if (sqrt((double)dx13 + dy13) + sqrt((double)dx23 + dy23) < sqrt((double)dx14 + dy14) + sqrt((double)dx24 + dy24)) {
moveMe->thisStepX = x3;
moveMe->thisStepY = y3;
} else {
moveMe->thisStepX = x4;
moveMe->thisStepY = y4;
}
}
}
float yDiff = moveMe->thisStepY - moveMe->y;
float xDiff = moveMe->x - moveMe->thisStepX;
if (xDiff || yDiff) {
moveMe->wantAngle = 180 + ANGLEFIX * atan2(xDiff, yDiff * 2);
moveMe->spinning = true;
}
moveMe->makeTalker();
return true;
}
void FloorManager::save(Common::WriteStream *stream) {
if (_currentFloor->numPolygons) {
stream->writeByte(1);
stream->writeUint16BE(_currentFloor->originalNum);
} else {
stream->writeByte(0);
}
}
bool FloorManager::load(Common::SeekableReadStream *stream) {
if (stream->readByte()) {
if (!setFloor(stream->readUint16BE()))
return false;
} else {
setFloorNull();
}
return true;
}
} // End of namespace Sludge

83
engines/sludge/floor.h Normal file
View File

@@ -0,0 +1,83 @@
/* 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 SLUDGE_FLOOR_H
#define SLUDGE_FLOOR_H
namespace Common {
struct Point;
class SeekableReadStream;
class WriteStream;
}
namespace Sludge {
class SludgeEngine;
struct OnScreenPerson;
struct FloorPolygon {
int numVertices;
int *vertexID;
};
struct Floor {
int originalNum;
Common::Point *vertex;
int numPolygons;
FloorPolygon *polygon;
int **matrix;
};
class FloorManager {
public:
FloorManager(SludgeEngine *vm);
~FloorManager();
bool init();
void kill();
void setFloorNull();
bool setFloor(int fileNum);
void drawFloor();
int inFloor(int x, int y);
bool isFloorNoPolygon() { return !_currentFloor || _currentFloor->numPolygons == 0; }
// For Person collision detection
bool handleClosestPoint(int &setX, int &setY, int &setPoly);
bool doBorderStuff(OnScreenPerson *moveMe);
// Save & load
void save(Common::WriteStream *stream);
bool load(Common::SeekableReadStream *stream);
private:
Floor *_currentFloor;
SludgeEngine *_vm;
bool getMatchingCorners(FloorPolygon &, FloorPolygon &, int &, int &);
bool closestPointOnLine(int &closestX, int &closestY, int x1, int y1, int x2, int y2, int xP, int yP);
bool pointInFloorPolygon(FloorPolygon &floorPoly, int x, int y);
bool polysShareSide(FloorPolygon &a, FloorPolygon &b);
void dumpFloor(int fileNum);
};
} // End of namespace Sludge
#endif

211
engines/sludge/fonttext.cpp Normal file
View File

@@ -0,0 +1,211 @@
/* 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/file.h"
#include "sludge/fonttext.h"
#include "sludge/graphics.h"
#include "sludge/moreio.h"
#include "sludge/newfatal.h"
#include "sludge/sludge.h"
#include "sludge/version.h"
namespace Sludge {
TextManager::TextManager() {
init();
}
TextManager::~TextManager() {
kill();
}
void TextManager::init() {
_theFont.total = 0;
_theFont.sprites = nullptr;
_fontHeight = 0;
_numFontColours = 0;
_loadedFontNum = 0;
_fontSpace = -1;
_pastePalette.init();
_fontTable.clear();
}
void TextManager::kill() {
GraphicsManager::forgetSpriteBank(_theFont);
_pastePalette.kill();
}
bool TextManager::isInFont(const Common::String &theText) {
if (_fontTable.empty())
return 0;
if (theText.empty())
return 0;
Common::U32String str32 = theText.decode(Common::kUtf8);
// We don't want to compare strings. Only single characters allowed!
if (str32.size() > 1)
return false;
uint32 c = str32[0];
// check if font order contains the utf8 char
return _fontOrder.contains(c);
}
int TextManager::stringLength(const Common::String &theText) {
Common::U32String str32 = theText.decode(Common::kUtf8);
return str32.size();
}
int TextManager::stringWidth(const Common::String &theText) {
int xOff = 0;
if (_fontTable.empty())
return 0;
Common::U32String str32 = theText.decode(Common::kUtf8);
for (uint i = 0; i < str32.size(); ++i) {
uint32 c = str32[i];
xOff += _theFont.sprites[fontInTable(c)].surface.w + _fontSpace;
}
return xOff;
}
void TextManager::pasteString(const Common::String &theText, int xOff, int y, SpritePalette &thePal) {
if (_fontTable.empty())
return;
xOff += (int)((float)(_fontSpace >> 1) / g_sludge->_gfxMan->getCamZoom());
Common::U32String str32 = theText.decode(Common::kUtf8);
for (uint32 i = 0; i < str32.size(); ++i) {
uint32 c = str32[i];
Sprite *mySprite = &_theFont.sprites[fontInTable(c)];
g_sludge->_gfxMan->fontSprite(xOff, y, *mySprite, thePal);
xOff += (int)((double)(mySprite->surface.w + _fontSpace) / g_sludge->_gfxMan->getCamZoom());
}
}
void TextManager::pasteStringToBackdrop(const Common::String &theText, int xOff, int y) {
if (_fontTable.empty())
return;
Common::U32String str32 = theText.decode(Common::kUtf8);
xOff += _fontSpace >> 1;
for (uint32 i = 0; i < str32.size(); ++i) {
uint32 c = str32[i];
Sprite *mySprite = &_theFont.sprites[fontInTable(c)];
g_sludge->_gfxMan->pasteSpriteToBackDrop(xOff, y, *mySprite, _pastePalette);
xOff += mySprite->surface.w + _fontSpace;
}
}
void TextManager::burnStringToBackdrop(const Common::String &theText, int xOff, int y) {
if (_fontTable.empty())
return;
Common::U32String str32 = theText.decode(Common::kUtf8);
xOff += _fontSpace >> 1;
for (uint i = 0; i < str32.size(); ++i) {
uint32 c = str32[i];
Sprite *mySprite = &_theFont.sprites[fontInTable(c)];
g_sludge->_gfxMan->burnSpriteToBackDrop(xOff, y, *mySprite, _pastePalette);
xOff += mySprite->surface.w + _fontSpace;
}
}
bool TextManager::loadFont(int filenum, const Common::String &charOrder, int h) {
_fontOrder = charOrder.decode(Common::kUtf8);
g_sludge->_gfxMan->forgetSpriteBank(_theFont);
_loadedFontNum = filenum;
// get max value among all utf8 chars
Common::U32String fontOrderString = _fontOrder;
// create an index table from utf8 char to the index
if (!_fontTable.empty()) {
_fontTable.clear();
}
for (uint i = 0; i < fontOrderString.size(); ++i) {
uint32 c = fontOrderString[i];
_fontTable[c] = i;
}
if (!g_sludge->_gfxMan->loadSpriteBank(filenum, _theFont, true)) {
fatal("Can't load font");
return false;
}
_numFontColours = _theFont.myPalette.total;
_fontHeight = h;
return true;
}
// load & save
void TextManager::saveFont(Common::WriteStream *stream) {
stream->writeByte(!_fontTable.empty());
if (!_fontTable.empty()) {
stream->writeUint16BE(_loadedFontNum);
stream->writeUint16BE(_fontHeight);
writeString(_fontOrder.encode(Common::kUtf8), stream);
}
stream->writeSint16LE(_fontSpace);
}
void TextManager::loadFont(int ssgVersion, Common::SeekableReadStream *stream) {
bool fontLoaded = stream->readByte();
int fontNum = 0;
Common::String charOrder = "";
if (fontLoaded) {
fontNum = stream->readUint16BE();
_fontHeight = stream->readUint16BE();
if (ssgVersion < VERSION(2, 2)) {
char *tmp = new char[257];
for (int a = 0; a < 256; a++) {
int x = stream->readByte();
tmp[x] = a;
}
tmp[256] = 0;
charOrder = tmp;
delete []tmp;
} else {
charOrder = readString(stream);
}
}
loadFont(fontNum, charOrder, _fontHeight);
_fontSpace = stream->readSint16LE();
}
} // End of namespace Sludge

80
engines/sludge/fonttext.h Normal file
View File

@@ -0,0 +1,80 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef SLUDGE_FONTTEXT_H
#define SLUDGE_FONTTEXT_H
#include "common/hashmap.h"
#include "common/ustr.h"
#include "sludge/sprites.h"
namespace Common {
class SeekableReadStream;
class WriteStream;
}
namespace Sludge {
struct SpriteBank;
class SpritePalette;
class TextManager {
public:
TextManager();
virtual ~TextManager();
void init();
void kill();
int stringWidth(const Common::String &theText);
int stringLength(const Common::String &theText);
bool loadFont(int filenum, const Common::String &charOrder, int);
void pasteString(const Common::String &theText, int, int, SpritePalette &);
void pasteStringToBackdrop(const Common::String &theText, int xOff, int y);
void burnStringToBackdrop(const Common::String &theText, int xOff, int y);
bool isInFont(const Common::String &theText);
// setter & getter
void setFontSpace(int fontSpace) { _fontSpace = fontSpace; }
int getFontHeight() const { return _fontHeight; }
void setPasterColor(byte r, byte g, byte b) { _pastePalette.setColor(r, g, b); }
// load & save
void saveFont(Common::WriteStream *stream);
void loadFont(int ssgVersion, Common::SeekableReadStream *stream);
private:
SpriteBank _theFont;
int _fontHeight, _numFontColours, _loadedFontNum;
Common::U32String _fontOrder;
int16 _fontSpace;
SpritePalette _pastePalette;
Common::HashMap<uint32, uint32> _fontTable;
inline uint32 fontInTable(uint32 x) { return _fontTable[x]; }
};
} // End of namespace Sludge
#endif

169
engines/sludge/freeze.cpp Normal file
View File

@@ -0,0 +1,169 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "sludge/cursors.h"
#include "sludge/event.h"
#include "sludge/graphics.h"
#include "sludge/freeze.h"
#include "sludge/newfatal.h"
#include "sludge/people.h"
#include "sludge/region.h"
#include "sludge/sludge.h"
#include "sludge/sludger.h"
#include "sludge/speech.h"
#include "sludge/statusba.h"
#include "sludge/zbuffer.h"
namespace Sludge {
void GraphicsManager::freezeGraphics() {
int w = _winWidth;
int h = _winHeight;
_freezeSurface.create(w, h, *g_sludge->getScreenPixelFormat());
displayBase();
_freezeSurface.copyFrom(_renderSurface);
}
bool GraphicsManager::freeze() {
FrozenStuffStruct *newFreezer = new FrozenStuffStruct;
if (!checkNew(newFreezer))
return false;
// Grab a copy of the current scene
freezeGraphics();
newFreezer->backdropSurface.copyFrom(_backdropSurface);
newFreezer->sceneWidth = _sceneWidth;
newFreezer->sceneHeight = _sceneHeight;
newFreezer->cameraX = _cameraX;
newFreezer->cameraY = _cameraY;
newFreezer->cameraZoom = _cameraZoom;
newFreezer->lightMapSurface.copyFrom(_lightMap);
newFreezer->lightMapNumber = _lightMapNumber;
newFreezer->parallaxLayers = _parallaxLayers;
_parallaxLayers = NULL;
newFreezer->zBufferTex = _zBuffer->tex;
newFreezer->zBufferNumber = _zBuffer->originalNum;
newFreezer->zPanels = _zBuffer->numPanels;
_zBuffer->tex = NULL;
// resizeBackdrop kills parallax stuff, light map, z-buffer...
if (!killResizeBackdrop(_winWidth, _winHeight))
return fatal("Can't create new temporary backdrop buffer");
// Copy the old scene to the new backdrop
_backdropSurface.copyFrom(_freezeSurface);
_backdropExists = true;
_vm->_peopleMan->freeze(newFreezer);
StatusStuff *newStatusStuff = new StatusStuff;
if (!checkNew(newStatusStuff))
return false;
newFreezer->frozenStatus = _vm->_statusBar->copyStatusBarStuff(newStatusStuff);
_vm->_regionMan->freeze(newFreezer);
_vm->_cursorMan->freeze(newFreezer);
_vm->_speechMan->freeze(newFreezer);
_vm->_evtMan->freeze(newFreezer);
newFreezer->next = _frozenStuff;
_frozenStuff = newFreezer;
return true;
}
int GraphicsManager::howFrozen() {
int a = 0;
FrozenStuffStruct *f = _frozenStuff;
while (f) {
a++;
f = f->next;
}
return a;
}
void GraphicsManager::unfreeze(bool killImage) {
FrozenStuffStruct *killMe = _frozenStuff;
if (!_frozenStuff)
return;
_sceneWidth = _frozenStuff->sceneWidth;
_sceneHeight = _frozenStuff->sceneHeight;
_cameraX = _frozenStuff->cameraX;
_cameraY = _frozenStuff->cameraY;
_vm->_evtMan->mouseX() = (int)(_vm->_evtMan->mouseX() * _cameraZoom);
_vm->_evtMan->mouseY() = (int)(_vm->_evtMan->mouseY() * _cameraZoom);
_cameraZoom = _frozenStuff->cameraZoom;
_vm->_evtMan->mouseX() = (int)(_vm->_evtMan->mouseX() / _cameraZoom);
_vm->_evtMan->mouseY() = (int)(_vm->_evtMan->mouseY() / _cameraZoom);
g_sludge->_peopleMan->resotre(_frozenStuff);
g_sludge->_regionMan->resotre(_frozenStuff);
killLightMap();
_lightMap.copyFrom(_frozenStuff->lightMapSurface);
_lightMapNumber = _frozenStuff->lightMapNumber;
if (_lightMapNumber) {
loadLightMap(_lightMapNumber);
}
if (killImage)
killBackDrop();
_backdropSurface.copyFrom(_frozenStuff->backdropSurface);
_backdropExists = true;
_zBuffer->tex = _frozenStuff->zBufferTex;
killZBuffer();
_zBuffer->originalNum = _frozenStuff->zBufferNumber;
_zBuffer->numPanels = _frozenStuff->zPanels;
if (_zBuffer->numPanels) {
setZBuffer(_zBuffer->originalNum);
}
killParallax();
_parallaxLayers = _frozenStuff->parallaxLayers;
_vm->_cursorMan->resotre(_frozenStuff);
_vm->_statusBar->restoreBarStuff(_frozenStuff->frozenStatus);
_vm->_evtMan->restore(_frozenStuff);
_vm->_speechMan->restore(_frozenStuff);
_frozenStuff = _frozenStuff->next;
// free current frozen screen struct
if (killMe->backdropSurface.getPixels())
killMe->backdropSurface.free();
if (killMe->lightMapSurface.getPixels())
killMe->lightMapSurface.free();
delete killMe;
killMe = NULL;
}
} // End of namespace Sludge

63
engines/sludge/freeze.h Normal file
View File

@@ -0,0 +1,63 @@
/* 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 SLUDGE_FREEZE_H
#define SLUDGE_FREEZE_H
#include "graphics/surface.h"
namespace Sludge {
struct OnScreenPerson;
struct PersonaAnimation;
struct ScreenRegion;
struct SpeechStruct;
struct StatusStuff;
struct EventHandlers;
struct ScreenRegion;
typedef Common::List<ScreenRegion *> ScreenRegionList;
typedef Common::List<OnScreenPerson *> OnScreenPersonList;
class Parallax;
struct FrozenStuffStruct {
OnScreenPersonList *allPeople;
ScreenRegionList *allScreenRegions;
Graphics::Surface backdropSurface;
Graphics::Surface lightMapSurface;
uint8 *zBufferTex;
int zPanels;
ParallaxLayers *parallaxLayers;
int lightMapNumber, zBufferNumber;
SpeechStruct *speech;
StatusStuff *frozenStatus;
EventHandlers *currentEvents;
PersonaAnimation *mouseCursorAnim;
int mouseCursorFrameNum;
int cameraX, cameraY, sceneWidth, sceneHeight;
float cameraZoom;
FrozenStuffStruct *next;
};
} // End of namespace Sludge
#endif

858
engines/sludge/function.cpp Normal file
View File

@@ -0,0 +1,858 @@
/* 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 "sludge/builtin.h"
#include "sludge/errors.h"
#include "sludge/fileset.h"
#include "sludge/function.h"
#include "sludge/newfatal.h"
#include "sludge/people.h"
#include "sludge/sludge.h"
#include "sludge/sound.h"
#include "sludge/speech.h"
namespace Sludge {
int numBIFNames = 0;
Common::String *allBIFNames = NULL;
int numUserFunc = 0;
Common::String *allUserFunc = NULL;
LoadedFunction *saverFunc;
LoadedFunction *allRunningFunctions = NULL;
VariableStack *noStack = NULL;
Variable *globalVars = NULL;
const char *sludgeText[] = { "?????", "RETURN", "BRANCH", "BR_ZERO",
"SET_GLOBAL", "SET_LOCAL", "LOAD_GLOBAL", "LOAD_LOCAL", "PLUS", "MINUS",
"MULT", "DIVIDE", "AND", "OR", "EQUALS", "NOT_EQ", "MODULUS",
"LOAD_VALUE", "LOAD_BUILT", "LOAD_FUNC", "CALLIT", "LOAD_STRING",
"LOAD_FILE", "LOAD_OBJTYPE", "NOT", "LOAD_NULL", "STACK_PUSH",
"LESSTHAN", "MORETHAN", "NEGATIVE", "U", "LESS_EQUAL", "MORE_EQUAL",
"INC_LOCAL", "DEC_LOCAL", "INC_GLOBAL", "DEC_GLOBAL", "INDEXSET",
"INDEXGET", "INC_INDEX", "DEC_INDEX", "QUICK_PUSH" };
void pauseFunction(LoadedFunction *fun) {
LoadedFunction **huntAndDestroy = &allRunningFunctions;
while (*huntAndDestroy) {
if (fun == *huntAndDestroy) {
(*huntAndDestroy) = (*huntAndDestroy)->next;
fun->next = NULL;
} else {
huntAndDestroy = &(*huntAndDestroy)->next;
}
}
}
void printStack(VariableStack *ptr) {
if (ptr == NULL)
debugN("<empty stack>");
while (ptr != NULL) {
ptr->thisVar.debugPrint();
ptr = ptr->next;
}
debug("%s", "");
}
void printLocals(Variable *localVars, int count) {
if (count == 0)
debugN("<none>");
for (int i = 0; i < count; i++)
localVars[i].debugPrint();
debug("%s", "");
}
void restartFunction(LoadedFunction *fun) {
fun->next = allRunningFunctions;
allRunningFunctions = fun;
}
void killSpeechTimers() {
LoadedFunction *thisFunction = allRunningFunctions;
while (thisFunction) {
if (thisFunction->freezerLevel == 0 && thisFunction->isSpeech
&& thisFunction->timeLeft) {
thisFunction->timeLeft = 0;
thisFunction->isSpeech = false;
}
thisFunction = thisFunction->next;
}
g_sludge->_speechMan->kill();
}
void completeTimers() {
LoadedFunction *thisFunction = allRunningFunctions;
while (thisFunction) {
if (thisFunction->freezerLevel == 0)
thisFunction->timeLeft = 0;
thisFunction = thisFunction->next;
}
}
void finishFunction(LoadedFunction *fun) {
int a;
pauseFunction(fun);
if (fun->stack)
fatal(ERROR_NON_EMPTY_STACK);
delete[] fun->compiledLines;
for (a = 0; a < fun->numLocals; a++)
fun->localVars[a].unlinkVar();
delete[] fun->localVars;
fun->reg.unlinkVar();
delete fun;
fun = NULL;
}
void abortFunction(LoadedFunction *fun) {
int a;
pauseFunction(fun);
while (fun->stack)
trimStack(fun->stack);
delete []fun->compiledLines;
for (a = 0; a < fun->numLocals; a++)
fun->localVars[a].unlinkVar();
delete []fun->localVars;
fun->reg.unlinkVar();
if (fun->calledBy)
abortFunction(fun->calledBy);
delete fun;
fun = NULL;
}
int cancelAFunction(int funcNum, LoadedFunction *myself, bool &killedMyself) {
int n = 0;
killedMyself = false;
LoadedFunction *fun = allRunningFunctions;
while (fun) {
if (fun->originalNumber == funcNum) {
fun->cancelMe = true;
n++;
if (fun == myself)
killedMyself = true;
}
fun = fun->next;
}
return n;
}
void freezeSubs() {
LoadedFunction *thisFunction = allRunningFunctions;
while (thisFunction) {
if (thisFunction->unfreezable) {
//msgBox ("SLUDGE debugging bollocks!", "Trying to freeze an unfreezable function!");
} else {
thisFunction->freezerLevel++;
}
thisFunction = thisFunction->next;
}
}
void unfreezeSubs() {
LoadedFunction *thisFunction = allRunningFunctions;
while (thisFunction) {
if (thisFunction->freezerLevel)
thisFunction->freezerLevel--;
thisFunction = thisFunction->next;
}
}
Common::String getCommandParameter(int com, int param) {
switch(com) {
case SLU_LOAD_BUILT:
return getBuiltInName(param);
case SLU_SET_GLOBAL:
return Common::String::format("global%d", param);
case SLU_LOAD_STRING:
return Common::String::format("\"%s\"", g_sludge->_resMan->getNumberedString(param).c_str());
default:
return Common::String::format("%d", param);
}
}
bool continueFunction(LoadedFunction *fun) {
bool keepLooping = true;
bool advanceNow;
uint param;
SludgeCommand com;
if (fun->cancelMe) {
abortFunction(fun);
return true;
}
while (keepLooping) {
advanceNow = true;
param = fun->compiledLines[fun->runThisLine].param;
com = fun->compiledLines[fun->runThisLine].theCommand;
if (debugChannelSet(-1, kSludgeDebugStackMachine)) {
debugN(" Stack before: ");
printStack(fun->stack);
debugN(" Reg before: ");
fun->reg.debugPrint();
debug("%s", "");
debugN(" Locals before: ");
printLocals(fun->localVars, fun->numLocals);
}
debugC(1, kSludgeDebugStackMachine, "Executing command function %d line %i: %s(%s)", fun->originalNumber, fun->runThisLine, sludgeText[com], getCommandParameter(com, param).c_str());
if (numBIFNames) {
setFatalInfo((fun->originalNumber < numUserFunc) ? allUserFunc[fun->originalNumber] : "Unknown user function", (com < numSludgeCommands) ? sludgeText[com] : ERROR_UNKNOWN_MCODE);
}
switch (com) {
case SLU_RETURN:
if (fun->calledBy) {
LoadedFunction *returnTo = fun->calledBy;
if (fun->returnSomething)
returnTo->reg.copyFrom(fun->reg);
finishFunction(fun);
fun = returnTo;
restartFunction(fun);
} else {
finishFunction(fun);
advanceNow = false; // So we don't do anything else with "fun"
keepLooping = false; // So we drop out of the loop
}
break;
case SLU_CALLIT:
switch (fun->reg.varType) {
case SVT_FUNC:
pauseFunction(fun);
if (numBIFNames)
setFatalInfo(
(fun->originalNumber < numUserFunc) ?
allUserFunc[fun->originalNumber] :
"Unknown user function",
(fun->reg.varData.intValue < numUserFunc) ?
allUserFunc[fun->reg.varData.intValue] :
"Unknown user function");
if (!startNewFunctionNum(fun->reg.varData.intValue, param, fun,
fun->stack))
return false;
fun = allRunningFunctions;
advanceNow = false; // So we don't do anything else with "fun"
break;
case SVT_BUILT: {
debugC(1, kSludgeDebugStackMachine, "Built-in init value: %i",
fun->reg.varData.intValue);
BuiltReturn br = callBuiltIn(fun->reg.varData.intValue, param,
fun);
switch (br) {
case BR_ERROR:
return fatal(
"Unknown error. This shouldn't happen. Please notify the SLUDGE developers.");
case BR_PAUSE:
pauseFunction(fun);
// fall through
case BR_KEEP_AND_PAUSE:
keepLooping = false;
break;
case BR_ALREADY_GONE:
keepLooping = false;
advanceNow = false;
break;
case BR_CALLAFUNC: {
int i = fun->reg.varData.intValue;
fun->reg.setVariable(SVT_INT, 1);
pauseFunction(fun);
if (numBIFNames)
setFatalInfo(
(fun->originalNumber < numUserFunc) ?
allUserFunc[fun->originalNumber] :
"Unknown user function",
(i < numUserFunc) ?
allUserFunc[i] :
"Unknown user function");
if (!startNewFunctionNum(i, 0, fun, noStack, false))
return false;
fun = allRunningFunctions;
advanceNow = false; // So we don't do anything else with "fun"
}
break;
default:
break;
}
}
break;
default:
return fatal(ERROR_CALL_NONFUNCTION);
}
break;
// These all grab things and shove 'em into the register
case SLU_LOAD_NULL:
fun->reg.setVariable(SVT_NULL, 0);
break;
case SLU_LOAD_FILE:
fun->reg.setVariable(SVT_FILE, param);
break;
case SLU_LOAD_VALUE:
fun->reg.setVariable(SVT_INT, param);
break;
case SLU_LOAD_LOCAL:
if (!fun->reg.copyFrom(fun->localVars[param]))
return false;
break;
case SLU_AND:
fun->reg.setVariable(SVT_INT,
fun->reg.getBoolean() && fun->stack->thisVar.getBoolean());
trimStack(fun->stack);
break;
case SLU_OR:
fun->reg.setVariable(SVT_INT,
fun->reg.getBoolean() || fun->stack->thisVar.getBoolean());
trimStack(fun->stack);
break;
case SLU_LOAD_FUNC:
fun->reg.setVariable(SVT_FUNC, param);
break;
case SLU_LOAD_BUILT:
fun->reg.setVariable(SVT_BUILT, param);
break;
case SLU_LOAD_OBJTYPE:
fun->reg.setVariable(SVT_OBJTYPE, param);
break;
case SLU_UNREG:
break;
case SLU_LOAD_STRING:
if (!fun->reg.loadStringToVar(param)) {
return false;
}
break;
case SLU_INDEXGET:
case SLU_INCREMENT_INDEX:
case SLU_DECREMENT_INDEX:
switch (fun->stack->thisVar.varType) {
case SVT_NULL:
if (com == SLU_INDEXGET) {
fun->reg.setVariable(SVT_NULL, 0);
trimStack(fun->stack);
} else {
return fatal(ERROR_INCDEC_UNKNOWN);
}
break;
case SVT_FASTARRAY:
case SVT_STACK:
if (fun->stack->thisVar.varData.theStack->first == NULL) {
return fatal(ERROR_INDEX_EMPTY);
} else {
int ii;
if (!fun->reg.getValueType(ii, SVT_INT))
return false;
Variable *grab =
(fun->stack->thisVar.varType == SVT_FASTARRAY) ?
fun->stack->thisVar.varData.fastArray->fastArrayGetByIndex(ii) :
fun->stack->thisVar.varData.theStack->first->stackGetByIndex(ii);
trimStack(fun->stack);
if (!grab) {
fun->reg.setVariable(SVT_NULL, 0);
} else {
int kk;
switch (com) {
case SLU_INCREMENT_INDEX:
if (!grab->getValueType(kk, SVT_INT))
return false;
fun->reg.setVariable(SVT_INT, kk);
grab->varData.intValue = kk + 1;
break;
case SLU_DECREMENT_INDEX:
if (!grab->getValueType(kk, SVT_INT))
return false;
fun->reg.setVariable(SVT_INT, kk);
grab->varData.intValue = kk - 1;
break;
default:
if (!fun->reg.copyFrom(*grab))
return false;
}
}
}
break;
default:
return fatal(ERROR_INDEX_NONSTACK);
}
break;
case SLU_INDEXSET:
switch (fun->stack->thisVar.varType) {
case SVT_STACK:
if (fun->stack->thisVar.varData.theStack->first == NULL) {
return fatal(ERROR_INDEX_EMPTY);
} else {
int ii;
if (!fun->reg.getValueType(ii, SVT_INT))
return false;
if (!fun->stack->thisVar.varData.theStack->first->stackSetByIndex(ii, fun->stack->next->thisVar)) {
return false;
}
trimStack(fun->stack);
trimStack(fun->stack);
}
break;
case SVT_FASTARRAY: {
int ii;
if (!fun->reg.getValueType(ii, SVT_INT))
return false;
Variable *v = fun->stack->thisVar.varData.fastArray->fastArrayGetByIndex(ii);
if (v == NULL)
return fatal("Not within bounds of fast array.");
if (!v->copyFrom(fun->stack->next->thisVar))
return false;
trimStack(fun->stack);
trimStack(fun->stack);
}
break;
default:
return fatal(ERROR_INDEX_NONSTACK);
}
break;
// What can we do with the register? Well, we can copy it into a local
// variable, a global or onto the stack...
case SLU_INCREMENT_LOCAL: {
int ii;
if (!fun->localVars[param].getValueType(ii, SVT_INT))
return false;
fun->reg.setVariable(SVT_INT, ii);
fun->localVars[param].setVariable(SVT_INT, ii + 1);
}
break;
case SLU_INCREMENT_GLOBAL: {
int ii;
if (!globalVars[param].getValueType(ii, SVT_INT))
return false;
fun->reg.setVariable(SVT_INT, ii);
globalVars[param].setVariable(SVT_INT, ii + 1);
}
break;
case SLU_DECREMENT_LOCAL: {
int ii;
if (!fun->localVars[param].getValueType(ii, SVT_INT))
return false;
fun->reg.setVariable(SVT_INT, ii);
fun->localVars[param].setVariable(SVT_INT, ii - 1);
}
break;
case SLU_DECREMENT_GLOBAL: {
int ii;
if (!globalVars[param].getValueType(ii, SVT_INT))
return false;
fun->reg.setVariable(SVT_INT, ii);
globalVars[param].setVariable(SVT_INT, ii - 1);
}
break;
case SLU_SET_LOCAL:
if (!fun->localVars[param].copyFrom(fun->reg))
return false;
break;
case SLU_SET_GLOBAL:
if (!globalVars[param].copyFrom(fun->reg))
return false;
break;
case SLU_LOAD_GLOBAL:
if (!fun->reg.copyFrom(globalVars[param]))
return false;
break;
case SLU_STACK_PUSH:
if (!addVarToStack(fun->reg, fun->stack))
return false;
break;
case SLU_QUICK_PUSH:
if (!addVarToStackQuick(fun->reg, fun->stack))
return false;
break;
case SLU_NOT:
fun->reg.setVariable(SVT_INT, !fun->reg.getBoolean());
break;
case SLU_BR_ZERO:
if (!fun->reg.getBoolean()) {
advanceNow = false;
fun->runThisLine = param;
}
break;
case SLU_BRANCH:
advanceNow = false;
fun->runThisLine = param;
break;
case SLU_NEGATIVE: {
int i;
if (!fun->reg.getValueType(i, SVT_INT))
return false;
fun->reg.setVariable(SVT_INT, -i);
}
break;
// All these things rely on there being somet' on the stack
case SLU_MULT:
case SLU_PLUS:
case SLU_MINUS:
case SLU_MODULUS:
case SLU_DIVIDE:
case SLU_EQUALS:
case SLU_NOT_EQ:
case SLU_LESSTHAN:
case SLU_MORETHAN:
case SLU_LESS_EQUAL:
case SLU_MORE_EQUAL:
if (fun->stack) {
int firstValue, secondValue;
switch (com) {
case SLU_PLUS:
fun->reg.addVariablesInSecond(fun->stack->thisVar);
trimStack(fun->stack);
break;
case SLU_EQUALS:
fun->reg.compareVariablesInSecond(fun->stack->thisVar);
trimStack(fun->stack);
break;
case SLU_NOT_EQ:
fun->reg.compareVariablesInSecond(fun->stack->thisVar);
trimStack(fun->stack);
fun->reg.varData.intValue = !fun->reg.varData.intValue;
break;
default:
if (!fun->stack->thisVar.getValueType(firstValue, SVT_INT))
return false;
if (!fun->reg.getValueType(secondValue, SVT_INT))
return false;
trimStack(fun->stack);
switch (com) {
case SLU_MULT:
fun->reg.setVariable(SVT_INT,
firstValue * secondValue);
break;
case SLU_MINUS:
fun->reg.setVariable(SVT_INT,
firstValue - secondValue);
break;
case SLU_MODULUS:
fun->reg.setVariable(SVT_INT,
firstValue % secondValue);
break;
case SLU_DIVIDE:
fun->reg.setVariable(SVT_INT,
firstValue / secondValue);
break;
case SLU_LESSTHAN:
fun->reg.setVariable(SVT_INT,
firstValue < secondValue);
break;
case SLU_MORETHAN:
fun->reg.setVariable(SVT_INT,
firstValue > secondValue);
break;
case SLU_LESS_EQUAL:
fun->reg.setVariable(SVT_INT,
firstValue <= secondValue);
break;
case SLU_MORE_EQUAL:
fun->reg.setVariable(SVT_INT,
firstValue >= secondValue);
break;
default:
break;
}
}
} else {
return fatal(ERROR_NOSTACK);
}
break;
default:
return fatal(ERROR_UNKNOWN_CODE);
}
if (advanceNow) {
if (debugChannelSet(-1, kSludgeDebugStackMachine)) {
debugN(" Stack after: ");
printStack(fun->stack);
debugN(" Reg after: ");
fun->reg.debugPrint();
debug("%s", "");
debugN(" Locals after: ");
printLocals(fun->localVars, fun->numLocals);
}
fun->runThisLine++;
}
}
return true;
}
void killAllFunctions() {
while (allRunningFunctions)
finishFunction(allRunningFunctions);
}
bool loadFunctionCode(LoadedFunction *newFunc) {
uint numLines, numLinesRead;
if (!g_sludge->_resMan->openSubSlice(newFunc->originalNumber))
return false;
debugC(3, kSludgeDebugDataLoad, "Load function code");
Common::SeekableReadStream *readStream = g_sludge->_resMan->getData();
newFunc->unfreezable = readStream->readByte();
numLines = readStream->readUint16BE();
debugC(3, kSludgeDebugDataLoad, "numLines: %i", numLines);
newFunc->numArgs = readStream->readUint16BE();
debugC(3, kSludgeDebugDataLoad, "numArgs: %i", newFunc->numArgs);
newFunc->numLocals = readStream->readUint16BE();
debugC(3, kSludgeDebugDataLoad, "numLocals: %i", newFunc->numLocals);
newFunc->compiledLines = new LineOfCode[numLines];
if (!checkNew(newFunc->compiledLines))
return false;
for (numLinesRead = 0; numLinesRead < numLines; numLinesRead++) {
byte com = readStream->readByte();
uint16 param = readStream->readUint16BE();
newFunc->compiledLines[numLinesRead].theCommand = (SludgeCommand)com;
newFunc->compiledLines[numLinesRead].param = param;
debugC(3, kSludgeDebugDataLoad, "command line %i: %s(%s)", numLinesRead,
sludgeText[com], getCommandParameter(com, param).c_str());
}
g_sludge->_resMan->finishAccess();
// Now we need to reserve memory for the local variables
newFunc->localVars = new Variable[newFunc->numLocals];
if (!checkNew(newFunc->localVars))
return false;
return true;
}
int startNewFunctionNum(uint funcNum, uint numParamsExpected,
LoadedFunction *calledBy, VariableStack *&vStack, bool returnSommet) {
LoadedFunction *newFunc = new LoadedFunction;
checkNew(newFunc);
newFunc->originalNumber = funcNum;
loadFunctionCode(newFunc);
if (newFunc->numArgs != (int)numParamsExpected)
return fatal("Wrong number of parameters!");
if (newFunc->numArgs > newFunc->numLocals)
return fatal("More arguments than local Variable space!");
// Now, lets copy the parameters from the calling function's stack...
while (numParamsExpected) {
numParamsExpected--;
if (vStack == NULL)
return fatal(
"Corrupted file!The stack's empty and there were still parameters expected");
newFunc->localVars[numParamsExpected].copyFrom(vStack->thisVar);
trimStack(vStack);
}
newFunc->cancelMe = false;
newFunc->timeLeft = 0;
newFunc->returnSomething = returnSommet;
newFunc->calledBy = calledBy;
newFunc->stack = NULL;
newFunc->freezerLevel = 0;
newFunc->runThisLine = 0;
newFunc->isSpeech = 0;
restartFunction(newFunc);
return 1;
}
bool runAllFunctions() {
LoadedFunction *thisFunction = allRunningFunctions;
LoadedFunction *nextFunction;
while (thisFunction) {
nextFunction = thisFunction->next;
if (!thisFunction->freezerLevel) {
if (thisFunction->timeLeft) {
if (thisFunction->timeLeft < 0) {
if (!g_sludge->_soundMan->stillPlayingSound(
g_sludge->_speechMan->getLastSpeechSound())) {
thisFunction->timeLeft = 0;
}
} else if (!--(thisFunction->timeLeft)) {
}
} else {
if (thisFunction->isSpeech) {
thisFunction->isSpeech = false;
g_sludge->_speechMan->kill();
}
if (!continueFunction(thisFunction))
return false;
}
}
thisFunction = nextFunction;
}
return true;
}
void saveFunction(LoadedFunction *fun, Common::WriteStream *stream) {
int a;
stream->writeUint16BE(fun->originalNumber);
if (fun->calledBy) {
stream->writeByte(1);
saveFunction(fun->calledBy, stream);
} else {
stream->writeByte(0);
}
stream->writeUint32LE(fun->timeLeft);
stream->writeUint16BE(fun->runThisLine);
stream->writeByte(fun->cancelMe);
stream->writeByte(fun->returnSomething);
stream->writeByte(fun->isSpeech);
fun->reg.save(stream);
if (fun->freezerLevel) {
fatal(ERROR_GAME_SAVE_FROZEN);
}
saveStack(fun->stack, stream);
for (a = 0; a < fun->numLocals; a++) {
fun->localVars[a].save(stream);
}
}
LoadedFunction *loadFunction(Common::SeekableReadStream *stream) {
int a;
// Reserve memory...
LoadedFunction *buildFunc = new LoadedFunction;
if (!checkNew(buildFunc))
return NULL;
// See what it was called by and load if we need to...
buildFunc->originalNumber = stream->readUint16BE();
buildFunc->calledBy = NULL;
if (stream->readByte()) {
buildFunc->calledBy = loadFunction(stream);
if (!buildFunc->calledBy) {
delete buildFunc;
return NULL;
}
}
buildFunc->timeLeft = stream->readUint32LE();
buildFunc->runThisLine = stream->readUint16BE();
buildFunc->freezerLevel = 0;
buildFunc->cancelMe = stream->readByte();
buildFunc->returnSomething = stream->readByte();
buildFunc->isSpeech = stream->readByte();
buildFunc->reg.load(stream);
loadFunctionCode(buildFunc);
buildFunc->stack = loadStack(stream, NULL);
for (a = 0; a < buildFunc->numLocals; a++) {
buildFunc->localVars[a].load(stream);
}
return buildFunc;
}
} // End of namespace Sludge

71
engines/sludge/function.h Normal file
View File

@@ -0,0 +1,71 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef SLUDGE_FUNCTION_H
#define SLUDGE_FUNCTION_H
#include "sludge/csludge.h"
#include "sludge/variable.h"
namespace Sludge {
struct Variable;
struct VariableStack;
struct LineOfCode {
SludgeCommand theCommand;
int32 param;
};
struct LoadedFunction {
int originalNumber;
LineOfCode *compiledLines;
int numLocals, timeLeft, numArgs;
Variable *localVars;
VariableStack *stack;
Variable reg;
uint runThisLine;
LoadedFunction *calledBy;
LoadedFunction *next;
bool returnSomething, isSpeech, unfreezable, cancelMe;
byte freezerLevel;
};
bool runAllFunctions();
int startNewFunctionNum(uint, uint, LoadedFunction *, VariableStack*&, bool = true);
void restartFunction(LoadedFunction *fun);
bool loadFunctionCode(LoadedFunction *newFunc);
void killAllFunctions();
void finishFunction(LoadedFunction *fun);
void abortFunction(LoadedFunction *fun);
void freezeSubs();
void unfreezeSubs();
void completeTimers();
void killSpeechTimers();
int cancelAFunction(int funcNum, LoadedFunction *myself, bool &killedMyself);
LoadedFunction *loadFunction(Common::SeekableReadStream *stream);
void saveFunction(LoadedFunction *fun, Common::WriteStream *stream);
} // End of namespace Sludge
#endif

View File

@@ -0,0 +1,205 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
This is the list of the built in functions
true or false states if it's a used function
in the current version of the engine,
but that value currently isn't used anywhere
*/
namespace Sludge {
#define FUNC(special,name,paramNum) {#name, builtIn_ ## name, paramNum},
static builtInFunctionData builtInFunctionArray[] = {
FUNC(true, say, -1)
FUNC(true, skipSpeech, 0)
FUNC(true, statusText, 1)
FUNC(true, pause, 1)
FUNC(true, onLeftMouse, -1)
FUNC(true, onRightMouse, -1)
FUNC(true, setCursor, 1)
FUNC(true, addOverlay, 3)
FUNC(true, addCharacter, 4)
FUNC(true, playSound, 1)
FUNC(true, getMouseX, 0)
FUNC(true, getMouseY, 0)
FUNC(true, addScreenRegion, 8)
FUNC(true, onMoveMouse, -1)
FUNC(true, onFocusChange, -1)
FUNC(true, getOverObject, 0)
FUNC(true, blankScreen, 0)
FUNC(true, moveCharacter, -1)
FUNC(true, onKeyboard, -1)
FUNC(true, getObjectX, 1)
FUNC(true, getObjectY, 1)
FUNC(true, random, 1)
FUNC(true, spawnSub, 1)
FUNC(true, blankArea, 4)
FUNC(true, hideCharacter, 1)
FUNC(true, showCharacter, 1)
FUNC(true, callEvent, 2)
FUNC(true, removeScreenRegion, 1)
FUNC(true, animate, 2)
FUNC(true, turnCharacter, 2)
FUNC(true, removeAllCharacters, 0)
FUNC(true, removeAllScreenRegions, 0)
FUNC(true, setScale, 2)
FUNC(true, newStack, -1)
FUNC(true, pushToStack, 2)
FUNC(true, popFromStack, 1)
FUNC(true, clearStatus, 0)
FUNC(true, addStatus, 0)
FUNC(true, removeLastStatus, 0)
FUNC(true, lightStatus, 1)
FUNC(true, getStatusText, 0)
FUNC(true, setStatusColour, 3)
FUNC(true, deleteFromStack, 2)
FUNC(true, freeze, 0)
FUNC(true, unfreeze, 0)
FUNC(true, pasteImage, 3)
FUNC(true, copyStack, 1)
FUNC(true, completeTimers, 0)
FUNC(true, setCharacterDrawMode, 2)
FUNC(true, anim, -1)
FUNC(true, costume, -1)
FUNC(true, pickOne, -1)
FUNC(true, setCostume, 2)
FUNC(true, wait, 2)
FUNC(true, somethingSpeaking, 0)
FUNC(true, substring, 3)
FUNC(true, stringLength, 1)
FUNC(true, darkBackground, 0)
FUNC(true, saveGame, 1)
FUNC(true, loadGame, 1)
FUNC(true, quitGame, 0)
FUNC(true, rename, 2)
FUNC(true, stackSize, 1)
FUNC(true, pasteString, 3)
FUNC(true, startMusic, 3)
FUNC(true, setDefaultMusicVolume, 1)
FUNC(true, setMusicVolume, 2)
FUNC(true, stopMusic, 1)
FUNC(true, stopSound, 1)
FUNC(true, setFont, 3)
FUNC(true, alignStatus, 1)
FUNC(true, showFloor, 0)
FUNC(true, showBoxes, 0)
FUNC(true, positionStatus, 2)
FUNC(true, setFloor, 1)
FUNC(true, forceCharacter, -1)
FUNC(true, jumpCharacter, -1)
FUNC(true, peekStart, 1)
FUNC(true, peekEnd, 1)
FUNC(true, enqueue, 2)
FUNC(true, setZBuffer, 1)
FUNC(true, getMatchingFiles, 1)
FUNC(true, inFont, 1)
FUNC(true, onLeftMouseUp, -1)
FUNC(true, onRightMouseUp, -1)
FUNC(true, loopSound, -1)
FUNC(true, removeCharacter, 1)
FUNC(true, stopCharacter, 1)
FUNC(true, launch, 1)
FUNC(true, howFrozen, 0)
FUNC(true, setPasteColour, 3)
FUNC(true, setLitStatusColour, 3)
FUNC(true, fileExists, 1)
FUNC(true, floatCharacter, 2)
FUNC(true, cancelSub, 1)
FUNC(true, setCharacterWalkSpeed, 2)
FUNC(true, deleteAllFromStack, 2)
FUNC(true, setCharacterExtra, 2)
FUNC(true, mixOverlay, 3)
FUNC(true, pasteCharacter, 1)
FUNC(true, setSceneDimensions, 2)
FUNC(true, aimCamera, 2)
FUNC(true, getMouseScreenX, 0)
FUNC(true, getMouseScreenY, 0)
FUNC(true, setDefaultSoundVolume, 1)
FUNC(true, setSoundVolume, 2)
FUNC(true, setSoundLoopPoints, 3)
FUNC(true, setSpeechMode, 1)
FUNC(true, setLightMap, -1)
FUNC(true, think, -1)
FUNC(true, getCharacterDirection, 1)
FUNC(true, isCharacter, 1)
FUNC(true, isScreenRegion, 1)
FUNC(true, isMoving, 1)
FUNC(true, deleteFile, 1)
FUNC(true, renameFile, 2)
FUNC(true, hardScroll, 1)
FUNC(true, stringWidth, 1)
FUNC(true, setSpeechSpeed, 1)
FUNC(true, normalCharacter, 1)
FUNC(true, fetchEvent, 2)
FUNC(true, transitionLevel, 1)
FUNC(true, spinCharacter, 2)
FUNC(true, setFontSpacing, 1)
FUNC(true, burnString, 3)
FUNC(true, captureAllKeys, 1)
FUNC(true, cacheSound, 1)
FUNC(true, setCharacterSpinSpeed, 2)
FUNC(true, transitionMode, 1)
FUNC(false, _rem_movieStart, 1)
FUNC(false, _rem_movieAbort, 0)
FUNC(false, _rem_moviePlaying, 0)
FUNC(false, _rem_updateDisplay, 1)
FUNC(true, getSoundCache, 0)
FUNC(true, saveCustomData, 2)
FUNC(true, loadCustomData, 1)
FUNC(true, setCustomEncoding, 1)
FUNC(true, freeSound, 1)
FUNC(true, parallaxAdd, 3)
FUNC(true, parallaxClear, 0)
FUNC(true, setBlankColour, 3)
FUNC(true, setBurnColour, 3)
FUNC(true, getPixelColour, 2)
FUNC(true, makeFastArray, 1)
FUNC(true, getCharacterScale, 1)
FUNC(true, getLanguageID, 0)
FUNC(false, _rem_launchWith, 2)
FUNC(true, getFramesPerSecond, 0)
FUNC(true, showThumbnail, 3)
FUNC(true, setThumbnailSize, 2)
FUNC(true, hasFlag, 2)
FUNC(true, snapshotGrab, 0)
FUNC(true, snapshotClear, 0)
FUNC(true, bodgeFilenames, 1)
FUNC(false, _rem_registryGetString, 2)
FUNC(true, quitWithFatalError, 1)
FUNC(true, _rem_setCharacterAA, 4)
FUNC(true, _rem_setMaximumAA, 3)
FUNC(true, setBackgroundEffect, -1)
FUNC(true, doBackgroundEffect, 0)
FUNC(true, setCharacterAngleOffset, 2)
FUNC(true, setCharacterTransparency, 2)
FUNC(true, setCharacterColourise, 5)
FUNC(true, zoomCamera, 1)
FUNC(true, playMovie, 1)
FUNC(true, stopMovie, 0)
FUNC(true, pauseMovie, 0)
};
#undef FUNC
const static int NUM_FUNCS = (sizeof (builtInFunctionArray) / sizeof (builtInFunctionArray[0]));
} // End of namespace Sludge

218
engines/sludge/graphics.cpp Normal file
View File

@@ -0,0 +1,218 @@
/* 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/system.h"
#include "engines/util.h"
#include "sludge/event.h"
#include "sludge/graphics.h"
#include "sludge/freeze.h"
#include "sludge/newfatal.h"
#include "sludge/sludge.h"
#include "sludge/sludger.h"
#include "sludge/zbuffer.h"
namespace Sludge {
GraphicsManager::GraphicsManager(SludgeEngine *vm) {
_vm = vm;
init();
}
GraphicsManager::~GraphicsManager() {
kill();
}
void GraphicsManager::init() {
// Init screen surface
_winWidth = _sceneWidth = 640;
_winHeight = _sceneHeight = 480;
// LightMap
_lightMapMode = LIGHTMAPMODE_PIXEL;
_lightMapNumber = 0;
_parallaxLayers = nullptr;
// Camera
_cameraZoom = 1.0;
_cameraX = _cameraY = 0;
// Freeze
_frozenStuff = nullptr;
// Back drop
_backdropExists = false;
// Sprite Bank
_allLoadedBanks.clear();
// ZBuffer
_zBuffer = new ZBufferData;
_zBuffer->originalNum = -1;
_zBuffer->tex = nullptr;
_zBufferSurface = nullptr;
// Colors
_currentBlankColour = _renderSurface.format.ARGBToColor(0xff, 0, 0, 0);
_currentBurnR = 0;
_currentBurnG = 0;
_currentBurnB = 0;
// Thumbnail
_thumbWidth = 0;
_thumbHeight = 0;
// Transition
resetRandW();
_brightnessLevel = 255;
_fadeMode = 2;
_transitionTexture = nullptr;
}
void GraphicsManager::kill() {
killParallax();
// kill frozen stuff
FrozenStuffStruct *killMe = _frozenStuff;
while (killMe) {
_frozenStuff = _frozenStuff->next;
if (killMe->backdropSurface.getPixels())
killMe->backdropSurface.free();
if (killMe->lightMapSurface.getPixels())
killMe->lightMapSurface.free();
delete killMe;
killMe = nullptr;
killMe = _frozenStuff;
}
// kill sprite banks
LoadedSpriteBanks::iterator it;
for (it = _allLoadedBanks.begin(); it != _allLoadedBanks.end(); ++it) {
delete (*it);
(*it) = nullptr;
}
_allLoadedBanks.clear();
// kill zbuffer
if (_zBuffer) {
killZBuffer();
delete _zBuffer;
_zBuffer = nullptr;
}
// kill surfaces
if (_renderSurface.getPixels())
_renderSurface.free();
if (_zBufferSurface) {
delete[] _zBufferSurface;
_zBufferSurface = nullptr;
}
if (_snapshotSurface.getPixels())
_snapshotSurface.free();
if (_backdropSurface.getPixels())
_backdropSurface.free();
if (_origBackdropSurface.getPixels())
_origBackdropSurface.free();
if (_transitionTexture) {
_transitionTexture->free();
delete _transitionTexture;
_transitionTexture = nullptr;
}
}
bool GraphicsManager::initGfx() {
initGraphics(_winWidth, _winHeight, _vm->getScreenPixelFormat());
_renderSurface.create(_winWidth, _winHeight, *_vm->getScreenPixelFormat());
_zBufferSurface = new uint8[_winWidth * _winHeight];
if (!killResizeBackdrop(_winWidth, _winHeight))
return fatal("Couldn't allocate memory for backdrop");
blankAllScreen();
return true;
}
void GraphicsManager::display() {
if (_brightnessLevel < 255)
fixBrightness();
g_system->copyRectToScreen((byte *)_renderSurface.getPixels(), _renderSurface.pitch, 0, 0, _renderSurface.w, _renderSurface.h);
g_system->updateScreen();
}
void GraphicsManager::clear() {
_renderSurface.fillRect(Common::Rect(0, 0, _backdropSurface.w, _backdropSurface.h), _renderSurface.format.ARGBToColor(0, 0, 0, 0));
}
void GraphicsManager::aimCamera(int cameraX, int cameraY) {
_cameraX = cameraX;
_cameraY = cameraY;
_cameraX -= (float)(_winWidth >> 1) / _cameraZoom;
_cameraY -= (float)(_winHeight >> 1) / _cameraZoom;
if (_cameraX < 0)
_cameraX = 0;
else if (_cameraX > _sceneWidth - (float)_winWidth / _cameraZoom)
_cameraX = _sceneWidth - (float)_winWidth / _cameraZoom;
if (_cameraY < 0)
_cameraY = 0;
else if (_cameraY > _sceneHeight - (float)_winHeight / _cameraZoom)
_cameraY = _sceneHeight - (float)_winHeight / _cameraZoom;
}
void GraphicsManager::zoomCamera(int z) {
_vm->_evtMan->mouseX() = _vm->_evtMan->mouseX() * _cameraZoom;
_vm->_evtMan->mouseY() = _vm->_evtMan->mouseY() * _cameraZoom;
_cameraZoom = (float)z * 0.01;
if ((float)_winWidth / _cameraZoom > _sceneWidth)
_cameraZoom = (float)_winWidth / _sceneWidth;
if ((float)_winHeight / _cameraZoom > _sceneHeight)
_cameraZoom = (float)_winHeight / _sceneHeight;
_vm->_evtMan->mouseX() = _vm->_evtMan->mouseX() / _cameraZoom;
_vm->_evtMan->mouseY() = _vm->_evtMan->mouseY() / _cameraZoom;
}
void GraphicsManager::saveColors(Common::WriteStream *stream) {
stream->writeUint16BE(_currentBlankColour);
stream->writeByte(_currentBurnR);
stream->writeByte(_currentBurnG);
stream->writeByte(_currentBurnB);
}
void GraphicsManager::loadColors(Common::SeekableReadStream *stream) {
_currentBlankColour = stream->readUint16BE();
_currentBurnR = stream->readByte();
_currentBurnG = stream->readByte();
_currentBurnB = stream->readByte();
}
} // End of namespace Sludge

278
engines/sludge/graphics.h Normal file
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/>.
*
*/
#ifndef SLUDGE_GRAPHICS_H
#define SLUDGE_GRAPHICS_H
#include "sludge/sprbanks.h"
namespace Common {
class SeekableReadStream;
class WriteStream;
}
namespace Sludge {
class Parallax;
class SludgeEngine;
class SpritePalette;
struct StackHandler;
struct FrozenStuffStruct;
struct LoadedSpriteBank;
struct OnScreenPerson;
struct SpriteBank;
struct Sprite;
struct VariableStack;
struct ZBufferData;
enum ELightMapMode {
LIGHTMAPMODE_NONE = -1,
LIGHTMAPMODE_HOTSPOT,
LIGHTMAPMODE_PIXEL,
LIGHTMAPMODE_NUM
};
// Parallax
struct ParallaxLayer {
Graphics::Surface surface;
int speedX, speedY;
bool wrapS, wrapT;
uint16 fileNum, fractionX, fractionY;
int cameraX, cameraY;
};
typedef Common::List<ParallaxLayer *> ParallaxLayers;
class GraphicsManager {
public:
GraphicsManager(SludgeEngine *vm);
virtual ~GraphicsManager();
void init();
void kill();
// graphics
void setWindowSize(uint winWidth, uint winHeight) { _winWidth = winWidth; _winHeight = winHeight; }
bool initGfx();
void display();
void clear();
// Parallax
bool loadParallax(uint16 v, uint16 fracX, uint16 fracY);
void killParallax();
void saveParallax(Common::WriteStream *fp);
void drawParallax();
// Backdrop
void killAllBackDrop();
bool resizeBackdrop(int x, int y);
bool killResizeBackdrop(int x, int y);
void killBackDrop();
void loadBackDrop(int fileNum, int x, int y);
void mixBackDrop(int fileNum, int x, int y);
void drawBackDrop();
void blankScreen(int x1, int y1, int x2, int y2);
void blankAllScreen();
void darkScreen();
void saveHSI(Common::WriteStream *stream);
bool loadHSI(int num, Common::SeekableReadStream *stream, int, int, bool);
bool mixHSI(int num, Common::SeekableReadStream *stream, int x = 0, int y = 0);
void drawLine(uint, uint, uint, uint);
void drawHorizontalLine(uint, uint, uint);
void drawVerticalLine(uint, uint, uint);
void hardScroll(int distance);
bool getRGBIntoStack(uint x, uint y, StackHandler *sH);
void saveBackdrop(Common::WriteStream *stream); // To game save
void loadBackdrop(int ssgVersion, Common::SeekableReadStream *streamn); // From game save
// Lightmap
int _lightMapMode;
void killLightMap();
bool loadLightMap(int v);
void saveLightMap(Common::WriteStream *stream);
bool loadLightMap(int ssgVersion, Common::SeekableReadStream *stream);
// Snapshot
void nosnapshot();
bool snapshot();
void saveSnapshot(Common::WriteStream *stream);
bool restoreSnapshot(Common::SeekableReadStream *stream);
// Camera
int getCamX() { return _cameraX; }
int getCamY() { return _cameraY; }
float getCamZoom() { return _cameraZoom; }
void aimCamera(int cameraX, int cameraY);
void zoomCamera(int z);
// Screen
int getCenterX(int width) { return (_winWidth - width) >> 1; }
int checkSizeValide(int width, int height) { return ((width >= 0) && (height >= 0) && (width < (int)_winWidth) && (height < (int)_winHeight)); }
// Freeze
bool freeze();
void unfreeze(bool killImage = true);
int howFrozen();
bool isFrozen() { return (_frozenStuff != nullptr); }
// Sprites
static void forgetSpriteBank(SpriteBank &forgetme);
bool loadSpriteBank(char *filename, SpriteBank &loadhere);
bool loadSpriteBank(int fileNum, SpriteBank &loadhere, bool isFont);
void fontSprite(int x1, int y1, Sprite &single, const SpritePalette &fontPal);
void flipFontSprite(int x1, int y1, Sprite &single, const SpritePalette &fontPal);
bool scaleSprite(Sprite &single, const SpritePalette &fontPal, OnScreenPerson *thisPerson, bool mirror);
void fixScaleSprite(int x1, int y1, Sprite &single, const SpritePalette &fontPal, OnScreenPerson *thisPerson, const int camX, const int camY, bool);
void pasteSpriteToBackDrop(int x1, int y1, Sprite &single, const SpritePalette &fontPal);
bool reserveSpritePal(SpritePalette &sP, int n);
void burnSpriteToBackDrop(int x1, int y1, Sprite &single, const SpritePalette &fontPal);
// Sprite Bank
LoadedSpriteBank *loadBankForAnim(int ID);
// ZBuffer
bool setZBuffer(int y);
void killZBuffer();
void drawZBuffer(int x, int y, bool upsidedown);
void saveZBuffer(Common::WriteStream *stream);
bool loadZBuffer(Common::SeekableReadStream *stream);
void drawSpriteToZBuffer(int x, int y, uint8 depth, const Graphics::Surface &surface);
void fillZBuffer(uint8 d);
// Colors
void setBlankColor(int r, int g, int b) { _currentBlankColour = _renderSurface.format.RGBToColor(r & 255, g & 255, b & 255);};
void setBurnColor(int r, int g, int b) {
_currentBurnR = r;
_currentBurnG = g;
_currentBurnB = b;
}
void saveColors(Common::WriteStream *stream);
void loadColors(Common::SeekableReadStream *stream);
// Thumbnail
bool setThumbnailSize(int thumbWidth, int thumbHeight);
bool saveThumbnail(Common::WriteStream *stream);
bool skipThumbnail(Common::SeekableReadStream *stream);
void showThumbnail(const Common::String &filename, int x, int y);
// Transition
void setBrightnessLevel(int brightnessLevel);
void setFadeMode(int fadeMode) { _fadeMode = fadeMode; };
void fixBrightness();
void resetRandW();
void reserveTransitionTexture();
void transitionFader();
void transitionDisolve();
void transitionTV();
void transitionBlinds();
void transitionSnapshotBox();
void transitionCrossFader();
// BG effects
bool blurScreen();
void blur_saveSettings(Common::WriteStream *stream);
void blur_loadSettings(Common::SeekableReadStream *stream);
bool blur_createSettings(int numParams, VariableStack *&stack);
uint getWinWidth() { return _winWidth; }
uint getWinHeight() { return _winHeight; }
private:
SludgeEngine *_vm;
uint _winWidth, _winHeight, _sceneWidth, _sceneHeight;
// renderSurface
Graphics::Surface _renderSurface;
// Z Buffer Surface
uint8 *_zBufferSurface = nullptr;
// Snapshot
Graphics::Surface _snapshotSurface;
// LightMap
int _lightMapNumber;
Graphics::Surface _lightMap;
// Camera
float _cameraZoom;
int _cameraX, _cameraY;
// Freeze
FrozenStuffStruct *_frozenStuff;
Graphics::Surface _freezeSurface;
void freezeGraphics();
// Back drop
Graphics::Surface _backdropSurface;
Graphics::Surface _origBackdropSurface;
bool _backdropExists;
bool reserveBackdrop();
// Sprites
void fontSprite(bool flip, int x, int y, Sprite &single, const SpritePalette &fontPal);
Graphics::Surface *duplicateSurface(Graphics::Surface *surface);
void blendColor(Graphics::Surface * surface, uint32 color, Graphics::TSpriteBlendMode mode);
Graphics::Surface *applyLightmapToSprite(Graphics::Surface *&blitted, OnScreenPerson *thisPerson, bool mirror, int x, int y, int x1, int y1, int diffX, int diffY);
// Sprite banks
LoadedSpriteBanks _allLoadedBanks;
// ZBuffer
ZBufferData *_zBuffer;
void sortZPal(int *oldpal, int *newpal, int size);
// Colors
uint _currentBlankColour;
byte _currentBurnR, _currentBurnG, _currentBurnB;
// Thumbnail
int _thumbWidth;
int _thumbHeight;
// Transition
byte _brightnessLevel;
byte _fadeMode;
#define RANDKK 17
uint32 _randbuffer[RANDKK][2];
int _randp1, _randp2;
Graphics::ManagedSurface *_transitionTexture;
// Parallax
ParallaxLayers *_parallaxLayers;
inline int sortOutPCamera(int cX, int fX, int sceneMax, int boxMax) {
return (fX == 65535) ? (sceneMax ? ((cX * boxMax) / sceneMax) : 0) : ((cX * fX) / 100);
}
};
} // End of namespace Sludge
#endif // SLUDGE_GRAPHICS_H

86
engines/sludge/hsi.cpp Normal file
View File

@@ -0,0 +1,86 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/debug.h"
#include "common/stream.h"
#include "graphics/surface.h"
#include "sludge/hsi.h"
#include "sludge/sludge.h"
namespace Sludge {
HSIDecoder::HSIDecoder() : _surface(nullptr), _palette(0), _reserve(-1) {
}
HSIDecoder::~HSIDecoder() {
destroy();
}
void HSIDecoder::destroy() {
if (_surface != nullptr) {
_surface->free();
delete _surface;
_surface = nullptr;
}
}
bool HSIDecoder::loadStream(Common::SeekableReadStream &stream) {
destroy();
int32 transCol = _reserve > 0 ? -1 : 63519;
int n;
uint16 width = stream.readUint16BE();
debugC(2, kSludgeDebugGraphics, "picWidth : %i", width);
uint16 height = stream.readUint16BE();
debugC(2, kSludgeDebugGraphics, "picHeight : %i", height);
_surface = new Graphics::Surface();
_surface->create(width, height, *g_sludge->getScreenPixelFormat());
for (uint16 y = 0; y < height; y++) {
uint16 x = 0;
while (x < width) {
uint16 c = stream.readUint16BE();
if (c & 32) {
n = stream.readByte() + 1;
c -= 32;
} else {
n = 1;
}
while (n--) {
byte *target = (byte *)_surface->getBasePtr(x, y);
if (_reserve != -1 && (c == transCol || c == 2015)) {
target[0] = (byte)0;
target[1] = (byte)0;
target[2] = (byte)0;
target[3] = (byte)0;
} else {
target[0] = (byte)255;
g_sludge->getOrigPixelFormat()->colorToRGB(c, target[3], target[2], target[1]);
}
x++;
}
}
}
return true;
}
} // End of namespace Sludge

49
engines/sludge/hsi.h Normal file
View File

@@ -0,0 +1,49 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef SLUDGE_HSI_H
#define SLUDGE_HSI_H
#include "graphics/palette.h"
#include "image/image_decoder.h"
namespace Sludge {
class HSIDecoder : public Image::ImageDecoder {
public:
HSIDecoder();
~HSIDecoder() override;
// ImageDecoder API
void destroy() override;
bool loadStream(Common::SeekableReadStream &stream) override;
Graphics::Surface *getSurface() const override { return _surface; }
const Graphics::Palette &getPalette() const override { return _palette; }
void setReserve(bool reserve) { _reserve = reserve; }
private:
Graphics::Surface *_surface;
Graphics::Palette _palette;
int _reserve;
};
} // End of namespace Sludge
#endif

View File

@@ -0,0 +1,111 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/debug.h"
#include "image/png.h"
#include "graphics/surface.h"
#include "sludge/fileset.h"
#include "sludge/hsi.h"
#include "sludge/imgloader.h"
#include "sludge/sludge.h"
namespace Sludge {
bool ImgLoader::loadImage(int num, const char *fname, Common::SeekableReadStream *stream, Graphics::Surface *dest, int reserve) {
debugC(3, kSludgeDebugGraphics, "Loading image at position: %d", (int)stream->pos());
bool dumpPng = false;
int32 start_ptr = stream->pos();
if (!loadPNGImage(stream, dest)) {
stream->seek(start_ptr);
if (!loadHSIImage(stream, dest, reserve)) {
return false;
} else {
if (num != -1) {
g_sludge->_resMan->dumpFile(num, Common::String::format("%s%%04d.slx", fname).c_str());
dumpPng = true;
}
}
} else {
if (num != -1)
g_sludge->_resMan->dumpFile(num, Common::String::format("%s%%04d.png", fname).c_str());
}
if (!g_sludge->_dumpScripts)
return true;
if (dumpPng || (fname && num == -1)) {
// Debug code to output light map image
Common::DumpFile *outFile = new Common::DumpFile();
Common::Path outName;
if (dumpPng)
outName = Common::Path(Common::String::format("dumps/%s%04d.png", fname, num));
else
outName = Common::Path(Common::String::format("dumps/%s.png", fname));
outFile->open(outName);
Image::writePNG(*outFile, *dest);
outFile->finalize();
outFile->close();
delete outFile;
}
return true;
}
bool ImgLoader::loadPNGImage(Common::SeekableReadStream *stream, Graphics::Surface *dest, bool checkSig) {
::Image::PNGDecoder png;
// set skip signature
if (!checkSig) {
png.setSkipSignature(true);
}
if (!png.loadStream(*stream))
return false;
// set value back
if (!checkSig) {
png.setSkipSignature(false);
}
const Graphics::Surface *sourceSurface = png.getSurface();
Graphics::Surface *pngSurface = sourceSurface->convertTo(*g_sludge->getScreenPixelFormat(), png.getPalette().data(), png.getPalette().size());
dest->copyFrom(*pngSurface);
pngSurface->free();
delete pngSurface;
return true;
}
bool ImgLoader::loadHSIImage(Common::SeekableReadStream *stream, Graphics::Surface *dest, int reserve) {
HSIDecoder hsiDecoder;
hsiDecoder.setReserve(reserve);
if (!hsiDecoder.loadStream(*stream)) {
return false;
}
dest->copyFrom(*(hsiDecoder.getSurface()));
return true;
}
} // End of namespace Sludge

View File

@@ -0,0 +1,41 @@
/* 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 SLUDGE_IMGLOADER_H
#define SLUDGE_IMGLOADER_H
#include "common/file.h"
namespace Sludge {
class ImgLoader {
protected:
ImgLoader() {}
public:
static bool loadImage(int num, const char *fname, Common::SeekableReadStream *stream, Graphics::Surface *dest, int reserve = -1);
static bool loadPNGImage(Common::SeekableReadStream *stream, Graphics::Surface *dest, bool checkSig = true);
static bool loadHSIImage(Common::SeekableReadStream *stream, Graphics::Surface *dest, int reserve = -1);
};
} // End of namespace Sludge
#endif

View File

@@ -0,0 +1,603 @@
/* 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 "backends/keymapper/action.h"
#include "backends/keymapper/keymapper.h"
#include "backends/keymapper/standard-actions.h"
#include "common/translation.h"
namespace Sludge {
inline Common::KeymapArray getSludgeKeymaps(const char *target, const Common::String &gameId) {
using namespace Common;
Keymap *gameKeyMap = new Keymap(Keymap::kKeymapTypeGame, "game-shortcuts", _("Game keymappings"));
Keymap *debugKeyMap = new Keymap(Keymap::kKeymapTypeGame, "debug", _("Debug keymappings"));
Keymap *menuKeymap = new Keymap(Keymap::kKeymapTypeGame, "menu", _("Menu keymappings"));
Keymap *minigameKeymap = new Keymap(Keymap::kKeymapTypeGame, "minigame", _("Minigame keymappings"));
Action *act;
if (gameId == "outoforder") {
act = new Action(kStandardActionLeftClick, _("Interact"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
gameKeyMap->addAction(act);
act = new Action(kStandardActionRightClick, _("Change action"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
gameKeyMap->addAction(act);
act = new Action(kStandardActionPause, _("Pause"));
act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE));
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_RIGHT");
gameKeyMap->addAction(act);
act = new Action("INVENTORY", _("Inventory"));
act->setKeyEvent(KeyState(KEYCODE_SPACE, ASCII_SPACE));
act->addDefaultInputMapping("SPACE");
act->addDefaultInputMapping("JOY_Y");
gameKeyMap->addAction(act);
act = new Action("SAVE", _("Quick save"));
act->setKeyEvent(KeyState(KEYCODE_s, 's'));
act->addDefaultInputMapping("s");
act->addDefaultInputMapping("JOY_LEFT_SHOULDER");
gameKeyMap->addAction(act);
act = new Action("SPEEDUP", _("Speed up dialog"));
act->setKeyEvent(KeyState(KEYCODE_PLUS, '+'));
act->addDefaultInputMapping("PLUS");
act->addDefaultInputMapping("JOY_UP");
gameKeyMap->addAction(act);
act = new Action("SPEEDDOWN", _("Slow down dialog"));
act->setKeyEvent(KeyState(KEYCODE_MINUS, '-'));
act->addDefaultInputMapping("MINUS");
act->addDefaultInputMapping("JOY_DOWN");
gameKeyMap->addAction(act);
} else if (gameId == "tsotc") {
act = new Action(kStandardActionLeftClick, _("Move / Interact"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
gameKeyMap->addAction(act);
act = new Action(kStandardActionRightClick, _("Skip dialog"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
gameKeyMap->addAction(act);
act = new Action("QUIT", _("Quit"));
act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE));
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_LEFT");
gameKeyMap->addAction(act);
act = new Action("LOADAUTOSAVE", _("Load auto save"));
act->setKeyEvent(KeyState(KEYCODE_a, 'a'));
act->addDefaultInputMapping("a");
act->addDefaultInputMapping("JOY_X");
gameKeyMap->addAction(act);
act = new Action("SAVE", _("Save game"));
act->setKeyEvent(KeyState(KEYCODE_s, 's'));
act->addDefaultInputMapping("s");
act->addDefaultInputMapping("JOY_LEFT_SHOULDER");
gameKeyMap->addAction(act);
act = new Action("LOAD", _("Load save"));
act->setKeyEvent(KeyState(KEYCODE_l, 'l'));
act->addDefaultInputMapping("l");
act->addDefaultInputMapping("JOY_RIGHT_SHOULDER");
gameKeyMap->addAction(act);
act = new Action("INVENTORY", _("Inventory"));
act->setKeyEvent(KeyState(KEYCODE_i, 'i'));
act->addDefaultInputMapping("i");
act->addDefaultInputMapping("JOY_Y");
gameKeyMap->addAction(act);
act = new Action("PAUSE", _("Pause"));
act->setKeyEvent(KeyState(KEYCODE_SPACE, ASCII_SPACE));
act->addDefaultInputMapping("SPACE");
act->addDefaultInputMapping("JOY_RIGHT");
gameKeyMap->addAction(act);
} else if (gameId == "gjgagsas") {
act = new Action(kStandardActionLeftClick, _("Move / Interact"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
gameKeyMap->addAction(act);
act = new Action(kStandardActionRightClick, _("Skip dialog"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
gameKeyMap->addAction(act);
act = new Action("QUIT", _("Quit"));
act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE));
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_LEFT");
gameKeyMap->addAction(act);
act = new Action("LOADAUTOSAVE", _("Load auto save"));
act->setKeyEvent(KeyState(KEYCODE_a, 'a'));
act->addDefaultInputMapping("a");
act->addDefaultInputMapping("JOY_X");
gameKeyMap->addAction(act);
act = new Action("SAVE", _("Save game"));
act->setKeyEvent(KeyState(KEYCODE_s, 's'));
act->addDefaultInputMapping("s");
act->addDefaultInputMapping("JOY_LEFT_SHOULDER");
gameKeyMap->addAction(act);
act = new Action("LOAD", _("Load save"));
act->setKeyEvent(KeyState(KEYCODE_l, 'l'));
act->addDefaultInputMapping("l");
act->addDefaultInputMapping("JOY_RIGHT_SHOULDER");
gameKeyMap->addAction(act);
act = new Action("INVENTORY", _("Inventory"));
act->setKeyEvent(KeyState(KEYCODE_i, 'i'));
act->addDefaultInputMapping("i");
act->addDefaultInputMapping("JOY_Y");
gameKeyMap->addAction(act);
} else if (gameId == "robinsrescue") {
act = new Action(kStandardActionLeftClick, _("Move / Interact"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
gameKeyMap->addAction(act);
act = new Action(kStandardActionRightClick, _("Inventory"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
gameKeyMap->addAction(act);
act = new Action(kStandardActionPause, _("Pause"));
act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE));
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("q");
act->addDefaultInputMapping("JOY_RIGHT");
gameKeyMap->addAction(act);
act = new Action("SKIPDLG", _("Skip dialog"));
act->setKeyEvent(KeyState(KEYCODE_PERIOD, '.'));
act->addDefaultInputMapping("PERIOD");
act->addDefaultInputMapping("JOY_X");
gameKeyMap->addAction(act);
act = new Action("SHOWFLOOR", _("DEBUG: Show floor"));
act->setKeyEvent(KeyState(KEYCODE_f, 'f'));
act->addDefaultInputMapping("f");
debugKeyMap->addAction(act);
act = new Action("SHOWBOXES", _("DEBUG: Show boxes"));
act->setKeyEvent(KeyState(KEYCODE_b, 'b'));
act->addDefaultInputMapping("b");
debugKeyMap->addAction(act);
} else if (gameId == "atw") {
act = new Action(kStandardActionLeftClick, _("Move / Interact"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
gameKeyMap->addAction(act);
act = new Action(kStandardActionRightClick, _("Inventory"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
gameKeyMap->addAction(act);
act = new Action("QUIT", _("Quit"));
act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE));
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("q");
act->addDefaultInputMapping("JOY_LEFT");
gameKeyMap->addAction(act);
} else if (gameId == "cubert") {
act = new Action(kStandardActionLeftClick, _("Move / Interact"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
gameKeyMap->addAction(act);
act = new Action(kStandardActionRightClick, _("Inventory / Examine"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
gameKeyMap->addAction(act);
act = new Action(kStandardActionPause, _("Pause"));
act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE));
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_RIGHT");
gameKeyMap->addAction(act);
} else if (gameId == "frasse") {
act = new Action(kStandardActionLeftClick, _("Move / Interact"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
gameKeyMap->addAction(act);
act = new Action(kStandardActionRightClick, _("Inventory"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
gameKeyMap->addAction(act);
act = new Action(kStandardActionPause, _("Pause"));
act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE));
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_RIGHT");
gameKeyMap->addAction(act);
act = new Action("SKIPDLG", _("Skip dialog"));
act->setKeyEvent(KeyState(KEYCODE_PERIOD, '.'));
act->addDefaultInputMapping("PERIOD");
act->addDefaultInputMapping("JOY_X");
gameKeyMap->addAction(act);
} else if (gameId == "tgttpoacs") {
act = new Action(kStandardActionLeftClick, _("Move / Interact"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
gameKeyMap->addAction(act);
act = new Action(kStandardActionRightClick, _("Examine / Skip dialog"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
gameKeyMap->addAction(act);
act = new Action(kStandardActionPause, _("Pause / Skip cutscene"));
act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE));
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_RIGHT_SHOULDER");
gameKeyMap->addAction(act);
act = new Action("SPEEDUP", _("Speed up dialog"));
act->setKeyEvent(KeyState(KEYCODE_PLUS, '+'));
act->addDefaultInputMapping("PLUS");
gameKeyMap->addAction(act);
act = new Action("SPEEDDOWN", _("Slow down dialog"));
act->setKeyEvent(KeyState(KEYCODE_MINUS, '-'));
act->addDefaultInputMapping("MINUS");
gameKeyMap->addAction(act);
act = new Action("SAVE", _("Quick save"));
act->setKeyEvent(KeyState(KEYCODE_s, 's'));
act->addDefaultInputMapping("s");
gameKeyMap->addAction(act);
act = new Action("LOAD", _("Quick load"));
act->setKeyEvent(KeyState(KEYCODE_l, 'l'));
act->addDefaultInputMapping("l");
gameKeyMap->addAction(act);
act = new Action("EXAMINE", _("Examine"));
act->setKeyEvent(KeyState(KEYCODE_e, 'e'));
act->addDefaultInputMapping("e");
gameKeyMap->addAction(act);
act = new Action("PICKUP", _("Pick up"));
act->setKeyEvent(KeyState(KEYCODE_p, 'p'));
act->addDefaultInputMapping("p");
gameKeyMap->addAction(act);
act = new Action("TALK", _("Talk to"));
act->setKeyEvent(KeyState(KEYCODE_t, 't'));
act->addDefaultInputMapping("t");
gameKeyMap->addAction(act);
act = new Action("SMELL", _("Smell"));
act->setKeyEvent(KeyState(KEYCODE_m, 'm'));
act->addDefaultInputMapping("m");
gameKeyMap->addAction(act);
act = new Action("USE", _("Use"));
act->setKeyEvent(KeyState(KEYCODE_u, 'u'));
act->addDefaultInputMapping("u");
gameKeyMap->addAction(act);
act = new Action("CONSUME", _("Consume"));
act->setKeyEvent(KeyState(KEYCODE_c, 'c'));
act->addDefaultInputMapping("c");
gameKeyMap->addAction(act);
act = new Action("QUIT", _("Quit"));
act->setKeyEvent(KeyState(KEYCODE_q, 'q'));
act->addDefaultInputMapping("q");
act->addDefaultInputMapping("JOY_LEFT_SHOULDER");
gameKeyMap->addAction(act);
act = new Action("START", _("Start"));
act->setKeyEvent(KeyState(KEYCODE_RETURN, ASCII_RETURN));
act->addDefaultInputMapping("RETURN");
act->addDefaultInputMapping("JOY_Y");
minigameKeymap->addAction(act);
act = new Action("QUIT", _("Quit"));
act->setKeyEvent(KeyState(KEYCODE_q, 'q'));
act->addDefaultInputMapping("q");
act->addDefaultInputMapping("JOY_X");
minigameKeymap->addAction(act);
act = new Action("CASTEARTH", _("Cast earth spell"));
act->setKeyEvent(KeyState(KEYCODE_z, 'z'));
act->addDefaultInputMapping("z");
act->addDefaultInputMapping("JOY_LEFT");
minigameKeymap->addAction(act);
act = new Action("CASTAIR", _("Cast air spell"));
act->setKeyEvent(KeyState(KEYCODE_x, 'x'));
act->addDefaultInputMapping("x");
act->addDefaultInputMapping("JOY_UP");
minigameKeymap->addAction(act);
act = new Action("CASTFIRE", _("Cast fire spell"));
act->setKeyEvent(KeyState(KEYCODE_c, 'c'));
act->addDefaultInputMapping("c");
act->addDefaultInputMapping("JOY_RIGHT");
minigameKeymap->addAction(act);
act = new Action("CASTWATER", _("Cast water spell"));
act->setKeyEvent(KeyState(KEYCODE_v, 'v'));
act->addDefaultInputMapping("v");
act->addDefaultInputMapping("JOY_DOWN");
minigameKeymap->addAction(act);
} else if (gameId == "interview") {
act = new Action(kStandardActionLeftClick, _("Move / Interact"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
gameKeyMap->addAction(act);
act = new Action(kStandardActionRightClick, _("Skip dialog"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
gameKeyMap->addAction(act);
act = new Action(kStandardActionPause, _("Pause / Skip cutscene"));
act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE));
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_RIGHT");
gameKeyMap->addAction(act);
act = new Action("LOAD", _("Quick load"));
act->setKeyEvent(KeyState(KEYCODE_l, 'l'));
act->addDefaultInputMapping("l");
act->addDefaultInputMapping("JOY_RIGHT_SHOULDER");
gameKeyMap->addAction(act);
act = new Action("SAVE", _("Quick save"));
act->setKeyEvent(KeyState(KEYCODE_s, 's'));
act->addDefaultInputMapping("s");
act->addDefaultInputMapping("JOY_LEFT_SHOULDER");
gameKeyMap->addAction(act);
act = new Action("QUIT", _("Quit"));
act->setKeyEvent(KeyState(KEYCODE_q, 'q'));
act->addDefaultInputMapping("q");
act->addDefaultInputMapping("JOY_LEFT");
gameKeyMap->addAction(act);
} else if (gameId == "leptonsquest") {
act = new Action(kStandardActionLeftClick, _("Move / Interact / Skip dialog"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
gameKeyMap->addAction(act);
act = new Action("QUIT", _("Quit"));
act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE));
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_LEFT");
gameKeyMap->addAction(act);
act = new Action("SHOWFLOOR", _("DEBUG: Show floor"));
act->setKeyEvent(KeyState(KEYCODE_f, 'f'));
act->addDefaultInputMapping("f");
debugKeyMap->addAction(act);
act = new Action("SHOWBOXES", _("DEBUG: Show boxes"));
act->setKeyEvent(KeyState(KEYCODE_b, 'b'));
act->addDefaultInputMapping("b");
debugKeyMap->addAction(act);
} else if (gameId == "life") {
act = new Action(kStandardActionLeftClick, _("Move / Interact"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
gameKeyMap->addAction(act);
act = new Action("SKIPDLG", _("Skip dialog"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping(".");
act->addDefaultInputMapping("JOY_B");
gameKeyMap->addAction(act);
act = new Action(kStandardActionPause, _("Pause"));
act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE));
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_RIGHT");
gameKeyMap->addAction(act);
act = new Action("SAVE", _("Quick save"));
act->setKeyEvent(KeyState(KEYCODE_s, 's'));
act->addDefaultInputMapping("s");
act->addDefaultInputMapping("JOY_LEFT_SHOULDER");
gameKeyMap->addAction(act);
act = new Action("LOAD", _("Quick load"));
act->setKeyEvent(KeyState(KEYCODE_l, 'l'));
act->addDefaultInputMapping("l");
act->addDefaultInputMapping("JOY_RIGHT_SHOULDER");
gameKeyMap->addAction(act);
} else if (gameId == "mandy") {
act = new Action(kStandardActionLeftClick, _("Move / Interact"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
gameKeyMap->addAction(act);
act = new Action(kStandardActionRightClick, _("Skip dialog"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
gameKeyMap->addAction(act);
act = new Action(kStandardActionPause, _("Pause"));
act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE));
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_RIGHT");
gameKeyMap->addAction(act);
act = new Action("SAVE", _("Quick save"));
act->setKeyEvent(KeyState(KEYCODE_s, 's'));
act->addDefaultInputMapping("s");
act->addDefaultInputMapping("JOY_LEFT_SHOULDER");
gameKeyMap->addAction(act);
act = new Action("LOAD", _("Quick load"));
act->setKeyEvent(KeyState(KEYCODE_l, 'l'));
act->addDefaultInputMapping("l");
act->addDefaultInputMapping("JOY_RIGHT_SHOULDER");
gameKeyMap->addAction(act);
} else if (gameId == "nsc") {
act = new Action(kStandardActionLeftClick, _("Move / Interact / Skip dialog"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
gameKeyMap->addAction(act);
act = new Action(kStandardActionRightClick, _("Inventory / Skip dialog"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
gameKeyMap->addAction(act);
act = new Action(kStandardActionPause, _("Pause / Skip cutscene"));
act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE));
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_RIGHT");
gameKeyMap->addAction(act);
} else if (gameId == "verbcoin") {
act = new Action(kStandardActionLeftClick, _("Move / Interact"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
gameKeyMap->addAction(act);
act = new Action(kStandardActionRightClick, _("Skip dialog"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
gameKeyMap->addAction(act);
act = new Action("QUIT", _("Quit"));
act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE));
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_LEFT");
gameKeyMap->addAction(act);
act = new Action("SHOWBOXES", _("DEBUG: Show boxes"));
act->setKeyEvent(KeyState(KEYCODE_SPACE, ASCII_SPACE));
act->addDefaultInputMapping("SPACE");
debugKeyMap->addAction(act);
act = new Action("SHOWFLOOR", _("DEBUG: Show floor"));
act->setKeyEvent(KeyState(KEYCODE_f, 'f'));
act->addDefaultInputMapping("f");
debugKeyMap->addAction(act);
} else {
// Default keymap for other games
warning("Game-specific keymap is not defined. Using default SLUDGE engine keymap");
act = new Action(kStandardActionLeftClick, _("Left click"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
gameKeyMap->addAction(act);
act = new Action(kStandardActionRightClick, _("Right click"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
gameKeyMap->addAction(act);
act = new Action(kStandardActionPause, _("Pause game"));
act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE));
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_RIGHT");
gameKeyMap->addAction(act);
}
act = new Action(kStandardActionLeftClick, _("Left click"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
menuKeymap->addAction(act);
act = new Action(kStandardActionRightClick, _("Right click"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
menuKeymap->addAction(act);
KeymapArray keyMaps(4);
keyMaps[0] = gameKeyMap;
keyMaps[1] = debugKeyMap;
keyMaps[2] = menuKeymap;
keyMaps[3] = minigameKeymap;
menuKeymap->setEnabled(false);
return keyMaps;
}
} // End of namespace Sludge

125
engines/sludge/language.cpp Normal file
View File

@@ -0,0 +1,125 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/debug.h"
#include "sludge/fileset.h"
#include "sludge/language.h"
#include "sludge/moreio.h"
#include "sludge/newfatal.h"
#include "sludge/sludge.h"
#include "sludge/version.h"
namespace Sludge {
LanguageManager::LanguageManager() {
init();
}
LanguageManager::~LanguageManager() {
kill();
}
void LanguageManager::init() {
_languageID = 0;
_languageIdx = -1;
_numLanguages = 0;
_languageTable = nullptr;
_languageNames = nullptr;
}
void LanguageManager::kill() {
if (_languageTable) {
delete []_languageTable;
_languageTable = nullptr;
}
if (_languageNames) {
delete []_languageNames;
_languageNames = nullptr;
}
}
void LanguageManager::createTable(Common::File *fp) {
// get number of languages
_numLanguages =
(gameVersion >= VERSION(1, 3)) ? (fp->readByte()) : 0;
debugC(2, kSludgeDebugDataLoad, "numLanguages : %c", _numLanguages);
// make language table
_languageTable = new uint[_numLanguages + 1];
if (!checkNew(_languageTable))
return;
_languageNames = new Common::String[_numLanguages + 1];
if (!checkNew(_languageNames))
return;
for (uint i = 0; i <= _numLanguages; i++) {
_languageTable[i] = i ? fp->readUint16BE() : 0;
debugC(2, kSludgeDebugDataLoad, "languageTable %i: %i", i, _languageTable[i]);
_languageNames[i].clear();
if (gameVersion >= VERSION(2, 0)) {
if (_numLanguages) {
_languageNames[i] = readString(fp);
debugC(2, kSludgeDebugDataLoad, "languageName %i: %s\n", i, _languageNames[i].c_str());
}
}
}
}
void LanguageManager::setLanguageID(uint id) {
_languageID = id;
// get index of language
setLanguageIndex(getLanguageForFileB());
}
int LanguageManager::getLanguageForFileB() {
int indexNum = -1;
for (uint i = 0; i <= _numLanguages; i++) {
if (_languageTable[i] == _languageID)
indexNum = i;
}
return indexNum;
}
void LanguageManager::saveLanguageSetting(Common::WriteStream *writeStream) {
writeStream->writeByte(_numLanguages);
}
void LanguageManager::loadLanguageSetting(Common::SeekableReadStream *readStream) {
uint languageIdx = readStream->readByte();
setLanguageIndex(languageIdx);
}
void LanguageManager::setLanguageIndex(int idx) {
if (idx < 0)
fatal("Can't find the translation data specified!");
if (idx != _languageIdx) {
// Load the saved language!
_languageIdx = idx;
// Now set file indices properly to the chosen language.
g_sludge->_resMan->setFileIndices(_numLanguages, _languageIdx);
}
}
} // End of namespace Sludge

54
engines/sludge/language.h Normal file
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/>.
*
*/
#ifndef SLUDGE_LANGUAGE_H
#define SLUDGE_LANGUAGE_H
#include "common/file.h"
namespace Sludge {
class LanguageManager {
public:
LanguageManager();
~LanguageManager();
void init();
void kill();
void createTable(Common::File *table);
void setLanguageID(uint id);
void saveLanguageSetting(Common::WriteStream *writeStream);
void loadLanguageSetting(Common::SeekableReadStream *readStream);
private:
uint _languageID; // id of selected language
int _languageIdx; // index of selected language in table
uint _numLanguages; // number of existing languages in game
uint *_languageTable; // indexes of existing languages
Common::String *_languageNames; // language names
int getLanguageForFileB();
void setLanguageIndex(int idx);
};
} // End of namespace Sludge
#endif

View File

@@ -0,0 +1,81 @@
/* 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/config-manager.h"
#include "common/system.h"
#include "sludge/event.h"
#include "sludge/function.h"
#include "sludge/graphics.h"
#include "sludge/people.h"
#include "sludge/saveload.h"
#include "sludge/sound.h"
#include "sludge/sludge.h"
#include "sludge/sludger.h"
#include "sludge/timing.h"
namespace Sludge {
extern VariableStack *noStack;
int main_loop(Common::String filename) {
if (!initSludge(filename)) {
return 0;
}
g_sludge->_gfxMan->initGfx();
startNewFunctionNum(0, 0, NULL, noStack);
g_sludge->_evtMan->startGame();
g_sludge->_timer->init();
int saveSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1;
if (saveSlot != -1)
g_sludge->loadNow = g_sludge->getSaveStateName(saveSlot);
while (!g_sludge->_evtMan->quit()) {
g_sludge->_evtMan->checkInput();
g_sludge->_peopleMan->walkAllPeople();
if (g_sludge->_evtMan->handleInput()) {
runAllFunctions();
handleSaveLoad();
}
sludgeDisplay();
g_sludge->_soundMan->handleSoundLists();
g_sludge->_timer->waitFrame();
}
killSludge();
// Load next game
if (!g_sludge->launchNext.empty()) {
Common::String name = g_sludge->launchNext;
g_sludge->launchNext.clear();
main_loop(name);
}
return (0);
}
}
// End of namespace Sludge

View File

@@ -0,0 +1,30 @@
/* 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 SLUDGE_MAIN_LOOP_H
#define SLUDGE_MAIN_LOOP_H
namespace Sludge {
int main_loop(Common::String filename);
} // End of namespace Sludge
#endif

View File

@@ -0,0 +1,69 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/advancedDetector.h"
#include "sludge/sludge.h"
#include "sludge/detection.h"
#include "sludge/keymapper_tables.h"
namespace Sludge {
uint SludgeEngine::getLanguageID() const { return _gameDescription->languageID; }
const char *SludgeEngine::getGameId() const { return _gameDescription->desc.gameId;}
uint32 SludgeEngine::getFeatures() const { return _gameDescription->desc.flags; }
Common::Language SludgeEngine::getLanguage() const { return _gameDescription->desc.language; }
const char *SludgeEngine::getGameFile() const {
return _gameDescription->desc.filesDescriptions[0].fileName;
}
} // End of namespace Sludge
class SludgeMetaEngine : public AdvancedMetaEngine<Sludge::SludgeGameDescription> {
public:
const char *getName() const override {
return "sludge";
}
bool hasFeature(MetaEngineFeature f) const override;
Common::Error createInstance(OSystem *syst, Engine **engine, const Sludge::SludgeGameDescription *desc) const override {
*engine = new Sludge::SludgeEngine(syst, desc);
return Common::kNoError;
}
Common::KeymapArray initKeymaps(const char *target) const override;
};
bool SludgeMetaEngine::hasFeature(MetaEngineFeature f) const {
return checkExtendedSaves(f) || (f == kSupportsLoadingDuringStartup);
}
Common::KeymapArray SludgeMetaEngine::initKeymaps(const char *target) const {
Common::String gameId = ConfMan.get("gameid", target);
return Sludge::getSludgeKeymaps(target, gameId);
}
#if PLUGIN_ENABLED_DYNAMIC(SLUDGE)
REGISTER_PLUGIN_DYNAMIC(SLUDGE, PLUGIN_TYPE_ENGINE, SludgeMetaEngine);
#else
REGISTER_PLUGIN_STATIC(SLUDGE, PLUGIN_TYPE_ENGINE, SludgeMetaEngine);
#endif

54
engines/sludge/module.mk Normal file
View File

@@ -0,0 +1,54 @@
MODULE := engines/sludge
MODULE_OBJS := \
backdrop.o \
bg_effects.o \
builtin.o \
cursors.o \
debugger.o \
event.o \
fileset.o \
floor.o \
freeze.o \
fonttext.o \
function.o \
graphics.o \
hsi.o \
imgloader.o \
language.o \
main_loop.o \
metaengine.o \
moreio.o \
movie.o \
newfatal.o \
objtypes.o \
people.o \
region.o \
savedata.o \
saveload.o \
sludge.o \
sludger.o \
sound.o \
speech.o \
sprbanks.o \
sprites.o \
statusba.o \
thumbnail.o \
timing.o \
transition.o \
variable.o \
zbuffer.o \
MODULE_DIRS += \
engines/sludge
# This module can be built as a plugin
ifeq ($(ENABLE_SLUDGE), DYNAMIC_PLUGIN)
PLUGIN := 1
endif
# Include common rules
include $(srcdir)/rules.mk
# Detection objects
DETECT_OBJS += $(MODULE)/detection.o

176
engines/sludge/moreio.cpp Normal file
View File

@@ -0,0 +1,176 @@
/* 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/file.h"
#include "sludge/newfatal.h"
namespace Sludge {
bool allowAnyFilename = true;
void writeString(Common::String s, Common::WriteStream *stream) {
int a, len = s.size();
stream->writeUint16BE(len);
for (a = 0; a < len; a++) {
stream->writeByte(s[a] + 1);
}
}
Common::String readString(Common::SeekableReadStream *stream) {
int len = stream->readUint16BE();
Common::String res = "";
for (int a = 0; a < len; a++) {
res += (char)(stream->readByte() - 1);
}
return res;
}
Common::String encodeFilename(const Common::String &nameIn) {
Common::String newName = "";
if (nameIn.empty())
return newName;
if (allowAnyFilename) {
for (uint i = 0; i < nameIn.size(); ++i) {
switch (nameIn[i]) {
case '<':
newName += '_';
newName += 'L';
break;
case '>':
newName += '_';
newName += 'G';
break;
case '|':
newName += '_';
newName += 'P';
break;
case '_':
newName += '_';
newName += 'U';
break;
case '\"':
newName += '_';
newName += 'S';
break;
case '\\':
newName += '_';
newName += 'B';
break;
case '/':
newName += '_';
newName += 'F';
break;
case ':':
newName += '_';
newName += 'C';
break;
case '*':
newName += '_';
newName += 'A';
break;
case '?':
newName += '_';
newName += 'Q';
break;
default:
newName += nameIn[i];
break;
}
}
} else {
newName.clear();
newName = nameIn;
for (uint i = 0; i < newName.size(); ++i) {
if (newName[i] == '\\')
newName.setChar('/', i);
}
}
return newName;
}
Common::String decodeFilename(const Common::String &nameIn) {
Common::String newName ="";
if (allowAnyFilename) {
for (uint i = 0; i < nameIn.size(); ++i) {
if (nameIn[i] == '_') {
++i;
switch (nameIn[i]) {
case 'L':
newName += '<';
break;
case 'G':
newName += '>';
break;
case 'P':
newName += '|';
break;
case 'U':
newName += '_';
break;
case 'S':
newName += '\"';
break;
case 'B':
newName += '\\';
break;
case 'F':
newName += '/';
break;
case 'C':
newName += ':';
break;
case 'A':
newName += '*';
break;
case 'Q':
newName += '?';
break;
default:
newName += '_';
--i;
break;
}
} else {
newName += nameIn[i];
}
}
return newName;
} else {
newName.clear();
newName = nameIn;
}
return newName;
}
char *createCString(const Common::String &s) {
uint n = s.size() + 1;
char *res = new char[n];
if (!checkNew(res)) {
fatal("createCString : Unable to copy String");
return NULL;
}
memcpy(res, s.c_str(), n);
return res;
}
} // End of namespace Sludge

37
engines/sludge/moreio.h Normal file
View File

@@ -0,0 +1,37 @@
/* 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 SLUDGE_MOREIO_H
#define SLUDGE_MOREIO_H
namespace Sludge {
// Read & Write
Common::String readString(Common::SeekableReadStream *stream);
void writeString(Common::String s, Common::WriteStream *stream);
Common::String encodeFilename(const Common::String &nameIn);
Common::String decodeFilename(const Common::String &nameIn);
char *createCString(const Common::String &s);
} // End of namespace Sludge
#endif

141
engines/sludge/movie.cpp Normal file
View File

@@ -0,0 +1,141 @@
/* 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 "sludge/sludge.h"
#include "sludge/event.h"
#include "sludge/fileset.h"
#include "sludge/graphics.h"
#include "sludge/movie.h"
#include "sludge/newfatal.h"
#include "sludge/sound.h"
#include "common/scummsys.h" // for USE_VPX
#include "common/substream.h"
#include "video/mkv_decoder.h"
#include "graphics/blit.h"
namespace Sludge {
MovieStates movieIsPlaying = kMovieNothing;
int movieIsEnding = 0;
float movieAspect = 1.6F;
int playMovie(int fileNumber) {
uint fsize;
if (!(fsize = g_sludge->_resMan->openFileFromNum(fileNumber)))
return fatal("playMovie(): Can't open movie");
#if !defined(USE_VPX)
warning("Sludge::playMovie - VPX support not compiled in, skipping movie");
#else
Video::MKVDecoder decoder;
Common::SeekableReadStream *stream = g_sludge->_resMan->getData();
Common::SeekableSubReadStream *video = new Common::SeekableSubReadStream(stream, stream->pos(), stream->pos() + fsize);
if (decoder.loadStream(video))
movieIsPlaying = kMoviePlaying;
decoder.start();
debug(1, "movieIsPlaying %d", movieIsPlaying);
while (movieIsPlaying) {
g_sludge->_evtMan->checkInput();
if (g_sludge->_evtMan->quit())
break;
g_sludge->_evtMan->handleInput();
if (decoder.isVideoLoaded()) {
if (decoder.endOfVideo()) {
debug(1, "End of video");
// Movie complete, so unload the movie
break;
} else if (decoder.needsUpdate()) {
const Graphics::Surface *s = decoder.decodeNextFrame();
if (s) {
// Transfer the next frame
assert(s->format.bytesPerPixel == 4);
if (((uint)s->w != g_sludge->_gfxMan->getWinWidth()) || ((uint)s->h != g_sludge->_gfxMan->getWinHeight())) {
Graphics::Surface *surf = g_system->lockScreen();
Graphics::scaleBlit((byte*)surf->getPixels(), (const byte*)s->getPixels(), surf->pitch, s->pitch,
g_sludge->_gfxMan->getWinWidth(), g_sludge->_gfxMan->getWinHeight(), s->w, s->h, s->format);
g_system->unlockScreen();
} else {
g_system->copyRectToScreen(s->getPixels(), s->pitch, 0, 0, s->w, s->h);
}
g_system->updateScreen();
} else {
warning("s is false");
}
}
}
}
#endif
movieIsPlaying = kMovieNothing;
g_sludge->_resMan->finishAccess();
setResourceForFatal(-1);
return 0;
}
MovieStates isMoviePlaying() {
return movieIsPlaying;
}
int stopMovie() {
int r = movieIsPlaying;
movieIsPlaying = kMovieNothing;
g_sludge->_resMan->finishAccess();
setResourceForFatal(-1);
return r;
}
int pauseMovie() {
#if 0
if (movieIsPlaying == kMoviePlaying) {
ALuint source = getSoundSource(movieAudioIndex);
if (source) {
alurePauseSource(source);
}
movieIsPlaying = kMoviePaused;
fprintf(stderr, "** Pausing **\n");
} else if (movieIsPlaying == kMoviePaused) {
ALuint source = getSoundSource(movieAudioIndex);
if (source) {
alureResumeSource(source);
}
fprintf(stderr, "** Restarted movie ** sound: %d source: %d\n", movieSoundPlaying, source);
movieIsPlaying = kMoviePlaying;
}
#endif
return movieIsPlaying;
}
} // End of namespace Sludge

44
engines/sludge/movie.h Normal file
View File

@@ -0,0 +1,44 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef SLUDGE_MOVIE_H
#define SLUDGE_MOVIE_H
namespace Sludge {
/*
movieIsPlaying tracks the state of movie playing
*/
enum MovieStates {
kMovieNothing = 0,
kMoviePlaying,
kMoviePaused
};
extern MovieStates movieIsPlaying;
extern int movieIsEnding;
int playMovie(int fileNumber);
int stopMovie();
MovieStates isMoviePlaying();
int pauseMovie();
} // End of namespace Sludge
#endif

View File

@@ -0,0 +1,97 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/debug.h"
#include "sludge/errors.h"
#include "sludge/fileset.h"
#include "sludge/newfatal.h"
#include "sludge/sludge.h"
#include "sludge/sound.h"
namespace Common {
DECLARE_SINGLETON(Sludge::FatalMsgManager);
}
namespace Sludge {
int inFatal(const Common::String &str) {
g_sludge->_soundMan->killSoundStuff();
error("%s", str.c_str());
return true;
}
FatalMsgManager::FatalMsgManager() {
reset();
}
FatalMsgManager::~FatalMsgManager() {
}
void FatalMsgManager::reset() {
_fatalMessage = "";
_fatalInfo = "Initialisation error! Something went wrong before we even got started!";
_resourceForFatal = -1;
}
bool FatalMsgManager::hasFatal() {
if (!_fatalMessage.empty())
return true;
return false;
}
void FatalMsgManager::setFatalInfo(const Common::String &userFunc, const Common::String &BIF) {
_fatalInfo = "Currently in this sub: " + userFunc + "\nCalling: " + BIF;
debugC(0, kSludgeDebugFatal, "%s", _fatalInfo.c_str());
}
void FatalMsgManager::setResourceForFatal(int n) {
_resourceForFatal = n;
}
int FatalMsgManager::fatal(const Common::String &str1) {
ResourceManager *resMan = g_sludge->_resMan;
if (resMan->hasResourceNames() && _resourceForFatal != -1) {
Common::String r = resMan->resourceNameFromNum(_resourceForFatal);
Common::String newStr = _fatalInfo + "\nResource: " + r + "\n\n" + str1;
inFatal(newStr);
} else {
Common::String newStr = _fatalInfo + "\n\n" + str1;
inFatal(newStr);
}
return 0;
}
int checkNew(const void *mem) {
if (mem == NULL) {
inFatal(ERROR_OUT_OF_MEMORY);
return 0;
}
return 1;
}
int fatal(const Common::String &str1, const Common::String &str2) {
Common::String newStr = str1 + " " + str2;
fatal(newStr);
return 0;
}
} // End of namespace Sludge

69
engines/sludge/newfatal.h Normal file
View File

@@ -0,0 +1,69 @@
/* 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 SLUDGE_NEWFATAL_H
#define SLUDGE_NEWFATAL_H
#include "common/str.h"
#include "common/singleton.h"
namespace Sludge {
class FatalMsgManager : public Common::Singleton<Sludge::FatalMsgManager>{
public:
FatalMsgManager();
~FatalMsgManager() override;
void reset();
bool hasFatal();
int fatal(const Common::String &str);
void setFatalInfo(const Common::String &userFunc, const Common::String &BIF);
void setResourceForFatal(int n);
private:
Common::String _fatalMessage;
Common::String _fatalInfo;
int _resourceForFatal;
};
inline bool hasFatal() {
return FatalMsgManager::instance().hasFatal();
}
inline int fatal(const Common::String &str) {
return FatalMsgManager::instance().fatal(str);
}
inline void setFatalInfo(const Common::String &userFunc, const Common::String &BIF) {
FatalMsgManager::instance().setFatalInfo(userFunc, BIF);
}
inline void setResourceForFatal(int n) {
FatalMsgManager::instance().setResourceForFatal(n);
}
int checkNew(const void *mem);
int fatal(const Common::String &str1, const Common::String &str2);
} // End of namespace Sludge
#endif

145
engines/sludge/objtypes.cpp Normal file
View File

@@ -0,0 +1,145 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "sludge/fileset.h"
#include "sludge/moreio.h"
#include "sludge/newfatal.h"
#include "sludge/objtypes.h"
#include "sludge/sludge.h"
#include "sludge/version.h"
namespace Sludge {
ObjectManager::~ObjectManager() {
kill();
}
bool ObjectManager::init() {
_allObjectTypes.clear();
return true;
}
void ObjectManager::kill() {
ObjectTypeList::iterator it;
for (it = _allObjectTypes.begin(); it != _allObjectTypes.end(); ++it) {
delete [](*it)->allCombis;
delete (*it);
(*it) = nullptr;
}
_allObjectTypes.clear();
}
ObjectType *ObjectManager::findObjectType(int i, bool skipLoad) {
ObjectTypeList::iterator it;
for (it = _allObjectTypes.begin(); it != _allObjectTypes.end(); ++it) {
if ((*it)->objectNum == i) {
return (*it);
}
}
if (skipLoad)
return nullptr;
return loadObjectType(i);
}
ObjectType *ObjectManager::loadObjectType(int i) {
int a, nameNum;
ObjectType *newType = new ObjectType;
ResourceManager *rm = _vm->_resMan;
if (checkNew(newType)) {
if (rm->openObjectSlice(i)) {
Common::SeekableReadStream *readStream = rm->getData();
nameNum = readStream->readUint16BE();
newType->r = (byte)readStream->readByte();
newType->g = (byte)readStream->readByte();
newType->b = (byte)readStream->readByte();
newType->speechGap = readStream->readByte();
newType->walkSpeed = readStream->readByte();
newType->wrapSpeech = readStream->readUint32LE();
newType->spinSpeed = readStream->readUint16BE();
if (gameVersion >= VERSION(1, 6)) {
// aaLoad
readStream->readByte();
readStream->readFloatLE();
readStream->readFloatLE();
}
if (gameVersion >= VERSION(1, 4)) {
newType->flags = readStream->readUint16BE();
} else {
newType->flags = 0;
}
newType->numCom = readStream->readUint16BE();
newType->allCombis = (newType->numCom) ? new Combination[newType->numCom] : nullptr;
for (a = 0; a < newType->numCom; a++) {
newType->allCombis[a].withObj = readStream->readUint16BE();
newType->allCombis[a].funcNum = readStream->readUint16BE();
}
rm->finishAccess();
newType->screenName = rm->getNumberedString(nameNum);
newType->objectNum = i;
_allObjectTypes.push_back(newType);
return newType;
}
}
return nullptr;
}
ObjectType *ObjectManager::loadObjectRef(Common::SeekableReadStream *stream) {
ObjectType *r = loadObjectType(stream->readUint16BE());
r->screenName.clear();
r->screenName = readString(stream);
return r;
}
void ObjectManager::saveObjectRef(ObjectType *r, Common::WriteStream *stream) {
stream->writeUint16BE(r->objectNum);
writeString(r->screenName, stream);
}
int ObjectManager::getCombinationFunction(int withThis, int thisObject) {
int i, num = 0;
ObjectType *obj = findObjectType(thisObject);
for (i = 0; i < obj->numCom; i++) {
if (obj->allCombis[i].withObj == withThis) {
num = obj->allCombis[i].funcNum;
break;
}
}
return num;
}
void ObjectManager::removeObjectType(ObjectType *oT) {
delete []oT->allCombis;
_allObjectTypes.remove(oT);
}
} // End of namespace Sludge

66
engines/sludge/objtypes.h Normal file
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 SLUDGE_OBJTYPES_H
#define SLUDGE_OBJTYPES_H
namespace Sludge {
class SludgeEngine;
struct Combination {
int withObj, funcNum;
};
struct ObjectType {
Common::String screenName;
int objectNum;
byte r, g, b;
int numCom;
int speechGap, walkSpeed, wrapSpeech, spinSpeed;
uint16 flags;
Combination *allCombis;
};
typedef Common::List<ObjectType *> ObjectTypeList;
class ObjectManager {
public:
ObjectManager(SludgeEngine *vm) : _vm(vm) { init(); }
~ObjectManager();
bool init();
void kill();
ObjectType *findObjectType(int i, bool skipLoad = false);
ObjectType *loadObjectType(int i);
int getCombinationFunction(int a, int b);
void removeObjectType(ObjectType *oT);
void saveObjectRef(ObjectType *r, Common::WriteStream *stream);
ObjectType *loadObjectRef(Common::SeekableReadStream *stream);
private:
ObjectTypeList _allObjectTypes;
SludgeEngine *_vm;
};
} // End of namespace Sludge
#endif

1039
engines/sludge/people.cpp Normal file

File diff suppressed because it is too large Load Diff

173
engines/sludge/people.h Normal file
View File

@@ -0,0 +1,173 @@
/* 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 SLUDGE_PEOPLE_H
#define SLUDGE_PEOPLE_H
#include "common/list.h"
namespace Sludge {
struct FrozenStuffStruct;
struct LoadedSpriteBank;
struct ScreenRegion;
struct VariableStack;
class SludgeEngine;
struct AnimFrame {
int frameNum, howMany;
int noise;
};
#define EXTRA_FRONT 1
#define EXTRA_FIXEDSIZE 2
#define EXTRA_NOSCALE 2 // Alternative name
#define EXTRA_NOZB 4
#define EXTRA_FIXTOSCREEN 8
#define EXTRA_NOLITE 16
#define EXTRA_NOREMOVE 32
#define EXTRA_RECTANGULAR 64
struct PersonaAnimation {
LoadedSpriteBank *theSprites;
AnimFrame *frames;
int numFrames;
PersonaAnimation();
PersonaAnimation(int num, VariableStack *&stacky);
PersonaAnimation(PersonaAnimation *orig);
~PersonaAnimation();
// Setter & getter
int getTotalTime();
// Save & load
bool save(Common::WriteStream *stream);
bool load(Common::SeekableReadStream *stream);
};
struct Persona {
PersonaAnimation **animation;
int numDirections;
// Save & load
bool save(Common::WriteStream *stream);
bool load(Common::SeekableReadStream *stream);
};
struct OnScreenPerson {
float x, y;
int height, floaty, walkSpeed;
float scale;
int walkToX, walkToY, thisStepX, thisStepY, inPoly, walkToPoly;
bool walking, spinning;
struct LoadedFunction *continueAfterWalking;
PersonaAnimation *myAnim;
PersonaAnimation *lastUsedAnim;
Persona *myPersona;
int frameNum, frameTick, angle, wantAngle, angleOffset;
bool show;
int direction, directionWhenDoneWalking;
struct ObjectType *thisType;
int extra, spinSpeed;
byte r, g, b, colourmix, transparency;
void makeTalker();
void makeSilent();
void setFrames(int a);
};
typedef Common::List<OnScreenPerson *> OnScreenPersonList;
class PeopleManager {
public:
PeopleManager(SludgeEngine *vm);
~PeopleManager();
// Initialisation and creation
bool init();
bool addPerson(int x, int y, int objNum, Persona *p);
// Draw to screen and to backdrop
void drawPeople();
void freezePeople(int, int);
// Removalisationisms
void kill();
void killMostPeople();
void removeOneCharacter(int i);
// Things which affect or use all characters
OnScreenPerson *findPerson(int v);
void setScale(int16 h, int16 d);
// Things which affect one character
void setShown(bool h, int ob);
void setDrawMode(int h, int ob);
void setPersonTransparency(int ob, byte x);
void setPersonColourise(int ob, byte r, byte g, byte b, byte colourmix);
// Moving 'em
void movePerson(int x, int y, int objNum);
bool makeWalkingPerson(int x, int y, int objNum, struct LoadedFunction *func, int di);
bool forceWalkingPerson(int x, int y, int objNum, struct LoadedFunction *func, int di);
void jumpPerson(int x, int y, int objNum);
void walkAllPeople();
bool turnPersonToFace(int thisNum, int direc);
bool stopPerson(int o);
bool floatCharacter(int f, int objNum);
bool setCharacterWalkSpeed(int f, int objNum);
// Animating 'em
void animatePerson(int obj, PersonaAnimation *);
void animatePerson(int obj, Persona *per);
bool setPersonExtra(int f, int newSetting);
// Loading and saving
bool savePeople(Common::WriteStream *stream);
bool loadPeople(Common::SeekableReadStream *stream);
// Freeze
void freeze(FrozenStuffStruct *frozenStuff);
void resotre(FrozenStuffStruct *frozenStuff);
private:
ScreenRegion *_personRegion;
OnScreenPersonList *_allPeople;
int16 _scaleHorizon;
int16 _scaleDivide;
SludgeEngine *_vm;
void shufflePeople();
// OnScreenPerson manipulation
void turnMeAngle(OnScreenPerson *thisPerson, int direc);
void spinStep(OnScreenPerson *thisPerson);
void rethinkAngle(OnScreenPerson *thisPerson);
void moveAndScale(OnScreenPerson &me, float x, float y);
void setMyDrawMode(OnScreenPerson *moveMe, int h);
bool walkMe(OnScreenPerson *thisPerson, bool move = true);
};
} // End of namespace Sludge
#endif

173
engines/sludge/region.cpp Normal file
View File

@@ -0,0 +1,173 @@
/* 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 "sludge/event.h"
#include "sludge/graphics.h"
#include "sludge/freeze.h"
#include "sludge/newfatal.h"
#include "sludge/objtypes.h"
#include "sludge/region.h"
#include "sludge/sludge.h"
#include "sludge/sludger.h"
namespace Sludge {
RegionManager::RegionManager(SludgeEngine *vm) {
_vm = vm;
_allScreenRegions = new ScreenRegionList;
_allScreenRegions->clear();
_lastRegion = nullptr;
_overRegion = nullptr;
}
RegionManager::~RegionManager() {
kill();
delete _allScreenRegions;
_allScreenRegions = nullptr;
}
void RegionManager::showBoxes() {
for (ScreenRegionList::iterator it = _allScreenRegions->begin(); it != _allScreenRegions->end(); ++it) {
g_sludge->_gfxMan->drawVerticalLine((*it)->x1, (*it)->y1, (*it)->y2);
g_sludge->_gfxMan->drawVerticalLine((*it)->x2, (*it)->y1, (*it)->y2);
g_sludge->_gfxMan->drawHorizontalLine((*it)->x1, (*it)->y1, (*it)->x2);
g_sludge->_gfxMan->drawHorizontalLine((*it)->x1, (*it)->y2, (*it)->x2);
}
}
void RegionManager::removeScreenRegion(int objectNum) {
for (ScreenRegionList::iterator it = _allScreenRegions->begin(); it != _allScreenRegions->end(); ++it) {
if ((*it)->thisType->objectNum == objectNum) {
ScreenRegion *killMe = *it;
g_sludge->_objMan->removeObjectType(killMe->thisType);
if (killMe == _overRegion)
_overRegion = nullptr;
delete killMe;
killMe = nullptr;
it = _allScreenRegions->reverse_erase(it);
}
}
}
void RegionManager::saveRegions(Common::WriteStream *stream) {
uint numRegions = _allScreenRegions->size();
stream->writeUint16BE(numRegions);
for (ScreenRegionList::iterator it = _allScreenRegions->begin(); it != _allScreenRegions->end(); ++it) {
stream->writeUint16BE((*it)->x1);
stream->writeUint16BE((*it)->y1);
stream->writeUint16BE((*it)->x2);
stream->writeUint16BE((*it)->y2);
stream->writeUint16BE((*it)->sX);
stream->writeUint16BE((*it)->sY);
stream->writeSint16BE((*it)->di);
g_sludge->_objMan->saveObjectRef((*it)->thisType, stream);
}
}
void RegionManager::loadRegions(Common::SeekableReadStream *stream) {
int numRegions = stream->readUint16BE();
while (numRegions--) {
ScreenRegion *newRegion = new ScreenRegion;
_allScreenRegions->push_back(newRegion);
newRegion->x1 = stream->readUint16BE();
newRegion->y1 = stream->readUint16BE();
newRegion->x2 = stream->readUint16BE();
newRegion->y2 = stream->readUint16BE();
newRegion->sX = stream->readUint16BE();
newRegion->sY = stream->readUint16BE();
newRegion->di = stream->readSint16BE();
newRegion->thisType = g_sludge->_objMan->loadObjectRef(stream);
}
}
void RegionManager::kill() {
for (ScreenRegionList::iterator it = _allScreenRegions->begin(); it != _allScreenRegions->end(); ++it) {
ScreenRegion *killRegion = (*it);
g_sludge->_objMan->removeObjectType(killRegion->thisType);
delete killRegion;
}
_allScreenRegions->clear();
_overRegion = nullptr;
_lastRegion = nullptr;
}
bool RegionManager::addScreenRegion(int x1, int y1, int x2, int y2, int sX, int sY, int di,
int objectNum) {
ScreenRegion *newRegion = new ScreenRegion;
if (!checkNew(newRegion))
return false;
newRegion->di = di;
newRegion->x1 = x1;
newRegion->y1 = y1;
newRegion->x2 = x2;
newRegion->y2 = y2;
newRegion->sX = sX;
newRegion->sY = sY;
newRegion->thisType = g_sludge->_objMan->loadObjectType(objectNum);
_allScreenRegions->push_front(newRegion);
return (bool) (newRegion->thisType != nullptr);
}
void RegionManager::updateOverRegion() {
int cameraX = g_sludge->_gfxMan->getCamX();
int cameraY = g_sludge->_gfxMan->getCamY();
for (ScreenRegionList::iterator it = _allScreenRegions->begin(); it != _allScreenRegions->end(); ++it) {
if ((g_sludge->_evtMan->mouseX() >= (*it)->x1 - cameraX)
&& (g_sludge->_evtMan->mouseY() >= (*it)->y1 - cameraY)
&& (g_sludge->_evtMan->mouseX() <= (*it)->x2 - cameraX)
&& (g_sludge->_evtMan->mouseY() <= (*it)->y2 - cameraY)) {
_overRegion = (*it);
return;
}
}
_overRegion = nullptr;
return;
}
ScreenRegion *RegionManager::getRegionForObject(int obj) {
for (ScreenRegionList::iterator it = _allScreenRegions->begin(); it != _allScreenRegions->end(); ++it) {
if (obj == (*it)->thisType->objectNum) {
return (*it);
}
}
return nullptr;
}
void RegionManager::freeze(FrozenStuffStruct *frozenStuff) {
frozenStuff->allScreenRegions = _allScreenRegions;
_allScreenRegions = new ScreenRegionList;
_overRegion = nullptr;
}
void RegionManager::resotre(FrozenStuffStruct *frozenStuff) {
// kill
kill();
delete _allScreenRegions;
_allScreenRegions = nullptr;
// restore
_allScreenRegions = frozenStuff->allScreenRegions;
_overRegion = nullptr;
}
} // End of namespace Sludge

77
engines/sludge/region.h Normal file
View File

@@ -0,0 +1,77 @@
/* 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 SLUDGE_REGION_H
#define SLUDGE_REGION_H
namespace Sludge {
struct ObjectType;
struct ScreenRegion {
int x1, y1, x2, y2, sX, sY, di;
ObjectType *thisType;
};
typedef Common::List<ScreenRegion *> ScreenRegionList;
class RegionManager {
public:
RegionManager(SludgeEngine *vm);
~RegionManager();
// Kill
void kill();
// Add & remove region
bool addScreenRegion(int x1, int y1, int x2, int y2, int, int, int, int objectNum);
void removeScreenRegion(int objectNum);
// Save & load
void loadRegions(Common::SeekableReadStream *stream);
void saveRegions(Common::WriteStream *stream);
// Draw
void showBoxes();
// Setter & getter
ScreenRegion *getRegionForObject(int obj);
ScreenRegion *getOverRegion() const { return _overRegion; }
void setOverRegion(ScreenRegion *newRegion) { _overRegion = newRegion; }
void updateOverRegion();
bool isRegionChanged() const { return _lastRegion != _overRegion; }
void updateLastRegion() { _lastRegion = _overRegion; }
void resetOverRegion() { _overRegion = nullptr; }
void resetLastRegion() { _lastRegion = nullptr; }
// Freeze
void freeze(FrozenStuffStruct *frozenStuff);
void resotre(FrozenStuffStruct *frozenStuff);
private:
SludgeEngine *_vm;
ScreenRegionList *_allScreenRegions;
ScreenRegion *_overRegion;
ScreenRegion *_lastRegion;
};
} // End of namespace Sludge
#endif

247
engines/sludge/savedata.cpp Normal file
View File

@@ -0,0 +1,247 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/file.h"
#include "common/savefile.h"
#include "common/system.h"
#include "sludge/sludge.h"
#include "sludge/newfatal.h"
#include "sludge/savedata.h"
#include "sludge/variable.h"
#define LOAD_ERROR "Can't load custom data...\n\n"
namespace Sludge {
const char CustomSaveHelper::UTF8_CHECKER[] = {'U', 'N', '\xef', '\xbf', '\xbd', 'L', 'O', '\xef', '\xbf', '\xbd', 'C', 'K', 'E', 'D', '\0'};
uint16 CustomSaveHelper::_saveEncoding = false;
char CustomSaveHelper::_encode1 = 0;
char CustomSaveHelper::_encode2 = 0;
void CustomSaveHelper::writeStringEncoded(const Common::String &checker, Common::WriteStream *stream) {
int len = checker.size();
stream->writeUint16BE(len);
for (int a = 0; a < len; a++) {
stream->writeByte(checker[a] ^ _encode1);
_encode1 += _encode2;
}
}
Common::String CustomSaveHelper::readStringEncoded(Common::SeekableReadStream *fp) {
int len = fp->readUint16BE();
Common::String res = "";
for (int a = 0; a < len; a++) {
res += (char)(fp->readByte() ^ _encode1);
_encode1 += _encode2;
}
return res;
}
char *CustomSaveHelper::readTextPlain(Common::SeekableReadStream *fp) {
int32 startPos;
uint32 stringSize = 0;
bool keepGoing = true;
char gotChar;
char *reply;
startPos = fp->pos();
while (keepGoing) {
gotChar = (char)fp->readByte();
if ((gotChar == '\n') || (fp->eos())) {
keepGoing = false;
} else {
stringSize++;
}
}
if ((stringSize == 0) && (fp->eos())) {
return NULL;
} else {
fp->seek(startPos, SEEK_SET);
reply = new char[stringSize + 1];
if (reply == NULL)
return NULL;
uint bytes_read = fp->read(reply, stringSize);
if (bytes_read != stringSize && fp->err()) {
warning("Reading error in readTextPlain.");
}
fp->readByte(); // Skip the newline character
reply[stringSize] = 0;
}
return reply;
}
bool CustomSaveHelper::fileToStack(const Common::String &filename, StackHandler *sH) {
Variable stringVar;
stringVar.varType = SVT_NULL;
Common::String checker = _saveEncoding ? "[Custom data (encoded)]\r\n" : "[Custom data (ASCII)]\n";
Common::InSaveFile *fp = g_system->getSavefileManager()->openForLoading(filename);
if (fp == NULL) {
// Try looking inside game folder
Common::File *f = new Common::File();
if (!f->open(Common::Path(filename)))
return fatal("No such file", filename); //TODO: false value
fp = f;
// WORKAROUND: For Otto Experiment, when looking for the otto.ini
// for the first time, include CRLF line ending to checker for both encoded and ASCII
// data. This is needed since the original otto.ini that comes with the installer
// have CRLF line ending.
Common::String gameId = g_sludge->getGameId();
if (gameId == "otto") {
checker = _saveEncoding ? "[Custom data (encoded)]\r\n" : "[Custom data (ASCII)]\r\n";
}
}
_encode1 = (byte)_saveEncoding & 255;
_encode2 = (byte)(_saveEncoding >> 8);
for (uint i = 0; i < checker.size(); ++i) {
if (fp->readByte() != checker[i]) {
delete fp;
return fatal(LOAD_ERROR "This isn't a SLUDGE custom data file:", filename);
}
}
if (_saveEncoding) {
checker = readStringEncoded(fp);
if (checker != UTF8_CHECKER) {
delete fp;
return fatal(LOAD_ERROR "The current file encoding setting does not match the encoding setting used when this file was created:", filename);
}
}
for (;;) {
if (_saveEncoding) {
char i = fp->readByte() ^ _encode1;
if (fp->eos())
break;
switch (i) {
case 0: {
Common::String g = readStringEncoded(fp);
stringVar.makeTextVar(g);
}
break;
case 1:
stringVar.setVariable(SVT_INT, fp->readUint32LE());
break;
case 2:
stringVar.setVariable(SVT_INT, fp->readByte());
break;
default:
fatal(LOAD_ERROR "Corrupt custom data file:", filename);
delete fp;
return false;
}
} else {
char *line = readTextPlain(fp);
if (!line)
break;
stringVar.makeTextVar(line);
}
if (sH->first == NULL) {
// Adds to the TOP of the array... oops!
if (!addVarToStackQuick(stringVar, sH->first))
return false;
sH->last = sH->first;
} else {
// Adds to the END of the array... much better
if (!addVarToStackQuick(stringVar, sH->last->next))
return false;
sH->last = sH->last->next;
}
}
delete fp;
return true;
}
bool CustomSaveHelper::stackToFile(const Common::String &filename, const Variable &from) {
Common::OutSaveFile *fp = g_system->getSavefileManager()->openForSaving(filename);
if (fp == NULL) {
return fatal("Can't create file", filename);
}
VariableStack *hereWeAre = from.varData.theStack -> first;
_encode1 = (byte)_saveEncoding & 255;
_encode2 = (byte)(_saveEncoding >> 8);
if (_saveEncoding) {
fp->writeString("[Custom data (encoded)]\r\n");
writeStringEncoded(UTF8_CHECKER, fp);
} else {
fp->writeString("[Custom data (ASCII)]\n");
}
while (hereWeAre) {
if (_saveEncoding) {
switch (hereWeAre -> thisVar.varType) {
case SVT_STRING:
fp->writeByte(_encode1);
writeStringEncoded(hereWeAre -> thisVar.varData.theString, fp);
break;
case SVT_INT:
// Small enough to be stored as a char
if (hereWeAre -> thisVar.varData.intValue >= 0 && hereWeAre -> thisVar.varData.intValue < 256) {
fp->writeByte(2 ^ _encode1);
fp->writeByte(hereWeAre -> thisVar.varData.intValue);
} else {
fp->writeByte(1 ^ _encode1);
fp->writeUint32LE(hereWeAre -> thisVar.varData.intValue);
}
break;
default:
fatal("Can't create an encoded custom data file containing anything other than numbers and strings", filename);
delete fp;
return false;
}
} else {
Common::String makeSureItsText = hereWeAre->thisVar.getTextFromAnyVar();
fp->writeString((makeSureItsText + "\n").c_str());
}
hereWeAre = hereWeAre -> next;
}
delete fp;
return true;
}
} // End of namespace Sludge

49
engines/sludge/savedata.h Normal file
View File

@@ -0,0 +1,49 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef SLUDGE_SAVEDATA_H
#define SLUDGE_SAVEDATA_H
namespace Sludge {
struct StackHandler;
struct Variable;
class CustomSaveHelper {
public:
static bool fileToStack(const Common::String &filename, StackHandler *sH);
static bool stackToFile(const Common::String &filename, const Variable &from);
static uint16 _saveEncoding;
private:
static const char UTF8_CHECKER[];
static char _encode1;
static char _encode2;
static void writeStringEncoded(const Common::String &checker, Common::WriteStream *stream);
static Common::String readStringEncoded(Common::SeekableReadStream *fp);
static char *readTextPlain(Common::SeekableReadStream *fp);
};
} // End of namespace Sludge
#endif

357
engines/sludge/saveload.cpp Normal file
View File

@@ -0,0 +1,357 @@
/* 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/system.h"
#include "common/savefile.h"
#include "engines/metaengine.h"
#include "sludge/cursors.h"
#include "sludge/errors.h"
#include "sludge/event.h"
#include "sludge/floor.h"
#include "sludge/fonttext.h"
#include "sludge/function.h"
#include "sludge/graphics.h"
#include "sludge/language.h"
#include "sludge/newfatal.h"
#include "sludge/people.h"
#include "sludge/region.h"
#include "sludge/savedata.h"
#include "sludge/saveload.h"
#include "sludge/sludge.h"
#include "sludge/sludger.h"
#include "sludge/sound.h"
#include "sludge/statusba.h"
#include "sludge/speech.h"
#include "sludge/version.h"
namespace Sludge {
//----------------------------------------------------------------------
// From elsewhere
//----------------------------------------------------------------------
extern LoadedFunction *saverFunc; // In function.cpp
extern LoadedFunction *allRunningFunctions; // In sludger.cpp
extern int numGlobals; // In sludger.cpp
extern Variable *globalVars; // In sludger.cpp
extern FILETIME fileTime; // In sludger.cpp
extern bool allowAnyFilename;
//----------------------------------------------------------------------
// Save everything
//----------------------------------------------------------------------
bool handleSaveLoad() {
if (!g_sludge->loadNow.empty()) {
if (g_sludge->loadNow[0] == ':') {
Common::String saveName = g_sludge->loadNow.c_str() + 1;
uint extensionLength = saveName.size() - saveName.rfind('.');
saveName = saveName.substr(0, saveName.size() - extensionLength);
int slot = -1;
if (g_sludge->_saveNameToSlot.contains(saveName)) {
slot = g_sludge->_saveNameToSlot[saveName];
} else {
// Find next available save slot
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
int maxSaveSlot = g_sludge->getMetaEngine()->getMaximumSaveSlot();
int autosaveSlot = g_sludge->getMetaEngine()->getAutosaveSlot();
for (int i = 0; i <= maxSaveSlot; ++i) {
if (i == autosaveSlot)
continue;
const Common::String filename = g_sludge->getMetaEngine()->getSavegameFile(i, g_sludge->getTargetName().c_str());
if (!saveFileMan->exists(filename)) {
slot = i;
break;
} else {
// If the game uses only one save for everything (like robinsresque)
// use that save
Common::InSaveFile *fp = g_system->getSavefileManager()->openForLoading(filename);
ExtendedSavegameHeader header;
if (MetaEngine::readSavegameHeader(fp, &header)) {
if (saveName == header.description) {
slot = i;
g_sludge->_saveNameToSlot[saveName] = slot;
delete fp;
break;
}
}
delete fp;
}
}
if (slot == -1) {
slot = g_sludge->getMetaEngine()->getMaximumSaveSlot();
}
}
g_sludge->saveGameState(slot, saveName, false);
saverFunc->reg.setVariable(SVT_INT, 1);
} else {
if (!loadGame(g_sludge->loadNow))
return false;
}
g_sludge->loadNow.clear();
}
return true;
}
bool saveGame(Common::OutSaveFile *saveFile) {
if (saveFile == NULL)
return false;
saveFile->writeString("SLUDSA");
saveFile->writeByte(0);
saveFile->writeByte(0);
saveFile->writeByte(MAJOR_VERSION);
saveFile->writeByte(MINOR_VERSION);
if (!g_sludge->_gfxMan->saveThumbnail(saveFile))
return false;
saveFile->write(&fileTime, sizeof(FILETIME));
// DON'T ADD ANYTHING NEW BEFORE THIS POINT!
saveFile->writeByte(allowAnyFilename);
saveFile->writeByte(false); // deprecated captureAllKeys
saveFile->writeByte(true);
g_sludge->_txtMan->saveFont(saveFile);
// Save backdrop
g_sludge->_gfxMan->saveBackdrop(saveFile);
// Save event handlers
g_sludge->_evtMan->saveHandlers(saveFile);
// Save regions
g_sludge->_regionMan->saveRegions(saveFile);
g_sludge->_cursorMan->saveCursor(saveFile);
// Save functions
LoadedFunction *thisFunction = allRunningFunctions;
int countFunctions = 0;
while (thisFunction) {
countFunctions++;
thisFunction = thisFunction->next;
}
saveFile->writeUint16BE(countFunctions);
thisFunction = allRunningFunctions;
while (thisFunction) {
saveFunction(thisFunction, saveFile);
thisFunction = thisFunction->next;
}
for (int a = 0; a < numGlobals; a++) {
globalVars[a].save(saveFile);
}
g_sludge->_peopleMan->savePeople(saveFile);
g_sludge->_floorMan->save(saveFile);
g_sludge->_gfxMan->saveZBuffer(saveFile);
g_sludge->_gfxMan->saveLightMap(saveFile);
g_sludge->_speechMan->save(saveFile);
g_sludge->_statusBar->saveStatusBars(saveFile);
g_sludge->_soundMan->saveSounds(saveFile);
saveFile->writeUint16BE(CustomSaveHelper::_saveEncoding);
g_sludge->_gfxMan->blur_saveSettings(saveFile);
g_sludge->_gfxMan->saveColors(saveFile);
g_sludge->_gfxMan->saveParallax(saveFile);
saveFile->writeByte(0);
g_sludge->_languageMan->saveLanguageSetting(saveFile);
g_sludge->_gfxMan->saveSnapshot(saveFile);
clearStackLib();
return true;
}
//----------------------------------------------------------------------
// Load everything
//----------------------------------------------------------------------
int ssgVersion;
bool loadGame(const Common::String &fname) {
Common::InSaveFile *fp = g_system->getSavefileManager()->openForLoading(fname);
FILETIME savedGameTime;
while (allRunningFunctions)
finishFunction(allRunningFunctions);
if (fp == NULL)
return false;
bool headerBad = false;
if (fp->readByte() != 'S')
headerBad = true;
if (fp->readByte() != 'L')
headerBad = true;
if (fp->readByte() != 'U')
headerBad = true;
if (fp->readByte() != 'D')
headerBad = true;
if (fp->readByte() != 'S')
headerBad = true;
if (fp->readByte() != 'A')
headerBad = true;
if (headerBad) {
fatal(ERROR_GAME_LOAD_NO, fname);
return false;
}
char c;
c = fp->readByte();
while ((c = fp->readByte()))
;
int majVersion = fp->readByte();
int minVersion = fp->readByte();
ssgVersion = VERSION(majVersion, minVersion);
if (ssgVersion >= VERSION(1, 4)) {
if (!g_sludge->_gfxMan->skipThumbnail(fp))
return fatal(ERROR_GAME_LOAD_CORRUPT, fname);
}
uint32 bytes_read = fp->read(&savedGameTime, sizeof(FILETIME));
if (bytes_read != sizeof(FILETIME) && fp->err()) {
warning("Reading error in loadGame.");
}
if (savedGameTime.dwLowDateTime != fileTime.dwLowDateTime || savedGameTime.dwHighDateTime != fileTime.dwHighDateTime) {
return fatal(ERROR_GAME_LOAD_WRONG, fname);
}
// DON'T ADD ANYTHING NEW BEFORE THIS POINT!
if (ssgVersion >= VERSION(1, 4)) {
allowAnyFilename = fp->readByte();
}
fp->readByte(); // deprecated captureAllKeys
fp->readByte(); // updateDisplay (part of movie playing)
g_sludge->_txtMan->loadFont(ssgVersion, fp);
g_sludge->_regionMan->kill();
g_sludge->_gfxMan->loadBackdrop(ssgVersion, fp);
g_sludge->_evtMan->loadHandlers(fp);
g_sludge->_regionMan->loadRegions(fp);
if (!g_sludge->_cursorMan->loadCursor(fp)) {
return false;
}
LoadedFunction *rFunc;
LoadedFunction **buildList = &allRunningFunctions;
int countFunctions = fp->readUint16BE();
while (countFunctions--) {
rFunc = loadFunction(fp);
rFunc->next = NULL;
(*buildList) = rFunc;
buildList = &(rFunc->next);
}
for (int a = 0; a < numGlobals; a++) {
globalVars[a].unlinkVar();
globalVars[a].load(fp);
}
g_sludge->_peopleMan->loadPeople(fp);
if (!g_sludge->_floorMan->load(fp)) {
return false;
}
if (!g_sludge->_gfxMan->loadZBuffer(fp))
return false;
if (!g_sludge->_gfxMan->loadLightMap(ssgVersion, fp)) {
return false;
}
g_sludge->_speechMan->load(fp);
g_sludge->_statusBar->loadStatusBars(fp);
g_sludge->_soundMan->loadSounds(fp);
CustomSaveHelper::_saveEncoding = fp->readUint16BE();
if (ssgVersion >= VERSION(1, 6)) {
if (ssgVersion < VERSION(2, 0)) {
// aaLoad
fp->readByte();
fp->readFloatLE();
fp->readFloatLE();
}
g_sludge->_gfxMan->blur_loadSettings(fp);
}
if (ssgVersion >= VERSION(1, 3)) {
g_sludge->_gfxMan->loadColors(fp);
// Read parallax layers
while (fp->readByte()) {
int im = fp->readUint16BE();
int fx = fp->readUint16BE();
int fy = fp->readUint16BE();
if (!g_sludge->_gfxMan->loadParallax(im, fx, fy))
return false;
}
g_sludge->_languageMan->loadLanguageSetting(fp);
}
g_sludge->_gfxMan->nosnapshot();
if (ssgVersion >= VERSION(1, 4)) {
if (fp->readByte()) {
if (!g_sludge->_gfxMan->restoreSnapshot(fp))
return false;
}
}
ExtendedSavegameHeader header;
if (MetaEngine::readSavegameHeader(fp, &header))
g_sludge->setTotalPlayTime(header.playtime);
delete fp;
clearStackLib();
return true;
}
} // End of namespace Sludge

36
engines/sludge/saveload.h Normal file
View File

@@ -0,0 +1,36 @@
/* 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 SLUDGE_LOADSAVE_H
#define SLUDGE_LOADSAVE_H
namespace Common {
class OutSaveFile;
}
namespace Sludge {
bool handleSaveLoad();
bool saveGame(Common::OutSaveFile *saveFile);
bool loadGame(const Common::String &fname);
} // End of namespace Sludge
#endif

204
engines/sludge/sludge.cpp Normal file
View File

@@ -0,0 +1,204 @@
/* 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/config-manager.h"
#include "common/debug-channels.h"
#include "common/error.h"
#include "common/random.h"
#include "common/savefile.h"
#include "engines/metaengine.h"
#include "sludge/cursors.h"
#include "sludge/debugger.h"
#include "sludge/event.h"
#include "sludge/fileset.h"
#include "sludge/fonttext.h"
#include "sludge/floor.h"
#include "sludge/function.h"
#include "sludge/graphics.h"
#include "sludge/language.h"
#include "sludge/main_loop.h"
#include "sludge/newfatal.h"
#include "sludge/objtypes.h"
#include "sludge/people.h"
#include "sludge/region.h"
#include "sludge/saveload.h"
#include "sludge/sludge.h"
#include "sludge/sound.h"
#include "sludge/speech.h"
#include "sludge/statusba.h"
#include "sludge/timing.h"
namespace Sludge {
extern LoadedFunction *allRunningFunctions; // In function.cpp
SludgeEngine *g_sludge;
Graphics::PixelFormat *SludgeEngine::getScreenPixelFormat() const { return _pixelFormat; }
Graphics::PixelFormat *SludgeEngine::getOrigPixelFormat() const { return _origFormat; }
SludgeEngine::SludgeEngine(OSystem *syst, const SludgeGameDescription *gameDesc) :
Engine(syst), _gameDescription(gameDesc) {
// register your random source
_rnd = new Common::RandomSource("sludge");
//DebugMan.enableDebugChannel("loading");
//DebugMan.enableDebugChannel("builtin");
_dumpScripts = ConfMan.getBool("dump_scripts");
// init graphics
_origFormat = new Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
_pixelFormat = new Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
// Init Strings
launchNext = "";
loadNow = "";
gamePath = "";
// Init managers
_timer = new Timer();
_fatalMan = new FatalMsgManager();
_peopleMan = new PeopleManager(this);
_resMan = new ResourceManager();
_languageMan = new LanguageManager();
_objMan = new ObjectManager(this);
_gfxMan = new GraphicsManager(this);
_evtMan = new EventManager(this);
_soundMan = new SoundManager();
_txtMan = new TextManager();
_cursorMan = new CursorManager(this);
_speechMan = new SpeechManager(this);
_regionMan = new RegionManager(this);
_floorMan = new FloorManager(this);
_statusBar = new StatusBarManager(this);
}
SludgeEngine::~SludgeEngine() {
// Dispose resources
delete _rnd;
_rnd = nullptr;
// Dispose pixel formats
delete _origFormat;
_origFormat = nullptr;
delete _pixelFormat;
_pixelFormat = nullptr;
// Dispose managers
delete _cursorMan;
_cursorMan = nullptr;
delete _txtMan;
_txtMan = nullptr;
delete _soundMan;
_soundMan = nullptr;
delete _evtMan;
_evtMan = nullptr;
delete _gfxMan;
_gfxMan = nullptr;
delete _objMan;
_objMan = nullptr;
delete _languageMan;
_languageMan = nullptr;
delete _resMan;
_resMan = nullptr;
delete _speechMan;
_speechMan = nullptr;
delete _regionMan;
_regionMan = nullptr;
delete _peopleMan;
_peopleMan = nullptr;
delete _floorMan;
_floorMan = nullptr;
delete _fatalMan;
_fatalMan = nullptr;
delete _statusBar;
delete _timer;
}
bool SludgeEngine::canLoadGameStateCurrently(Common::U32String *msg) {
return !g_sludge->_evtMan->quit();
}
bool SludgeEngine::canSaveGameStateCurrently(Common::U32String *msg) {
if (g_sludge->_evtMan->quit())
return false;
if (g_sludge->_gfxMan->isFrozen()) {
return false;
}
Sludge::LoadedFunction *thisFunction = allRunningFunctions;
while (thisFunction) {
if (thisFunction->freezerLevel)
return false;
thisFunction = thisFunction->next;
}
return true;
}
Common::Error SludgeEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
Common::OutSaveFile *saveFile = _saveFileMan->openForSaving(getSaveStateName(slot));
if (!saveFile)
return Common::kWritingFailed;
Common::Error result = saveGame(saveFile) ? Common::kNoError : Common::kWritingFailed;
if (result.getCode() == Common::kNoError) {
getMetaEngine()->appendExtendedSave(saveFile, getTotalPlayTime(), desc, isAutosave);
saveFile->finalize();
}
delete saveFile;
return result;
}
Common::Error SludgeEngine::loadGameState(int slot) {
saveAutosaveIfEnabled();
Common::Error result = loadGame(getSaveStateName(slot)) ? Common::kNoError : Common::kReadingFailed;
return result;
}
bool SludgeEngine::hasFeature(EngineFeature f) const {
return (f == kSupportsReturnToLauncher) ||
(f == kSupportsLoadingDuringRuntime) ||
(f == kSupportsSavingDuringRuntime);
}
Common::Error SludgeEngine::run() {
// set global variable
g_sludge = this;
setDebugger(new Debugger(this));
// debug log
main_loop(getGameFile());
return Common::kNoError;
}
} // End of namespace Sludge

138
engines/sludge/sludge.h Normal file
View File

@@ -0,0 +1,138 @@
/* 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 SLUDGE_SLUDGE_H
#define SLUDGE_SLUDGE_H
#include "common/hash-str.h"
#include "engines/engine.h"
namespace Common {
class RandomSource;
}
namespace Graphics {
struct PixelFormat;
}
namespace Sludge {
class CursorManager;
class EventManager;
class FatalMsgManager;
class FloorManager;
class GraphicsManager;
class LanguageManager;
class ObjectManager;
class PeopleManager;
class ResourceManager;
class RegionManager;
class SoundManager;
class SpeechManager;
class StatusBarManager;
class TextManager;
class Timer;
struct SludgeGameDescription;
#define IN_THE_CENTRE 65535
// debug channels
enum {
kSludgeDebugFatal = 1,
kSludgeDebugDataLoad,
kSludgeDebugStackMachine,
kSludgeDebugBuiltin,
kSludgeDebugGraphics,
kSludgeDebugZBuffer,
kSludgeDebugSound,
};
class SludgeEngine: public Engine {
protected:
// Engine APIs
Common::Error run() override;
public:
// global String variables
Common::String launchNext;
Common::String loadNow;
Common::String gamePath;
// timer
Timer *_timer;
// managers
ResourceManager *_resMan;
LanguageManager *_languageMan;
ObjectManager *_objMan;
GraphicsManager *_gfxMan;
EventManager *_evtMan;
SoundManager *_soundMan;
TextManager *_txtMan;
CursorManager *_cursorMan;
SpeechManager *_speechMan;
RegionManager *_regionMan;
PeopleManager *_peopleMan;
FloorManager *_floorMan;
FatalMsgManager *_fatalMan;
StatusBarManager *_statusBar;
bool _dumpScripts;
SludgeEngine(OSystem *syst, const SludgeGameDescription *gameDesc);
~SludgeEngine() override;
uint getLanguageID() const;
const char *getGameId() const;
uint32 getFeatures() const;
Common::String getTargetName() const { return _targetName; }
Common::Language getLanguage() const;
Graphics::PixelFormat *getScreenPixelFormat() const;
Graphics::PixelFormat *getOrigPixelFormat() const;
Common::RandomSource *getRandomSource() const { return _rnd; };
const char *getGameFile() const;
bool hasFeature(EngineFeature f) const override;
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave) override;
Common::Error loadGameState(int slot) override;
const SludgeGameDescription *_gameDescription;
Common::HashMap<Common::String, int> _saveNameToSlot;
private:
Common::RandomSource *_rnd;
Graphics::PixelFormat *_pixelFormat;
Graphics::PixelFormat *_origFormat;
};
extern SludgeEngine *g_sludge;
} // End of namespace Sludge
#endif

306
engines/sludge/sludger.cpp Normal file
View File

@@ -0,0 +1,306 @@
/* 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/config-manager.h"
#include "sludge/cursors.h"
#include "sludge/errors.h"
#include "sludge/event.h"
#include "sludge/fonttext.h"
#include "sludge/floor.h"
#include "sludge/fileset.h"
#include "sludge/function.h"
#include "sludge/graphics.h"
#include "sludge/imgloader.h"
#include "sludge/language.h"
#include "sludge/moreio.h"
#include "sludge/newfatal.h"
#include "sludge/objtypes.h"
#include "sludge/people.h"
#include "sludge/region.h"
#include "sludge/savedata.h"
#include "sludge/sludge.h"
#include "sludge/sludger.h"
#include "sludge/sound.h"
#include "sludge/speech.h"
#include "sludge/statusba.h"
#include "sludge/timing.h"
#include "sludge/version.h"
namespace Sludge {
extern int numBIFNames;
extern Common::String *allBIFNames;
extern int numUserFunc;
extern Common::String *allUserFunc;
int selectedLanguage = 0;
int gameVersion;
FILETIME fileTime;
int numGlobals = 0;
extern Variable *globalVars;
extern VariableStack *noStack;
extern bool allowAnyFilename;
Common::File *openAndVerify(const Common::String &filename, char extra1, char extra2,
const char *er, int &fileVersion) {
Common::File *fp = new Common::File();
if (!fp->open(Common::Path(filename))) {
fatal("Can't open file", filename);
return NULL;
}
bool headerBad = false;
if (fp->readByte() != 'S')
headerBad = true;
if (fp->readByte() != 'L')
headerBad = true;
if (fp->readByte() != 'U')
headerBad = true;
if (fp->readByte() != 'D')
headerBad = true;
if (fp->readByte() != extra1)
headerBad = true;
if (fp->readByte() != extra2)
headerBad = true;
if (headerBad) {
fatal(er, filename);
return NULL;
}
char c;
c = fp->readByte();
while ((c = fp->readByte()))
;
int majVersion = fp->readByte();
debugC(2, kSludgeDebugDataLoad, "majVersion %i", majVersion);
int minVersion = fp->readByte();
debugC(2, kSludgeDebugDataLoad, "minVersion %i", minVersion);
fileVersion = majVersion * 256 + minVersion;
Common::String txtVer = "";
if (fileVersion > WHOLE_VERSION) {
txtVer = Common::String::format(ERROR_VERSION_TOO_LOW_2, majVersion, minVersion);
fatal(ERROR_VERSION_TOO_LOW_1, txtVer);
return NULL;
} else if (fileVersion < MINIM_VERSION) {
txtVer = Common::String::format(ERROR_VERSION_TOO_HIGH_2, majVersion, minVersion);
fatal(ERROR_VERSION_TOO_HIGH_1, txtVer);
return NULL;
}
return fp;
}
void initSludge() {
g_sludge->_timer->reset();
g_sludge->_languageMan->init();
g_sludge->_gfxMan->init();
g_sludge->_resMan->init();
g_sludge->_peopleMan->init();
g_sludge->_floorMan->init();
g_sludge->_objMan->init();
g_sludge->_speechMan->init();
g_sludge->_statusBar->init();
g_sludge->_evtMan->init();
g_sludge->_txtMan->init();
g_sludge->_cursorMan->init();
g_sludge->_soundMan->init();
if (!ConfMan.hasKey("mute") || !ConfMan.getBool("mute")) {
g_sludge->_soundMan->initSoundStuff();
}
CustomSaveHelper::_saveEncoding = false;
// global variables
numGlobals = 0;
allowAnyFilename = true;
noStack = nullptr;
numBIFNames = numUserFunc = 0;
allUserFunc = allBIFNames = nullptr;
}
void killSludge() {
killAllFunctions();
g_sludge->_speechMan->kill();
g_sludge->_peopleMan->kill();
g_sludge->_regionMan->kill();
g_sludge->_floorMan->kill();
g_sludge->_languageMan->kill();
g_sludge->_gfxMan->kill();
g_sludge->_resMan->kill();
g_sludge->_objMan->kill();
g_sludge->_soundMan->killSoundStuff();
g_sludge->_evtMan->kill();
g_sludge->_txtMan->kill();
g_sludge->_cursorMan->kill();
// global variables
numBIFNames = numUserFunc = 0;
delete []allUserFunc;
delete []allBIFNames;
}
bool initSludge(const Common::String &filename) {
initSludge();
Common::File *fp = openAndVerify(filename, 'G', 'E', ERROR_BAD_HEADER, gameVersion);
if (!fp)
return false;
char c = fp->readByte();
if (c) {
numBIFNames = fp->readUint16BE();
debugC(2, kSludgeDebugDataLoad, "numBIFNames %i", numBIFNames);
allBIFNames = new Common::String[numBIFNames];
if (!checkNew(allBIFNames)) {
delete fp;
return false;
}
for (int fn = 0; fn < numBIFNames; fn++) {
allBIFNames[fn].clear();
allBIFNames[fn] = readString(fp);
}
numUserFunc = fp->readUint16BE();
debugC(2, kSludgeDebugDataLoad, "numUserFunc %i", numUserFunc);
allUserFunc = new Common::String[numUserFunc];
if (!checkNew(allUserFunc)) {
delete fp;
return false;
}
for (int fn = 0; fn < numUserFunc; fn++) {
allUserFunc[fn].clear();
allUserFunc[fn] = readString(fp);
}
if (gameVersion >= VERSION(1, 3)) {
g_sludge->_resMan->readResourceNames(fp);
}
}
int winWidth = fp->readUint16BE();
debugC(2, kSludgeDebugDataLoad, "winWidth : %i", winWidth);
int winHeight = fp->readUint16BE();
debugC(2, kSludgeDebugDataLoad, "winHeight : %i", winHeight);
g_sludge->_gfxMan->setWindowSize(winWidth, winHeight);
int specialSettings = fp->readByte();
debugC(2, kSludgeDebugDataLoad, "specialSettings : %i", specialSettings);
g_sludge->_timer->setDesiredFPS(1000 / fp->readByte());
readString(fp); // Unused - was used for registration purposes.
uint bytes_read = fp->read(&fileTime, sizeof(FILETIME));
if (bytes_read != sizeof(FILETIME) && fp->err()) {
debug(0, "Reading error in initSludge.");
}
Common::String dataFol = (gameVersion >= VERSION(1, 3)) ? readString(fp) : "";
debugC(2, kSludgeDebugDataLoad, "dataFol : %s", dataFol.c_str());
g_sludge->_languageMan->createTable(fp);
if (gameVersion >= VERSION(1, 6)) {
fp->readByte();
// aaLoad
fp->readByte();
fp->readFloatLE();
fp->readFloatLE();
}
Common::String checker = readString(fp);
debugC(2, kSludgeDebugDataLoad, "checker : %s", checker.c_str());
if (checker != "okSoFar")
return fatal(ERROR_BAD_HEADER, filename);
byte customIconLogo = fp->readByte();
debugC(2, kSludgeDebugDataLoad, "Game icon type: %i", customIconLogo);
if (customIconLogo & 1) {
// There is an icon - read it!
debugC(2, kSludgeDebugDataLoad, "There is an icon - read it!");
// read game icon
Graphics::Surface gameIcon;
if (!ImgLoader::loadImage(-1, "icon", fp, &gameIcon, false)) {
delete fp;
return false;
}
}
if (customIconLogo & 2) {
// There is a logo - read it!
debugC(2, kSludgeDebugDataLoad, "There is a logo - read it!");
// read game logo
Graphics::Surface gameLogo;
if (!ImgLoader::loadImage(-1, "logo", fp, &gameLogo)) {
delete fp;
return false;
}
}
numGlobals = fp->readUint16BE();
debugC(2, kSludgeDebugDataLoad, "numGlobals : %i", numGlobals);
globalVars = new Variable[numGlobals];
if (!checkNew(globalVars)) {
delete fp;
return false;
}
// Get language selected by user
g_sludge->_resMan->setData(fp);
g_sludge->_languageMan->setLanguageID(g_sludge->getLanguageID());
if (!dataFol.empty()) {
Common::String dataFolder = encodeFilename(dataFol);
}
g_sludge->_statusBar->positionStatus(10, winHeight - 15);
return true;
}
void displayBase() {
g_sludge->_gfxMan->clear(); // Clear screen
g_sludge->_gfxMan->drawBackDrop();// Draw Backdrop
g_sludge->_gfxMan->drawZBuffer(g_sludge->_gfxMan->getCamX(), g_sludge->_gfxMan->getCamY(), false);
g_sludge->_peopleMan->drawPeople();// Then add any moving characters...
}
void sludgeDisplay() {
displayBase();
g_sludge->_speechMan->display();
g_sludge->_statusBar->draw();
g_sludge->_cursorMan->displayCursor();
g_sludge->_gfxMan->display();
}
} // End of namespace Sludge

44
engines/sludge/sludger.h Normal file
View File

@@ -0,0 +1,44 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef SLUDGER_H
#define SLUDGER_H
#include "common/file.h"
namespace Sludge {
typedef struct _FILETIME {
uint32 dwLowDateTime;
uint32 dwHighDateTime;
} FILETIME;
bool initSludge(const Common::String &);
void initSludge();
void killSludge();
void displayBase();
void sludgeDisplay();
Common::File *openAndVerify(const Common::String &filename, char extra1, char extra2, const char *er, int &fileVersion);
} // End of namespace Sludge
#endif

606
engines/sludge/sound.cpp Normal file
View File

@@ -0,0 +1,606 @@
/* 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 "audio/audiostream.h"
#include "audio/decoders/wave.h"
#include "audio/decoders/mp3.h"
#include "audio/decoders/vorbis.h"
#include "audio/mods/mod_xm_s3m.h"
#include "audio/mods/universaltracker.h"
#include "sludge/errors.h"
#include "sludge/fileset.h"
#include "sludge/newfatal.h"
#include "sludge/sludge.h"
#include "sludge/sound.h"
#include "sludge/variable.h"
namespace Sludge {
const int SoundManager::MAX_SAMPLES = 8;
const int SoundManager::MAX_MODS = 3;
SoundManager::SoundManager() {
_soundCache = nullptr;
_soundCache = new SoundThing[MAX_SAMPLES];
_modCache = nullptr;
_modCache = new SoundThing[MAX_MODS];
init();
}
SoundManager::~SoundManager() {
killSoundStuff();
delete []_soundCache;
_soundCache = nullptr;
delete []_modCache;
_modCache = nullptr;
}
void SoundManager::init() {
// there's possibility that several sound list played at the same time
_soundListHandles.clear();
_soundOK = false;
_silenceIKillYou = false;
_isHandlingSoundList = false;
_defVol = 128;
_defSoundVol = 255;
_modLoudness = 0.95f;
_emptySoundSlot = 0;
}
bool SoundManager::initSoundStuff() {
for (int a = 0; a < MAX_SAMPLES; ++a) {
_soundCache[a].fileLoaded = -1;
_soundCache[a].looping = false;
_soundCache[a].inSoundList = false;
}
for (int a = 0; a < MAX_MODS; ++a) {
_modCache[a].fileLoaded = -1;
_modCache[a].looping = false;
_modCache[a].inSoundList = false;
}
return _soundOK = true;
}
void SoundManager::killSoundStuff() {
if (!_soundOK)
return;
for (int i = 0; i < MAX_SAMPLES; ++i)
freeSound(i);
for (int i = 0; i < MAX_MODS; ++i)
stopMOD(i);
}
/*
* Some setters:
*/
void SoundManager::setMusicVolume(int a, int v) {
if (!_soundOK)
return;
if (g_sludge->_mixer->isSoundHandleActive(_modCache[a].handle)) {
_modCache[a].vol = v;
g_sludge->_mixer->setChannelVolume(_modCache[a].handle, _modLoudness * v);
}
}
void SoundManager::setDefaultMusicVolume(int v) {
_defVol = v;
}
void SoundManager::setSoundVolume(int a, int v) {
if (!_soundOK)
return;
int ch = findInSoundCache(a);
if (ch != -1) {
if (g_sludge->_mixer->isSoundHandleActive(_soundCache[ch].handle)) {
_soundCache[ch].vol = v;
g_sludge->_mixer->setChannelVolume(_soundCache[ch].handle, v);
}
}
}
void SoundManager::setDefaultSoundVolume(int v) {
_defSoundVol = v;
}
void SoundManager::setSoundLoop(int a, int s, int e) {
//#pragma unused (a,s,e)
}
int SoundManager::findInSoundCache(int a) {
int i;
for (i = 0; i < MAX_SAMPLES; i++) {
if (_soundCache[i].fileLoaded == a) {
return i;
}
}
return -1;
}
void SoundManager::stopMOD(int i) {
if (!_soundOK)
return;
if (_modCache[i].fileLoaded >= 0) {
if (g_sludge->_mixer->isSoundHandleActive(_modCache[i].handle)) {
g_sludge->_mixer->stopHandle(_modCache[i].handle);
}
}
_modCache[i].fileLoaded = -1;
}
void SoundManager::huntKillSound(int filenum) {
if (!_soundOK)
return;
int gotSlot = findInSoundCache(filenum);
if (gotSlot == -1)
return;
freeSound(gotSlot);
}
void SoundManager::freeSound(int a) {
if (!_soundOK)
return;
_silenceIKillYou = true;
if (_soundCache[a].fileLoaded >= 0) {
if (g_sludge->_mixer->isSoundHandleActive(_soundCache[a].handle)) {
g_sludge->_mixer->stopHandle(_soundCache[a].handle);
if (_soundCache[a].inSoundList)
handleSoundLists();
}
}
_soundCache[a].inSoundList = false;
_soundCache[a].looping = false;
_soundCache[a].fileLoaded = -1;
_silenceIKillYou = false;
}
void SoundManager::huntKillFreeSound(int filenum) {
if (!_soundOK)
return;
int gotSlot = findInSoundCache(filenum);
if (gotSlot == -1)
return;
freeSound(gotSlot);
}
/*
* Loading and playing:
*/
bool SoundManager::playMOD(int f, int a, int fromTrack) {
if (!_soundOK)
return true;
stopMOD(a);
// load sound
setResourceForFatal(f);
uint length = g_sludge->_resMan->openFileFromNum(f);
if (length == 0) {
g_sludge->_resMan->finishAccess();
setResourceForFatal(-1);
return false;
}
g_sludge->_resMan->dumpFile(f, "music%04d.xm");
// make audio stream
Common::SeekableReadStream *readStream = g_sludge->_resMan->getData();
Common::SeekableReadStream *memImage = readStream->readStream(length);
if (memImage->size() != (int)length || readStream->err()) {
return fatal("SoundManager::playMOD(): Sound reading failed");
}
Audio::RewindableAudioStream *mod = nullptr;
if (Audio::probeModXmS3m(memImage)) {
mod = Audio::makeModXmS3mStream(memImage, DisposeAfterUse::NO, fromTrack);
if (mod) {
delete memImage;
}
}
if (!mod) {
mod = Audio::makeUniversalTrackerStream(memImage, DisposeAfterUse::YES);
}
if (!mod) {
warning("Could not load MOD file");
g_sludge->_resMan->finishAccess();
return false;
}
Audio::LoopingAudioStream *stream = new Audio::LoopingAudioStream(mod, 0, DisposeAfterUse::YES, false);
if (stream) {
// play sound
_modCache[a].fileLoaded = f;
_modCache[a].vol = _defVol;
g_sludge->_mixer->playStream(Audio::Mixer::kMusicSoundType, &_modCache[a].handle, stream, -1, _modCache[a].vol);
} else {
_modCache[a].fileLoaded = -1;
}
g_sludge->_resMan->finishAccess();
setResourceForFatal(-1);
return true;
}
bool SoundManager::stillPlayingSound(int ch) {
if (_soundOK)
if (ch != -1)
if (_soundCache[ch].fileLoaded != -1)
if (g_sludge->_mixer->isSoundHandleActive(_soundCache[ch].handle))
return true;
return false;
}
bool SoundManager::forceRemoveSound() {
for (int a = 0; a < MAX_SAMPLES; a++) {
if (_soundCache[a].fileLoaded != -1) {
freeSound(a);
return 1;
}
}
return 0;
}
int SoundManager::findEmptySoundSlot() {
for (int t = 0; t < MAX_SAMPLES; t++) {
_emptySoundSlot++;
_emptySoundSlot %= MAX_SAMPLES;
if (!g_sludge->_mixer->isSoundHandleActive(_soundCache[_emptySoundSlot].handle) && !_soundCache[_emptySoundSlot].inSoundList)
return _emptySoundSlot;
}
// Argh! They're all playing! Let's trash the oldest that's not looping...
for (int t = 0; t < MAX_SAMPLES; t++) {
_emptySoundSlot++;
_emptySoundSlot %= MAX_SAMPLES;
if (!_soundCache[_emptySoundSlot].looping && !_soundCache[_emptySoundSlot].inSoundList)
return _emptySoundSlot;
}
// Holy crap, they're all looping! What's this twat playing at?
_emptySoundSlot++;
_emptySoundSlot %= MAX_SAMPLES;
return _emptySoundSlot;
}
int SoundManager::cacheSound(int f) {
return 0; // don't load source in advance
}
int SoundManager::makeSoundAudioStream(int f, Audio::AudioStream *&audiostream, bool loopy) {
if (!_soundOK)
return -1;
int a = findInSoundCache(f);
if (a == -1) {
if (f == -2)
return -1;
a = findEmptySoundSlot();
}
freeSound(a);
setResourceForFatal(f);
uint32 length = g_sludge->_resMan->openFileFromNum(f);
if (!length)
return -1;
g_sludge->_resMan->dumpFile(f, "sound%04d.ogg");
Common::SeekableReadStream *readStream = g_sludge->_resMan->getData();
uint curr_ptr = readStream->pos();
uint32 tag = readStream->readUint32BE();
readStream->seek(curr_ptr);
Audio::RewindableAudioStream *stream = nullptr;
switch (tag) {
case MKTAG('R','I','F','F'):
stream = Audio::makeWAVStream(readStream->readStream(length), DisposeAfterUse::YES);
break;
case MKTAG('O','g','g','S'):
#ifdef USE_VORBIS
stream = Audio::makeVorbisStream(readStream->readStream(length), DisposeAfterUse::YES);
#endif
break;
default:
// TODO: Detect this correctly
#ifdef USE_MAD
stream = Audio::makeMP3Stream(readStream->readStream(length), DisposeAfterUse::YES);
#endif
break;
}
g_sludge->_resMan->finishAccess();
if (stream) {
audiostream = Audio::makeLoopingAudioStream(stream, loopy ? 0 : 1);
_soundCache[a].fileLoaded = f;
_soundCache[a].looping = loopy;
setResourceForFatal(-1);
} else {
audiostream = nullptr;
warning("SoundManager::makeSoundAudioStream(): Unsupported sound format %s", tag2str(tag));
_soundCache[a].fileLoaded = -1;
_soundCache[a].looping = false;
return -1;
}
return a;
}
bool SoundManager::startSound(int f, bool loopy) {
if (_soundOK) {
// Load sound
Audio::AudioStream *stream = nullptr;
int a = makeSoundAudioStream(f, stream, loopy);
if (a == -1) {
warning("Failed to cache sound!");
return false;
}
// play sound
_soundCache[a].looping = loopy;
_soundCache[a].vol = _defSoundVol;
g_sludge->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundCache[a].handle, stream, -1, _soundCache[a].vol);
}
return true;
}
void SoundManager::saveSounds(Common::WriteStream *stream) {
if (_soundOK) {
for (int i = 0; i < MAX_SAMPLES; i++) {
if (_soundCache[i].looping) {
stream->writeByte(1);
stream->writeUint16BE(_soundCache[i].fileLoaded);
stream->writeUint16BE(_soundCache[i].vol);
}
}
}
stream->writeByte(0);
stream->writeUint16BE(_defSoundVol);
stream->writeUint16BE(_defVol);
}
void SoundManager::loadSounds(Common::SeekableReadStream *stream) {
for (int i = 0; i < MAX_SAMPLES; i++)
freeSound(i);
while (stream->readByte()) {
int fileLoaded = stream->readUint16BE();
_defSoundVol = stream->readUint16BE();
startSound(fileLoaded, 1);
}
_defSoundVol = stream->readUint16BE();
_defVol = stream->readUint16BE();
}
bool SoundManager::getSoundCacheStack(StackHandler *sH) {
Variable newFileHandle;
newFileHandle.varType = SVT_NULL;
for (int a = 0; a < MAX_SAMPLES; a++) {
if (_soundCache[a].fileLoaded != -1) {
newFileHandle.setVariable(SVT_FILE, _soundCache[a].fileLoaded);
if (!addVarToStackQuick(newFileHandle, sH->first))
return false;
if (sH->last == NULL)
sH->last = sH->first;
}
}
return true;
}
bool SoundManager::deleteSoundFromList(SoundList*&s) {
// Don't delete a playing sound.
if (s->cacheIndex)
return false;
SoundList*o = NULL;
if (!s->next) {
o = s->prev;
if (o)
o->next = NULL;
delete s;
s = o;
return (s != NULL);
}
if (s != s->next) {
o = s->next;
o->prev = s->prev;
if (o->prev)
o->prev->next = o;
}
delete s;
s = o;
return (s != NULL);
}
void SoundManager::handleSoundLists() {
if (_isHandlingSoundList)
return;
_isHandlingSoundList = true;
for (SoundListHandles::iterator it = _soundListHandles.begin(); it != _soundListHandles.end(); ++it) {
SoundList*s = (*it);
int a = s->cacheIndex;
bool remove = false;
if (!g_sludge->_mixer->isSoundHandleActive(_soundCache[a].handle)) { // reach the end of stream
s->cacheIndex = false;
_soundCache[a].inSoundList = false;
if (_silenceIKillYou) {
while (deleteSoundFromList(s))
;
remove = (s == NULL); // s not null if still playing
} else {
if (s->next) {
if (s->next == s) { // loop the same sound
int v = _defSoundVol;
_defSoundVol = _soundCache[a].vol;
startSound(s->sound, true);
_defSoundVol = v;
while (deleteSoundFromList(s))
;
remove = (s == NULL); // s not null if still playing
} else { // repush the next sound list
s->next->vol = _soundCache[a].vol;
playSoundList(s->next);
remove = true; // remove this one
}
} else {
while (deleteSoundFromList(s))
;
remove = (s == NULL); // s not null if still playing
}
}
}
if (remove) {
it = _soundListHandles.reverse_erase(it);
}
}
_isHandlingSoundList = false;
}
// loop a list of sound
void SoundManager::playSoundList(SoundList*s) {
if (_soundOK) {
// Load sound
Audio::AudioStream *stream;
int a = makeSoundAudioStream(s->sound, stream, false);
if (a == -1) {
warning("Failed to cache sound!");
return;
}
// Play sound
_soundCache[a].looping = false;
if (s->vol < 0)
_soundCache[a].vol = _defSoundVol;
else
_soundCache[a].vol = s->vol;
s-> cacheIndex = a;
g_sludge->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundCache[a].handle, stream, -1, _soundCache[a].vol);
_soundCache[a].inSoundList = true;
// push sound list
_soundListHandles.push_back(s);
}
}
void playMovieStream(int a) {
#if 0
if (! soundOK) return;
ALboolean ok;
ALuint src;
alGenSources(1, &src);
if (alGetError() != AL_NO_ERROR) {
debugOut("Failed to create OpenAL source!\n");
return;
}
alSourcef(src, AL_GAIN, (float) soundCache[a].vol / 256);
ok = alurePlaySourceStream(src, soundCache[a].stream,
10, 0, sound_eos_callback, &intpointers[a]);
if (!ok) {
debugOut("Failed to play stream: %s\n", alureGetErrorString());
alDeleteSources(1, &src);
if (alGetError() != AL_NO_ERROR) {
debugOut("Failed to delete OpenAL source!\n");
}
soundCache[a].playingOnSource = 0;
} else {
soundCache[a].playingOnSource = src;
soundCache[a].playing = true;
}
#endif
}
#if 0
int initMovieSound(int f, ALenum format, int audioChannels, ALuint samplerate,
ALuint(*callback)(void *userdata, ALubyte *data, ALuint bytes)) {
if (! soundOK) return 0;
int retval;
int a = findEmptySoundSlot();
freeSound(a);
soundCache[a].looping = false;
#if 0
// audioChannel * sampleRate gives us a buffer of half a second. Not much, but it should be enough.
soundCache[a].stream = alureCreateStreamFromCallback(
callback,
&intpointers[a], format, samplerate,
audioChannels * samplerate, 0, NULL);
#endif
if (soundCache[a].stream != NULL) {
soundCache[a].fileLoaded = f;
soundCache[a].vol = defSoundVol;
retval = a;
} else {
#if 0
debugOut("Failed to create stream from sound: %s\n",
alureGetErrorString());
#endif
warning(ERROR_SOUND_ODDNESS);
soundCache[a].stream = NULL;
soundCache[a].playing = false;
soundCache[a].playingOnSource = 0;
soundCache[a].fileLoaded = -1;
retval = -1;
}
//fprintf (stderr, "Stream %d created. Sample rate: %d Channels: %d\n", retval, samplerate, audioChannels);
return retval;
}
#endif
uint SoundManager::getSoundSource(int index) {
warning("getSoundSource, Unimplemented");
return 0; /*soundCache[index].playingOnSource;*/
}
} // End of namespace Sludge

124
engines/sludge/sound.h Normal file
View File

@@ -0,0 +1,124 @@
/* 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 SLUDGE_SOUND_H
#define SLUDGE_SOUND_H
#include "common/list.h"
#include "audio/mixer.h"
namespace Common {
class SeekableReadStream;
class WriteStream;
}
//#include "sludge/variable.h"
namespace Sludge {
struct StackHandler;
// Sound list stuff
struct SoundList{
int sound;
struct SoundList*next;
struct SoundList*prev;
int cacheIndex;
int vol;
};
class SoundManager {
public:
SoundManager();
virtual ~SoundManager();
// Sound list
void playSoundList(SoundList*s);
void handleSoundLists(); // to produce the same effects as end of stream call back functions
// GENERAL...
void init();
bool initSoundStuff();
void killSoundStuff();
// MUSIC...
bool playMOD(int, int, int);
void stopMOD(int);
void setMusicVolume(int a, int v);
void setDefaultMusicVolume(int v);
// SAMPLES...
int cacheSound(int f);
bool startSound(int, bool = false);
void huntKillSound(int a);
void huntKillFreeSound(int filenum);
void setSoundVolume(int a, int v);
void setDefaultSoundVolume(int v);
void setSoundLoop(int a, int s, int e);
bool stillPlayingSound(int ch);
bool getSoundCacheStack(StackHandler *sH);
int findInSoundCache(int a);
// Load & save
void loadSounds(Common::SeekableReadStream *stream);
void saveSounds(Common::WriteStream *stream);
uint getSoundSource(int index);
private:
const static int MAX_SAMPLES;
const static int MAX_MODS;
struct SoundThing {
Audio::SoundHandle handle;
int fileLoaded, vol; //Used for wav/ogg sounds only. (sound saving/loading)
bool looping; //Used for wav/ogg sounds only. (sound saving/loading)
bool inSoundList; //Used for wav/ogg sounds only
};
typedef Common::List<SoundList *> SoundListHandles;
// there's possibility that several sound list played at the same time
SoundListHandles _soundListHandles;
bool _soundOK;
bool _silenceIKillYou;
bool _isHandlingSoundList;
SoundThing *_soundCache;
SoundThing *_modCache;
int _defVol;
int _defSoundVol;
float _modLoudness;
int _emptySoundSlot;
void freeSound(int a);
bool forceRemoveSound();
bool deleteSoundFromList(SoundList*&s);
int findEmptySoundSlot();
int makeSoundAudioStream(int f, Audio::AudioStream *&audiostream, bool loopy);
};
} // End of namespace Sludge
#endif

297
engines/sludge/speech.cpp Normal file
View File

@@ -0,0 +1,297 @@
/* 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/system.h"
#include "sludge/fonttext.h"
#include "sludge/graphics.h"
#include "sludge/freeze.h"
#include "sludge/moreio.h"
#include "sludge/newfatal.h"
#include "sludge/objtypes.h"
#include "sludge/people.h"
#include "sludge/region.h"
#include "sludge/sludge.h"
#include "sludge/sludger.h"
#include "sludge/sound.h"
#include "sludge/speech.h"
namespace Sludge {
void SpeechManager::init() {
_speechMode = 0;
_speechSpeed = 1;
_speech = new SpeechStruct;
if (checkNew(_speech)) {
_speech->currentTalker = NULL;
_speech->allSpeech.clear();
_speech->speechY = 0;
_speech->lastFile = -1;
}
}
void SpeechManager::kill() {
if (!_speech)
return;
if (_speech->lastFile != -1) {
_vm->_soundMan->huntKillSound(_speech->lastFile);
_speech->lastFile = -1;
}
if (_speech->currentTalker) {
_speech->currentTalker->makeSilent();
_speech->currentTalker = nullptr;
}
for (SpeechLineList::iterator it = _speech->allSpeech.begin(); it != _speech->allSpeech.end(); ++it) {
SpeechLine *killMe = *it;
delete killMe;
killMe = nullptr;
}
_speech->allSpeech.clear();
}
void SpeechManager::setObjFontColour(ObjectType *t) {
_speech->talkCol.setColor(t->r, t->g, t->b);
}
void SpeechManager::addSpeechLine(const Common::String &theLine, int x, int &offset) {
float cameraZoom = g_sludge->_gfxMan->getCamZoom();
int halfWidth = (g_sludge->_txtMan->stringWidth(theLine) >> 1) / cameraZoom;
int xx1 = x - (halfWidth);
int xx2 = x + (halfWidth);
// Create new speech line
SpeechLine *newLine = new SpeechLine;
checkNew(newLine);
newLine->textLine.clear();
newLine->textLine = theLine;
newLine->x = xx1;
_speech->allSpeech.push_front(newLine);
// Calculate offset
if ((xx1 < 5) && (offset < (5 - xx1))) {
offset = 5 - xx1;
} else if ((xx2 >= ((float) g_system->getWidth() / cameraZoom) - 5)
&& (offset > (((float) g_system->getWidth() / cameraZoom) - 5 - xx2))) {
offset = ((float) g_system->getWidth() / cameraZoom) - 5 - xx2;
}
}
int SpeechManager::isThereAnySpeechGoingOn() {
return _speech->allSpeech.empty() ? -1 : _speech->lookWhosTalking;
}
int SpeechManager::getLastSpeechSound() {
return _vm->_soundMan->findInSoundCache(_speech->lastFile);
}
int SpeechManager::wrapSpeechXY(const Common::String &theText, int x, int y, int wrap, int sampleFile) {
float cameraZoom = g_sludge->_gfxMan->getCamZoom();
int fontHeight = g_sludge->_txtMan->getFontHeight();
int cameraY = g_sludge->_gfxMan->getCamY();
int a, offset = 0;
kill();
int speechTime = (theText.size() + 20) * _speechSpeed;
if (speechTime < 1)
speechTime = 1;
if (sampleFile != -1) {
if (_speechMode >= 1) {
if (g_sludge->_soundMan->startSound(sampleFile, false)) {
speechTime = -10;
_speech->lastFile = sampleFile;
if (_speechMode == 2) return -10;
}
}
}
_speech->speechY = y;
char *tmp, *txt;
tmp = txt = createCString(theText);
while ((int)strlen(txt) > wrap) {
a = wrap;
while (txt[a] != ' ') {
a--;
if (a == 0) {
a = wrap;
break;
}
}
txt[a] = 0;
addSpeechLine(txt, x, offset);
txt[a] = ' ';
txt += a + 1;
y -= fontHeight / cameraZoom;
}
addSpeechLine(txt, x, offset);
y -= fontHeight / cameraZoom;
delete []tmp;
if (y < 0)
_speech->speechY -= y;
else if (_speech->speechY > cameraY + (float) (g_system->getHeight() - fontHeight / 3) / cameraZoom)
_speech->speechY = cameraY
+ (float) (g_system->getHeight() - fontHeight / 3) / cameraZoom;
if (offset) {
for (SpeechLineList::iterator it = _speech->allSpeech.begin(); it != _speech->allSpeech.end(); ++it) {
(*it)->x += offset;
}
}
return speechTime;
}
int SpeechManager::wrapSpeechPerson(const Common::String &theText, OnScreenPerson &thePerson, int sampleFile, bool animPerson) {
int cameraX = g_sludge->_gfxMan->getCamX();
int cameraY = g_sludge->_gfxMan->getCamY();
int i = wrapSpeechXY(theText, thePerson.x - cameraX,
thePerson.y - cameraY
- (thePerson.scale * (thePerson.height - thePerson.floaty))
- thePerson.thisType->speechGap,
thePerson.thisType->wrapSpeech, sampleFile);
if (animPerson) {
thePerson.makeTalker();
_speech->currentTalker = &thePerson;
}
return i;
}
int SpeechManager::wrapSpeech(const Common::String &theText, int objT, int sampleFile, bool animPerson) {
int i;
int cameraX = g_sludge->_gfxMan->getCamX();
int cameraY = g_sludge->_gfxMan->getCamY();
_speech->lookWhosTalking = objT;
OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(objT);
if (thisPerson) {
setObjFontColour(thisPerson->thisType);
i = wrapSpeechPerson(theText, *thisPerson, sampleFile, animPerson);
} else {
ScreenRegion *thisRegion = g_sludge->_regionMan->getRegionForObject(objT);
if (thisRegion) {
setObjFontColour(thisRegion->thisType);
i = wrapSpeechXY(theText,
((thisRegion->x1 + thisRegion->x2) >> 1) - cameraX,
thisRegion->y1 - thisRegion->thisType->speechGap - cameraY,
thisRegion->thisType->wrapSpeech, sampleFile);
} else {
ObjectType *temp = g_sludge->_objMan->findObjectType(objT);
setObjFontColour(temp);
i = wrapSpeechXY(theText, g_system->getWidth() >> 1, 10, temp->wrapSpeech,
sampleFile);
}
}
return i;
}
void SpeechManager::display() {
float cameraZoom = g_sludge->_gfxMan->getCamZoom();
int fontHeight = g_sludge->_txtMan->getFontHeight();
int viewY = _speech->speechY;
for (SpeechLineList::iterator it = _speech->allSpeech.begin(); it != _speech->allSpeech.end(); ++it) {
g_sludge->_txtMan->pasteString((*it)->textLine, (*it)->x, viewY, _speech->talkCol);
viewY -= fontHeight / cameraZoom;
}
}
void SpeechManager::save(Common::WriteStream *stream) {
stream->writeByte(_speechMode);
stream->writeByte(_speech->talkCol.originalRed);
stream->writeByte(_speech->talkCol.originalGreen);
stream->writeByte(_speech->talkCol.originalBlue);
stream->writeFloatLE(_speechSpeed);
// Write y co-ordinate
stream->writeUint16BE(_speech->speechY);
// Write which character's talking
stream->writeUint16BE(_speech->lookWhosTalking);
if (_speech->currentTalker) {
stream->writeByte(1);
stream->writeUint16BE(_speech->currentTalker->thisType->objectNum);
} else {
stream->writeByte(0);
}
// Write what's being said
for (SpeechLineList::iterator it = _speech->allSpeech.begin(); it != _speech->allSpeech.end(); ++it) {
stream->writeByte(1);
writeString((*it)->textLine, stream);
stream->writeUint16BE((*it)->x);
}
stream->writeByte(0);
}
bool SpeechManager::load(Common::SeekableReadStream *stream) {
// read speech mode
_speechMode = stream->readByte();
_speech->currentTalker = nullptr;
kill();
byte r = stream->readByte();
byte g = stream->readByte();
byte b = stream->readByte();
_speech->talkCol.setColor(r, g, b);
_speechSpeed = stream->readFloatLE();
// Read y co-ordinate
_speech->speechY = stream->readUint16BE();
// Read which character's talking
_speech->lookWhosTalking = stream->readUint16BE();
if (stream->readByte()) {
_speech->currentTalker = g_sludge->_peopleMan->findPerson(stream->readUint16BE());
} else {
_speech->currentTalker = NULL;
}
// Read what's being said
_speech->lastFile = -1;
while (stream->readByte()) {
SpeechLine *newOne = new SpeechLine;
if (!checkNew(newOne))
return false;
newOne->textLine = readString(stream);
newOne->x = stream->readUint16BE();
_speech->allSpeech.push_back(newOne);
}
return true;
}
void SpeechManager::freeze(FrozenStuffStruct *frozenStuff) {
frozenStuff->speech = _speech;
init();
}
void SpeechManager::restore(FrozenStuffStruct *frozenStuff) {
kill();
delete _speech;
_speech = frozenStuff->speech;
}
} // End of namespace Sludge

86
engines/sludge/speech.h Normal file
View File

@@ -0,0 +1,86 @@
/* 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 SLUDGE_TALK_H
#define SLUDGE_TALK_H
#include "sludge/sprites.h"
namespace Sludge {
struct ObjectType;
struct SpeechLine {
Common::String textLine;
int x;
};
typedef Common::List<SpeechLine *> SpeechLineList;
struct SpeechStruct {
OnScreenPerson *currentTalker;
SpeechLineList allSpeech;
int speechY, lastFile, lookWhosTalking;
SpritePalette talkCol;
};
class SpeechManager {
public:
SpeechManager(SludgeEngine *vm) : _vm(vm) { init(); }
~SpeechManager() { kill(); }
void init();
void kill();
int wrapSpeech(const Common::String &theText, int objT, int sampleFile, bool);
void display();
int isThereAnySpeechGoingOn();
bool isCurrentTalker(OnScreenPerson *person) { return person == _speech->currentTalker; }
int getLastSpeechSound();
// setters & getters
void setObjFontColour(ObjectType *t);
void setSpeechSpeed(float speed) { _speechSpeed = speed; }
float getSpeechSpeed() { return _speechSpeed; }
void setSpeechMode(int speechMode) { _speechMode = speechMode; }
// load & save
void save(Common::WriteStream *stream);
bool load(Common::SeekableReadStream *stream);
// freeze & restore
void freeze(FrozenStuffStruct *frozenStuff);
void restore(FrozenStuffStruct *frozenStuff);
private:
SludgeEngine *_vm;
int _speechMode;
SpeechStruct *_speech;
float _speechSpeed;
void addSpeechLine(const Common::String &theLine, int x, int &offset);
int wrapSpeechXY(const Common::String &theText, int x, int y, int wrap, int sampleFile);
int wrapSpeechPerson(const Common::String &theText, OnScreenPerson &thePerson, int sampleFile, bool animPerson);
};
} // End of namespace Sludge
#endif

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/>.
*
*/
#include "sludge/graphics.h"
#include "sludge/newfatal.h"
#include "sludge/sludge.h"
namespace Sludge {
LoadedSpriteBank *GraphicsManager::loadBankForAnim(int ID) {
// Check if already exist
LoadedSpriteBanks::iterator it;
for (it = _allLoadedBanks.begin(); it != _allLoadedBanks.end(); ++it) {
if ((*it)->ID == ID) {
return (*it);
}
}
// Else create a new sprite bank
LoadedSpriteBank *returnMe = new LoadedSpriteBank;
if (checkNew(returnMe)) {
returnMe->ID = ID;
if (loadSpriteBank(ID, returnMe->bank, false)) {
returnMe->timesUsed = 0;
debugC(3, kSludgeDebugDataLoad, "loadBankForAnim: New sprite bank created OK");
_allLoadedBanks.push_back(returnMe);
return returnMe;
} else {
debugC(3, kSludgeDebugDataLoad, "loadBankForAnim: I guess I couldn't load the sprites...");
return nullptr;
}
} else
return nullptr;
}
} // End of namespace Sludge

36
engines/sludge/sprbanks.h Normal file
View File

@@ -0,0 +1,36 @@
/* 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 SLUDGE_SPRBANKS_H
#define SLUDGE_SPRBANKS_H
#include "sludge/sprites.h"
namespace Sludge {
struct LoadedSpriteBank {
int ID, timesUsed;
SpriteBank bank;
};
typedef Common::List<LoadedSpriteBank *> LoadedSpriteBanks;
} // End of namespace Sludge
#endif

599
engines/sludge/sprites.cpp Normal file
View File

@@ -0,0 +1,599 @@
/* 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 "sludge/event.h"
#include "sludge/fileset.h"
#include "sludge/graphics.h"
#include "sludge/imgloader.h"
#include "sludge/newfatal.h"
#include "sludge/people.h"
#include "sludge/sludge.h"
#include "sludge/zbuffer.h"
namespace Sludge {
// This function is only used to kill text font
void GraphicsManager::forgetSpriteBank(SpriteBank &forgetme) {
// kill the sprite bank
if (forgetme.myPalette.pal) {
delete[] forgetme.myPalette.pal;
forgetme.myPalette.pal = NULL;
delete[] forgetme.myPalette.r;
forgetme.myPalette.r = NULL;
delete[] forgetme.myPalette.g;
forgetme.myPalette.g = NULL;
delete[] forgetme.myPalette.b;
forgetme.myPalette.b = NULL;
}
if (forgetme.sprites) {
for (int i = 0; i < forgetme.total; ++i) {
forgetme.sprites[i].surface.free();
forgetme.sprites[i].burnSurface.free();
}
delete []forgetme.sprites;
forgetme.sprites = NULL;
}
}
bool GraphicsManager::reserveSpritePal(SpritePalette &sP, int n) {
if (sP.pal) {
delete[] sP.pal;
delete[] sP.r;
delete[] sP.g;
delete[] sP.b;
}
sP.pal = new uint16[n];
if (!checkNew(sP.pal))
return false;
sP.r = new byte[n];
if (!checkNew(sP.r))
return false;
sP.g = new byte[n];
if (!checkNew(sP.g))
return false;
sP.b = new byte[n];
if (!checkNew(sP.b))
return false;
sP.total = n;
return (bool)(sP.pal != NULL) && (sP.r != NULL) && (sP.g != NULL) && (sP.b != NULL);
}
bool GraphicsManager::loadSpriteBank(int fileNum, SpriteBank &loadhere, bool isFont) {
int total, spriteBankVersion = 0, howmany = 0, startIndex = 0;
byte *data;
setResourceForFatal(fileNum);
if (!g_sludge->_resMan->openFileFromNum(fileNum))
return fatal("Can't open sprite bank / font");
g_sludge->_resMan->dumpFile(fileNum, "bank%04d.duc");
loadhere.isFont = isFont;
Common::SeekableReadStream *readStream = g_sludge->_resMan->getData();
total = readStream->readUint16BE();
if (!total) {
spriteBankVersion = readStream->readByte();
if (spriteBankVersion == 1) {
total = 0;
} else {
total = readStream->readUint16BE();
}
}
if (total <= 0)
return fatal("No sprites in bank or invalid sprite bank file");
if (spriteBankVersion > 3)
return fatal("Unsupported sprite bank file format");
loadhere.total = total;
loadhere.sprites = new Sprite[total];
if (!checkNew(loadhere.sprites))
return false;
byte **spriteData = new byte *[total];
if (!checkNew(spriteData))
return false;
// version 1, 2, read how many now
if (spriteBankVersion && spriteBankVersion < 3) {
howmany = readStream->readByte();
startIndex = 1;
}
// version 3, sprite is png
if (spriteBankVersion == 3) {
debugC(2, kSludgeDebugGraphics, "png sprite");
for (int i = 0; i < total; i++) {
loadhere.sprites[i].xhot = readStream->readSint16LE();
loadhere.sprites[i].yhot = readStream->readSint16LE();
if (!ImgLoader::loadPNGImage(readStream, &loadhere.sprites[i].surface, false)) {
return fatal("fail to read png sprite");
}
}
g_sludge->_resMan->finishAccess();
setResourceForFatal(-1);
return true;
}
// version 0, 1, 2
for (int i = 0; i < total; i++) {
uint picwidth, picheight;
// load sprite width, height, relative position
if (spriteBankVersion == 2) {
picwidth = readStream->readUint16BE();
picheight = readStream->readUint16BE();
loadhere.sprites[i].xhot = readStream->readSint16LE();
loadhere.sprites[i].yhot = readStream->readSint16LE();
} else {
picwidth = (byte)readStream->readByte();
picheight = (byte)readStream->readByte();
loadhere.sprites[i].xhot = readStream->readByte();
loadhere.sprites[i].yhot = readStream->readByte();
}
// init data
loadhere.sprites[i].surface.create(picwidth, picheight, *g_sludge->getScreenPixelFormat());
if (isFont) {
loadhere.sprites[i].burnSurface.create(picwidth, picheight, *g_sludge->getScreenPixelFormat());
}
data = (byte *)new byte[picwidth * (picheight + 1)];
if (!checkNew(data))
return false;
memset(data + picwidth * picheight, 0, picwidth);
spriteData[i] = data;
// read color
if (spriteBankVersion == 2) { // RUN LENGTH COMPRESSED DATA
uint size = picwidth * picheight;
uint pip = 0;
while (pip < size) {
byte col = readStream->readByte();
int looper;
if (col > howmany) {
col -= howmany + 1;
looper = readStream->readByte() + 1;
} else
looper = 1;
while (looper--) {
data[pip++] = col;
}
}
} else { // RAW DATA
uint bytes_read = readStream->read(data, picwidth * picheight);
if (bytes_read != picwidth * picheight && readStream->err()) {
warning("Reading error in loadSpriteBank.");
}
}
}
// read howmany for version 0
if (!spriteBankVersion) {
howmany = readStream->readByte();
startIndex = readStream->readByte();
}
// Make palette for version 0, 1, 2
if (!reserveSpritePal(loadhere.myPalette, howmany + startIndex))
return false;
for (int i = 0; i < howmany; i++) {
loadhere.myPalette.r[i + startIndex] = (byte)readStream->readByte();
loadhere.myPalette.g[i + startIndex] = (byte)readStream->readByte();
loadhere.myPalette.b[i + startIndex] = (byte)readStream->readByte();
loadhere.myPalette.pal[i + startIndex] =
(uint16)g_sludge->getOrigPixelFormat()->RGBToColor(
loadhere.myPalette.r[i + startIndex],
loadhere.myPalette.g[i + startIndex],
loadhere.myPalette.b[i + startIndex]);
}
loadhere.myPalette.originalRed = loadhere.myPalette.originalGreen = loadhere.myPalette.originalBlue = 255;
// convert
for (int i = 0; i < total; i++) {
int fromhere = 0;
int transColour = -1;
int size = loadhere.sprites[i].surface.w * loadhere.sprites[i].surface.h;
while (fromhere < size) {
byte s = spriteData[i][fromhere++];
if (s) {
transColour = s;
break;
}
}
fromhere = 0;
for (int y = 0; y < loadhere.sprites[i].surface.h; y++) {
for (int x = 0; x < loadhere.sprites[i].surface.w; x++) {
byte *target = (byte *)loadhere.sprites[i].surface.getBasePtr(x, y);
byte s = spriteData[i][fromhere++];
if (s) {
target[0] = (byte)255;
target[1] = (byte)loadhere.myPalette.b[s];
target[2] = (byte)loadhere.myPalette.g[s];
target[3] = (byte)loadhere.myPalette.r[s];
transColour = s;
} else if (transColour >= 0) {
target[0] = (byte)0;
target[1] = (byte)loadhere.myPalette.b[transColour];
target[2] = (byte)loadhere.myPalette.g[transColour];
target[3] = (byte)loadhere.myPalette.r[transColour];
}
if (isFont) {
target = (byte *)loadhere.sprites[i].burnSurface.getBasePtr(x, y);
if (s)
target[0] = loadhere.myPalette.r[s];
target[1] = (byte)255;
target[2] = (byte)255;
target[3] = (byte)255;
}
}
}
delete[] spriteData[i];
}
delete[] spriteData;
spriteData = NULL;
g_sludge->_resMan->finishAccess();
setResourceForFatal(-1);
return true;
}
// pasteSpriteToBackDrop uses the colour specified by the setPasteColour (or setPasteColor)
void GraphicsManager::pasteSpriteToBackDrop(int x1, int y1, Sprite &single, const SpritePalette &fontPal) {
if (!single.surface.w || !single.surface.h) {
// Skip surfaces with a 0 width/height (e.g. the space character on Out of Order) to avoid crashes in the blitting code.
return;
}
// kill zBuffer
if (_zBuffer->originalNum >= 0 && _zBuffer->tex) {
int num = _zBuffer->originalNum;
killZBuffer();
_zBuffer->originalNum = num;
}
x1 -= single.xhot;
y1 -= single.yhot;
Graphics::ManagedSurface tmp;
tmp.copyFrom(single.surface);
tmp.blendBlitTo(_backdropSurface, x1, y1, Graphics::FLIP_NONE, nullptr, MS_RGB(fontPal.originalRed, fontPal.originalGreen, fontPal.originalBlue));
}
// burnSpriteToBackDrop adds text in the colour specified by setBurnColour
// using the differing brightness levels of the font to achieve an anti-aliasing effect.
void GraphicsManager::burnSpriteToBackDrop(int x1, int y1, Sprite &single, const SpritePalette &fontPal) {
if (!single.burnSurface.w || !single.burnSurface.h) {
// Skip surfaces with a 0 width/height (e.g. the space character on Out of Order) to avoid crashes in the blitting code.
return;
}
// kill zBuffer
if (_zBuffer->originalNum >= 0 && _zBuffer->tex) {
int num = _zBuffer->originalNum;
killZBuffer();
_zBuffer->originalNum = num;
}
x1 -= single.xhot;
y1 -= single.yhot - 1;
Graphics::ManagedSurface tmp;
tmp.copyFrom(single.burnSurface);
tmp.blendBlitTo(_backdropSurface, x1, y1, Graphics::FLIP_NONE, nullptr,
MS_RGB(_currentBurnR, _currentBurnG, _currentBurnB));
}
void GraphicsManager::fontSprite(bool flip, int x, int y, Sprite &single, const SpritePalette &fontPal) {
if (!single.surface.w || !single.surface.h) {
// Skip surfaces with a 0 width/height (e.g. the space character on Out of Order) to avoid crashes in the blitting code.
return;
}
float x1 = (float)x - (float)single.xhot / _cameraZoom;
float y1 = (float)y - (float)single.yhot / _cameraZoom;
// Use Managed surface to scale and blit
Graphics::ManagedSurface tmp;
tmp.copyFrom(single.surface);
tmp.blendBlitTo(_renderSurface, x1, y1, (flip ? Graphics::FLIP_H : Graphics::FLIP_NONE), 0, MS_RGB(fontPal.originalRed, fontPal.originalGreen, fontPal.originalBlue));
if (single.burnSurface.getPixels() != nullptr) {
Graphics::ManagedSurface tmp2;
tmp2.copyFrom(single.burnSurface);
tmp2.blendBlitTo(_renderSurface, x1, y1, (flip ? Graphics::FLIP_H : Graphics::FLIP_NONE), 0, MS_RGB(fontPal.originalRed, fontPal.originalGreen, fontPal.originalBlue));
}
}
void GraphicsManager::fontSprite(int x, int y, Sprite &single, const SpritePalette &fontPal) {
fontSprite(false, x, y, single, fontPal);
}
void GraphicsManager::flipFontSprite(int x, int y, Sprite &single, const SpritePalette &fontPal) {
fontSprite(true, x, y, single, fontPal);
}
Graphics::Surface *GraphicsManager::duplicateSurface(Graphics::Surface *surface) {
Graphics::Surface *res = new Graphics::Surface();
res->copyFrom(*surface);
return res;
}
void GraphicsManager::blendColor(Graphics::Surface *blitted, uint32 color, Graphics::TSpriteBlendMode mode) {
Graphics::ManagedSurface tmp(blitted->w, blitted->h, blitted->format);
tmp.fillRect(Common::Rect(0, 0, tmp.w, tmp.h), color);
tmp.blendBlitTo(*blitted, 0, 0, Graphics::FLIP_NONE, nullptr, MS_ARGB((uint)255, (uint)255, (uint)255, (uint)255), (int)blitted->w, (int)blitted->h, mode);
tmp.free();
}
Graphics::Surface *GraphicsManager::applyLightmapToSprite(Graphics::Surface *&blitted, OnScreenPerson *thisPerson, bool mirror, int x, int y, int x1, int y1, int diffX, int diffY) {
Graphics::Surface * toDetele = nullptr;
// if light map is used
bool light = !(thisPerson->extra & EXTRA_NOLITE);
// apply light map and set light map color
byte curLight[3];
if (light && _lightMap.getPixels()) {
if (_lightMapMode == LIGHTMAPMODE_HOTSPOT) {
int lx = x + _cameraX;
int ly = y + _cameraY;
if (lx < 0 || ly < 0 || lx >= (int)_sceneWidth || ly >= (int)_sceneHeight) {
curLight[0] = curLight[1] = curLight[2] = 255;
} else {
byte *target = (byte *)_lightMap.getBasePtr(lx, ly);
curLight[0] = target[3];
curLight[1] = target[2];
curLight[2] = target[1];
}
} else if (_lightMapMode == LIGHTMAPMODE_PIXEL) {
curLight[0] = curLight[1] = curLight[2] = 255;
toDetele = blitted = duplicateSurface(blitted);
// apply light map texture
Graphics::ManagedSurface tmp;
tmp.copyFrom(_lightMap);
Common::Rect rect_h(_sceneWidth - x1 - diffX, y1, _sceneWidth - x1, y1 + diffY);
Common::Rect rect_none(x1, y1, x1 + diffX, y1 + diffY);
tmp.blendBlitTo(*blitted, 0, 0,
(mirror ? Graphics::FLIP_H : Graphics::FLIP_NONE),
(mirror ? &rect_h : &rect_none),
MS_ARGB((uint)255, (uint)255, (uint)255, (uint)255),
(int)blitted->w, (int)blitted->h, Graphics::BLEND_MULTIPLY);
} else {
curLight[0] = curLight[1] = curLight[2] = 255;
}
} else {
curLight[0] = curLight[1] = curLight[2] = 255;
}
// calculate light map color
float fr, fg, fb;
fr = fg = fb = 0.0F;
if (thisPerson->colourmix) {
fr = curLight[0]*thisPerson->r * thisPerson->colourmix / 65025 / 255.0F;
fg = curLight[1]*thisPerson->g * thisPerson->colourmix / 65025 / 255.0F;
fb = curLight[2]*thisPerson->b * thisPerson->colourmix / 65025 / 255.0F;
}
uint32 primaryColor = MS_ARGB(255,
(uint8)(fr + curLight[0] * (255 - thisPerson->colourmix) / 255.f),
(uint8)(fg + curLight[1] * (255 - thisPerson->colourmix) / 255.f),
(uint8)(fb + curLight[2] * (255 - thisPerson->colourmix) / 255.f));
uint32 secondaryColor = MS_ARGB(0xff, (uint8)(fr * 255), (uint8)(fg * 255), (uint8)(fb * 255));
// apply primary color
if (primaryColor != (uint32)MS_ARGB(255, 255, 255, 255)) {
if (!toDetele) {
toDetele = blitted = duplicateSurface(blitted);
blendColor(blitted, primaryColor, Graphics::BLEND_MULTIPLY);
}
}
// apply secondary light map color
if (secondaryColor != 0x0) {
if (!toDetele) {
toDetele = blitted = duplicateSurface(blitted);
}
blendColor(blitted, secondaryColor, Graphics::BLEND_ADDITIVE);
}
return toDetele;
}
bool GraphicsManager::scaleSprite(Sprite &single, const SpritePalette &fontPal, OnScreenPerson *thisPerson, bool mirror) {
float x = thisPerson->x;
float y = thisPerson->y;
float scale = thisPerson->scale;
bool useZB = !(thisPerson->extra & EXTRA_NOZB);
if (scale <= 0.05)
return false;
int diffX = (int)(((float)single.surface.w) * scale);
int diffY = (int)(((float)single.surface.h) * scale);
float x1, y1, x2, y2;
if (thisPerson->extra & EXTRA_FIXTOSCREEN) {
x = x / _cameraZoom;
y = y / _cameraZoom;
if (single.xhot < 0)
x1 = x - (int)((mirror ? (float)(single.surface.w - single.xhot) : (float)(single.xhot + 1)) * scale / _cameraZoom);
else
x1 = x - (int)((mirror ? (float)(single.surface.w - (single.xhot + 1)) : (float)single.xhot) * scale / _cameraZoom);
y1 = y - (int)((single.yhot - thisPerson->floaty) * scale / _cameraZoom);
x2 = x1 + (int)(diffX / _cameraZoom);
y2 = y1 + (int)(diffY / _cameraZoom);
} else {
x -= _cameraX;
y -= _cameraY;
if (single.xhot < 0)
x1 = x - (int)((mirror ? (float)(single.surface.w - single.xhot) : (float)(single.xhot + 1)) * scale);
else
x1 = x - (int)((mirror ? (float)(single.surface.w - (single.xhot + 1)) : (float)single.xhot) * scale);
y1 = y - (int)((single.yhot - thisPerson->floaty) * scale);
x2 = x1 + diffX;
y2 = y1 + diffY;
}
uint8 z;
if (useZB && _zBuffer->numPanels) {
int i;
for (i = 1; i < _zBuffer->numPanels; i++) {
if (_zBuffer->panel[i] >= y + _cameraY) {
i--;
break;
}
}
z = ((i + 1) * 2) + 1;
} else {
z = 0xFF;
}
Graphics::Surface *blitted = &single.surface;
Graphics::Surface *toDelete = applyLightmapToSprite(blitted, thisPerson, mirror, x, y, x1, y1, diffX, diffY);
// Use Managed surface to scale and blit
if (!_zBuffer->numPanels) {
Graphics::ManagedSurface tmp;
tmp.copyFrom(*blitted);
tmp.blendBlitTo(_renderSurface, x1, y1, (mirror ? Graphics::FLIP_H : Graphics::FLIP_NONE), nullptr, MS_ARGB(255 - thisPerson->transparency, 255, 255, 255), diffX, diffY);
} else {
// TODO: you dont need to copy the whole render surface, just the part to which the sprite may be drawn
Graphics::ManagedSurface scaled;
scaled.copyFrom(_renderSurface);
Graphics::ManagedSurface tmp;
tmp.copyFrom(*blitted);
tmp.blendBlitTo(scaled, x1, y1, (mirror ? Graphics::FLIP_H : Graphics::FLIP_NONE), nullptr, MS_ARGB(255 - thisPerson->transparency, 255, 255, 255), diffX, diffY);
drawSpriteToZBuffer(0, 0, z, scaled.rawSurface());
}
if (toDelete) {
toDelete->free();
delete toDelete;
toDelete = nullptr;
}
// Are we pointing at the sprite?
if (_vm->_evtMan->mouseX() >= x1 && _vm->_evtMan->mouseX() < x2
&& _vm->_evtMan->mouseY() >= y1 && _vm->_evtMan->mouseY() < y2) {
if (thisPerson->extra & EXTRA_RECTANGULAR)
return true;
// check if point to non transparent part
int pixelx = (int)(single.surface.w * (_vm->_evtMan->mouseX() - x1) / (x2 - x1));
int pixely = (int)(single.surface.h * (_vm->_evtMan->mouseY() - y1) / (y2 - y1));
uint32 *colorPtr = (uint32 *)single.surface.getBasePtr(pixelx, pixely);
uint8 a, r, g, b;
g_sludge->getScreenPixelFormat()->colorToARGB(*colorPtr, a, r, g, b);
return a != 0;
}
return false;
}
// Paste a scaled sprite onto the backdrop
void GraphicsManager::fixScaleSprite(int x, int y, Sprite &single, const SpritePalette &fontPal, OnScreenPerson *thisPerson, int camX, int camY, bool mirror) {
float scale = thisPerson->scale;
bool useZB = !(thisPerson->extra & EXTRA_NOZB);
if (scale <= 0.05)
return;
int diffX = (int)(((float)single.surface.w) * scale);
int diffY = (int)(((float)single.surface.h) * scale);
int x1;
if (single.xhot < 0)
x1 = x - (int)((mirror ? (float)(single.surface.w - single.xhot) : (float)(single.xhot + 1)) * scale);
else
x1 = x - (int)((mirror ? (float)(single.surface.w - (single.xhot + 1)) : (float)single.xhot) * scale);
int y1 = y - (int)((single.yhot - thisPerson->floaty) * scale);
uint8 z;
if (useZB && _zBuffer->numPanels) {
int i;
for (i = 1; i < _zBuffer->numPanels; i++) {
if (_zBuffer->panel[i] >= y + _cameraY) {
i--;
break;
}
}
z = ((i + 1) * 2) + 1;
} else {
z = 0xFF;
}
Graphics::Surface *blitted = &single.surface;
Graphics::Surface *toDelete = applyLightmapToSprite(blitted, thisPerson, mirror, x, y, x1, y1, diffX, diffY);
// draw backdrop
drawBackDrop();
// draw zBuffer
if (_zBuffer->numPanels) {
drawZBuffer((int)(x1 + camX), (int)(y1 + camY), false);
}
// draw sprite
if (!_zBuffer->numPanels) {
Graphics::ManagedSurface tmp;
tmp.copyFrom(single.surface);
tmp.blendBlitTo(_renderSurface, x1, y1, (mirror ? Graphics::FLIP_H : Graphics::FLIP_NONE), nullptr, MS_ARGB((uint)255, (uint)255, (uint)255, (uint)255), diffX, diffY);
} else {
Graphics::ManagedSurface scaled;
scaled.copyFrom(_renderSurface);
Graphics::ManagedSurface tmp;
tmp.copyFrom(*blitted);
tmp.blendBlitTo(scaled, x1, y1, (mirror ? Graphics::FLIP_H : Graphics::FLIP_NONE), nullptr, MS_ARGB(255 - thisPerson->transparency, 255, 255, 255), diffX, diffY);
drawSpriteToZBuffer(0, 0, z, scaled.rawSurface());
}
if (toDelete) {
toDelete->free();
delete toDelete;
toDelete = nullptr;
}
// copy screen to backdrop
_backdropSurface.copyFrom(_renderSurface);
}
} // End of namespace Sludge

102
engines/sludge/sprites.h Normal file
View File

@@ -0,0 +1,102 @@
/* 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 SLUDGE_SPRITES_H
#define SLUDGE_SPRITES_H
#include "graphics/managed_surface.h"
namespace Sludge {
struct Sprite {
int xhot, yhot;
Graphics::Surface surface;
Graphics::Surface burnSurface;
};
class SpritePalette {
public:
uint16 *pal;
byte *r;
byte *g;
byte *b;
byte originalRed, originalGreen, originalBlue, total;
SpritePalette() { init(); }
~SpritePalette() { kill(); }
void init() {
pal = nullptr;
r = g = b = nullptr;
total = 0;
originalRed = originalGreen = originalBlue = 255;
}
void kill() {
if (pal) {
delete[] pal;
pal = nullptr;
}
if (r) {
delete[] r;
r = nullptr;
}
if (g) {
delete[] g;
g = nullptr;
}
if (b) {
delete[] b;
b = nullptr;
}
}
void setColor(byte red, byte green, byte blue) {
originalRed = red;
originalGreen = green;
originalBlue = blue;
}
};
struct SpriteBank {
int total;
int type;
Sprite *sprites;
SpritePalette myPalette;
bool isFont;
};
// Sprite display informations
struct SpriteDisplay {
int x, y;
int width, height;
bool freeAfterUse;
Graphics::FLIP_FLAGS flip;
Graphics::Surface *surface;
byte transparency;
SpriteDisplay(int xpos, int ypos, Graphics::FLIP_FLAGS f, Graphics::Surface *ptr, int w = -1, int h = 1, bool free = false, byte trans = 255) :
x(xpos), y(ypos), flip(f), surface(ptr), width(w), height(h), freeAfterUse(free), transparency(trans) {
}
};
} // End of namespace Sludge
#endif

231
engines/sludge/statusba.cpp Normal file
View File

@@ -0,0 +1,231 @@
/* 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/file.h"
#include "common/system.h"
#include "sludge/fonttext.h"
#include "sludge/graphics.h"
#include "sludge/moreio.h"
#include "sludge/newfatal.h"
#include "sludge/sludge.h"
#include "sludge/statusba.h"
namespace Sludge {
StatusBarManager::StatusBarManager(SludgeEngine *sludge) {
_nowStatus = &_mainStatus;
_sludge = sludge;
}
void StatusBarManager::init() {
_mainStatus.firstStatusBar = NULL;
_mainStatus.alignStatus = IN_THE_CENTRE;
_mainStatus.litStatus = -1;
_mainStatus.statusX = 10;
_mainStatus.statusY = g_system->getHeight() - 15;
statusBarColour(255, 255, 255);
statusBarLitColour(255, 255, 128);
}
void StatusBarManager::setLitStatus(int i) {
_nowStatus->litStatus = i;
}
void StatusBarManager::killLastStatus() {
if (_nowStatus->firstStatusBar) {
StatusBar *kill = _nowStatus->firstStatusBar;
_nowStatus->firstStatusBar = kill->next;
delete kill;
}
}
void StatusBarManager::clear() {
StatusBar *stat = _nowStatus->firstStatusBar;
StatusBar *kill;
_nowStatus->litStatus = -1;
while (stat) {
kill = stat;
stat = stat->next;
delete kill;
}
_nowStatus->firstStatusBar = NULL;
}
void StatusBarManager::addStatusBar() {
StatusBar *newStat = new StatusBar;
if (checkNew(newStat)) {
newStat->next = _nowStatus->firstStatusBar;
newStat->text.clear();
_nowStatus->firstStatusBar = newStat;
}
}
void StatusBarManager::set(Common::String &txt) {
if (_nowStatus->firstStatusBar) {
_nowStatus->firstStatusBar->text.clear();
_nowStatus->firstStatusBar->text = txt;
}
}
void StatusBarManager::positionStatus(int x, int y) {
_nowStatus->statusX = x;
_nowStatus->statusY = y;
}
void StatusBarManager::draw() {
float cameraZoom = _sludge->_gfxMan->getCamZoom();
int y = _nowStatus->statusY, n = 0;
StatusBar *stat = _nowStatus->firstStatusBar;
while (stat) {
switch (_nowStatus->alignStatus) {
case IN_THE_CENTRE:
_sludge->_txtMan->pasteString(stat->text,
((g_system->getWidth() - _sludge->_txtMan->stringWidth(stat->text)) >> 1) / cameraZoom, y / cameraZoom,
(n++ == _nowStatus->litStatus) ? _litVerbLinePalette : _verbLinePalette);
break;
case 1001:
_sludge->_txtMan->pasteString(stat->text,
(g_system->getWidth() - _sludge->_txtMan->stringWidth(stat->text)) - _nowStatus->statusX / cameraZoom, y / cameraZoom,
(n ++ == _nowStatus->litStatus) ? _litVerbLinePalette : _verbLinePalette);
break;
default:
_sludge->_txtMan->pasteString(stat->text,
_nowStatus->statusX / cameraZoom, y / cameraZoom,
(n ++ == _nowStatus->litStatus) ? _litVerbLinePalette : _verbLinePalette);
}
stat = stat->next;
y -= _sludge->_txtMan->getFontHeight();
}
}
void StatusBarManager::statusBarColour(byte r, byte g, byte b) {
_verbLinePalette.setColor(r, g, b);
_nowStatus->statusR = r;
_nowStatus->statusG = g;
_nowStatus->statusB = b;
}
void StatusBarManager::statusBarLitColour(byte r, byte g, byte b) {
_litVerbLinePalette.setColor(r, g, b);
_nowStatus->statusLR = r;
_nowStatus->statusLG = g;
_nowStatus->statusLB = b;
}
StatusStuff *StatusBarManager::copyStatusBarStuff(StatusStuff *here) {
// Things we want to keep
here->statusLR = _nowStatus->statusLR;
here->statusLG = _nowStatus->statusLG;
here->statusLB = _nowStatus->statusLB;
here->statusR = _nowStatus->statusR;
here->statusG = _nowStatus->statusG;
here->statusB = _nowStatus->statusB;
here->alignStatus = _nowStatus->alignStatus;
here->statusX = _nowStatus->statusX;
here->statusY = _nowStatus->statusY;
// Things we want to clear
here->litStatus = -1;
here->firstStatusBar = NULL;
StatusStuff *old = _nowStatus;
_nowStatus = here;
return old;
}
void StatusBarManager::restoreBarStuff(StatusStuff *here) {
delete _nowStatus;
_verbLinePalette.setColor((byte)here->statusR, (byte)here->statusG, (byte)here->statusB);
_litVerbLinePalette.setColor((byte)here->statusLR, (byte)here->statusLG, (byte)here->statusLB);
_nowStatus = here;
}
const Common::String StatusBarManager::statusBarText() {
if (_nowStatus->firstStatusBar) {
return _nowStatus->firstStatusBar->text;
} else {
return "";
}
}
void StatusBarManager::saveStatusBars(Common::WriteStream *stream) {
StatusBar *viewLine = _nowStatus->firstStatusBar;
stream->writeUint16BE(_nowStatus->alignStatus);
stream->writeSint16LE(_nowStatus->litStatus);
stream->writeUint16BE(_nowStatus->statusX);
stream->writeUint16BE(_nowStatus->statusY);
stream->writeByte(_nowStatus->statusR);
stream->writeByte(_nowStatus->statusG);
stream->writeByte(_nowStatus->statusB);
stream->writeByte(_nowStatus->statusLR);
stream->writeByte(_nowStatus->statusLG);
stream->writeByte(_nowStatus->statusLB);
// Write what's being said
while (viewLine) {
stream->writeByte(1);
writeString(viewLine->text, stream);
viewLine = viewLine->next;
}
stream->writeByte(0);
}
bool StatusBarManager::loadStatusBars(Common::SeekableReadStream *stream) {
clear();
_nowStatus->alignStatus = stream->readUint16BE();
_nowStatus->litStatus = stream->readSint16LE();
_nowStatus->statusX = stream->readUint16BE();
_nowStatus->statusY = stream->readUint16BE();
_nowStatus->statusR = stream->readByte();
_nowStatus->statusG = stream->readByte();
_nowStatus->statusB = stream->readByte();
_nowStatus->statusLR = stream->readByte();
_nowStatus->statusLG = stream->readByte();
_nowStatus->statusLB = stream->readByte();
_verbLinePalette.setColor((byte)_nowStatus->statusR, (byte)_nowStatus->statusG, (byte)_nowStatus->statusB);
_litVerbLinePalette.setColor((byte)_nowStatus->statusLR, (byte)_nowStatus->statusLG, (byte)_nowStatus->statusLB);
// Read what's being said
StatusBar **viewLine = &(_nowStatus->firstStatusBar);
StatusBar *newOne;
while (stream->readByte()) {
newOne = new StatusBar;
if (!checkNew(newOne))
return false;
newOne->text = readString(stream);
newOne->next = NULL;
(*viewLine) = newOne;
viewLine = &(newOne->next);
}
return true;
}
} // End of namespace Sludge

78
engines/sludge/statusba.h Normal file
View File

@@ -0,0 +1,78 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef SLUDGE_STATUSBA_H
#define SLUDGE_STATUSBA_H
namespace Sludge {
struct StatusBar {
Common::String text;
StatusBar *next;
};
struct StatusStuff {
StatusBar *firstStatusBar;
uint16 alignStatus;
int litStatus;
int statusX, statusY;
int statusR, statusG, statusB;
int statusLR, statusLG, statusLB;
};
class StatusBarManager {
public:
StatusBarManager(SludgeEngine *sludge);
void init();
void set(Common::String &txt);
void clear();
void addStatusBar();
void killLastStatus();
void statusBarColour(byte r, byte g, byte b);
void statusBarLitColour(byte r, byte g, byte b);
void setLitStatus(int i);
const Common::String statusBarText();
void positionStatus(int, int);
void draw();
// Load and save
bool loadStatusBars(Common::SeekableReadStream *stream);
void saveStatusBars(Common::WriteStream *stream);
// For freezing
void restoreBarStuff(StatusStuff *here);
StatusStuff *copyStatusBarStuff(StatusStuff *here);
void setAlignStatus(uint16 val) { _nowStatus->alignStatus = val; }
private:
SpritePalette _verbLinePalette;
SpritePalette _litVerbLinePalette;
StatusStuff _mainStatus;
StatusStuff *_nowStatus;
SludgeEngine *_sludge;
};
} // End of namespace Sludge
#endif

View File

@@ -0,0 +1,141 @@
/* 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/savefile.h"
#include "common/system.h"
#include "image/png.h"
#include "sludge/errors.h"
#include "sludge/graphics.h"
#include "sludge/imgloader.h"
#include "sludge/newfatal.h"
#include "sludge/version.h"
namespace Sludge {
bool GraphicsManager::setThumbnailSize(int thumbWidth, int thumbHeight) {
if (checkSizeValide(thumbWidth, thumbHeight))
{
_thumbWidth = thumbWidth;
_thumbHeight = thumbHeight;
return true;
}
return false;
}
bool GraphicsManager::saveThumbnail(Common::WriteStream *stream) {
stream->writeUint32LE(_thumbWidth);
stream->writeUint32LE(_thumbHeight);
if (_thumbWidth && _thumbHeight) {
if (!freeze())
return false;
if(!Image::writePNG(*stream, _renderSurface))
return false;
unfreeze(true);
}
stream->writeByte('!');
return true;
}
void GraphicsManager::showThumbnail(const Common::String &filename, int atX, int atY) {
Common::InSaveFile *fp = g_system->getSavefileManager()->openForLoading(filename);
if (fp == nullptr)
return;
bool headerBad = false;
if (fp->readByte() != 'S')
headerBad = true;
if (fp->readByte() != 'L')
headerBad = true;
if (fp->readByte() != 'U')
headerBad = true;
if (fp->readByte() != 'D')
headerBad = true;
if (fp->readByte() != 'S')
headerBad = true;
if (fp->readByte() != 'A')
headerBad = true;
if (headerBad) {
fatal(ERROR_GAME_LOAD_NO, filename);
return;
}
char c = fp->readByte();
while ((c = fp->readByte()))
;
int majVersion = fp->readByte();
int minVersion = fp->readByte();
int ssgVersion = VERSION(majVersion, minVersion);
if (ssgVersion >= VERSION(1, 4)) {
int fileWidth = fp->readUint32LE();
int fileHeight = fp->readUint32LE();
Graphics::ManagedSurface thumbnail;
if (!ImgLoader::loadPNGImage(fp, thumbnail.surfacePtr()))
return;
delete fp;
fp = nullptr;
if (atX < 0) {
fileWidth += atX;
atX = 0;
}
if (atY < 0) {
fileHeight += atY;
atY = 0;
}
if (fileWidth + atX > (int)_sceneWidth)
fileWidth = _sceneWidth - atX;
if (fileHeight + atY > (int)_sceneHeight)
fileHeight = _sceneHeight - atY;
thumbnail.blendBlitTo(_backdropSurface, atX, atY, Graphics::FLIP_NONE, nullptr, MS_ARGB((uint)255, (uint)255, (uint)255, (uint)255), fileWidth, fileHeight);
thumbnail.free();
}
}
bool GraphicsManager::skipThumbnail(Common::SeekableReadStream *stream) {
_thumbWidth = stream->readUint32LE();
_thumbHeight = stream->readUint32LE();
// Load image
Graphics::Surface tmp;
if (_thumbWidth && _thumbHeight) {
if (!ImgLoader::loadPNGImage(stream, &tmp))
return false;
else
tmp.free();
}
// Check flag
return (stream->readByte() == '!');
return true;
}
} // End of namespace Sludge

87
engines/sludge/timing.cpp Normal file
View File

@@ -0,0 +1,87 @@
/* 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/system.h"
#include "sludge/timing.h"
namespace Sludge {
Timer::Timer(){
reset();
}
void Timer::reset(void) {
_desiredFPS = 300;
_startTime = 0;
_endTime = 0;
_desiredFrameTime = 0;
_addNextTime = 0;
// FPS stats
_lastFPS = -1;
_thisFPS = -1;
_lastSeconds = 0;
}
void Timer::init(void) {
_desiredFrameTime = 1000 / _desiredFPS;
_startTime = g_system->getMillis();
}
void Timer::initSpecial(int t) {
_desiredFrameTime = 1000 / t;
_startTime = g_system->getMillis();
}
void Timer::updateFpsStats() {
uint32 currentSeconds = g_system->getMillis() / 1000;
if (_lastSeconds != currentSeconds) {
_lastSeconds = currentSeconds;
_lastFPS = _thisFPS;
_thisFPS = 1;
} else {
++_thisFPS;
}
}
void Timer::waitFrame(void) {
uint32 timetaken;
for (;;) {
_endTime = g_system->getMillis();
timetaken = _addNextTime + _endTime - _startTime;
if (timetaken >= _desiredFrameTime)
break;
g_system->delayMillis(1);
}
_addNextTime = timetaken - _desiredFrameTime;
if (_addNextTime > _desiredFrameTime)
_addNextTime = _desiredFrameTime;
_startTime = _endTime;
// Stats
updateFpsStats();
}
} // End of namespace Sludge

53
engines/sludge/timing.h Normal file
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/>.
*
*/
#ifndef SLUDGE_TIMING_H
#define SLUDGE_TIMING_H
namespace Sludge {
class Timer {
public:
Timer();
void setDesiredFPS(int t) { _desiredFPS = t; }
void reset(void);
void init(void);
void initSpecial(int t);
void waitFrame(void);
int getLastFps() const { return _lastFPS; }
private:
int _desiredFPS; // desired frames per second
uint32 _startTime, _endTime;
uint32 _desiredFrameTime;
uint32 _addNextTime;
// FPS stats
void updateFpsStats();
int _lastFPS;
int _thisFPS;
uint32 _lastSeconds;
};
} // End of namespace Sludge
#endif

View File

@@ -0,0 +1,234 @@
/* 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/textconsole.h"
#include "sludge/graphics.h"
namespace Sludge {
extern float snapTexW, snapTexH;
void GraphicsManager::setBrightnessLevel(int brightnessLevel) {
_brightnessLevel = CLIP(brightnessLevel, 0, 255);
}
//----------------------------------------------------
// PROPER BRIGHTNESS FADING
//----------------------------------------------------
unsigned lastFrom, lastTo;
void GraphicsManager::transitionFader() {
blendColor(&_renderSurface, MS_ARGB(255 - _brightnessLevel, 0, 0, 0), Graphics::BLEND_NORMAL);
}
void GraphicsManager::transitionCrossFader() {
if (!_snapshotSurface.getPixels())
return;
if (_brightnessLevel == 255)
return;
Graphics::ManagedSurface tmp;
tmp.copyFrom(_snapshotSurface);
tmp.blendBlitTo(_renderSurface, 0, 0, Graphics::FLIP_NONE, nullptr, MS_ARGB(255 - _brightnessLevel, 0xff, 0xff, 0xff));
}
void GraphicsManager::transitionSnapshotBox() {
if (!_snapshotSurface.getPixels())
return;
if (_brightnessLevel == 255)
return;
uint32 xScale = (255 - _brightnessLevel) * _winWidth / 255;
uint32 yScale = (255 - _brightnessLevel) * _winHeight / 255;
Graphics::Surface *surf = _snapshotSurface.scale(xScale, yScale);
_renderSurface.copyRectToSurface(surf->getPixels(), surf->pitch, (_winWidth - xScale) / 2, (_winHeight - yScale) / 2, xScale, yScale);
delete surf;
}
//----------------------------------------------------
// FAST PSEUDO-RANDOM NUMBER STUFF FOR DISOLVE EFFECT
//----------------------------------------------------
void GraphicsManager::resetRandW() {
int32 seed = 12345;
for (int i = 0; i < RANDKK; i++) {
for (int j = 0; j < 2; j++) {
seed = seed * 2891336453u + 1;
_randbuffer[i][j] = seed;
}
}
_randp1 = 0;
_randp2 = 10;
}
void GraphicsManager::reserveTransitionTexture() {
_transitionTexture = new Graphics::ManagedSurface;
_transitionTexture->create(256, 256, Graphics::BlendBlit::getSupportedPixelFormat());
}
void GraphicsManager::transitionDisolve() {
if (!_transitionTexture)
reserveTransitionTexture();
if (!_brightnessLevel) {
transitionFader();
return;
}
byte *toScreen = (byte *)_transitionTexture->getPixels();
byte *end = (byte *)_transitionTexture->getBasePtr(255, 255);
do {
// generate next number
uint32 n = _randbuffer[_randp1][1];
uint32 y = (n << 27) | ((n >> (32 - 27)) + _randbuffer[_randp2][1]);
n = _randbuffer[_randp1][0];
_randbuffer[_randp1][1] = (n << 19) | ((n >> (32 - 19)) + _randbuffer[_randp2][0]);
_randbuffer[_randp1][0] = y;
// rotate list pointers
if (!_randp1--)
_randp1 = RANDKK - 1;
if (!_randp2--)
_randp2 = RANDKK - 1;
if ((y & 0xff) > _brightnessLevel) {
toScreen[0] = 255;
toScreen[1] = toScreen[2] = toScreen[3] = 0;
} else {
toScreen[0] = toScreen[1] = toScreen[2] = toScreen[3] = 0;
}
toScreen += 4;
} while (toScreen < end);
// The original stretched the texture, we just tile it
for (uint y = 0; y < _sceneHeight; y += _transitionTexture->h)
for (uint x = 0; x < _sceneWidth; x += _transitionTexture->w)
_transitionTexture->blendBlitTo(_renderSurface, x, y);
}
void GraphicsManager::transitionTV() {
if (!_transitionTexture)
reserveTransitionTexture();
byte *toScreen = (byte *)_transitionTexture->getPixels();
byte *end = (byte *)_transitionTexture->getBasePtr(255, 255);
do {
// generate next number
uint32 n = _randbuffer[_randp1][1];
uint32 y = (n << 27) | ((n >> (32 - 27)) + _randbuffer[_randp2][1]);
n = _randbuffer[_randp1][0];
_randbuffer[_randp1][1] = (n << 19) | ((n >> (32 - 19)) + _randbuffer[_randp2][0]);
_randbuffer[_randp1][0] = y;
// rotate list pointers
if (!_randp1--)
_randp1 = RANDKK - 1;
if (!_randp2--)
_randp2 = RANDKK - 1;
if ((y & 255u) > _brightnessLevel) {
toScreen[0] = (n & 255);
toScreen[1] = toScreen[2] = toScreen[3] = (n & 255);
} else {
toScreen[0] = toScreen[1] = toScreen[2] = toScreen[3] = 0;
}
toScreen += 4;
} while (toScreen < end);
// The original stretched the texture, we just tile it
for (uint y = 0; y < _sceneHeight; y += _transitionTexture->h)
for (uint x = 0; x < _sceneWidth; x += _transitionTexture->w)
_transitionTexture->blendBlitTo(_renderSurface, x, y);
}
void GraphicsManager::transitionBlinds() {
if (!_transitionTexture)
reserveTransitionTexture();
int level = _brightnessLevel / 16;
for (int b = 0; b < 16; b++) {
byte *toScreen = (byte *)_transitionTexture->getBasePtr(0, b * 16);
if (level)
memset(toScreen, 0, 256 * 4 * level);
if (level < 32) {
for (int y = 0; y < 16 - level; y++) {
toScreen = (byte *)_transitionTexture->getBasePtr(0, b * 16 + y);
for (int i = 0; i < 256; i++) {
toScreen[0] = 0xff;
toScreen[1] = toScreen[2] = toScreen[3] = 0;
toScreen += 4;
}
}
}
}
// The original stretched the texture, we just tile it
for (uint y = 0; y < _sceneHeight; y += _transitionTexture->h)
for (uint x = 0; x < _sceneWidth; x += _transitionTexture->w)
_transitionTexture->blendBlitTo(_renderSurface, x, y);
}
//----------------------------------------------------
void GraphicsManager::fixBrightness() {
switch (_fadeMode) {
case 0:
transitionFader();
break;
case 1:
resetRandW();
// Fall through!
case 2:
transitionDisolve();
break;
case 3:
transitionTV();
break;
case 4:
transitionBlinds();
break;
case 5:
transitionCrossFader();
break;
case 6:
transitionSnapshotBox();
break;
default:
break;
}
}
} // End of namespace Sludge

813
engines/sludge/variable.cpp Normal file
View File

@@ -0,0 +1,813 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/debug.h"
#include "common/savefile.h"
#include "common/system.h"
#include "engines/metaengine.h"
#include "sludge/fileset.h"
#include "sludge/moreio.h"
#include "sludge/newfatal.h"
#include "sludge/objtypes.h"
#include "sludge/people.h"
#include "sludge/sludge.h"
#include "sludge/sprbanks.h"
#include "sludge/variable.h"
namespace Sludge {
const char *typeName[] = { "undefined", "number", "user function", "string",
"built-in function", "file", "stack", "object type", "animation",
"costume", "fast array" };
void Variable::unlinkVar() {
switch (varType) {
case SVT_STRING:
delete []varData.theString;
varData.theString = NULL;
break;
case SVT_STACK:
varData.theStack->timesUsed--;
if (varData.theStack->timesUsed <= 0) {
while (varData.theStack->first)
trimStack(varData.theStack->first);
delete varData.theStack;
varData.theStack = NULL;
}
break;
case SVT_FASTARRAY:
varData.fastArray->timesUsed--;
if (varData.theStack->timesUsed <= 0) {
delete varData.fastArray->fastVariables;
delete[] varData.fastArray;
varData.fastArray = NULL;
}
break;
case SVT_ANIM:
if (varData.animHandler) {
delete varData.animHandler;
varData.animHandler = nullptr;
}
break;
default:
break;
}
}
void Variable::setVariable(VariableType vT, int value) {
unlinkVar();
varType = vT;
varData.intValue = value;
}
void Variable::makeAnimationVariable(PersonaAnimation *i) {
unlinkVar();
varType = SVT_ANIM;
varData.animHandler = i;
}
PersonaAnimation *Variable::getAnimationFromVar() {
if (varType == SVT_ANIM)
return new PersonaAnimation(varData.animHandler);
if (varType == SVT_INT && varData.intValue == 0)
return new PersonaAnimation();
fatal("Expecting an animation variable; found Variable of type", typeName[varType]);
return NULL;
}
void Variable::makeCostumeVariable(Persona *i) {
unlinkVar();
varType = SVT_COSTUME;
varData.costumeHandler = i;
}
Persona *Variable::getCostumeFromVar() {
Persona *p = NULL;
switch (varType) {
case SVT_ANIM:
p = new Persona;
if (!checkNew(p))
return NULL;
p->numDirections = 1;
p->animation = new PersonaAnimation *[3];
if (!checkNew(p->animation))
return NULL;
for (int iii = 0; iii < 3; iii++)
p->animation[iii] = new PersonaAnimation(varData.animHandler);
break;
case SVT_COSTUME:
return varData.costumeHandler;
break;
default:
fatal("Expecting an animation variable; found Variable of type", typeName[varType]);
}
return p;
}
void Variable::debugPrint() {
switch (varType) {
case SVT_NULL:
debugN("SVT_NULL() ");
break;
case SVT_INT:
debugN("SVT_INT(%d) ", varData.intValue);
break;
case SVT_STRING:
debugN("SVT_STRING(\"%s\") ", Common::toPrintable(varData.theString).c_str());
break;
case SVT_BUILT:
debugN("SVT_BUILT(%d) ", varData.intValue);
break;
case SVT_STACK:
debugN("SVT_STACK(");
varData.theStack->debugPrint();
debugN(") ");
break;
case SVT_FUNC:
debugN("SVT_FUNC(%d) ", varData.intValue);
break;
case SVT_FILE:
debugN("SVT_FILE(\"%s\") ", g_sludge->_resMan->resourceNameFromNum(varData.intValue).c_str());
break;
case SVT_ANIM:
debugN("SVT_ANIM(Frames: %d, ID: %d) ", varData.animHandler->numFrames, varData.animHandler->numFrames ? varData.animHandler->theSprites->ID : -1337);
break;
case SVT_OBJTYPE:
debugN("SVT_OBJTYPE(%d) ", varData.intValue);
break;
case SVT_COSTUME:
debugN("SVT_COSTUME(numDirections: %d) ", varData.costumeHandler->numDirections);
break;
case SVT_FASTARRAY:
debugN("FASTARRAY(");
varData.fastArray->debugPrint();
debugN(") ");
break;
default :
debugN("<UNK %d> ", varType);
}
}
int StackHandler::getStackSize() const {
int r = 0;
VariableStack *a = first;
while (a) {
r++;
a = a->next;
}
return r;
}
static int stringCompareToIgnoreCase(const Common::String &s1, const Common::String &s2) {
return s1.compareToIgnoreCase(s2) > 0;
}
bool StackHandler::getSavedGamesStack(const Common::String &ext) {
// Make pattern
//uint len = realExtension.size();
// Get all saved files
SaveStateList sa = g_sludge->getMetaEngine()->listSaves(g_sludge->getTargetName().c_str());
Common::StringArray realNames;
g_sludge->_saveNameToSlot.clear();
for (auto &savestate : sa) {
Common::String name = savestate.getDescription();
realNames.push_back(name);
g_sludge->_saveNameToSlot[name] = savestate.getSaveSlot();
}
Common::sort(realNames.begin(), realNames.end(), stringCompareToIgnoreCase);
// Save file names to stacks
Variable newName;
newName.varType = SVT_NULL;
for (Common::StringArray::iterator it = realNames.begin(); it != realNames.end(); ++it) {
newName.makeTextVar((*it));
if (!addVarToStack(newName, first))
return false;
if (last == NULL)
last = first;
}
return true;
}
void StackHandler::debugPrint() {
VariableStack *a = first;
debugN("{");
while (a) {
a->thisVar.debugPrint();
a = a->next;
}
debugN("}");
}
bool Variable::copyStack(const Variable &from) {
varType = SVT_STACK;
varData.theStack = new StackHandler;
if (!checkNew(varData.theStack))
return false;
varData.theStack->first = NULL;
varData.theStack->last = NULL;
varData.theStack->timesUsed = 1;
VariableStack *a = from.varData.theStack->first;
while (a) {
addVarToStack(a->thisVar, varData.theStack->first);
if (varData.theStack->last == NULL) {
varData.theStack->last = varData.theStack->first;
}
a = a->next;
}
return true;
}
void Variable::addVariablesInSecond(const Variable &other) {
if (other.varType == SVT_INT && varType == SVT_INT) {
varData.intValue += other.varData.intValue;
} else {
Common::String string1 = other.getTextFromAnyVar();
Common::String string2 = getTextFromAnyVar();
unlinkVar();
varData.theString = createCString(string1 + string2);
varType = SVT_STRING;
}
}
int Variable::compareVars(const Variable &other) const {
int re = 0;
if (other.varType == varType) {
switch (other.varType) {
case SVT_NULL:
re = 1;
break;
case SVT_COSTUME:
re = (other.varData.costumeHandler == varData.costumeHandler);
break;
case SVT_ANIM:
re = (other.varData.animHandler == varData.animHandler);
break;
case SVT_STRING:
re = (strcmp(other.varData.theString, varData.theString) == 0);
break;
case SVT_STACK:
re = (other.varData.theStack == varData.theStack);
break;
default:
re = (other.varData.intValue == varData.intValue);
}
}
return re;
}
void Variable::compareVariablesInSecond(const Variable &other) {
setVariable(SVT_INT, compareVars(other));
}
void Variable::makeTextVar(const Common::String &txt) {
unlinkVar();
varType = SVT_STRING;
varData.theString = createCString(txt);
}
bool Variable::loadStringToVar(int value) {
makeTextVar(g_sludge->_resMan->getNumberedString(value));
return (bool)(varData.theString != NULL);
}
Common::String Variable::getTextFromAnyVar(bool skipLoad) const {
switch (varType) {
case SVT_STRING:
return varData.theString;
case SVT_FASTARRAY: {
Common::String builder = "FAST:";
Common::String builder2 = "";
Common::String grabText = "";
for (int i = 0; i < varData.fastArray->size; i++) {
builder2 = builder + " ";
grabText = varData.fastArray->fastVariables[i].getTextFromAnyVar(skipLoad);
builder.clear();
builder = builder2 + grabText;
}
return builder;
}
case SVT_STACK: {
Common::String builder = "ARRAY:";
Common::String builder2 = "";
Common::String grabText = "";
VariableStack *stacky = varData.theStack->first;
while (stacky) {
builder2 = builder + " ";
grabText = stacky->thisVar.getTextFromAnyVar(skipLoad);
builder.clear();
builder = builder2 + grabText;
stacky = stacky->next;
}
return builder;
}
case SVT_INT: {
Common::String buff = Common::String::format("%i", varData.intValue);
return buff;
}
case SVT_FILE: {
return g_sludge->_resMan->resourceNameFromNum(varData.intValue);
}
case SVT_OBJTYPE: {
ObjectType *thisType = g_sludge->_objMan->findObjectType(varData.intValue, skipLoad);
if (thisType)
return thisType->screenName;
else
return Common::String::format("<unloaded id %d>", varData.intValue);
break;
}
default:
break;
}
return typeName[varType];
}
bool Variable::getBoolean() const {
switch (varType) {
case SVT_NULL:
return false;
case SVT_INT:
return (bool)(varData.intValue != 0);
case SVT_STACK:
return (bool)(varData.theStack->first != NULL);
case SVT_STRING:
return (bool)(varData.theString[0] != 0);
case SVT_FASTARRAY:
return (bool)(varData.fastArray->size != 0);
default:
break;
}
return true;
}
bool Variable::copyMain(const Variable &from) {
varType = from.varType;
switch (varType) {
case SVT_INT:
case SVT_FUNC:
case SVT_BUILT:
case SVT_FILE:
case SVT_OBJTYPE:
varData.intValue = from.varData.intValue;
return true;
case SVT_FASTARRAY:
varData.fastArray = from.varData.fastArray;
varData.fastArray->timesUsed++;
return true;
case SVT_STRING:
varData.theString = createCString(from.varData.theString);
return varData.theString ? true : false;
case SVT_STACK:
varData.theStack = from.varData.theStack;
varData.theStack->timesUsed++;
return true;
case SVT_COSTUME:
varData.costumeHandler = from.varData.costumeHandler;
return true;
case SVT_ANIM:
varData.animHandler = new PersonaAnimation(from.varData.animHandler);
return true;
case SVT_NULL:
return true;
default:
break;
}
fatal("Unknown value type");
return false;
}
bool Variable::copyFrom(const Variable &from) {
unlinkVar();
return copyMain(from);
}
Variable *FastArrayHandler::fastArrayGetByIndex(uint theIndex) {
if ((int)theIndex >= size)
return NULL;
return &fastVariables[theIndex];
}
void FastArrayHandler::debugPrint() {
debugN("[");
for (int i = 0; i < size; i++)
fastVariables[i].debugPrint();
debugN("]");
}
bool Variable::makeFastArraySize(int size) {
if (size < 0)
return fatal("Can't create a fast array with a negative number of elements!");
unlinkVar();
varType = SVT_FASTARRAY;
varData.fastArray = new FastArrayHandler;
if (!checkNew(varData.fastArray))
return false;
varData.fastArray->fastVariables = new Variable[size];
if (!checkNew(varData.fastArray->fastVariables))
return false;
varData.fastArray->size = size;
varData.fastArray->timesUsed = 1;
return true;
}
bool Variable::makeFastArrayFromStack(const StackHandler *stacky) {
int size = stacky->getStackSize();
if (!makeFastArraySize(size))
return false;
// Now let's fill up the new array
VariableStack *allV = stacky->first;
size = 0;
while (allV) {
varData.fastArray->fastVariables[size].copyMain(allV->thisVar);
size++;
allV = allV->next;
}
return true;
}
bool addVarToStack(const Variable &va, VariableStack *&thisStack) {
VariableStack *newStack = new VariableStack;
if (!checkNew(newStack))
return false;
if (!newStack->thisVar.copyMain(va))
return false;
newStack->next = thisStack;
thisStack = newStack;
debugC(2, kSludgeDebugStackMachine, "Variable %s was added to stack", va.getTextFromAnyVar(true).c_str());
return true;
}
bool addVarToStackQuick(Variable &va, VariableStack *&thisStack) {
VariableStack *newStack = new VariableStack;
if (!checkNew(newStack))
return false;
// if (! copyMain (va, newStack -> thisVar)) return false;
memcpy(&(newStack->thisVar), &va, sizeof(Variable));
va.varType = SVT_NULL;
newStack->next = thisStack;
thisStack = newStack;
debugC(2, kSludgeDebugStackMachine, "Variable %s was added to stack quick", va.getTextFromAnyVar(true).c_str());
return true;
}
bool VariableStack::stackSetByIndex(uint theIndex, const Variable &va) {
VariableStack *vS = this;
while (theIndex--) {
vS = vS->next;
if (!vS)
return fatal("Index past end of stack.");
}
return vS->thisVar.copyFrom(va);
}
Variable *VariableStack::stackGetByIndex(uint theIndex) {
VariableStack *vS = this;
while (theIndex--) {
vS = vS->next;
if (!vS) {
return NULL;
}
}
return &(vS->thisVar);
}
int deleteVarFromStack(const Variable &va, VariableStack *&thisStack, bool allOfEm) {
VariableStack **huntVar = &thisStack;
VariableStack *killMe;
int reply = 0;
while (*huntVar) {
if (va.compareVars((*huntVar)->thisVar)) {
killMe = *huntVar;
*huntVar = killMe->next;
killMe->thisVar.unlinkVar();
delete killMe;
if (!allOfEm)
return 1;
reply++;
} else {
huntVar = &((*huntVar)->next);
}
}
return reply;
}
// Would be a LOT better just to keep this up to date in the above function... ah well
VariableStack *VariableStack::stackFindLast() {
VariableStack *hunt = this;
while (hunt->next)
hunt = hunt->next;
return hunt;
}
bool Variable::getValueType(int &toHere, VariableType vT) const {
if (varType != vT) {
Common::String e1 = "Can only perform specified operation on a value which is of type ";
e1 += typeName[vT];
Common::String e2 = "... value supplied was of type ";
e2 += typeName[varType];
fatal(e1, e2);
return false;
}
toHere = varData.intValue;
return true;
}
void trimStack(VariableStack *&stack) {
VariableStack *killMe = stack;
stack = stack->next;
debugC(2, kSludgeDebugStackMachine, "Variable %s was removed from stack", killMe->thisVar.getTextFromAnyVar(true).c_str());
// When calling this, we've ALWAYS checked that stack != NULL
killMe->thisVar.unlinkVar();
delete killMe;
}
//----------------------------------------------------------------------
// Globals (so we know what's saved already and what's a reference
//----------------------------------------------------------------------
struct stackLibrary {
StackHandler *stack;
stackLibrary *next;
};
int stackLibTotal = 0;
stackLibrary *stackLib = NULL;
//----------------------------------------------------------------------
// For saving and loading stacks...
//----------------------------------------------------------------------
void saveStack(VariableStack *vs, Common::WriteStream *stream) {
int elements = 0;
int a;
VariableStack *search = vs;
while (search) {
elements++;
search = search->next;
}
stream->writeUint16BE(elements);
search = vs;
for (a = 0; a < elements; a++) {
search->thisVar.save(stream);
search = search->next;
}
}
VariableStack *loadStack(Common::SeekableReadStream *stream, VariableStack **last) {
int elements = stream->readUint16BE();
int a;
VariableStack *first = NULL;
VariableStack **changeMe = &first;
for (a = 0; a < elements; a++) {
VariableStack *nS = new VariableStack;
if (!checkNew(nS))
return NULL;
nS->thisVar.load(stream);
if (last && a == elements - 1) {
*last = nS;
}
nS->next = NULL;
(*changeMe) = nS;
changeMe = &(nS->next);
}
return first;
}
bool saveStackRef(StackHandler *vs, Common::WriteStream *stream) {
stackLibrary *s = stackLib;
int a = 0;
while (s) {
if (s->stack == vs) {
stream->writeByte(1);
stream->writeUint16BE(stackLibTotal - a);
return true;
}
s = s->next;
a++;
}
stream->writeByte(0);
saveStack(vs->first, stream);
s = new stackLibrary;
stackLibTotal++;
if (!checkNew(s))
return false;
s->next = stackLib;
s->stack = vs;
stackLib = s;
return true;
}
void clearStackLib() {
stackLibrary *k;
while (stackLib) {
k = stackLib;
stackLib = stackLib->next;
delete k;
}
stackLibTotal = 0;
}
StackHandler *getStackFromLibrary(int n) {
n = stackLibTotal - n;
while (n) {
stackLib = stackLib->next;
n--;
}
return stackLib->stack;
}
StackHandler *loadStackRef(Common::SeekableReadStream *stream) {
StackHandler *nsh;
if (stream->readByte()) { // It's one we've loaded already...
nsh = getStackFromLibrary(stream->readUint16BE());
nsh->timesUsed++;
} else {
// Load the new stack
nsh = new StackHandler;
if (!checkNew(nsh))
return NULL;
nsh->last = NULL;
nsh->first = loadStack(stream, &nsh->last);
nsh->timesUsed = 1;
// Add it to the library of loaded stacks
stackLibrary *s = new stackLibrary;
if (!checkNew(s))
return NULL;
s->stack = nsh;
s->next = stackLib;
stackLib = s;
stackLibTotal++;
}
return nsh;
}
//----------------------------------------------------------------------
// For saving and loading variables...
//----------------------------------------------------------------------
bool Variable::save(Common::WriteStream *stream) {
stream->writeByte(varType);
switch (varType) {
case SVT_INT:
case SVT_FUNC:
case SVT_BUILT:
case SVT_FILE:
case SVT_OBJTYPE:
stream->writeUint32LE(varData.intValue);
return true;
case SVT_STRING:
writeString(varData.theString, stream);
return true;
case SVT_STACK:
return saveStackRef(varData.theStack, stream);
case SVT_COSTUME:
varData.costumeHandler->save(stream);
return false;
case SVT_ANIM:
varData.animHandler->save(stream);
return false;
case SVT_NULL:
return false;
default:
fatal("Can't save variables of this type:", (varType < SVT_NUM_TYPES - 1) ? typeName[varType] : "bad ID");
}
return true;
}
bool Variable::load(Common::SeekableReadStream *stream) {
varType = (VariableType)stream->readByte();
switch (varType) {
case SVT_INT:
case SVT_FUNC:
case SVT_BUILT:
case SVT_FILE:
case SVT_OBJTYPE:
varData.intValue = stream->readUint32LE();
return true;
case SVT_STRING:
varData.theString = createCString(readString(stream));
return true;
case SVT_STACK:
varData.theStack = loadStackRef(stream);
return true;
case SVT_COSTUME:
varData.costumeHandler = new Persona;
if (!checkNew(varData.costumeHandler))
return false;
varData.costumeHandler->load(stream);
return true;
case SVT_ANIM:
varData.animHandler = new PersonaAnimation;
if (!checkNew(varData.animHandler))
return false;
varData.animHandler->load(stream);
return true;
default:
break;
}
return true;
}
} // End of namespace Sludge

160
engines/sludge/variable.h Normal file
View File

@@ -0,0 +1,160 @@
/* 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 SLUDGE_VARIABLE_H
#define SLUDGE_VARIABLE_H
namespace Common {
class SeekableReadStream;
class WriteStream;
}
namespace Sludge {
struct Persona;
struct PersonaAnimation;
struct Variable;
struct VariableStack;
enum VariableType {
SVT_NULL,
SVT_INT,
SVT_FUNC,
SVT_STRING,
SVT_BUILT,
SVT_FILE,
SVT_STACK,
SVT_OBJTYPE,
SVT_ANIM,
SVT_COSTUME,
SVT_FASTARRAY,
SVT_NUM_TYPES
};
struct FastArrayHandler {
struct Variable *fastVariables;
int size;
int timesUsed;
Variable *fastArrayGetByIndex(uint theIndex);
void debugPrint();
};
struct StackHandler {
struct VariableStack *first;
struct VariableStack *last;
int timesUsed;
int getStackSize() const;
bool getSavedGamesStack(const Common::String &ext);
void debugPrint();
};
union VariableData {
signed int intValue;
const char *theString;
StackHandler *theStack;
PersonaAnimation *animHandler;
Persona *costumeHandler;
FastArrayHandler *fastArray;
};
struct Variable {
VariableType varType;
VariableData varData;
Variable() {
varType = SVT_NULL;
varData.intValue = 0;
}
void unlinkVar();
void setVariable(VariableType vT, int value);
// Copy from another variable
bool copyFrom(const Variable &from);
bool copyMain(const Variable &from); // without variable unlink
// Load & save
bool save(Common::WriteStream *stream);
bool load(Common::SeekableReadStream *stream);
// Text variable
void makeTextVar(const Common::String &txt);
bool loadStringToVar(int value);
// Animation variable
void makeAnimationVariable(PersonaAnimation *i);
struct PersonaAnimation *getAnimationFromVar();
// Custome variable
void makeCostumeVariable(Persona *i);
struct Persona *getCostumeFromVar();
// Fast array variable
bool makeFastArrayFromStack(const StackHandler *stacky);
bool makeFastArraySize(int size);
// Stack variable
bool copyStack(const Variable &from);
// Add variables
void addVariablesInSecond(const Variable &other);
void compareVariablesInSecond(const Variable &other);
int compareVars(const Variable &other) const;
// General getters
Common::String getTextFromAnyVar(bool skipLoad = false) const;
bool getBoolean() const;
bool getValueType(int &toHere, VariableType vT) const;
void debugPrint();
};
struct VariableStack {
Variable thisVar;
VariableStack *next;
// Variable getter & setter
bool stackSetByIndex(uint, const Variable &);
Variable *stackGetByIndex(uint);
// Find last
VariableStack *stackFindLast();
};
// Stacky stuff
bool addVarToStack(const Variable &va, VariableStack *&thisStack);
bool addVarToStackQuick(Variable &va, VariableStack *&thisStack);
void trimStack(VariableStack *&stack);
int deleteVarFromStack(const Variable &va, VariableStack *&thisStack, bool allOfEm = false);
// load & save
void saveStack(VariableStack *vs, Common::WriteStream *stream);
VariableStack *loadStack(Common::SeekableReadStream *stream, VariableStack **last);
bool saveStackRef(StackHandler *vs, Common::WriteStream *stream);
StackHandler *loadStackRef(Common::SeekableReadStream *stream);
void clearStackLib();
} // End of namespace Sludge
#endif

37
engines/sludge/version.h Normal file
View File

@@ -0,0 +1,37 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#define MAJOR_VERSION 2
#define MINOR_VERSION 2
#define RELEASE_VERSION 1
#define BUILD_VERSION 208
#define TEXT_VERSION "2.2.1"
#define WHOLE_VERSION (MAJOR_VERSION * 256 + MINOR_VERSION) // This version
#define MINIM_VERSION (1 * 256 + 2) // Earliest version of games the engine can run
#define COPYRIGHT_TEXT "\251 Hungry Software and contributors 2000-2014"
#define VERSION(a,b) (a * 256 + b)
namespace Sludge {
extern int gameVersion;
} // End of namespace Sludge

232
engines/sludge/zbuffer.cpp Normal file
View File

@@ -0,0 +1,232 @@
/* 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 "image/png.h"
#include "sludge/fileset.h"
#include "sludge/graphics.h"
#include "sludge/newfatal.h"
#include "sludge/sludge.h"
#include "sludge/zbuffer.h"
#include "graphics/managed_surface.h"
namespace Sludge {
void GraphicsManager::killZBuffer() {
if (_zBuffer->tex) {
delete[] _zBuffer->tex;
_zBuffer->tex = nullptr;
}
_zBuffer->numPanels = 0;
_zBuffer->originalNum = -1;
}
void GraphicsManager::sortZPal(int *oldpal, int *newpal, int size) {
int i, tmp;
for (i = 0; i < size; i++) {
newpal[i] = i;
}
if (size < 2)
return;
for (i = 1; i < size; i++) {
if (oldpal[newpal[i]] < oldpal[newpal[i - 1]]) {
tmp = newpal[i];
newpal[i] = newpal[i - 1];
newpal[i - 1] = tmp;
i = 0;
}
}
}
bool GraphicsManager::setZBuffer(int num) {
// if the backdrop has not been set yet
// set zbuffer later
if (!_backdropSurface.getPixels()) {
_zBuffer->originalNum = num;
return true;
}
debug (kSludgeDebugGraphics, "Setting zBuffer");
uint32 stillToGo = 0;
int yPalette[16], sorted[16], sortback[16];
killZBuffer();
setResourceForFatal(num);
_zBuffer->originalNum = num;
uint fsize = g_sludge->_resMan->openFileFromNum(num);
if (!fsize)
return false;
Common::SeekableReadStream *readStream = g_sludge->_resMan->getData();
g_sludge->_resMan->dumpFile(num, "zbuffer%04d.zbu");
if (readStream->readByte() != 'S')
return fatal("Not a Z-buffer file");
if (readStream->readByte() != 'z')
return fatal("Not a Z-buffer file");
if (readStream->readByte() != 'b')
return fatal("Not a Z-buffer file");
switch (readStream->readByte()) {
case 0:
_zBuffer->width = 640;
_zBuffer->height = 480;
break;
case 1:
_zBuffer->width = readStream->readUint16BE();
_zBuffer->height = readStream->readUint16BE();
break;
default:
return fatal("Extended Z-buffer format not supported in this version of the SLUDGE engine");
}
if (_zBuffer->width != _sceneWidth || _zBuffer->height != _sceneHeight) {
Common::String tmp = Common::String::format("Z-w: %d Z-h:%d w: %d, h:%d", _zBuffer->width, _zBuffer->height, _sceneWidth, _sceneHeight);
return fatal("Z-buffer width and height don't match scene width and height", tmp);
}
_zBuffer->numPanels = readStream->readByte();
debugC(2, kSludgeDebugZBuffer, "Loading zBuffer : %i panels", _zBuffer->numPanels);
for (int y = 0; y < _zBuffer->numPanels; y++) {
yPalette[y] = readStream->readUint16BE();
}
sortZPal(yPalette, sorted, _zBuffer->numPanels);
for (int y = 0; y < _zBuffer->numPanels; y++) {
_zBuffer->panel[y] = yPalette[sorted[y]];
sortback[sorted[y]] = y;
debugC(2, kSludgeDebugZBuffer, "Y-value : %i", _zBuffer->panel[y]);
}
int picWidth = _sceneWidth;
int picHeight = _sceneHeight;
_zBuffer->tex = nullptr;
_zBuffer->tex = new uint8[picHeight * picWidth];
int n = 0;
for (uint y = 0; y < _sceneHeight; y++) {
for (uint x = 0; x < _sceneWidth; x++) {
if (stillToGo == 0) {
n = readStream->readByte();
stillToGo = n >> 4;
if (stillToGo == 15)
stillToGo = readStream->readUint16BE() + 16l;
else
stillToGo++;
n &= 15;
}
_zBuffer->tex[y*picWidth + x] = sortback[n];
stillToGo--;
}
}
g_sludge->_resMan->finishAccess();
setResourceForFatal(-1);
return true;
}
void GraphicsManager::fillZBuffer(uint8 d) {
memset(_zBufferSurface, d, _winHeight * _winWidth);
}
void GraphicsManager::drawSpriteToZBuffer(int x, int y, uint8 depth, const Graphics::Surface &surface) {
for (uint y1 = 0; y1 < (uint)surface.h; y1++) {
for (uint x1 = 0; x1 < (uint)surface.w; x1++) {
if (x1 + x >= _sceneWidth || y1 + y >= _sceneHeight) {
continue;
}
byte *target = (byte *)_renderSurface.getBasePtr(x1 + x, y1 + y);
const byte *source = (const byte *)surface.getBasePtr(x1, y1);
if (depth > _zBufferSurface[(y1 + y) * _winWidth + (x1 + x)]) {
if (source[0] == 0xff) {
// Completely opaque, so copy RGB values over
target[0] = 0xff;
target[1] = source[1];
target[2] = source[2];
target[3] = source[3];
}
}
}
}
}
void GraphicsManager::drawZBuffer(int x, int y, bool upsidedown) {
if (!_zBuffer->numPanels || !_zBuffer->tex)
return;
fillZBuffer(0);
int w = MIN<uint>(_zBuffer->width, _winWidth + x);
int h = MIN<uint>(_zBuffer->height, _winHeight + y);
for (int y1 = y; y1 < h; y1++) {
for (int x1 = x; x1 < w; x1++) {
uint8 z = 0;
if (upsidedown) {
z = (_zBuffer->tex[(_zBuffer->height - y1) * _zBuffer->width + x1] + 1) * 2;
} else {
z = (_zBuffer->tex[y1 * _zBuffer->width + x1] + 1) * 2;
}
if ( z > _zBufferSurface[(y1 - y) * _winWidth + (x1 - x)])
_zBufferSurface[(y1 - y) * _winWidth + (x1 - x)] = z;
}
}
}
void GraphicsManager::saveZBuffer(Common::WriteStream *stream) {
if (_zBuffer->numPanels > 0) {
stream->writeByte(1);
stream->writeUint16BE(_zBuffer->originalNum);
} else {
stream->writeByte(0);
}
}
bool GraphicsManager::loadZBuffer(Common::SeekableReadStream *stream) {
if (stream->readByte()) {
if (!setZBuffer(stream->readUint16BE()))
return false;
}
return true;
}
} // End of namespace Sludge

39
engines/sludge/zbuffer.h Normal file
View File

@@ -0,0 +1,39 @@
/* 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 SLUDGE_ZBUFFER_H
#define SLUDGE_ZBUFFER_H
namespace Sludge {
struct ZBufferData {
// bool loaded;
uint width, height;
int numPanels;
int panel[16];
int originalNum;
uint8 *tex;
Graphics::Surface *sprites;
};
} // End of namespace Sludges
#endif