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/cge/POTFILES Normal file
View File

@@ -0,0 +1,2 @@
engines/cge/detection.cpp
engines/cge/metaengine.cpp

385
engines/cge/bitmap.cpp Normal file
View File

@@ -0,0 +1,385 @@
/* 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 code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#include "cge/bitmap.h"
#include "cge/vga13h.h"
#include "cge/cge_main.h"
#include "common/system.h"
#include "common/debug.h"
#include "common/debug-channels.h"
namespace CGE {
Bitmap::Bitmap(CGEEngine *vm, const char *fname) : _m(nullptr), _v(nullptr), _map(0), _vm(vm) {
debugC(1, kCGEDebugBitmap, "Bitmap::Bitmap(%s)", fname);
char pat[kMaxPath];
forceExt(pat, fname, ".VBM");
if (_vm->_resman->exist(pat)) {
EncryptedStream file(_vm->_resman, pat);
if (file.err())
error("Unable to find VBM [%s]", fname);
if (!loadVBM(&file))
error("Bad VBM [%s]", fname);
} else {
error("Bad VBM [%s]", fname);
}
}
Bitmap::Bitmap(CGEEngine *vm, uint16 w, uint16 h, uint8 *map) : _w(w), _h(h), _m(map), _v(nullptr), _map(0), _b(nullptr), _vm(vm) {
debugC(1, kCGEDebugBitmap, "Bitmap::Bitmap(%d, %d, map)", w, h);
if (map)
code();
}
// following routine creates filled rectangle
// immediately as VGA video chunks, in near memory as fast as possible,
// especially for text line real time display
Bitmap::Bitmap(CGEEngine *vm, uint16 w, uint16 h, uint8 fill)
: _w((w + 3) & ~3), // only full uint32 allowed!
_h(h), _m(nullptr), _map(0), _b(nullptr), _vm(vm) {
debugC(1, kCGEDebugBitmap, "Bitmap::Bitmap(%d, %d, %d)", w, h, fill);
uint16 dsiz = _w >> 2; // data size (1 plane line size)
uint16 lsiz = 2 + dsiz + 2; // uint16 for line header, uint16 for gap
uint16 psiz = _h * lsiz; // - last gape, but + plane trailer
uint8 *v = new uint8[4 * psiz + _h * sizeof(*_b)];// the same for 4 planes
// + room for wash table
assert(v != nullptr);
WRITE_LE_UINT16(v, (kBmpCPY | dsiz)); // data chunk hader
memset(v + 2, fill, dsiz); // data bytes
WRITE_LE_UINT16(v + lsiz - 2, (kBmpSKP | ((kScrWidth / 4) - dsiz))); // gap
// Replicate lines
byte *destP;
for (destP = v + lsiz; destP < (v + psiz); destP += lsiz)
Common::copy(v, v + lsiz, destP);
WRITE_LE_UINT16(v + psiz - 2, kBmpEOI); // plane trailer uint16
// Replicate planes
for (destP = v + psiz; destP < (v + 4 * psiz); destP += psiz)
Common::copy(v, v + psiz, destP);
HideDesc *b = (HideDesc *)(v + 4 * psiz);
b->_skip = (kScrWidth - _w) >> 2;
b->_hide = _w >> 2;
// Replicate across the entire table
for (HideDesc *hdP = b + 1; hdP < (b + _h); hdP++)
*hdP = *b;
b->_skip = 0; // fix the first entry
_v = v;
_b = b;
}
Bitmap::Bitmap(CGEEngine *vm, const Bitmap &bmp) : _w(bmp._w), _h(bmp._h), _m(nullptr), _v(nullptr), _map(0), _b(nullptr), _vm(vm) {
debugC(1, kCGEDebugBitmap, "Bitmap::Bitmap(bmp)");
uint8 *v0 = bmp._v;
if (!v0)
return;
uint16 vsiz = (uint8 *)(bmp._b) - (uint8 *)(v0);
uint16 siz = vsiz + _h * sizeof(HideDesc);
uint8 *v1 = new uint8[siz];
assert(v1 != nullptr);
memcpy(v1, v0, siz);
_b = (HideDesc *)((_v = v1) + vsiz);
}
Bitmap::~Bitmap() {
debugC(6, kCGEDebugBitmap, "Bitmap::~Bitmap()");
free(_m);
delete[] _v;
}
Bitmap &Bitmap::operator=(const Bitmap &bmp) {
debugC(1, kCGEDebugBitmap, "&Bitmap::operator =");
if (this == &bmp)
return *this;
uint8 *v0 = bmp._v;
_w = bmp._w;
_h = bmp._h;
_m = nullptr;
_map = 0;
_vm = bmp._vm;
delete[] _v;
if (v0 == nullptr) {
_v = nullptr;
} else {
uint16 vsiz = (uint8 *)bmp._b - (uint8 *)v0;
uint16 siz = vsiz + _h * sizeof(HideDesc);
uint8 *v1 = new uint8[siz];
assert(v1 != nullptr);
memcpy(v1, v0, siz);
_b = (HideDesc *)((_v = v1) + vsiz);
}
return *this;
}
char *Bitmap::forceExt(char *buf, const char *name, const char *ext) {
Common::strcpy_s(buf, kMaxPath, name);
char *dot = strrchr(buf, '.');
if (dot)
*dot = '\0';
Common::strcat_s(buf, kMaxPath, ext);
return buf;
}
BitmapPtr Bitmap::code() {
debugC(1, kCGEDebugBitmap, "Bitmap::code()");
if (!_m)
return nullptr;
uint16 cnt;
if (_v) { // old X-map exists, so remove it
delete[] _v;
_v = nullptr;
}
while (true) { // at most 2 times: for (V == NULL) & for allocated block;
uint8 *im = _v + 2;
uint16 *cp = (uint16 *) _v;
int bpl;
if (_v) { // 2nd pass - fill the hide table
for (uint16 i = 0; i < _h; i++) {
_b[i]._skip = 0xFFFF;
_b[i]._hide = 0x0000;
}
}
for (bpl = 0; bpl < 4; bpl++) { // once per each bitplane
uint8 *bm = _m;
bool skip = (bm[bpl] == kPixelTransp);
uint16 j;
cnt = 0;
for (uint16 i = 0; i < _h; i++) { // once per each line
uint8 pix;
for (j = bpl; j < _w; j += 4) {
pix = bm[j];
if (_v && pix != kPixelTransp) {
if (j < _b[i]._skip)
_b[i]._skip = j;
if (j >= _b[i]._hide)
_b[i]._hide = j + 1;
}
if ((pix == kPixelTransp) != skip || cnt >= 0x3FF0) { // end of block
cnt |= (skip) ? kBmpSKP : kBmpCPY;
if (_v)
WRITE_LE_UINT16(cp, cnt); // store block description uint16
cp = (uint16 *) im;
im += 2;
skip = (pix == kPixelTransp);
cnt = 0;
}
if (!skip) {
if (_v)
*im = pix;
im++;
}
cnt++;
}
bm += _w;
if (_w < kScrWidth) {
if (skip) {
cnt += (kScrWidth - j + 3) / 4;
} else {
cnt |= kBmpCPY;
if (_v)
WRITE_LE_UINT16(cp, cnt);
cp = (uint16 *) im;
im += 2;
skip = true;
cnt = (kScrWidth - j + 3) / 4;
}
}
}
if (cnt && ! skip) {
cnt |= kBmpCPY;
if (_v)
WRITE_LE_UINT16(cp, cnt);
cp = (uint16 *) im;
im += 2;
}
if (_v)
WRITE_LE_UINT16(cp, kBmpEOI);
cp = (uint16 *) im;
im += 2;
}
if (_v)
break;
uint16 sizV = (uint16)(im - 2 - _v);
_v = new uint8[sizV + _h * sizeof(*_b)];
assert(_v != nullptr);
_b = (HideDesc *)(_v + sizV);
}
cnt = 0;
for (uint16 i = 0; i < _h; i++) {
if (_b[i]._skip == 0xFFFF) { // whole line is skipped
_b[i]._skip = (cnt + kScrWidth) >> 2;
cnt = 0;
} else {
uint16 s = _b[i]._skip & ~3;
uint16 h = (_b[i]._hide + 3) & ~3;
_b[i]._skip = (cnt + s) >> 2;
_b[i]._hide = (h - s) >> 2;
cnt = kScrWidth - h;
}
}
return this;
}
bool Bitmap::solidAt(int16 x, int16 y) {
debugC(6, kCGEDebugBitmap, "Bitmap::solidAt(%d, %d)", x, y);
if ((x >= _w) || (y >= _h))
return false;
uint8 *m = _v;
uint16 r = static_cast<uint16>(x) % 4;
uint16 n0 = (kScrWidth * y + x) / 4;
uint16 n = 0;
while (r) {
uint16 w, t;
w = READ_LE_UINT16(m);
m += 2;
t = w & 0xC000;
w &= 0x3FFF;
switch (t) {
case kBmpEOI:
r--;
// fall through
case kBmpSKP:
w = 0;
break;
case kBmpREP:
w = 1;
break;
case kBmpCPY:
default:
break;
}
m += w;
}
while (true) {
uint16 w, t;
w = READ_LE_UINT16(m);
m += 2;
t = w & 0xC000;
w &= 0x3FFF;
if (n > n0)
return false;
n += w;
switch (t) {
default:
case kBmpEOI:
return false;
case kBmpSKP:
w = 0;
break;
case kBmpREP:
case kBmpCPY:
if (n - w <= n0 && n > n0)
return true;
break;
}
m += ((t == kBmpREP) ? 1 : w);
}
}
bool Bitmap::loadVBM(EncryptedStream *f) {
debugC(5, kCGEDebugBitmap, "Bitmap::loadVBM(f)");
uint16 p = 0, n = 0;
if (!f->err())
f->read((uint8 *)&p, sizeof(p));
p = FROM_LE_16(p);
if (!f->err())
f->read((uint8 *)&n, sizeof(n));
n = FROM_LE_16(n);
if (!f->err())
f->read((uint8 *)&_w, sizeof(_w));
_w = FROM_LE_16(_w);
if (!f->err())
f->read((uint8 *)&_h, sizeof(_h));
_h = FROM_LE_16(_h);
if (!f->err()) {
if (p) {
if (_vm->_bitmapPalette) {
// Read in the palette
byte palData[kPalSize];
f->read(palData, kPalSize);
const byte *srcP = palData;
for (int idx = 0; idx < kPalCount; idx++, srcP += 3) {
_vm->_bitmapPalette[idx]._r = *srcP;
_vm->_bitmapPalette[idx]._g = *(srcP + 1);
_vm->_bitmapPalette[idx]._b = *(srcP + 2);
}
} else
f->seek(f->pos() + kPalSize);
}
}
if ((_v = new uint8[n]) == nullptr)
return false;
if (!f->err())
f->read(_v, n);
_b = (HideDesc *)(_v + n - _h * sizeof(HideDesc));
return (!f->err());
}
} // End of namespace CGE

86
engines/cge/bitmap.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/>.
*
*/
/*
* This code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#ifndef CGE_BITMAP_H
#define CGE_BITMAP_H
#include "cge/general.h"
#include "common/file.h"
namespace CGE {
class CGEEngine;
class EncryptedStream;
#define kMaxPath 128
enum {
kBmpEOI = 0x0000,
kBmpSKP = 0x4000,
kBmpREP = 0x8000,
kBmpCPY = 0xC000
};
#include "common/pack-start.h"
struct HideDesc {
uint16 _skip;
uint16 _hide;
} PACKED_STRUCT;
#include "common/pack-end.h"
class Bitmap {
CGEEngine *_vm;
char *forceExt(char *buf, const char *name, const char *ext);
bool loadVBM(EncryptedStream *f);
public:
uint16 _w;
uint16 _h;
uint8 *_m;
uint8 *_v;
int32 _map;
HideDesc *_b;
Bitmap(CGEEngine *vm, const char *fname);
Bitmap(CGEEngine *vm, uint16 w, uint16 h, uint8 *map);
Bitmap(CGEEngine *vm, uint16 w, uint16 h, uint8 fill);
Bitmap(CGEEngine *vm, const Bitmap &bmp);
~Bitmap();
Bitmap *code();
Bitmap &operator=(const Bitmap &bmp);
void hide(int16 x, int16 y);
void show(int16 x, int16 y);
void xShow(int16 x, int16 y);
bool solidAt(int16 x, int16 y);
};
typedef Bitmap *BitmapPtr;
} // End of namespace CGE
#endif

258
engines/cge/cge.cpp Normal file
View File

@@ -0,0 +1,258 @@
/* 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/scummsys.h"
#include "common/config-manager.h"
#include "common/debug.h"
#include "common/debug-channels.h"
#include "common/error.h"
#include "common/file.h"
#include "common/fs.h"
#include "common/text-to-speech.h"
#include "engines/advancedDetector.h"
#include "engines/util.h"
#include "gui/message.h"
#include "cge/cge.h"
#include "cge/vga13h.h"
#include "cge/cge_main.h"
#include "cge/talk.h"
#include "cge/text.h"
#include "cge/walk.h"
namespace CGE {
const int CGEEngine::_maxSceneArr[5] = {1, 8, 16, 23, 24};
CGEEngine::CGEEngine(OSystem *syst, const ADGameDescription *gameDescription)
: Engine(syst), _gameDescription(gameDescription), _randomSource("cge") {
_bitmapPalette = nullptr;
_pocLight = nullptr;
_keyboard = nullptr;
_mouse = nullptr;
_sprite = nullptr;
_miniScene = nullptr;
_shadow = nullptr;
_horzLine = nullptr;
_infoLine = nullptr;
_debugLine = nullptr;
_sceneLight = nullptr;
_commandHandler = nullptr;
_commandHandlerTurbo = nullptr;
_eventManager = nullptr;
_fx = nullptr;
_sound = nullptr;
_resman = nullptr;
for (int i = 0; i < 8; i++)
_pocket[i] = nullptr;
_hero = nullptr;
_text = nullptr;
_talk = nullptr;
_midiPlayer = nullptr;
_miniShp = nullptr;
_miniShpList = nullptr;
_sprTv = nullptr;
_sprK1 = nullptr;
_sprK2 = nullptr;
_sprK3 = nullptr;
_font = nullptr;
_vga = nullptr;
_sys = nullptr;
_quitFlag = false;
_showBoundariesFl = false;
_music = true;
_dark = false;
_game = false;
_endGame = false;
for (int i = 0; i < 4; i++)
_flag[i] = false;
_startupMode = 1;
_oldLev = 0;
_pocPtr = 0;
_startGameSlot = -1;
_recentStep = -2;
_lastFrame = 0;
_lastTick = 0;
_maxScene = 0;
_now = 1;
_lev = -1;
_mode = 0;
_gameCase2Cpt = 0;
_offUseCount = 0;
_volume[0] = 0;
_volume[1] = 0;
for (int i = 0; i < kPocketNX; i++)
_pocref[i] = -1;
initSceneValues();
}
void CGEEngine::initSceneValues() {
for (int i = 0; i < kSceneMax; i++) {
_heroXY[i].x = 0;
_heroXY[i].y = 0;
}
for (int i = 0; i < kSceneMax + 1; i++) {
_barriers[i]._horz = 0xFF;
_barriers[i]._vert = 0xFF;
}
}
void CGEEngine::init() {
debugC(1, kCGEDebugEngine, "CGEEngine::init()");
// Initialize fields
_hero = nullptr;
_shadow = nullptr;
_miniScene = nullptr;
_miniShp = nullptr;
_miniShpList = nullptr;
_sprite = nullptr;
_resman = new ResourceManager();
// Create debugger console
setDebugger(new CGEConsole(this));
// Initialize engine objects
_font = new Font(this, "CGE");
_text = new Text(this, "CGE");
_talk = nullptr;
_vga = new Vga(this);
_sys = new System(this);
_pocLight = new PocLight(this);
for (int i = 0; i < kPocketNX; i++)
_pocket[i] = nullptr;
_horzLine = new HorizLine(this);
_infoLine = new InfoLine(this, kInfoW);
_sceneLight = new SceneLight(this);
_debugLine = new InfoLine(this, kScrWidth);
_commandHandler = new CommandHandler(this, false);
_commandHandlerTurbo = new CommandHandler(this, true);
_midiPlayer = new MusicPlayer(this);
_mouse = new Mouse(this);
_keyboard = new Keyboard(this);
_eventManager = new EventManager(this);
_fx = new Fx(this, 16); // must precede SOUND!!
_sound = new Sound(this);
_offUseCount = atoi(_text->getText(kOffUseCount));
_startGameSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1;
Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
if (ttsMan != nullptr)
ttsMan->enable(ConfMan.getBool("tts_enabled"));
}
void CGEEngine::deinit() {
// Delete engine objects
delete _vga;
delete _sys;
delete _sprite;
delete _miniScene;
delete _shadow;
delete _horzLine;
delete _infoLine;
delete _sceneLight;
delete _debugLine;
delete _text;
delete _pocLight;
delete _keyboard;
delete _mouse;
delete _eventManager;
delete _sound;
delete _fx;
delete _midiPlayer;
delete _font;
delete _commandHandler;
delete _commandHandlerTurbo;
delete _hero;
delete _resman;
if (_miniShpList) {
for (int i = 0; _miniShpList[i]; ++i)
delete _miniShpList[i];
delete[] _miniShpList;
}
}
CGEEngine::~CGEEngine() {
debugC(1, kCGEDebugEngine, "CGEEngine::~CGEEngine()");
}
Common::Error CGEEngine::run() {
debugC(1, kCGEDebugEngine, "CGEEngine::run()");
if (_gameDescription->flags & ADGF_DEMO) {
warning("Demos of Soltys are not supported.\nPlease get a free version on ScummVM download page");
return Common::kUnsupportedGameidError;
}
// Initialize graphics using following:
initGraphics(kScrWidth, kScrHeight);
// Setup necessary game objects
init();
// Run the game
cge_main();
// If game is finished, display ending message
if (_flag[3]) {
Common::String msg = Common::String(_text->getText(kSayTheEnd));
if (!msg.empty()) {
g_system->delayMillis(10);
GUI::MessageDialog dialog(msg);
dialog.runModal();
Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
if (ttsMan != nullptr && ConfMan.getBool("tts_enabled")) {
ttsMan->say(msg);
}
}
}
// Remove game objects
deinit();
return Common::kNoError;
}
bool CGEEngine::hasFeature(EngineFeature f) const {
return
(f == kSupportsReturnToLauncher) ||
(f == kSupportsLoadingDuringRuntime) ||
(f == kSupportsSavingDuringRuntime);
}
bool CGEEngine::canLoadGameStateCurrently(Common::U32String *msg) {
return (_startupMode == 0) && _mouse->_active;
}
bool CGEEngine::canSaveGameStateCurrently(Common::U32String *msg) {
return (_startupMode == 0) && _mouse->_active &&
_commandHandler->idle() && !_hero->_flags._hide;
}
} // End of namespace CGE

353
engines/cge/cge.h Normal file
View File

@@ -0,0 +1,353 @@
/* 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 CGE_CGE_H
#define CGE_CGE_H
#include "common/random.h"
#include "common/savefile.h"
#include "common/serializer.h"
#include "common/str.h"
#include "common/rect.h"
#include "engines/engine.h"
#include "gui/debugger.h"
#include "graphics/surface.h"
#include "cge/console.h"
#include "cge/bitmap.h"
#include "cge/sound.h"
struct ADGameDescription;
namespace CGE {
class Console;
class Sprite;
class Cluster;
class Vga;
class System;
class Keyboard;
class Mouse;
class HorizLine;
class InfoLine;
class SceneLight;
class CommandHandler;
class EventManager;
class ResourceManager;
class Walk;
class Text;
class Talk;
#define kSavegameVersion 3
#define kSavegameStrSize 11
#define kPocketX 174
#define kPocketY 176
#define kPocketDX 18
#define kPocketDY 22
#define kPocketNX 8
#define kPocketNY 1
#define kPocketSX 8
#define kPocketSY 3
#define kSceneDx 9
#define kSceneDy 10
#define kSceneNx 8
#define kSceneNy 3
#define kSceneMax kSceneNx * kSceneNy
#define kPathMax 128
#define kCryptSeed 0xA5
#define kMaxFile 128
#define kMapXCnt 40
#define kMapZCnt 20
#define kMapTop 80
#define kSayTheEnd 41
enum CGEAction {
kActionNone,
kActionInfo,
kActionEscape,
kActionSave,
kActionLoad,
kActionQuit,
kActionInv1,
kActionInv2,
kActionInv3,
kActionInv4,
kActionInv5,
kActionInv6,
kActionInv7,
kActionInv8,
kActionAltDice,
kActionLevel0,
kActionLevel1,
kActionLevel2,
kActionLevel3,
kActionLevel4
};
// our engine debug channels
enum {
kCGEDebugBitmap = 1,
kCGEDebugFile,
kCGEDebugEngine,
};
enum SnList {
kNear, kTake
};
enum CallbackType {
kNullCB = 0, kQGame, kMiniStep, kXScene, kSoundSetVolume
};
struct SavegameHeader {
uint8 version;
Common::String saveName;
Graphics::Surface *thumbnail;
int16 saveYear, saveMonth, saveDay;
int16 saveHour, saveMinutes;
uint32 playTime;
};
extern const char *savegameStr;
struct Bar {
uint8 _horz;
uint8 _vert;
};
class Font {
char _path[kPathMax];
void load();
CGEEngine *_vm;
public:
uint8 *_widthArr;
uint16 *_pos;
uint8 *_map;
Font(CGEEngine *vm, const char *name);
~Font();
uint16 width(const char *text);
void save();
};
class CGEEngine : public Engine {
private:
uint32 _lastFrame, _lastTick;
void tick();
void syncHeader(Common::Serializer &s);
void writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header);
void syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream, bool tiny);
bool savegameExists(int slotNumber);
public:
CGEEngine(OSystem *syst, const ADGameDescription *gameDescription);
~CGEEngine() override;
bool hasFeature(EngineFeature f) const override;
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
Common::Error loadGameState(int slot) override;
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
static const int _maxSceneArr[5];
bool _quitFlag;
bool _showBoundariesFl;
const ADGameDescription *_gameDescription;
int _startupMode;
int _oldLev;
int _pocPtr;
bool _music;
int _pocref[kPocketNX];
uint8 _volume[2];
int _maxScene;
bool _flag[4];
bool _dark;
bool _game;
bool _endGame;
int _now;
int _lev;
int _mode;
int _gameCase2Cpt;
int _offUseCount;
Dac *_bitmapPalette;
uint8 _clusterMap[kMapZCnt][kMapXCnt];
Sprite *_sprTv;
Sprite *_sprK1;
Sprite *_sprK2;
Sprite *_sprK3;
Common::Point _heroXY[kSceneMax];
Bar _barriers[kSceneMax + 1];
Font *_font;
Vga *_vga;
System *_sys;
Sprite *_pocLight;
Keyboard *_keyboard;
Mouse *_mouse;
Sprite *_sprite;
Sprite *_miniScene;
Sprite *_shadow;
HorizLine *_horzLine;
InfoLine *_infoLine;
InfoLine *_debugLine;
SceneLight *_sceneLight;
CommandHandler *_commandHandler;
CommandHandler *_commandHandlerTurbo;
EventManager *_eventManager;
Fx *_fx;
Sound *_sound;
ResourceManager *_resman;
Sprite *_pocket[kPocketNX];
Walk *_hero;
Text *_text;
Talk *_talk;
Common::RandomSource _randomSource;
MusicPlayer *_midiPlayer;
BitmapPtr *_miniShp;
BitmapPtr *_miniShpList;
int _startGameSlot;
Common::Error run() override;
void cge_main();
void switchScene(int newScene);
void startCountDown();
void quit();
void resetQSwitch();
void optionTouch(int opt, uint16 mask);
void resetGame();
bool loadGame(int slotNumber, SavegameHeader *header = NULL, bool tiny = false);
void setMapBrick(int x, int z);
void switchMapping();
void loadSprite(const char *fname, int ref, int scene, int col, int row, int pos);
void loadScript(const char *fname);
void loadUser();
void runGame();
bool showTitle(const char *name);
void movie(const char *ext);
void inf(const char *text, bool wideSpace = false);
void selectSound();
void dummy() {}
void NONE();
void SB();
void sceneDown();
void sceneUp();
void xScene();
void qGame();
void SBM();
void GUS();
void GUSM();
void MIDI();
void AUTO();
void setPortD();
void setPortM();
void setIRQ();
void setDMA();
void mainLoop();
void handleFrame();
void saveGame(int slotNumber, const Common::String &desc);
WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail = true);
void switchMusic();
void selectPocket(int n);
void expandSprite(Sprite *spr);
void contractSprite(Sprite *spr);
int findPocket(Sprite *spr);
void feedSnail(Sprite *spr, SnList snq);
void pocFul();
void hide1(Sprite *spr);
void loadMapping();
void heroCover(int cvr);
void trouble(int seq, int text);
void offUse();
void tooFar();
void loadHeroXY();
void keyClick();
void switchColorMode();
void killSprite();
void switchDebug();
void miniStep(int stp);
void postMiniStep(int stp);
void showBak(int ref);
void initSceneValues();
char *mergeExt(char *buf, const char *name, const char *ext);
int takeEnum(const char **tab, const char *text);
int newRandom(int range);
void sndSetVolume();
Sprite *locate(int ref);
Sprite *spriteAt(int x, int y);
Cluster XZ(int16 x, int16 y);
void killText();
void snBackPt(Sprite *spr, int stp);
void snHBarrier(const int scene, const int barX);
void snVBarrier(const int scene, const int barY);
void snCover(Sprite *spr, int xref);
void snFlag(int indx, bool v);
void snFlash(bool on);
void snGame(Sprite *spr, int num);
void snGhost(Bitmap *bmp);
void snGive(Sprite *spr, int stp);
void snHide(Sprite *spr, int val);
void snKeep(Sprite *spr, int stp);
void snKill(Sprite *spr);
void snLevel(Sprite *spr, int lev);
void snLight(bool in);
void snMouse(bool on);
void snNNext(Sprite *spr, int p);
void snPort(Sprite *spr, int port);
void snReach(Sprite *spr, int mode);
void snRelZ(Sprite *spr, int z);
void snRNNext(Sprite *spr, int p);
void snRTNext(Sprite *spr, int p);
void snSend(Sprite *spr, int val);
void snRelX(Sprite *spr, int x);
void snRelY(Sprite *spr, int y);
void snRmNear(Sprite *spr);
void snRmTake(Sprite *spr);
void snRSeq(Sprite *spr, int val);
void snSeq(Sprite *spr, int val);
void snSetRef(Sprite *spr, int nr);
void snSetX(Sprite *spr, int x);
void snSetX0(int scene, int x0);
void snSetXY(Sprite *spr, uint16 xy);
void snSetY(Sprite *spr, int y);
void snSetY0(int scene, int y0);
void snSetZ(Sprite *spr, int z);
void snSlave(Sprite *spr, int ref);
void snSound(Sprite *spr, int wav);
void snSwap(Sprite *spr, int xref);
void snTNext(Sprite *spr, int p);
void snTrans(Sprite *spr, int trans);
void snUncover(Sprite *spr, Sprite *xspr);
void snWalk(Sprite *spr, int x, int y);
void snZTrim(Sprite *spr);
protected:
int _recentStep;
private:
void init();
void deinit();
};
} // End of namespace CGE
#endif

1560
engines/cge/cge_main.cpp Normal file

File diff suppressed because it is too large Load Diff

110
engines/cge/cge_main.h Normal file
View File

@@ -0,0 +1,110 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#ifndef CGE_CGEMAIN_H
#define CGE_CGEMAIN_H
#include "cge/events.h"
namespace CGE {
#define kSceneX 4
#define kSceneY 166
#define kSceneSX 0
#define kSceneSY 0
#define kInfoX 177
#define kInfoY 164
#define kInfoW 140
#define kButtonX 151
#define kButtonY 164
#define kMiniX 86
#define kMiniY 162
#define kLineMax 512
#define kDistMax 3
#define kLgoExt ".LGO"
#define kSvgExt ".SVG"
#define kPaylistExt ".X00"
#define kWinkExt ".X01"
#define kIntroExt ".X02"
#define kEndgExt ".X03"
#define kWalkSide 10
#define kBusyRef 500
#define kSystemRate 6 // 12 Hz
#define kHeroFun0 (40 * 12)
#define kHeroFun1 ( 2 * 12)
#define kShowScummVMVersion 15
#define kTSeq 96
#define kBadSVG 99
#define kSeqHTalk (kTSeq + 4)
#define kSeqTooFar (kTSeq + 5)
#define kSeqNoWay (kTSeq + 5)
#define kSeqPocketFull (kTSeq + 5)
#define kSeqOffUse (kTSeq + 6)
#define kQuitTitle 200
#define kQuit 201
#define kNoQuit 202
#define kDemo 300
#define kOffUseCount 600
#define kOffUse 601
#define kNoWay 671
#define kTooFar 681
#define kPocketFull 691
#define kPanHeight 40
#define kScrWidth 320
#define kScrHeight 200
#define kWorldHeight (kScrHeight - kPanHeight)
#define kStackSize 2048
#define kSavegameCheckSum (1956 + _now + _oldLev + _game + _music + kDemo)
#define kSavegame0Name ("{{INIT}}" kSvgExt)
#define kSavegameStrSize 11
#define kGameFrameDelay (1000 / 50)
#define kGameTickDelay (1000 / 62)
class System : public Sprite {
public:
int _funDel;
System(CGEEngine *vm);
void setPal();
void funTouch();
void touch(uint16 mask, int x, int y) override;
void tick() override;
private:
CGEEngine *_vm;
};
class Square : public Sprite {
public:
Square(CGEEngine *vm);
void touch(uint16 mask, int x, int y) override;
private:
CGEEngine *_vm;
};
} // End of namespace CGE
#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 cge "CGE" yes "" "" "" "midi"

47
engines/cge/console.cpp Normal file
View File

@@ -0,0 +1,47 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "cge/console.h"
#include "cge/cge.h"
namespace CGE {
CGEConsole::CGEConsole(CGEEngine *vm) : GUI::Debugger(), _vm(vm) {
registerCmd("Boundaries", WRAP_METHOD(CGEConsole, Cmd_boundaries));
}
CGEConsole::~CGEConsole() {
}
/**
* This command shows and hides boundaries
*/
bool CGEConsole::Cmd_boundaries(int argc, const char **argv) {
if (argc != 1) {
debugPrintf("Usage: %s\n", argv[0]);
return true;
}
_vm->_showBoundariesFl = !_vm->_showBoundariesFl;
return false;
}
} // End of namespace CGE

43
engines/cge/console.h Normal file
View File

@@ -0,0 +1,43 @@
/* 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 CGE_CONSOLE_H
#define CGE_CONSOLE_H
#include "gui/debugger.h"
namespace CGE {
class CGEEngine;
class CGEConsole : public GUI::Debugger {
public:
CGEConsole(CGEEngine *vm);
~CGEConsole() override;
private:
CGEEngine *_vm;
bool Cmd_boundaries(int argc, const char **argv);
};
} // End of namespace CGE
#endif

4
engines/cge/credits.pl Normal file
View File

@@ -0,0 +1,4 @@
begin_section("CGE");
add_person("Arnaud Boutonn&eacute;", "Strangerke", "");
add_person("Paul Gilbert", "dreammaster", "");
end_section();

168
engines/cge/detection.cpp Normal file
View File

@@ -0,0 +1,168 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "base/plugins.h"
#include "engines/advancedDetector.h"
#include "common/translation.h"
#include "cge/fileio.h"
#include "cge/cge.h"
#include "cge/detection.h"
static const DebugChannelDef debugFlagList[] = {
{CGE::kCGEDebugBitmap, "bitmap", "CGE Bitmap debug channel"},
{CGE::kCGEDebugFile, "file", "CGE IO debug channel"},
{CGE::kCGEDebugEngine, "engine", "CGE Engine debug channel"},
DEBUG_CHANNEL_END
};
namespace CGE {
static const PlainGameDescriptor CGEGames[] = {
{ "soltys", "So\305\202tys" },
{ nullptr, nullptr }
};
static const ADGameDescription gameDescriptions[] = {
{
"soltys", "Freeware",
AD_ENTRY2s("vol.cat", "0c33e2c304821a2444d297fc5e2d67c6", 50176,
"vol.dat", "f9ae2e7f8f7cac91378cdafca43faf1e", 8437676),
Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO2(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF, GAMEOPTION_TTS)
},
{
"soltys", MetaEngineDetection::GAME_NOT_IMPLEMENTED,
AD_ENTRY2s("vol.cat", "1e077c8ff58109a187f07ac54b0c873a", 18788,
"vol.dat", "75d385a6074c58b69f7730481f256051", 1796710),
Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO , GUIO2(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF, GAMEOPTION_TTS)
},
{
"soltys", MetaEngineDetection::GAME_NOT_IMPLEMENTED,
AD_ENTRY2s("vol.cat", "f17987487fab1ebddd781d8d02fedecc", 7168,
"vol.dat", "c5d9b15863cab61dc125551576dece04", 1075272),
Common::PL_POL, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSUPPORTED , GUIO2(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF, GAMEOPTION_TTS)
},
{
"soltys", MetaEngineDetection::GAME_NOT_IMPLEMENTED,
AD_ENTRY2s("vol.cat", "ad3c90abf775a45380ce56e4494923fb", 9216,
"vol.dat", "c5d9b15863cab61dc125551576dece04", 1518836),
Common::PL_POL, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSUPPORTED , GUIO2(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF, GAMEOPTION_TTS)
},
{
"soltys", "Freeware v1.0",
AD_ENTRY2s("vol.cat", "f1675684c68ab90272f5776f8f2c3974", 50176,
"vol.dat", "4ffeff4abc99ac5999b55ccfc56ab1df", 8430868),
Common::EN_ANY, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO2(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF, GAMEOPTION_TTS)
},
{
"soltys", "Freeware v1.0",
AD_ENTRY2s("vol.cat", "20fdce799adb618100ef9ee2362be875", 50176,
"vol.dat", "0e43331c846094d77f5dd201827e0a3b", 8439339),
Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO2(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF, GAMEOPTION_TTS)
},
{
"soltys", "Freeware v1.0",
AD_ENTRY2s("vol.cat", "fcae86b20eaa5cedec17b24fa5e85eb4", 50176,
"vol.dat", "ff10d54acc2c95696c57e05819b6906f", 8450151),
Common::ES_ESP, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO2(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF, GAMEOPTION_TTS)
},
{
"soltys", "Russian fan-translation v1.0",
AD_ENTRY2s("vol.cat", "e9f6069c9c4d4156a8dbe004a9c1960d", 50176,
"vol.dat", "f9ae2e7f8f7cac91378cdafca43faf1e", 8749623),
Common::RU_RUS, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO2(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF, GAMEOPTION_TTS)
},
{
"soltys", "Russian fan-translation v1.1",
AD_ENTRY2s("vol.cat", "72a93fa5b81f29aaf362f1dc8a5956e0", 50176,
"vol.dat", "b93e053cabf8dfdcece3de59a8e2f9e1", 8739481),
Common::RU_RUS, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO2(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF, GAMEOPTION_TTS)
},
AD_TABLE_END_MARKER
};
class CGEMetaEngineDetection : public AdvancedMetaEngineDetection<ADGameDescription> {
public:
CGEMetaEngineDetection() : AdvancedMetaEngineDetection(CGE::gameDescriptions, CGEGames) {
}
const char *getName() const override {
return "cge";
}
const char *getEngineName() const override {
return "CGE";
}
const char *getOriginalCopyright() const override {
return "So\305\202tys (C) 1994-1996 L.K. Avalon";
}
const DebugChannelDef *getDebugChannels() const override {
return debugFlagList;
}
ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist, ADDetectedGameExtraInfo **extra) const override;
};
static ADGameDescription s_fallbackDesc = {
"soltys",
"Unknown version",
AD_ENTRY1(nullptr, nullptr), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor
Common::UNK_LANG,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
};
static const ADFileBasedFallback fileBasedFallback[] = {
{ &s_fallbackDesc, { "vol.cat", "vol.dat", nullptr } },
{ nullptr, { nullptr } }
};
ADDetectedGame CGEMetaEngineDetection::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist, ADDetectedGameExtraInfo **extra) const {
ADDetectedGame game = detectGameFilebased(allFiles, CGE::fileBasedFallback);
if (!game.desc)
return ADDetectedGame();
SearchMan.addDirectory("CGEMetaEngineDetection::fallbackDetect", fslist.begin()->getParent());
ResourceManager *resman;
resman = new ResourceManager();
bool sayFileFound = resman->exist("CGE.SAY");
delete resman;
SearchMan.remove("CGEMetaEngineDetection::fallbackDetect");
if (!sayFileFound)
return ADDetectedGame();
return game;
}
} // End of namespace CGE
REGISTER_PLUGIN_STATIC(CGE_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, CGE::CGEMetaEngineDetection);

28
engines/cge/detection.h Normal file
View File

@@ -0,0 +1,28 @@
/* 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 CGE_DETECTION_H
#define CGE_DETECTION_H
#define GAMEOPTION_COLOR_BLIND_DEFAULT_OFF GUIO_GAMEOPTIONS1
#define GAMEOPTION_TTS GUIO_GAMEOPTIONS2
#endif

298
engines/cge/events.cpp Normal file
View File

@@ -0,0 +1,298 @@
/* 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 code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#include "gui/saveload.h"
#include "common/config-manager.h"
#include "common/events.h"
#include "engines/advancedDetector.h"
#include "cge/events.h"
#include "cge/events.h"
#include "cge/text.h"
#include "cge/cge_main.h"
namespace CGE {
/*----------------- KEYBOARD interface -----------------*/
Keyboard::Keyboard(CGEEngine *vm) : _client(nullptr), _vm(vm) {
_keyAlt = false;
}
Keyboard::~Keyboard() {
}
Sprite *Keyboard::setClient(Sprite *spr) {
SWAP(_client, spr);
return spr;
}
void Keyboard::handleAction(Common::Event &event) {
_keyAlt = false;
switch (event.customType) {
case kActionInfo:
// Display ScummVM version and translation strings
for (int i = 0; i < 5; i++)
_vm->_commandHandler->addCommand(kCmdInf, 1, kShowScummVMVersion + i, nullptr);
break;
case kActionSave:
_vm->saveGameDialog();
break;
case kActionLoad:
_vm->loadGameDialog();
break;
case kActionQuit:
_vm->quit();
break;
case kActionEscape:
if (_client) {
CGEEvent &evt = _vm->_eventManager->getNextEvent();
evt._x = 0;
evt._y = 0;
evt._mask = kEventEsc; // Event mask
evt._spritePtr = _client; // Sprite pointer
}
break;
case kActionAltDice:
_keyAlt = true;
break;
case kActionInv1:
case kActionInv2:
case kActionInv3:
case kActionInv4:
case kActionInv5:
case kActionInv6:
case kActionInv7:
case kActionInv8:
_vm->selectPocket(event.customType - kActionInv1);
break;
case kActionLevel0:
case kActionLevel1:
case kActionLevel2:
case kActionLevel3:
case kActionLevel4:
_vm->_commandHandler->addCommand(kCmdLevel, -1, event.customType - kActionLevel0, nullptr);
break;
default:
break;
}
}
/*----------------- MOUSE interface -----------------*/
Mouse::Mouse(CGEEngine *vm) : Sprite(vm, nullptr), _busy(nullptr), _hold(nullptr), _hx(0), _vm(vm) {
_hold = nullptr;
_hx = 0;
_hy = 0;
_exist = true;
_buttons = 0;
_busy = nullptr;
_active = false;
_flags._kill = false;
const Seq ms[] = {
{ 0, 0, 0, 0, 1 },
{ 1, 1, 0, 0, 1 }
};
Seq *seq = (Seq *)malloc(2 * sizeof(Seq));
Common::copy(ms, ms + 2, seq);
setSeq(seq);
BitmapPtr *MC = new BitmapPtr[3];
MC[0] = new Bitmap(_vm, "MOUSE");
MC[1] = new Bitmap(_vm, "DUMMY");
MC[2] = nullptr;
setShapeList(MC);
gotoxy(kScrWidth / 2, kScrHeight / 2);
_z = 127;
step(1);
}
Mouse::~Mouse() {
off();
}
void Mouse::on() {
if (_seqPtr && _exist) {
_active = true;
step(0);
if (_busy)
_busy->step(0);
}
}
void Mouse::off() {
if (_seqPtr == 0) {
if (_exist) {
_active = false;
}
step(1);
if (_busy)
_busy->step(1);
}
}
void Mouse::newMouse(Common::Event &event) {
if (!_active)
return;
CGEEvent &evt = _vm->_eventManager->getNextEvent();
evt._x = event.mouse.x;
evt._y = event.mouse.y;
evt._spritePtr = _vm->spriteAt(evt._x, evt._y);
switch (event.type) {
case Common::EVENT_MOUSEMOVE:
evt._mask = kMouseRoll;
break;
case Common::EVENT_LBUTTONDOWN:
evt._mask = kMouseLeftDown;
_buttons |= 1;
break;
case Common::EVENT_LBUTTONUP:
evt._mask = kMouseLeftUp;
_buttons &= ~1;
break;
case Common::EVENT_RBUTTONDOWN:
evt._mask = kMouseRightDown;
_buttons |= 2;
break;
case Common::EVENT_RBUTTONUP:
evt._mask = kMouseRightUp;
_buttons &= ~2;
break;
default:
break;
}
}
/*----------------- EventManager interface -----------------*/
EventManager::EventManager(CGEEngine *vm) : _vm(vm){
_eventQueueHead = 0;
_eventQueueTail = 0;
for (uint16 k = 0; k < kEventMax; k++) {
_eventQueue[k]._mask = 0;
_eventQueue[k]._x = 0;
_eventQueue[k]._y = 0;
_eventQueue[k]._spritePtr = nullptr;
}
_event.joystick.axis = 0;
_event.joystick.position = 0;
_event.joystick.button = 0;
}
void EventManager::poll() {
while (g_system->getEventManager()->pollEvent(_event)) {
switch (_event.type) {
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
// Handle keyboard events
_vm->_keyboard->handleAction(_event);
handleEvents();
break;
case Common::EVENT_MOUSEMOVE:
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONDOWN:
case Common::EVENT_RBUTTONUP:
// Handle mouse events
_vm->_mouse->newMouse(_event);
handleEvents();
break;
default:
break;
}
}
}
void EventManager::handleEvents() {
while (_eventQueueTail != _eventQueueHead) {
CGEEvent e = _eventQueue[_eventQueueTail];
if (e._mask) {
if (_vm->_mouse->_hold && e._spritePtr != _vm->_mouse->_hold)
_vm->_mouse->_hold->touch(e._mask | kEventAttn, e._x - _vm->_mouse->_hold->_x, e._y - _vm->_mouse->_hold->_y);
// update mouse cursor position
if (e._mask & kMouseRoll)
_vm->_mouse->gotoxy(e._x, e._y);
// activate current touched SPRITE
if (e._spritePtr) {
e._spritePtr->touch(e._mask, e._x - e._spritePtr->_x, e._y - e._spritePtr->_y);
} else if (_vm->_sys)
_vm->_sys->touch(e._mask, e._x, e._y);
if (e._mask & kMouseLeftDown) {
_vm->_mouse->_hold = e._spritePtr;
if (_vm->_mouse->_hold) {
_vm->_mouse->_hold->_flags._hold = true;
if (_vm->_mouse->_hold->_flags._drag) {
_vm->_mouse->_hx = e._x - _vm->_mouse->_hold->_x;
_vm->_mouse->_hy = e._y - _vm->_mouse->_hold->_y;
}
}
}
if (e._mask & kMouseLeftUp) {
if (_vm->_mouse->_hold) {
_vm->_mouse->_hold->_flags._hold = false;
_vm->_mouse->_hold = nullptr;
}
}
///Touched = e.Ptr;
// discard Text if button released
if (e._mask & (kMouseLeftUp | kMouseRightUp))
_vm->killText();
}
_eventQueueTail = (_eventQueueTail + 1) % kEventMax;
}
if (_vm->_mouse->_hold) {
if (_vm->_mouse->_hold->_flags._drag)
_vm->_mouse->_hold->gotoxy(_vm->_mouse->_x - _vm->_mouse->_hx, _vm->_mouse->_y - _vm->_mouse->_hy);
}
}
void EventManager::clearEvent(Sprite *spr) {
if (spr) {
for (uint16 e = _eventQueueTail; e != _eventQueueHead; e = (e + 1) % kEventMax)
if (_eventQueue[e]._spritePtr == spr)
_eventQueue[e]._mask = 0;
} else
_eventQueueTail = _eventQueueHead;
}
CGEEvent &EventManager::getNextEvent() {
CGEEvent &evt = _eventQueue[_eventQueueHead];
_eventQueueHead = (_eventQueueHead + 1) % kEventMax;
return evt;
}
} // End of namespace CGE

113
engines/cge/events.h Normal file
View File

@@ -0,0 +1,113 @@
/* 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 code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#ifndef CGE_EVENTS_H
#define CGE_EVENTS_H
#include "common/events.h"
#include "cge/game.h"
#include "cge/talk.h"
#include "cge/vga13h.h"
namespace CGE {
/*----------------- KEYBOARD interface -----------------*/
#define kEventMax 256
enum EventMask {
kMouseRoll = 1 << 0,
kMouseLeftDown = 1 << 1,
kMouseLeftUp = 1 << 2,
kMouseRightDown = 1 << 3,
kMouseRightUp = 1 << 4,
kEventAttn = 1 << 5,
kEventEsc = 1 << 7
};
class Keyboard {
private:
CGEEngine *_vm;
public:
Sprite *_client;
bool _keyAlt;
void handleAction(Common::Event &event);
Sprite *setClient(Sprite *spr);
Keyboard(CGEEngine *vm);
~Keyboard();
};
/*----------------- MOUSE interface -----------------*/
struct CGEEvent {
uint16 _mask;
uint16 _x;
uint16 _y;
Sprite *_spritePtr;
};
class Mouse : public Sprite {
public:
Sprite *_hold;
bool _active;
int _hx;
int _hy;
bool _exist;
int _buttons;
Sprite *_busy;
Mouse(CGEEngine *vm);
~Mouse() override;
void on();
void off();
void newMouse(Common::Event &event);
private:
CGEEngine *_vm;
};
/*----------------- EventManager interface -----------------*/
class EventManager {
private:
CGEEngine *_vm;
Common::Event _event;
CGEEvent _eventQueue[kEventMax];
uint16 _eventQueueHead;
uint16 _eventQueueTail;
void handleEvents();
public:
EventManager(CGEEngine *vm);
void poll();
void clearEvent(Sprite *spr);
CGEEvent &getNextEvent();
};
} // End of namespace CGE
#endif

269
engines/cge/fileio.cpp Normal file
View File

@@ -0,0 +1,269 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#include "common/system.h"
#include "common/str.h"
#include "common/debug.h"
#include "common/debug-channels.h"
#include "common/memstream.h"
#include "cge/cge.h"
#include "cge/fileio.h"
namespace CGE {
/*-----------------------------------------------------------------------
* BtPage
*-----------------------------------------------------------------------*/
void BtPage::readBTree(Common::ReadStream &s) {
_header._count = s.readUint16LE();
_header._down = s.readUint16LE();
if (_header._down == kBtValNone) {
// Leaf list
for (int i = 0; i < kBtLeafCount; ++i) {
s.read(_leaf[i]._key, kBtKeySize);
_leaf[i]._pos = s.readUint32LE();
_leaf[i]._size = s.readUint16LE();
}
} else {
// Root index
for (int i = 0; i < kBtInnerCount; ++i) {
s.read(_inner[i]._key, kBtKeySize);
_inner[i]._down = s.readUint16LE();
}
}
}
/*-----------------------------------------------------------------------
* ResourceManager
*-----------------------------------------------------------------------*/
ResourceManager::ResourceManager() {
debugC(1, kCGEDebugFile, "ResourceManager::ResourceManager()");
_datFile = new Common::File();
_datFile->open(kDatName);
_catFile = new Common::File();
_catFile->open(kCatName);
if (!_datFile->isOpen() || !_catFile->isOpen())
error("Unable to open data files");
for (int i = 0; i < kBtLevel; i++) {
_buff[i]._page = new BtPage;
_buff[i]._pageNo = kBtValNone;
_buff[i]._index = -1;
assert(_buff[i]._page != nullptr);
}
}
ResourceManager::~ResourceManager() {
debugC(1, kCGEDebugFile, "ResourceManager::~ResourceManager()");
_datFile->close();
delete _datFile;
_catFile->close();
delete _catFile;
for (int i = 0; i < kBtLevel; i++)
delete _buff[i]._page;
}
void ResourceManager::XCrypt(byte *buf, uint16 length) {
byte *b = buf;
for (uint16 i = 0; i < length; i++)
*b++ ^= kCryptSeed;
}
bool ResourceManager::seek(int32 offs, int whence) {
return _datFile->seek(offs, whence);
}
uint16 ResourceManager::read(byte *buf, uint16 length) {
if (!_datFile->isOpen())
return 0;
uint16 bytesRead = _datFile->read(buf, length);
if (!bytesRead)
error("Read %s - %d bytes", _datFile->getName(), length);
XCrypt(buf, length);
return bytesRead;
}
BtPage *ResourceManager::getPage(int level, uint16 pageId) {
debugC(1, kCGEDebugFile, "ResourceManager::getPage(%d, %d)", level, pageId);
if (level >= kBtLevel)
return nullptr;
if (_buff[level]._pageNo != pageId) {
int32 pos = pageId * kBtSize;
_buff[level]._pageNo = pageId;
if (_catFile->size() <= pos)
return nullptr;
// In the original, there was a check verifying if the
// purpose was to write a new file. This should only be
// to create a new file, thus it was removed.
_catFile->seek(pageId * kBtSize, SEEK_SET);
// Read in the page
byte buffer[kBtSize];
int bytesRead = catRead(buffer, kBtSize);
// Unpack it into the page structure
Common::MemoryReadStream stream(buffer, bytesRead, DisposeAfterUse::NO);
_buff[level]._page->readBTree(stream);
_buff[level]._index = -1;
}
return _buff[level]._page;
}
BtKeypack *ResourceManager::find(const char *key) {
debugC(1, kCGEDebugFile, "ResourceManager::find(%s)", key);
int lev = 0;
uint16 nxt = kBtValRoot;
while (!_catFile->eos()) {
BtPage *pg = getPage(lev, nxt);
if (!pg)
return nullptr;
// search
if (pg->_header._down != kBtValNone) {
int i;
for (i = 0; i < pg->_header._count; i++) {
if (scumm_strnicmp((const char *)key, (const char*)pg->_inner[i]._key, kBtKeySize) < 0)
break;
}
nxt = (i) ? pg->_inner[i - 1]._down : pg->_header._down;
_buff[lev]._index = i - 1;
lev++;
} else {
int i;
for (i = 0; i < pg->_header._count - 1; i++) {
if (scumm_stricmp((const char *)key, (const char *)pg->_leaf[i]._key) <= 0)
break;
}
_buff[lev]._index = i;
return &pg->_leaf[i];
}
}
return nullptr;
}
bool ResourceManager::exist(const char *name) {
debugC(1, kCGEDebugFile, "ResourceManager::exist(%s)", name);
BtKeypack* result = find(name);
if (!result)
return false;
return scumm_stricmp(result->_key, name) == 0;
}
uint16 ResourceManager::catRead(byte *buf, uint16 length) {
if (!_catFile->isOpen())
return 0;
uint16 bytesRead = _catFile->read(buf, length);
if (!bytesRead)
error("Read %s - %d bytes", _catFile->getName(), length);
XCrypt(buf, length);
return bytesRead;
}
/*-----------------------------------------------------------------------
* EncryptedStream
*-----------------------------------------------------------------------*/
EncryptedStream::EncryptedStream(ResourceManager *resman, const char *name) {
debugC(3, kCGEDebugFile, "EncryptedStream::EncryptedStream(%s)", name);
_error = false;
BtKeypack *kp = resman->find(name);
if (scumm_stricmp(kp->_key, name) != 0)
_error = true;
resman->seek(kp->_pos);
byte *dataBuffer;
int bufSize;
if ((strlen(name) > 4) && (scumm_stricmp(name + strlen(name) - 4, ".SPR") == 0)) {
// SPR files have some inconsistencies. Some have extra 0x1A at the end, some others
// do not have a carriage return at the end of the last line
// Therefore, we remove this ending 0x1A and add extra new lines.
// This fixes bug #6060
dataBuffer = (byte *)malloc(kp->_size + 2);
resman->read(dataBuffer, kp->_size);
if (dataBuffer[kp->_size - 1] == 0x1A)
dataBuffer[kp->_size - 1] = '\n';
dataBuffer[kp->_size] = '\n';
dataBuffer[kp->_size + 1] = '\n';
bufSize = kp->_size + 2;
} else {
dataBuffer = (byte *)malloc(kp->_size);
resman->read(dataBuffer, kp->_size);
bufSize = kp->_size;
}
_readStream = new Common::MemoryReadStream(dataBuffer, bufSize, DisposeAfterUse::YES);
}
uint32 EncryptedStream::read(byte *dataPtr, uint32 dataSize) {
return _readStream->read(dataPtr, dataSize);
}
bool EncryptedStream::err() {
return (_error || _readStream->err());
}
bool EncryptedStream::eos() {
return _readStream->eos();
}
bool EncryptedStream::seek(int32 offset) {
return _readStream->seek(offset);
}
Common::String EncryptedStream::readLine() {
return _readStream->readLine();
}
int32 EncryptedStream::size() {
return _readStream->size();
}
int32 EncryptedStream::pos() {
return _readStream->pos();
}
EncryptedStream::~EncryptedStream() {
delete _readStream;
}
} // End of namespace CGE

116
engines/cge/fileio.h Normal file
View File

@@ -0,0 +1,116 @@
/* 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 code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#ifndef CGE_FILEIO_H
#define CGE_FILEIO_H
#include "cge/general.h"
#include "common/stream.h"
namespace CGE {
#define kBtSize 1024
#define kBtKeySize 13
#define kBtLevel 2
#define kBtInnerCount ((kBtSize - 4 /*sizeof(Hea) */) / (kBtKeySize + 2 /*sizeof(Inner) */))
#define kBtLeafCount ((kBtSize - 4 /*sizeof(Hea) */) / (kBtKeySize + 4 + 2 /*sizeof(BtKeypack) */))
#define kBtValNone 0xFFFF
#define kBtValRoot 0
#define kCatName "VOL.CAT"
#define kDatName "VOL.DAT"
struct BtKeypack {
char _key[kBtKeySize];
uint32 _pos;
uint16 _size;
};
struct Inner {
uint8 _key[kBtKeySize];
uint16 _down;
};
struct Header {
uint16 _count;
uint16 _down;
};
struct BtPage {
Header _header;
union {
// dummy filler to make proper size of union
uint8 _data[kBtSize - 4]; /* 4 is the size of struct Header */
// inner version of data: key + word-sized page link
Inner _inner[kBtInnerCount];
// leaf version of data: key + all user data
BtKeypack _leaf[kBtLeafCount];
};
void readBTree(Common::ReadStream &s);
};
class ResourceManager {
struct {
BtPage *_page;
uint16 _pageNo;
int _index;
} _buff[kBtLevel];
BtPage *getPage(int level, uint16 pageId);
uint16 catRead(byte *buf, uint16 length);
Common::File *_catFile;
Common::File *_datFile;
void XCrypt(byte *buf, uint16 length);
public:
ResourceManager();
~ResourceManager();
uint16 read(byte *buf, uint16 length);
bool seek(int32 offs, int whence = SEEK_SET);
BtKeypack *find(const char *key);
bool exist(const char *name);
};
class EncryptedStream {
private:
Common::SeekableReadStream *_readStream;
bool _error;
public:
EncryptedStream(ResourceManager *resman, const char *name);
~EncryptedStream();
bool err();
bool eos();
bool seek(int32 offset);
int32 pos();
int32 size();
uint32 read(byte *dataPtr, uint32 dataSize);
Common::String readLine();
};
} // End of namespace CGE
#endif

53
engines/cge/game.cpp 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/>.
*
*/
/*
* This code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#include "cge/game.h"
#include "cge/events.h"
namespace CGE {
Fly::Fly(CGEEngine *vm, Bitmap **shpl)
: Sprite(vm, shpl), _tx(0), _ty(0), _vm(vm) {
step(_vm->newRandom(2));
gotoxy(kFlyL + _vm->newRandom(kFlyR - kFlyL - _w), kFlyT + _vm->newRandom(kFlyB - kFlyT - _h));
}
void Fly::tick() {
step();
if (_flags._kept)
return;
if (_vm->newRandom(10) < 1) {
_tx = _vm->newRandom(3) - 1;
_ty = _vm->newRandom(3) - 1;
}
if (_x + _tx < kFlyL || _x + _tx + _w > kFlyR)
_tx = -_tx;
if (_y + _ty < kFlyT || _y + _ty + _h > kFlyB)
_ty = -_ty;
gotoxy(_x + _tx, _y + _ty);
}
} // End of namespace CGE

52
engines/cge/game.h Normal file
View File

@@ -0,0 +1,52 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#ifndef CGE_GAME_H
#define CGE_GAME_H
#include "cge/vga13h.h"
namespace CGE {
enum {
kFlyL = 20,
kFlyT = 40,
kFlyR = 110,
kFlyB = 100
};
class Fly : public Sprite {
private:
CGEEngine *_vm;
public:
int _tx, _ty;
Fly(CGEEngine *vm, Bitmap **shpl);
void tick() override;
};
} // End of namespace CGE
#endif

42
engines/cge/general.h Normal file
View File

@@ -0,0 +1,42 @@
/* 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 code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#ifndef CGE_GENERAL_H
#define CGE_GENERAL_H
#include "common/file.h"
namespace CGE {
struct Dac {
uint8 _r;
uint8 _g;
uint8 _b;
};
} // End of namespace CGE
#endif

338
engines/cge/metaengine.cpp Normal file
View File

@@ -0,0 +1,338 @@
/* 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 "graphics/thumbnail.h"
#include "engines/advancedDetector.h"
#include "common/savefile.h"
#include "common/system.h"
#include "common/translation.h"
#include "backends/keymapper/action.h"
#include "backends/keymapper/keymapper.h"
#include "backends/keymapper/standard-actions.h"
#include "cge/cge.h"
#include "cge/detection.h"
namespace CGE {
static const ADExtraGuiOptionsMap optionsList[] = {
{
GAMEOPTION_COLOR_BLIND_DEFAULT_OFF,
{
_s("Color Blind Mode"),
_s("Enable Color Blind Mode by default"),
"enable_color_blind",
false,
0,
0
}
},
#ifdef USE_TTS
{
GAMEOPTION_TTS,
{
_s("Enable Text to Speech"),
_s("Use TTS to read text in the game (if TTS is available)"),
"tts_enabled",
false,
0,
0
}
},
#endif
AD_EXTRA_GUI_OPTIONS_TERMINATOR
};
class CGEMetaEngine : public AdvancedMetaEngine<ADGameDescription> {
public:
const char *getName() const override {
return "cge";
}
const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override {
return optionsList;
}
bool hasFeature(MetaEngineFeature f) const override;
Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
int getMaximumSaveSlot() const override;
SaveStateList listSaves(const char *target) const override;
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override;
bool removeSaveState(const char *target, int slot) const override;
Common::KeymapArray initKeymaps(const char *target) const override;
};
bool CGEMetaEngine::hasFeature(MetaEngineFeature f) const {
return
(f == kSupportsListSaves) ||
(f == kSupportsLoadingDuringStartup) ||
(f == kSupportsDeleteSave) ||
(f == kSavesSupportMetaInfo) ||
(f == kSavesSupportThumbnail) ||
(f == kSavesSupportCreationDate) ||
(f == kSavesSupportPlayTime) ||
(f == kSimpleSavesNames);
}
bool CGEMetaEngine::removeSaveState(const char *target, int slot) const {
Common::String fileName = Common::String::format("%s.%03d", target, slot);
return g_system->getSavefileManager()->removeSavefile(fileName);
}
int CGEMetaEngine::getMaximumSaveSlot() const {
return 99;
}
SaveStateList CGEMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringArray filenames;
Common::String pattern = target;
pattern += ".###";
filenames = saveFileMan->listSavefiles(pattern);
SaveStateList saveList;
for (const auto &filename : filenames) {
// Obtain the last 3 digits of the filename, since they correspond to the save slot
int slotNum = atoi(filename.c_str() + filename.size() - 3);
if (slotNum >= 0 && slotNum <= 99) {
Common::InSaveFile *file = saveFileMan->openForLoading(filename);
if (file) {
CGE::SavegameHeader header;
// Check to see if it's a ScummVM savegame or not
char buffer[kSavegameStrSize + 1];
file->read(buffer, kSavegameStrSize + 1);
if (!strncmp(buffer, CGE::savegameStr, kSavegameStrSize + 1)) {
// Valid savegame
if (CGE::CGEEngine::readSavegameHeader(file, header)) {
saveList.push_back(SaveStateDescriptor(this, slotNum, header.saveName));
}
} else {
// Must be an original format savegame
saveList.push_back(SaveStateDescriptor(this, slotNum, "Unknown"));
}
delete file;
}
}
}
// Sort saves based on slot number.
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
SaveStateDescriptor CGEMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
Common::String fileName = Common::String::format("%s.%03d", target, slot);
Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(fileName);
if (f) {
CGE::SavegameHeader header;
// Check to see if it's a ScummVM savegame or not
char buffer[kSavegameStrSize + 1];
f->read(buffer, kSavegameStrSize + 1);
bool hasHeader = !strncmp(buffer, CGE::savegameStr, kSavegameStrSize + 1) &&
CGE::CGEEngine::readSavegameHeader(f, header, false);
delete f;
if (!hasHeader) {
// Original savegame perhaps?
SaveStateDescriptor desc(this, slot, "Unknown");
return desc;
} else {
// Create the return descriptor
SaveStateDescriptor desc(this, slot, header.saveName);
desc.setThumbnail(header.thumbnail);
desc.setSaveDate(header.saveYear, header.saveMonth, header.saveDay);
desc.setSaveTime(header.saveHour, header.saveMinutes);
if (header.playTime) {
desc.setPlayTime(header.playTime * 1000);
}
return desc;
}
}
return SaveStateDescriptor();
}
Common::Error CGEMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
*engine = new CGE::CGEEngine(syst, desc);
return Common::kNoError;
}
Common::KeymapArray CGEMetaEngine::initKeymaps(const char *target) const {
using namespace Common;
Keymap *keymap = new Keymap(Keymap::kKeymapTypeGame, "Soltys", _("Game Keymappings"));
Action *act;
act = new Action(kStandardActionLeftClick, _("Left click"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
keymap->addAction(act);
act = new Action(kStandardActionRightClick, _("Right click"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
keymap->addAction(act);
act = new Action(kStandardActionSkip, _("Exit / Skip"));
act->setCustomEngineActionEvent(kActionEscape);
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_X");
keymap->addAction(act);
act = new Action(kStandardActionSave, _("Save game"));
act->setCustomEngineActionEvent(kActionSave);
act->addDefaultInputMapping("F5");
act->addDefaultInputMapping("JOY_LEFT_SHOULDER");
keymap->addAction(act);
act = new Action(kStandardActionLoad, _("Load game"));
act->setCustomEngineActionEvent(kActionLoad);
act->addDefaultInputMapping("F7");
act->addDefaultInputMapping("JOY_RIGHT_SHOULDER");
keymap->addAction(act);
// I18N: 3-4 dialogs of game version info, (translation) credits, etc.
act = new Action("INFO", _("Game info"));
act->setCustomEngineActionEvent(kActionInfo);
act->addDefaultInputMapping("F1");
act->addDefaultInputMapping("JOY_LEFT_TRIGGER");
keymap->addAction(act);
// I18N: This opens a Quit Prompt where you have to choose
// [Confirm] or [Continue Playing] lines with Left Click.
act = new Action("QUIT", _("Quit prompt"));
act->setCustomEngineActionEvent(kActionQuit);
act->addDefaultInputMapping("A+x");
act->addDefaultInputMapping("JOY_RIGHT_TRIGGER");
keymap->addAction(act);
// I18N: Here ALTered Item refers to the dice that has been altered/changed.
// In order to escape the dice game loop press Right/Left Alt
act = new Action("ALTITEM", _("ALTered Item"));
act->setCustomEngineActionEvent(kActionAltDice);
act->addDefaultInputMapping("LALT");
act->addDefaultInputMapping("RALT");
act->addDefaultInputMapping("JOY_Y");
keymap->addAction(act);
act = new Action("INV1", _("Inventory Item 1 (Select / Deselect)"));
act->setCustomEngineActionEvent(kActionInv1);
act->addDefaultInputMapping("1");
keymap->addAction(act);
act = new Action("INV2", _("Inventory Item 2 (Select / Deselect)"));
act->setCustomEngineActionEvent(kActionInv2);
act->addDefaultInputMapping("2");
keymap->addAction(act);
act = new Action("INV3", _("Inventory Item 3 (Select / Deselect)"));
act->setCustomEngineActionEvent(kActionInv3);
act->addDefaultInputMapping("3");
keymap->addAction(act);
act = new Action("INV4", _("Inventory Item 4 (Select / Deselect)"));
act->setCustomEngineActionEvent(kActionInv4);
act->addDefaultInputMapping("4");
keymap->addAction(act);
act = new Action("INV5", _("Inventory Item 5 (Select / Deselect)"));
act->setCustomEngineActionEvent(kActionInv5);
act->addDefaultInputMapping("5");
keymap->addAction(act);
act = new Action("INV6", _("Inventory Item 6 (Select / Deselect)"));
act->setCustomEngineActionEvent(kActionInv6);
act->addDefaultInputMapping("6");
keymap->addAction(act);
act = new Action("INV7", _("Inventory Item 7 (Select / Deselect)"));
act->setCustomEngineActionEvent(kActionInv7);
act->addDefaultInputMapping("7");
keymap->addAction(act);
act = new Action("INV8", _("Inventory Item 8 (Select / Deselect)"));
act->setCustomEngineActionEvent(kActionInv8);
act->addDefaultInputMapping("8");
keymap->addAction(act);
// I18N: There are 24 single-room/screen locations in the game.
// You switch between them from numbered buttons on interface.
// Sets the current access to only the first Location
act = new Action("DEBUGLOC1", _("DEBUG: Access to location 1"));
act->setCustomEngineActionEvent(kActionLevel0);
act->addDefaultInputMapping("A+0");
keymap->addAction(act);
// I18N: Sets the current access to Locations 1 to 8.
act = new Action("DEBUGLOC18", _("DEBUG: Access to locations 1-8"));
act->setCustomEngineActionEvent(kActionLevel1);
act->addDefaultInputMapping("A+1");
keymap->addAction(act);
// I18N: Sets the current access to Locations 1 to 16.
act = new Action("DEBUGLOC116", _("DEBUG: Access to locations 1-16"));
act->setCustomEngineActionEvent(kActionLevel2);
act->addDefaultInputMapping("A+2");
keymap->addAction(act);
// I18N: Sets the current access to Locations 1 to 23.
act = new Action("DEBUGLOC123", _("DEBUG: Access to locations 1-23"));
act->setCustomEngineActionEvent(kActionLevel3);
act->addDefaultInputMapping("A+3");
keymap->addAction(act);
// I18N: Sets the current access to Locations 1 to 24.
act = new Action("DEBUGLOC124", _("DEBUG: Access to locations 1-24"));
act->setCustomEngineActionEvent(kActionLevel4);
act->addDefaultInputMapping("A+4");
keymap->addAction(act);
return Keymap::arrayOf(keymap);
}
} // End of namespace CGE
#if PLUGIN_ENABLED_DYNAMIC(CGE)
REGISTER_PLUGIN_DYNAMIC(CGE, PLUGIN_TYPE_ENGINE, CGE::CGEMetaEngine);
#else
REGISTER_PLUGIN_STATIC(CGE, PLUGIN_TYPE_ENGINE, CGE::CGEMetaEngine);
#endif

39
engines/cge/module.mk Normal file
View File

@@ -0,0 +1,39 @@
MODULE := engines/cge
MODULE_OBJS := \
bitmap.o \
cge.o \
cge_main.o \
console.o \
events.o \
fileio.o \
game.o \
metaengine.o \
snail.o \
sound.o \
talk.o \
text.o \
vga13h.o \
vmenu.o \
walk.o
MODULE_DIRS += \
engines/cge
# This module can be built as a plugin
ifeq ($(ENABLE_CGE), DYNAMIC_PLUGIN)
PLUGIN := 1
endif
# Include common rules
include $(srcdir)/rules.mk
# Detection objects
DETECT_OBJS += $(MODULE)/detection.o
# Skip building the following objects if a static
# module is enabled, because it already has the contents.
ifneq ($(ENABLE_CGE), STATIC_PLUGIN)
# External dependencies for detection.
DETECT_OBJS += $(MODULE)/fileio.o
endif

1281
engines/cge/snail.cpp Normal file

File diff suppressed because it is too large Load Diff

85
engines/cge/snail.h Normal file
View File

@@ -0,0 +1,85 @@
/* 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 code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#ifndef CGE_COMMANDHANDLER_H
#define CGE_COMMANDHANDLER_H
#include "cge/cge.h"
namespace CGE {
#define kCommandFrameRate 80
#define kCommandFrameDelay (1000 / kCommandFrameRate)
#define kDressed 3
enum CommandType {
kCmdLabel, kCmdPause, kCmdWait, kCmdLevel, kCmdHide,
kCmdSay, kCmdInf, kCmdTime, kCmdCave, kCmdKill,
kCmdRSeq, kCmdSeq, kCmdSend, kCmdSwap, kCmdKeep,
kCmdGive, kCmdIf, kCmdGame, kCmdSetX0, kCmdSetY0,
kCmdSlave, kCmdSetXY, kCmdRelX, kCmdRelY, kCmdRelZ,
kCmdSetX, kCmdSetY, kCmdSetZ, kCmdTrans, kCmdPort,
kCmdNext, kCmdNNext, kCmdTNext, kCmdRNNext, kCmdRTNext,
kCmdRMNear, kCmdRmTake, kCmdFlag, kCmdSetRef, kCmdBackPt,
kCmdFlash, kCmdLight, kCmdSetVBarrier, kCmdSetHBarrier, kCmdWalk,
kCmdReach, kCmdCover, kCmdUncover, kCmdClear, kCmdTalk,
kCmdMouse, kCmdSound, kCmdCount, kCmdExec, kCmdStep,
kCmdZTrim, kCmdGhost
};
class CommandHandler {
public:
struct Command {
CommandType _commandType;
int _ref;
int _val;
void *_spritePtr;
CallbackType _cbType;
} *_commandList;
static const char *_commandText[];
bool _talkEnable;
CommandHandler(CGEEngine *vm, bool turbo);
~CommandHandler();
void runCommand();
void addCommand(CommandType com, int ref, int val, void *ptr);
void addCallback(CommandType com, int ref, int val, CallbackType cbType);
void insertCommand(CommandType com, int ref, int val, void *ptr);
bool idle();
void reset();
private:
CGEEngine *_vm;
bool _turbo;
uint8 _head;
uint8 _tail;
bool _busy;
bool _textDelay;
uint32 _timerExpiry;
};
} // End of namespace CGE
#endif

307
engines/cge/sound.cpp Normal file
View File

@@ -0,0 +1,307 @@
/* 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 code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#include "cge/sound.h"
#include "cge/text.h"
#include "cge/cge_main.h"
#include "common/config-manager.h"
#include "common/memstream.h"
#include "audio/audiostream.h"
#include "audio/decoders/wave.h"
#include "audio/mididrv.h"
#include "audio/midiparser.h"
namespace CGE {
DataCk::DataCk(byte *buf, int bufSize) {
_buf = buf;
_ckSize = bufSize;
}
DataCk::~DataCk() {
free(_buf);
}
Sound::Sound(CGEEngine *vm) : _vm(vm) {
_audioStream = nullptr;
_soundRepeatCount = 1;
open();
}
Sound::~Sound() {
close();
}
void Sound::close() {
_vm->_midiPlayer->killMidi();
_vm->_mixer->stopAll();
}
void Sound::open() {
setRepeat(1);
play((*_vm->_fx)[30000], 8);
}
void Sound::setRepeat(int16 count) {
_soundRepeatCount = count;
}
int16 Sound::getRepeat() {
return _soundRepeatCount;
}
void Sound::play(DataCk *wav, int pan) {
if (wav) {
stop();
_smpinf._saddr = &*(wav->addr());
_smpinf._slen = (uint16)wav->size();
_smpinf._span = pan;
_smpinf._counter = getRepeat();
sndDigiStart(&_smpinf);
}
}
void Sound::sndDigiStart(SmpInfo *PSmpInfo) {
// Create an audio stream wrapper for sound
Common::MemoryReadStream *stream = new Common::MemoryReadStream(PSmpInfo->_saddr,
PSmpInfo->_slen, DisposeAfterUse::NO);
_audioStream = Audio::makeWAVStream(stream, DisposeAfterUse::YES);
// Start the new sound
_vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle,
Audio::makeLoopingAudioStream(_audioStream, (uint)PSmpInfo->_counter));
// CGE pan:
// 8 = Center
// Less = Left
// More = Right
_vm->_mixer->setChannelBalance(_soundHandle, (int8)CLIP(((PSmpInfo->_span - 8) * 16), -127, 127));
}
void Sound::stop() {
sndDigiStop(&_smpinf);
}
void Sound::sndDigiStop(SmpInfo *PSmpInfo) {
if (_vm->_mixer->isSoundHandleActive(_soundHandle))
_vm->_mixer->stopHandle(_soundHandle);
_audioStream = nullptr;
}
Fx::Fx(CGEEngine *vm, int size) : _current(nullptr), _vm(vm) {
_cache = new Handler[size];
for (_size = 0; _size < size; _size++) {
_cache[_size]._ref = 0;
_cache[_size]._wav = nullptr;
}
}
Fx::~Fx() {
clear();
delete[] _cache;
}
void Fx::clear() {
for (Handler *p = _cache, *q = p + _size; p < q; p++) {
if (p->_ref) {
p->_ref = 0;
delete p->_wav;
p->_wav = nullptr;
}
}
_current = nullptr;
}
int Fx::find(int ref) {
int i = 0;
for (Handler *p = _cache, *q = p + _size; p < q; p++) {
if (p->_ref == ref)
break;
else
++i;
}
return i;
}
void Fx::preload(int ref0) {
Handler *cacheLim = _cache + _size;
char filename[12];
for (int ref = ref0; ref < ref0 + 10; ref++) {
Common::sprintf_s(filename, "FX%05d.WAV", ref);
EncryptedStream file(_vm->_resman, filename);
DataCk *wav = loadWave(&file);
if (wav) {
Handler *p = &_cache[find(0)];
if (p >= cacheLim) {
delete wav;
break;
}
delete p->_wav;
p->_wav = wav;
p->_ref = ref;
} else {
warning("Unable to load %s", filename);
}
}
}
DataCk *Fx::load(int idx, int ref) {
char filename[12];
Common::sprintf_s(filename, "FX%05d.WAV", ref);
EncryptedStream file(_vm->_resman, filename);
DataCk *wav = loadWave(&file);
if (wav) {
Handler *p = &_cache[idx];
delete p->_wav;
p->_wav = wav;
p->_ref = ref;
} else {
warning("Unable to load %s", filename);
}
return wav;
}
DataCk *Fx::loadWave(EncryptedStream *file) {
byte *data = (byte *)malloc(file->size());
if (!data)
return nullptr;
file->read(data, file->size());
return new DataCk(data, file->size());
}
DataCk *Fx::operator[](int ref) {
int i;
if ((i = find(ref)) < _size)
_current = _cache[i]._wav;
else {
if ((i = find(0)) >= _size) {
clear();
i = 0;
}
_current = load(i, ref);
}
return _current;
}
MusicPlayer::MusicPlayer(CGEEngine *vm) : _vm(vm) {
_data = nullptr;
_isGM = false;
MidiPlayer::createDriver();
int ret = _driver->open();
if (ret == 0) {
if (_nativeMT32)
_driver->sendMT32Reset();
else
_driver->sendGMReset();
// TODO: Load cmf.ins with the instrument table. It seems that an
// interface for such an operation is supported for AdLib. Maybe for
// this card, setting instruments is necessary.
_driver->setTimerCallback(this, &timerCallback);
}
_dataSize = -1;
}
MusicPlayer::~MusicPlayer() {
killMidi();
}
void MusicPlayer::killMidi() {
Audio::MidiPlayer::stop();
free(_data);
_data = nullptr;
}
void MusicPlayer::loadMidi(int ref) {
// Work out the filename and check the given MIDI file exists
Common::String filename = Common::String::format("%.2d.MID", ref);
if (!_vm->_resman->exist(filename.c_str()))
return;
// Stop any currently playing MIDI file
killMidi();
// Read in the data for the file
EncryptedStream mid(_vm->_resman, filename.c_str());
_dataSize = mid.size();
_data = (byte *)malloc(_dataSize);
mid.read(_data, _dataSize);
// Start playing the music
sndMidiStart();
}
void MusicPlayer::sndMidiStart() {
_isGM = true;
MidiParser *parser = MidiParser::createParser_SMF();
if (parser->loadMusic(_data, _dataSize)) {
parser->setTrack(0);
parser->setMidiDriver(this);
parser->setTimerRate(_driver->getBaseTempo());
parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
_parser = parser;
syncVolume();
// Al the tracks are supposed to loop
_isLooping = true;
_isPlaying = true;
}
}
void MusicPlayer::send(uint32 b) {
if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) {
b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
}
Audio::MidiPlayer::send(b);
}
void MusicPlayer::sendToChannel(byte channel, uint32 b) {
if (!_channelsTable[channel]) {
_channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
// If a new channel is allocated during the playback, make sure
// its volume is correctly initialized.
if (_channelsTable[channel])
_channelsTable[channel]->volume(_channelsVolume[channel] * _masterVolume / 255);
}
if (_channelsTable[channel])
_channelsTable[channel]->send(b);
}
} // End of namespace CGE

134
engines/cge/sound.h Normal file
View File

@@ -0,0 +1,134 @@
/* 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 code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#ifndef CGE_SOUND_H
#define CGE_SOUND_H
#include "cge/fileio.h"
#include "audio/midiplayer.h"
#include "audio/mixer.h"
#include "common/memstream.h"
namespace Audio {
class RewindableAudioStream;
}
namespace CGE {
class CGEEngine;
// sample info
struct SmpInfo {
const uint8 *_saddr; // address
uint16 _slen; // length
uint16 _span; // left/right pan (0-15)
int _counter; // number of time the sample should be played
};
class DataCk {
byte *_buf;
int _ckSize;
public:
DataCk(byte *buf, int bufSize);
~DataCk();
inline const byte *addr() {
return _buf;
}
inline int size() {
return _ckSize;
}
};
class Sound {
public:
SmpInfo _smpinf;
Sound(CGEEngine *vm);
~Sound();
void open();
void close();
void play(DataCk *wav, int pan);
int16 getRepeat();
void setRepeat(int16 count);
void stop();
private:
int _soundRepeatCount;
CGEEngine *_vm;
Audio::SoundHandle _soundHandle;
Audio::RewindableAudioStream *_audioStream;
void sndDigiStart(SmpInfo *PSmpInfo);
void sndDigiStop(SmpInfo *PSmpInfo);
};
class Fx {
CGEEngine *_vm;
struct Handler {
int _ref;
DataCk *_wav;
} *_cache;
int _size;
DataCk *load(int idx, int ref);
DataCk *loadWave(EncryptedStream *file);
int find(int ref);
public:
DataCk *_current;
Fx(CGEEngine *vm, int size);
~Fx();
void clear();
void preload(int ref0);
DataCk *operator[](int ref);
};
class MusicPlayer: public Audio::MidiPlayer {
private:
CGEEngine *_vm;
byte *_data;
int _dataSize;
bool _isGM;
// Start MIDI File
void sndMidiStart();
// Stop MIDI File
void sndMidiStop();
public:
MusicPlayer(CGEEngine *vm);
~MusicPlayer() override;
void loadMidi(int ref);
void killMidi();
void send(uint32 b) override;
void sendToChannel(byte channel, uint32 b) override;
};
} // End of namespace CGE
#endif

270
engines/cge/talk.cpp Normal file
View File

@@ -0,0 +1,270 @@
/* 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 code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#include "cge/general.h"
#include "cge/talk.h"
#include "cge/game.h"
#include "cge/events.h"
#include "cge/cge_main.h"
#include "common/config-manager.h"
#include "common/text-to-speech.h"
namespace CGE {
Font::Font(CGEEngine *vm, const char *name) : _vm(vm) {
_map = (uint8 *)malloc(kMapSize);
_pos = (uint16 *)malloc(kPosSize * sizeof(uint16));
_widthArr = (uint8 *)malloc(kWidSize);
assert((_map != nullptr) && (_pos != nullptr) && (_widthArr != nullptr));
_vm->mergeExt(_path, name, kFontExt);
load();
}
Font::~Font() {
free(_map);
free(_pos);
free(_widthArr);
}
void Font::load() {
EncryptedStream f(_vm->_resman, _path);
assert(!f.err());
f.read(_widthArr, kWidSize);
assert(!f.err());
uint16 p = 0;
for (uint16 i = 0; i < kPosSize; i++) {
_pos[i] = p;
p += _widthArr[i];
}
f.read(_map, p);
}
uint16 Font::width(const char *text) {
uint16 w = 0;
if (!text)
return 0;
while (*text)
w += _widthArr[(unsigned char)*(text++)];
return w;
}
Talk::Talk(CGEEngine *vm, const char *text, TextBoxStyle mode, bool wideSpace)
: Sprite(vm, nullptr), _mode(mode), _wideSpace(wideSpace), _vm(vm) {
_ts = nullptr;
_flags._syst = true;
update(text);
}
Talk::Talk(CGEEngine *vm)
: Sprite(vm, nullptr), _mode(kTBPure), _vm(vm) {
_ts = nullptr;
_flags._syst = true;
_wideSpace = false;
}
void Talk::textToSpeech(const char *text) {
Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
if (text != nullptr && ttsMan != nullptr && ConfMan.getBool("tts_enabled"))
ttsMan->say(text);
}
void Talk::update(const char *text) {
textToSpeech(text);
const uint16 vmarg = (_mode) ? kTextVMargin : 0;
const uint16 hmarg = (_mode) ? kTextHMargin : 0;
uint16 mw = 0;
uint16 ln = vmarg;
uint8 *m;
if (!_ts) {
uint16 k = 2 * hmarg;
uint16 mh = 2 * vmarg + kFontHigh;
for (const char *p = text; *p; p++) {
if (*p == '|' || *p == '\n') {
mh += kFontHigh + kTextLineSpace;
if (k > mw)
mw = k;
k = 2 * hmarg;
} else if ((*p == 0x20) && (_vm->_font->_widthArr[(unsigned char)*p] > 4) && (!_wideSpace))
k += _vm->_font->_widthArr[(unsigned char)*p] - 2;
else
k += _vm->_font->_widthArr[(unsigned char)*p];
}
if (k > mw)
mw = k;
_ts = new BitmapPtr[2];
_ts[0] = box(mw, mh);
_ts[1] = nullptr;
}
m = _ts[0]->_m + ln * mw + hmarg;
while (*text) {
if (*text == '|' || *text == '\n') {
m = _ts[0]->_m + (ln += kFontHigh + kTextLineSpace) * mw + hmarg;
} else {
int cw = _vm->_font->_widthArr[(unsigned char)*text];
uint8 *f = _vm->_font->_map + _vm->_font->_pos[(unsigned char)*text];
// Handle properly space size, after it was enlarged to display properly
// 'F1' text.
int8 fontStart = 0;
if ((*text == 0x20) && (cw > 4) && (!_wideSpace))
fontStart = 2;
for (int i = fontStart; i < cw; i++) {
uint8 *pp = m;
uint16 n;
uint16 b = *(f++);
for (n = 0; n < kFontHigh; n++) {
if (b & 1)
*pp = kTextColFG;
b >>= 1;
pp += mw;
}
m++;
}
}
text++;
}
_ts[0]->code();
setShapeList(_ts);
}
Bitmap *Talk::box(uint16 w, uint16 h) {
if (w < 8)
w = 8;
if (h < 8)
h = 8;
uint16 n = w * h;
uint8 *b = (uint8 *)malloc(n);
assert(b != nullptr);
memset(b, kTextColBG, n);
if (_mode) {
uint8 *p = b;
uint8 *q = b + n - w;
memset(p, kVgaColLightGray, w);
memset(q, kVgaColDarkGray, w);
while (p < q) {
p += w;
*(p - 1) = kVgaColDarkGray;
*p = kVgaColLightGray;
}
p = b;
const uint16 r = (_mode == kTBRound) ? kTextRoundCorner : 0;
for (int i = 0; i < r; i++) {
int j;
for (j = 0; j < r - i; j++) {
p[j] = kPixelTransp;
p[w - j - 1] = kPixelTransp;
q[j] = kPixelTransp;
q[w - j - 1] = kPixelTransp;
}
p[j] = kVgaColLightGray;
p[w - j - 1] = kVgaColDarkGray;
q[j] = kVgaColLightGray;
q[w - j - 1] = kVgaColDarkGray;
p += w;
q -= w;
}
}
return new Bitmap(_vm, w, h, b);
}
InfoLine::InfoLine(CGEEngine *vm, uint16 w) : Talk(vm), _oldText(nullptr), _vm(vm) {
if (!_ts) {
_ts = new BitmapPtr[2];
_ts[1] = nullptr;
}
_ts[0] = new Bitmap(_vm, w, kFontHigh, kTextColBG);
setShapeList(_ts);
}
void InfoLine::update(const char *text) {
if (text == _oldText)
return;
_oldText = text;
textToSpeech(text);
uint16 w = _ts[0]->_w;
uint16 h = _ts[0]->_h;
uint8 *v = (uint8 *)_ts[0]->_v;
uint16 dsiz = w >> 2; // data size (1 plane line size)
uint16 lsiz = 2 + dsiz + 2; // uint16 for line header, uint16 for gap
uint16 psiz = h * lsiz; // - last gape, but + plane trailer
uint16 size = 4 * psiz; // whole map size
// clear whole rectangle
memset(v + 2, kTextColBG, dsiz); // data bytes
for (byte *pDest = v + lsiz; pDest < (v + psiz); pDest += lsiz) {
Common::copy(v, v + lsiz, pDest);
}
*(uint16 *)(v + psiz - 2) = TO_LE_16(kBmpEOI); // plane trailer uint16
for (byte *pDest = v + psiz; pDest < (v + 4 * psiz); pDest += psiz) {
Common::copy(v, v + psiz, pDest);
}
// paint text line
if (text) {
uint8 *p = v + 2, * q = p + size;
while (*text) {
uint16 cw = _vm->_font->_widthArr[(unsigned char)*text];
uint8 *fp = _vm->_font->_map + _vm->_font->_pos[(unsigned char)*text];
// Handle properly space size, after it was enlarged to display properly
// 'F1' text.
int8 fontStart = 0;
if ((*text == 0x20) && (cw > 4) && (!_wideSpace))
fontStart = 2;
for (int i = fontStart; i < cw; i++) {
uint16 b = fp[i];
for (uint16 n = 0; n < kFontHigh; n++) {
if (b & 1)
*p = kTextColFG;
b >>= 1;
p += lsiz;
}
if (p >= q)
p = p - size + 1;
}
text++;
}
}
}
} // End of namespace CGE

76
engines/cge/talk.h Normal file
View File

@@ -0,0 +1,76 @@
/* 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 code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#ifndef CGE_TALK_H
#define CGE_TALK_H
#include "cge/general.h"
#include "cge/vga13h.h"
namespace CGE {
#define kTextColFG kVgaColDark // foreground color
#define kTextColBG kVgaColGray // background color
#define kTextHMargin (6&~1) // EVEN horizontal margins!
#define kTextVMargin 5 // vertical margins
#define kTextLineSpace 2 // line spacing
#define kTextRoundCorner 3 // rounded corners
#define kWidSize 256
#define kPosSize 256
#define kMapSize (256*8)
#define kFontHigh 8
#define kFontExt ".CFT"
enum TextBoxStyle { kTBPure, kTBRect, kTBRound };
class Talk : public Sprite {
protected:
TextBoxStyle _mode;
BitmapPtr *_ts;
Bitmap *box(uint16 w, uint16 h);
bool _wideSpace;
public:
Talk(CGEEngine *vm, const char *text, TextBoxStyle mode, bool wideSpace = false);
Talk(CGEEngine *vm);
void textToSpeech(const char *text);
virtual void update(const char *text);
private:
CGEEngine *_vm;
};
class InfoLine : public Talk {
const char *_oldText;
public:
InfoLine(CGEEngine *vm, uint16 wid);
void update(const char *text) override;
private:
CGEEngine *_vm;
};
} // End of namespace CGE
#endif

216
engines/cge/text.cpp Normal file
View File

@@ -0,0 +1,216 @@
/* 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 code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#include "cge/general.h"
#include "cge/text.h"
#include "cge/talk.h"
#include "cge/game.h"
#include "cge/snail.h"
#include "cge/cge_main.h"
#include "common/str.h"
namespace CGE {
Text::Text(CGEEngine *vm, const char *fname) : _vm(vm) {
_vm->mergeExt(_fileName, fname, kSayExt);
if (!_vm->_resman->exist(_fileName))
error("No talk (%s)", _fileName);
int16 txtCount = count() + 1;
if (!txtCount)
error("Unable to read dialog file %s", _fileName);
_cache = new Handler[txtCount];
for (_size = 0; _size < txtCount; _size++) {
_cache[_size]._ref = 0;
_cache[_size]._text = nullptr;
}
load();
}
Text::~Text() {
clear();
delete[] _cache;
}
int16 Text::count() {
EncryptedStream tf(_vm->_resman, _fileName);
if (tf.err())
return -1;
Common::String line;
char tmpStr[kLineMax + 1];
int counter = 0;
for (line = tf.readLine(); !tf.eos(); line = tf.readLine()) {
char *s;
assert(line.size() <= 513);
Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
if ((s = strtok(tmpStr, " =,;/\t\n")) == nullptr)
continue;
if (!Common::isDigit(*s))
continue;
counter++;
}
return counter;
}
void Text::clear() {
for (Handler *p = _cache, *q = p + _size; p < q; p++) {
if (p->_ref) {
p->_ref = 0;
delete[] p->_text;
p->_text = nullptr;
}
}
}
void Text::load() {
EncryptedStream tf(_vm->_resman, _fileName);
assert(!tf.err());
Common::String line;
char tmpStr[kLineMax + 1];
int idx;
for (idx = 0, line = tf.readLine(); !tf.eos(); line = tf.readLine()) {
int n = line.size();
char *s;
Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
if ((s = strtok(tmpStr, " =,;/\t\n")) == nullptr)
continue;
if (!Common::isDigit(*s))
continue;
int r = atoi(s);
s += strlen(s);
if (s < tmpStr + n)
++s;
_cache[idx]._ref = r;
size_t ln = strlen(s) + 1;
_cache[idx]._text = new char[ln];
Common::strcpy_s(_cache[idx]._text, ln, s);
idx++;
}
}
char *Text::getText(int ref) {
int i;
for (i = 0; (i < _size) && (_cache[i]._ref != ref); i++)
;
if (i < _size)
return _cache[i]._text;
warning("getText: Unable to find ref %d", ref);
return nullptr;
}
void Text::say(const char *text, Sprite *spr) {
_vm->killText();
if (!text)
return;
if (*text == 0)
return;
_vm->_talk = new Talk(_vm, text, kTBRound);
if (!_vm->_talk)
return;
bool east = spr->_flags._east;
int x = (east) ? (spr->_x + spr->_w - 2) : (spr->_x + 2);
int y = spr->_y + 2;
Speaker *speaker = new Speaker(_vm);
uint16 sw = speaker->_w;
if (east) {
if (x + sw + kTextRoundCorner + 5 >= kScrWidth)
east = false;
} else {
if (x <= 5 + kTextRoundCorner + sw)
east = true;
}
x = (east) ? (spr->_x + spr->_w - 2) : (spr->_x + 2 - sw);
if (spr->_ref == 1)
x += ((east) ? -10 : 10); // Hero
_vm->_talk->_flags._kill = true;
_vm->_talk->_flags._bDel = true;
_vm->_talk->setName(_vm->_text->getText(kSayName));
_vm->_talk->gotoxy(x - (_vm->_talk->_w - sw) / 2 - 3 + 6 * east, y - speaker->_h - _vm->_talk->_h + 1);
_vm->_talk->_z = 125;
_vm->_talk->_ref = kSayRef;
speaker->gotoxy(x, _vm->_talk->_y + _vm->_talk->_h - 1);
speaker->_z = 126;
speaker->_flags._slav = true;
speaker->_flags._kill = true;
speaker->setName(_vm->_text->getText(kSayName));
speaker->step(east);
speaker->_ref = kSayRef;
_vm->_vga->_showQ->insert(_vm->_talk, _vm->_vga->_showQ->last());
_vm->_vga->_showQ->insert(speaker, _vm->_vga->_showQ->last());
}
void CGEEngine::inf(const char *text, bool wideSpace) {
debugC(1, kCGEDebugEngine, "CGEEngine::inf(%s)", text);
if (!text)
return;
if (*text == 0)
return;
killText();
_talk = new Talk(this, text, kTBRect, wideSpace);
if (!_talk)
return;
_talk->_flags._kill = true;
_talk->_flags._bDel = true;
_talk->setName(_text->getText(kInfName));
_talk->center();
_talk->gotoxy(_talk->_x, _talk->_y - 20);
_talk->_z = 126;
_talk->_ref = kInfRef;
_vga->_showQ->insert(_talk, _vga->_showQ->last());
}
void Text::sayTime(Sprite *spr) {
TimeDate curTime;
_vm->_system->getTimeAndDate(curTime);
char t[6];
Common::sprintf_s(t, "%d:%02d", curTime.tm_hour, curTime.tm_min);
say(t, spr);
}
} // End of namespace CGE

65
engines/cge/text.h Normal file
View File

@@ -0,0 +1,65 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#ifndef CGE_TEXT_H
#define CGE_TEXT_H
#include "cge/talk.h"
namespace CGE {
#define kSayExt ".SAY"
#define kSysTextMax 1000
#define kTextNoMouse 95
#define kInfName 101
#define kSayName 102
#define kInfRef 301
#define kSayRef 302
class Text {
struct Handler {
int _ref;
char *_text;
} *_cache;
int _size;
char _fileName[kPathMax];
void load();
int16 count();
public:
Text(CGEEngine *vm, const char *fname);
~Text();
void clear();
char *getText(int ref);
void say(const char *text, Sprite *spr);
void sayTime(Sprite *spr);
private:
CGEEngine *_vm;
};
} // End of namespace CGE
#endif

1014
engines/cge/vga13h.cpp Normal file

File diff suppressed because it is too large Load Diff

243
engines/cge/vga13h.h Normal file
View File

@@ -0,0 +1,243 @@
/* 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 code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#ifndef CGE_VGA13H_H
#define CGE_VGA13H_H
#include "common/serializer.h"
#include "common/events.h"
#include "graphics/surface.h"
#include "cge/general.h"
#include "cge/bitmap.h"
#include "cge/snail.h"
#include "cge/cge.h"
namespace CGE {
#define kFadeStep 2
#define kVgaColDark 207
#define kVgaColDarkGray 225 /*219*/
#define kVgaColGray 231
#define kVgaColLightGray 237
#define kPixelTransp 0xFE
#define kNoSeq (-1)
#define kNoPtr ((uint8)-1)
#define kSprExt ".SPR"
#define kPalCount 256
#define kPalSize (kPalCount * 3)
struct Seq {
uint8 _now;
uint8 _next;
int8 _dx;
int8 _dy;
int _dly;
};
class SprExt {
public:
int _x0;
int _y0;
int _x1;
int _y1;
BitmapPtr _b0;
BitmapPtr _b1;
BitmapPtr *_shpList;
Seq *_seq;
char *_name;
CommandHandler::Command *_near;
CommandHandler::Command *_take;
SprExt() :
_x0(0), _y0(0),
_x1(0), _y1(0),
_b0(NULL), _b1(NULL),
_shpList(NULL), _seq(NULL),
_name(NULL), _near(NULL), _take(NULL)
{}
};
class Sprite {
protected:
SprExt *_ext;
public:
int _ref;
signed char _scene;
struct Flags {
bool _hide; // general visibility switch
bool _near; // Near action lock
bool _drag; // sprite is moveable
bool _hold; // sprite is held with mouse
bool _dummy; // interrupt driven animation
bool _slav; // slave object
bool _syst; // system object
bool _kill; // dispose memory after remove
bool _xlat; // 2nd way display: xlat table
bool _port; // portable
bool _kept; // kept in pocket
bool _east; // talk to east (in opposite to west)
bool _shad; // shadow
bool _back; // 'send to background' request
bool _bDel; // delete bitmaps in ~SPRITE
bool _tran; // transparent (untouchable)
} _flags;
int _x;
int _y;
signed char _z;
uint16 _w;
uint16 _h;
uint16 _time;
uint8 _nearPtr;
uint8 _takePtr;
int _seqPtr;
int _shpCnt;
char _file[kMaxFile];
Sprite *_prev;
Sprite *_next;
bool works(Sprite *spr);
bool seqTest(int n);
inline bool active() {
return _ext != NULL;
}
Sprite(CGEEngine *vm, BitmapPtr *shp);
virtual ~Sprite();
BitmapPtr shp();
BitmapPtr *setShapeList(BitmapPtr *shp);
Sprite *expand();
Sprite *contract();
Sprite *backShow(bool fast = false);
void setName(char *newName);
inline char *name() {
return (_ext) ? _ext->_name : NULL;
}
void gotoxy(int x, int y);
void center();
void show();
void hide();
BitmapPtr ghost();
void show(uint16 pg);
void makeXlat(uint8 *x);
void killXlat();
void step(int nr = -1);
Seq *setSeq(Seq *seq);
CommandHandler::Command *snList(SnList type);
virtual void touch(uint16 mask, int x, int y);
virtual void tick();
void sync(Common::Serializer &s);
private:
CGEEngine *_vm;
};
class Queue {
Sprite *_head;
Sprite *_tail;
public:
Queue(bool show);
~Queue();
bool _show;
void append(Sprite *spr);
void insert(Sprite *spr, Sprite *nxt);
void insert(Sprite *spr);
Sprite *remove(Sprite *spr);
Sprite *first() {
return _head;
}
Sprite *last() {
return _tail;
}
Sprite *locate(int ref);
void clear();
};
class Vga {
CGEEngine *_vm;
bool _setPal;
Dac *_oldColors;
Dac *_newColors;
const char *_msg;
const char *_name;
void updateColors();
void setColors();
void waitVR();
uint8 closest(Dac *pal, const uint8 colR, const uint8 colG, const uint8 colB);
public:
uint32 _frmCnt;
Queue *_showQ;
Queue *_spareQ;
int _mono;
Graphics::Surface *_page[4];
Dac *_sysPal;
Vga(CGEEngine *vm);
~Vga();
uint8 *glass(Dac *pal, const uint8 colR, const uint8 colG, const uint8 colB);
void getColors(Dac *tab);
void setColors(Dac *tab, int lum);
void clear(uint8 color);
void copyPage(uint16 d, uint16 s);
void sunrise(Dac *tab);
void sunset();
void show();
void update();
void palToDac(const byte *palData, Dac *tab);
void dacToPal(const Dac *tab, byte *palData);
};
class HorizLine: public Sprite {
CGEEngine *_vm;
public:
HorizLine(CGEEngine *vm);
};
class SceneLight: public Sprite {
CGEEngine *_vm;
public:
SceneLight(CGEEngine *vm);
};
class Speaker: public Sprite {
CGEEngine *_vm;
public:
Speaker(CGEEngine *vm);
};
class PocLight: public Sprite {
CGEEngine *_vm;
public:
PocLight(CGEEngine *vm);
};
} // End of namespace CGE
#endif

141
engines/cge/vmenu.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/>.
*
*/
/*
* This code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#include "cge/vmenu.h"
#include "cge/events.h"
#include "cge/cge_main.h"
namespace CGE {
MenuBar::MenuBar(CGEEngine *vm, uint16 w) : Talk(vm), _vm(vm) {
int h = kFontHigh + 2 * kMenuBarVM;
int i = (w += 2 * kMenuBarHM) * h;
uint8 *p = (uint8 *)malloc(sizeof(uint8) * i);
memset(p + w, kPixelTransp, i - 2 * w);
memset(p, kMenuBarLT, w);
memset(p + i - w, kMenuBarRB, w);
uint8 *p1 = p;
uint8 *p2 = p + i - 1;
for (int cpt = 0; cpt < h; cpt++) {
*p1 = kMenuBarLT;
*p2 = kMenuBarRB;
p1 += w;
p2 -= w;
}
_ts = new BitmapPtr[2];
_ts[0] = new Bitmap(_vm, w, h, p);
_ts[1] = nullptr;
setShapeList(_ts);
_flags._slav = true;
_flags._tran = true;
_flags._kill = true;
_flags._bDel = true;
}
Vmenu *Vmenu::_addr = nullptr;
int Vmenu::_recent = -1;
Vmenu::Vmenu(CGEEngine *vm, Choice *list, int x, int y)
: Talk(vm, VMGather(list), kTBRect), _menu(list), _bar(nullptr), _vmgt(nullptr), _vm(vm) {
Choice *cp;
_addr = this;
_items = 0;
for (cp = list; cp->_text; cp++)
_items++;
_flags._bDel = true;
_flags._kill = true;
if (x < 0 || y < 0)
center();
else
gotoxy(x - _w / 2, y - (kTextVMargin + kFontHigh / 2));
_vm->_vga->_showQ->insert(this, _vm->_vga->_showQ->last());
_bar = new MenuBar(_vm, _w - 2 * kTextHMargin);
_bar->gotoxy(_x + kTextHMargin - kMenuBarHM, _y + kTextVMargin - kMenuBarVM);
_vm->_vga->_showQ->insert(_bar, _vm->_vga->_showQ->last());
}
Vmenu::~Vmenu() {
_addr = nullptr;
}
#define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember))
void Vmenu::touch(uint16 mask, int x, int y) {
if (!_items)
return;
Sprite::touch(mask, x, y);
y -= kTextVMargin - 1;
int n = 0;
bool ok = false;
uint16 h = kFontHigh + kTextLineSpace;
if (y >= 0) {
n = y / h;
if (n < _items)
ok = (x >= kTextHMargin && x < _w - kTextHMargin/* && y % h < FONT_HIG*/);
else
n = _items - 1;
}
_bar->gotoxy(_x + kTextHMargin - kMenuBarHM, _y + kTextVMargin + n * h - kMenuBarVM);
if (ok && (mask & kMouseLeftUp)) {
_items = 0;
_vm->_commandHandlerTurbo->addCommand(kCmdKill, -1, 0, this);
_recent = n;
assert(_menu[n].Proc);
CALL_MEMBER_FN(*_vm, _menu[n].Proc)();
}
}
char *Vmenu::VMGather(Choice *list) {
Choice *cp;
int len = 0, h = 0;
for (cp = list; cp->_text; cp++) {
len += strlen(cp->_text);
h++;
}
len += h;
_vmgt = new char[len];
if (_vmgt) {
*_vmgt = '\0';
for (cp = list; cp->_text; cp++) {
if (*_vmgt)
Common::strcat_s(_vmgt, len, "|");
Common::strcat_s(_vmgt, len, cp->_text);
h++;
}
}
return _vmgt;
}
} // End of namespace CGE

72
engines/cge/vmenu.h Normal file
View File

@@ -0,0 +1,72 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#ifndef CGE_VMENU_H
#define CGE_VMENU_H
#include "cge/talk.h"
namespace CGE {
#define kMenuBarVM 1
#define kMenuBarHM 3
#define kMenuBarLT kVgaColLightGray
#define kMenuBarRB kVgaColDarkGray
struct Choice {
const char *_text;
void (CGEEngine::*Proc)();
};
class MenuBar : public Talk {
public:
MenuBar(CGEEngine *vm, uint16 w);
private:
CGEEngine *_vm;
};
class Vmenu : public Talk {
public:
static Vmenu *_addr;
static int _recent;
MenuBar *_bar;
Vmenu(CGEEngine *vm, Choice *list, int x, int y);
~Vmenu() override;
void touch(uint16 mask, int x, int y) override;
private:
char *_vmgt;
CGEEngine *_vm;
uint16 _items;
Choice *_menu;
char *VMGather(Choice *list);
};
} // End of namespace CGE
#endif

272
engines/cge/walk.cpp Normal file
View File

@@ -0,0 +1,272 @@
/* 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 code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#include "cge/walk.h"
#include "cge/cge_main.h"
namespace CGE {
Cluster::Cluster(CGEEngine *vm, int16 a, int16 b) : _vm(vm) {
_pt = Common::Point(a, b);
}
Cluster::Cluster(CGEEngine *vm) : _vm(vm) {
_pt = Common::Point(-1, -1);
}
uint8 &Cluster::cell() {
return _vm->_clusterMap[_pt.y][_pt.x];
}
bool Cluster::isValid() const {
return (_pt.x >= 0) && (_pt.x < kMapXCnt) && (_pt.y >= 0) && (_pt.y < kMapZCnt);
}
Walk::Walk(CGEEngine *vm, BitmapPtr *shpl)
: Sprite(vm, shpl), _dir(kDirNone), _tracePtr(-1), _level(0), _target(-1, -1), _findLevel(-1), _here(vm), _vm(vm) {
for (int i = 0; i < kMaxFindLevel; i++) {
Cluster *tmpClust = new Cluster(_vm);
_trace.push_back(tmpClust);
}
}
Walk::~Walk() {
for (uint idx = 0; idx < _trace.size(); ++idx)
delete _trace[idx];
}
void Walk::tick() {
if (_flags._hide)
return;
_here = _vm->XZ(_x + _w / 2, _y + _h);
if (_dir != kDirNone) {
_vm->_sys->funTouch();
for (Sprite *spr = _vm->_vga->_showQ->first(); spr; spr = spr->_next) {
if (distance(spr) < 2) {
if (!spr->_flags._near) {
_vm->feedSnail(spr, kNear);
spr->_flags._near = true;
}
} else {
spr->_flags._near = false;
}
}
}
if (_flags._hold || _tracePtr < 0) {
park();
} else {
if (_here._pt == _trace[_tracePtr]->_pt) {
if (--_tracePtr < 0)
park();
} else {
Common::Point tmpPoint = _trace[_tracePtr]->_pt - _here._pt;
int16 dx = tmpPoint.x;
int16 dz = tmpPoint.y;
Dir d = (dx) ? ((dx > 0) ? kDirEast : kDirWest) : ((dz > 0) ? kDirSouth : kDirNorth);
turn(d);
}
}
step();
if ((_dir == kDirWest && _x <= 0) ||
(_dir == kDirEast && _x + _w >= kScrWidth) ||
(_dir == kDirSouth && _y + _w >= kWorldHeight - 2)) {
park();
} else {
// take current Z position
_z = _here._pt.y;
_vm->_commandHandlerTurbo->addCommand(kCmdZTrim, -1, 0, this); // update Hero's pos in show queue
}
}
int Walk::distance(Sprite *spr) {
int dx = spr->_x - (_x + _w - kWalkSide);
if (dx < 0)
dx = (_x + kWalkSide) - (spr->_x + spr->_w);
if (dx < 0)
dx = 0;
dx /= kMapGridX;
int dz = spr->_z - _z;
if (dz < 0)
dz = - dz;
dx = dx * dx + dz * dz;
for (dz = 1; dz * dz < dx; dz++)
;
return dz - 1;
}
/**
* Turn the character to a given direction
* @param d Direction
*/
void Walk::turn(Dir d) {
Dir dir = (_dir == kDirNone) ? kDirSouth : _dir;
if (d != _dir) {
step((d == dir) ? (1 + dir + dir) : (9 + 4 * dir + d));
_dir = d;
}
}
/**
* Stop the character and reset his direction
*/
void Walk::park() {
if (_time == 0)
_time++;
if (_dir != kDirNone) {
step(9 + 4 * _dir + _dir);
_dir = kDirNone;
_tracePtr = -1;
}
}
void Walk::findWay(Cluster c) {
if (c._pt == _here._pt)
return;
for (_findLevel = 1; _findLevel <= kMaxFindLevel; _findLevel++) {
_target = _here._pt;
int16 x = c._pt.x;
int16 z = c._pt.y;
if (find1Way(Cluster(_vm, x, z)))
break;
}
_tracePtr = (_findLevel > kMaxFindLevel) ? -1 : (_findLevel - 1);
if (_tracePtr < 0)
noWay();
_time = 1;
}
void Walk::findWay(Sprite *spr) {
if (!spr || spr == this)
return;
int x = spr->_x;
int z = spr->_z;
if (spr->_flags._east)
x += spr->_w + _w / 2 - kWalkSide;
else
x -= _w / 2 - kWalkSide;
findWay(Cluster(_vm, (x / kMapGridX),
((z < kMapZCnt - kDistMax) ? (z + 1)
: (z - 1))));
}
bool Walk::lower(Sprite *spr) {
return (spr->_y > _y + (_h * 3) / 5);
}
void Walk::reach(Sprite *spr, int mode) {
if (spr) {
_vm->_hero->findWay(spr);
if (mode < 0) {
mode = spr->_flags._east;
if (lower(spr))
mode += 2;
}
}
// note: insert SNAIL commands in reverse order
_vm->_commandHandler->insertCommand(kCmdPause, -1, 64, nullptr);
_vm->_commandHandler->insertCommand(kCmdSeq, -1, kTSeq + mode, this);
if (spr) {
_vm->_commandHandler->insertCommand(kCmdWait, -1, -1, _vm->_hero);
//SNINSERT(SNWALK, -1, -1, spr);
}
// sequence is not finished,
// now it is just at sprite appear (disappear) point
}
void Walk::noWay() {
_vm->trouble(kSeqNoWay, kNoWay);
}
bool Cluster::chkBar() const {
assert(_vm->_now <= kSceneMax);
return (_pt.x == _vm->_barriers[_vm->_now]._horz) || (_pt.y == _vm->_barriers[_vm->_now]._vert);
}
bool Walk::find1Way(Cluster c) {
const Cluster tab[4] = { Cluster(_vm, -1, 0), Cluster(_vm, 1, 0), Cluster(_vm, 0, -1), Cluster(_vm, 0, 1)};
const int tabLen = 4;
if (c._pt == _target)
// Found destination
return true;
if (_level >= _findLevel)
// Nesting limit
return false;
// Look for barriers
if (c.chkBar())
return false;
if (c.cell())
// Location is occupied
return false;
// Loop through each direction
Cluster start = c;
for (int i = 0; i < tabLen; i++) {
// Reset to starting position
c = start;
do {
c._pt += tab[i]._pt;
if (!c.isValid())
// Break to check next direction
break;
// Recursively check for further paths
++_level;
++start.cell();
bool foundPath = find1Way(c);
--start.cell();
--_level;
if (foundPath) {
// Set route point
_trace[_level]->_pt = start._pt;
return true;
}
} while (!c.chkBar() && !c.cell());
}
return false;
}
} // End of namespace CGE

85
engines/cge/walk.h Normal file
View File

@@ -0,0 +1,85 @@
/* 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 code is based on original Soltys source code
* Copyright (c) 1994-1995 Janusz B. Wisniewski and L.K. Avalon
*/
#ifndef CGE_WALK_H
#define CGE_WALK_H
#include "common/rect.h"
#include "cge/vga13h.h"
#include "cge/events.h"
namespace CGE {
#define kMapArrSize (kMapZCnt * kMapXCnt)
#define kMapHig 80
#define kMapGridX (kScrWidth / kMapXCnt)
#define kMapGridZ (kMapHig / kMapZCnt)
#define kMaxFindLevel 3
enum Dir { kDirNone = -1, kDirNorth, kDirEast, kDirSouth, kDirWest };
class Cluster {
public:
CGEEngine *_vm;
Common::Point _pt;
public:
uint8 &cell();
Cluster(CGEEngine *vm, int16 a, int16 b);
Cluster(CGEEngine *vm);
bool chkBar() const;
bool isValid() const;
};
class Walk : public Sprite {
private:
CGEEngine *_vm;
public:
Cluster _here;
int _tracePtr;
int _level;
int _findLevel;
Common::Point _target;
Common::Array<Cluster *> _trace;
Dir _dir;
Walk(CGEEngine *vm, BitmapPtr *shpl);
~Walk() override;
void tick() override;
void findWay(Cluster c);
void findWay(Sprite *spr);
int distance(Sprite *spr);
void turn(Dir d);
void park();
bool lower(Sprite *spr);
void reach(Sprite *spr, int mode = -1);
void noWay();
bool find1Way(Cluster c);
};
} // End of namespace CGE
#endif