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

@@ -0,0 +1,2 @@
engines/prince/metaengine.cpp
engines/prince/saveload.cpp

View File

@@ -0,0 +1,177 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "prince/animation.h"
#include "prince/decompress.h"
#include "common/debug.h"
#include "common/endian.h"
namespace Prince {
Animation::Animation() : _loopCount(0), _phaseCount(0), _frameCount(0), _baseX(0), _baseY(0)
{
}
Animation::~Animation() {
clear();
}
void Animation::clear() {
_phaseList.clear();
for (int i = 0; i < _frameCount; i++) {
_frameList[i]._surface->free();
delete _frameList[i]._surface;
_frameList[i]._surface = nullptr;
if (_frameList[i]._compressedData != nullptr) {
free(_frameList[i]._compressedData);
_frameList[i]._compressedData = nullptr;
}
}
}
bool Animation::loadStream(Common::SeekableReadStream &stream) {
stream.skip(2); // skip not used x and y coord diff
_loopCount = stream.readUint16LE();
_phaseCount = stream.readUint16LE();
stream.skip(2); // skip _frameCount here
_baseX = stream.readUint16LE();
_baseY = stream.readUint16LE();
uint32 phaseTableOffset = stream.readUint32LE();
uint32 tableOfFrameOffsets = stream.pos();
stream.seek(phaseTableOffset);
Phase tempPhase;
_frameCount = 0;
for (int phase = 0; phase < _phaseCount; phase++) {
tempPhase._phaseOffsetX = stream.readSint16LE();
tempPhase._phaseOffsetY = stream.readSint16LE();
tempPhase._phaseToFrameIndex = stream.readUint16LE();
if (tempPhase._phaseToFrameIndex > _frameCount) {
_frameCount = tempPhase._phaseToFrameIndex;
}
_phaseList.push_back(tempPhase);
stream.skip(2);
}
if (_phaseCount) {
_frameCount++;
}
Frame tempFrame;
for (int frame = 0; frame < _frameCount; frame++) {
stream.seek(tableOfFrameOffsets + frame * 4);
uint32 frameInfoOffset = stream.readUint32LE();
stream.seek(frameInfoOffset);
uint16 frameWidth = stream.readUint16LE();
uint16 frameHeight = stream.readUint16LE();
uint32 frameDataPos = stream.pos();
uint32 frameDataOffset = stream.readUint32BE();
tempFrame._surface = new Graphics::Surface();
tempFrame._surface->create(frameWidth, frameHeight, Graphics::PixelFormat::createFormatCLUT8());
if (frameDataOffset == MKTAG('m', 'a', 's', 'm')) {
tempFrame._isCompressed = true;
tempFrame._dataSize = stream.readUint32LE();
tempFrame._compressedData = (byte *)malloc(tempFrame._dataSize);
stream.read(tempFrame._compressedData, tempFrame._dataSize);
} else {
tempFrame._isCompressed = false;
tempFrame._dataSize = 0;
tempFrame._compressedData = nullptr;
stream.seek(frameDataPos);
for (uint16 i = 0; i < frameHeight; i++) {
stream.read(tempFrame._surface->getBasePtr(0, i), frameWidth);
}
}
_frameList.push_back(tempFrame);
}
return true;
}
int16 Animation::getLoopCount() const {
return _loopCount;
}
int32 Animation::getPhaseCount() const {
return _phaseCount;
}
int32 Animation::getFrameCount() const {
return _frameCount;
}
int16 Animation::getBaseX() const {
return _baseX;
}
int16 Animation::getBaseY() const {
return _baseY;
}
int16 Animation::getPhaseOffsetX(int phaseIndex) const {
if (phaseIndex < _phaseCount) {
return _phaseList[phaseIndex]._phaseOffsetX;
} else {
error("getPhaseOffsetX() phaseIndex: %d, phaseCount: %d", phaseIndex, _phaseCount);
}
}
int16 Animation::getPhaseOffsetY(int phaseIndex) const {
if (phaseIndex < _phaseCount) {
return _phaseList[phaseIndex]._phaseOffsetY;
} else {
error("getPhaseOffsetY() phaseIndex: %d, phaseCount: %d", phaseIndex, _phaseCount);
}
}
int16 Animation::getPhaseFrameIndex(int phaseIndex) const {
if (phaseIndex < _phaseCount) {
return _phaseList[phaseIndex]._phaseToFrameIndex;
} else {
error("getPhaseFrameIndex() phaseIndex: %d, phaseCount: %d", phaseIndex, _phaseCount);
}
}
Graphics::Surface *Animation::getFrame(int frameIndex) {
if (frameIndex < _frameCount) {
if (_frameList[frameIndex]._isCompressed) {
Decompressor dec;
byte *ddata = (byte *)malloc(_frameList[frameIndex]._dataSize);
dec.decompress(_frameList[frameIndex]._compressedData, ddata, _frameList[frameIndex]._dataSize);
int frameHeight = _frameList[frameIndex]._surface->h;
int frameWidth = _frameList[frameIndex]._surface->w;
for (uint16 i = 0; i < frameHeight; i++) {
memcpy(_frameList[frameIndex]._surface->getBasePtr(0, i), ddata + frameWidth * i, frameWidth);
}
free(ddata);
free(_frameList[frameIndex]._compressedData);
_frameList[frameIndex]._compressedData = nullptr;
_frameList[frameIndex]._dataSize = 0;
_frameList[frameIndex]._isCompressed = false;
}
return _frameList[frameIndex]._surface;
} else {
error("getFrame() frameIndex: %d, frameCount: %d", frameIndex, _frameCount);
}
}
} // End of namespace Prince

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/>.
*
*/
#ifndef PRINCE_ANIMATION_H
#define PRINCE_ANIMATION_H
#include "common/array.h"
#include "common/stream.h"
#include "graphics/surface.h"
namespace Prince {
class Animation {
public:
Animation();
~Animation();
bool loadStream(Common::SeekableReadStream &stream);
int16 getLoopCount() const;
int32 getPhaseCount() const;
int32 getFrameCount() const;
int16 getBaseX() const;
int16 getBaseY() const;
int16 getPhaseOffsetX(int phaseIndex) const;
int16 getPhaseOffsetY(int phaseIndex) const;
int16 getPhaseFrameIndex(int phaseIndex) const;
Graphics::Surface *getFrame(int frameIndex);
void clear();
private:
struct Phase {
int16 _phaseOffsetX;
int16 _phaseOffsetY;
uint16 _phaseToFrameIndex;
};
struct Frame {
bool _isCompressed;
uint32 _dataSize;
byte *_compressedData;
Graphics::Surface *_surface;
};
Common::Array<Frame> _frameList;
Common::Array<Phase> _phaseList;
int16 _loopCount;
int16 _phaseCount;
int32 _frameCount;
int16 _baseX;
int16 _baseY;
};
} // End of namespace Prince
#endif

192
engines/prince/archive.cpp Normal file
View File

@@ -0,0 +1,192 @@
/* 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 "prince/archive.h"
#include "prince/decompress.h"
#include "common/stream.h"
#include "common/debug.h"
#include "common/memstream.h"
namespace Prince {
PtcArchive::PtcArchive() : _stream(nullptr) {
}
PtcArchive::~PtcArchive() {
close();
}
static void decrypt(byte *buffer, uint32 size) {
uint32 key = 0xDEADF00D;
while (size--) {
*buffer++ += key & 0xFF;
key ^= 0x2E84299A;
key += MKTAG('B', 'L', 'A', 'H');
key = ((key & 1) << 31) | (key >> 1);
}
}
bool PtcArchive::open(const Common::Path &filename) {
_stream = SearchMan.createReadStreamForMember(filename);
if (!_stream)
return false;
_stream->readUint32LE(); // magic
uint32 fileTableOffset = _stream->readUint32LE() ^ 0x4D4F4B2D; // MOK-
uint32 fileTableSize = _stream->readUint32LE() ^ 0x534F4654; // SOFT
debug(8, "fileTableOffset : %08X", fileTableOffset);
debug(8, "fileTableSize: %08X", fileTableSize);
_stream->seek(fileTableOffset);
byte *fileTable = (byte *)malloc(fileTableSize);
byte *fileTableEnd = fileTable + fileTableSize;
_stream->read(fileTable, fileTableSize);
decrypt(fileTable, fileTableSize);
for (byte *fileItem = fileTable; fileItem < fileTableEnd; fileItem += 32) {
FileEntry item;
Common::String name = (const char*)fileItem;
item._offset = READ_LE_UINT32(fileItem + 24);
item._size = READ_LE_UINT32(fileItem + 28);
debug(8, "%12s %8X %d", name.c_str(), item._offset, item._size);
_items[name] = item;
}
free(fileTable);
return true;
}
bool PtcArchive::openTranslation(const Common::Path &filename) {
_stream = SearchMan.createReadStreamForMember(filename);
if (!_stream)
return false;
Common::Array<Common::String> translationNames;
Common::String translationFileName;
const int kTranslationFiles = 5;
for (int i = 0; i < kTranslationFiles; i++) {
translationFileName = _stream->readLine();
translationNames.push_back(translationFileName);
}
FileEntry item;
for (int i = 0; i < kTranslationFiles; i++) {
item._offset = _stream->readUint32LE();
item._size = _stream->readUint32LE();
_items[translationNames[i]] = item;
}
if ((int32)_items[translationNames[0]]._offset == _stream->pos()) {
warning("v0 translation file detected, update is needed");
return true;
}
// We have latter versions of the file
if (_stream->readByte() != '\n') {
error("Malformed prince_translation.dat file");
}
Common::String version = _stream->readLine();
Common::String stamp = _stream->readLine();
warning("%s translation file detected, built on %s", version.c_str(), stamp.c_str());
if (version.equals("v1.0")) {
// No more data, we all fine
return true;
}
// Here we have format extension data
return true;
}
void PtcArchive::close() {
delete _stream;
_stream = nullptr;
_items.clear();
}
bool PtcArchive::hasFile(const Common::Path &path) const {
Common::String name = path.toString();
// TODO: check if path matching should be added
return _items.contains(name);
}
int PtcArchive::listMembers(Common::ArchiveMemberList &list) const {
int matches = 0;
for (const auto &item : _items) {
list.push_back(Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(item._key, *this)));
matches++;
}
return matches;
}
const Common::ArchiveMemberPtr PtcArchive::getMember(const Common::Path &path) const {
if (!hasFile(path)) {
Common::ArchiveMemberPtr();
}
return Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(path, *this));
}
Common::SeekableReadStream *PtcArchive::createReadStreamForMember(const Common::Path &path) const {
Common::String name = path.toString();
if (!_items.contains(name)) {
return nullptr;
}
debug(8, "PtcArchive::createReadStreamForMember(%s)", name.c_str());
const FileEntry &entryHeader = _items[name];
if (entryHeader._size < 4)
return nullptr;
uint32 size = entryHeader._size;
_stream->seek(entryHeader._offset);
// This *HAS* to be malloc (not new[]) because MemoryReadStream uses free() to free the memory
byte *buffer = (byte *)malloc(size);
_stream->read(buffer, size);
if (READ_BE_UINT32(buffer) == MKTAG('M', 'A', 'S', 'M')) {
Decompressor dec;
uint32 decompLen = READ_BE_UINT32(buffer + 14);
byte *decompData = (byte *)malloc(decompLen);
dec.decompress(buffer + 18, decompData, decompLen);
free(buffer);
size = decompLen;
buffer = decompData;
debug(8, "PtcArchive::createReadStreamForMember: decompressed %d to %d bytes", entryHeader._size, decompLen);
}
return new Common::MemoryReadStream(buffer, size, DisposeAfterUse::YES);
}
} // End of namespace Prince

61
engines/prince/archive.h Normal file
View File

@@ -0,0 +1,61 @@
/* 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 PRINCE_ARCHIVE_H
#define PRINCE_ARCHIVE_H
#include "common/archive.h"
#include "common/hashmap.h"
#include "common/hash-str.h"
namespace Prince {
class PtcArchive : public Common::Archive {
public:
PtcArchive();
~PtcArchive() override;
bool open(const Common::Path &filename);
bool openTranslation(const Common::Path &filename);
void close();
bool isOpen() const { return _stream != 0; }
// Common::Archive API implementation
bool hasFile(const Common::Path &path) const override;
int listMembers(Common::ArchiveMemberList &list) const override;
const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override;
Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override;
private:
struct FileEntry {
uint32 _offset;
uint32 _size;
};
Common::SeekableReadStream *_stream;
typedef Common::HashMap<Common::String, FileEntry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap;
FileMap _items;
};
} // End of namespace Prince
#endif

44
engines/prince/common.h Normal file
View File

@@ -0,0 +1,44 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PRINCE_COMMON_H
#define PRINCE_COMMON_H
namespace Prince {
enum Direction {
kDirLD,
kDirL,
kDirLU,
kDirRD,
kDirR,
kDirRU,
kDirUL,
kDirU,
kDirUR,
kDirDL,
kDirD,
kDirDR
};
} // End of namespace Prince
#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 prince "The Prince and The Coward" yes "" "" "highres" "midi"

View File

@@ -0,0 +1,5 @@
begin_section("Prince");
add_person("Eugene Sandulenko", "sev", "");
add_person("&#321;ukasz W&#261;tka", "lukaslw", "");
add_person("Kamil Zbr&oacute;g", "", "");
end_section();

153
engines/prince/cursor.cpp Normal file
View File

@@ -0,0 +1,153 @@
/* 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/cursorman.h"
#include "prince/prince.h"
#include "prince/cursor.h"
#include "prince/debugger.h"
#include "prince/script.h"
#include "common/debug.h"
namespace Prince {
Cursor::Cursor() : _surface(nullptr) {
}
Cursor::~Cursor() {
if (_surface != nullptr) {
_surface->free();
delete _surface;
_surface = nullptr;
}
}
bool Cursor::loadStream(Common::SeekableReadStream &stream) {
stream.skip(4);
uint16 width = stream.readUint16LE();
uint16 height = stream.readUint16LE();
_surface = new Graphics::Surface();
_surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
for (int h = 0; h < height; h++) {
stream.read(_surface->getBasePtr(0, h), width);
}
return true;
}
void PrinceEngine::changeCursor(uint16 curId) {
_debugger->_cursorNr = curId;
_mouseFlag = curId;
_flags->setFlagValue(Flags::MOUSEENABLED, curId);
const Graphics::Surface *curSurface = nullptr;
switch (curId) {
default:
error("Unknown cursor Id: %d", curId);
case 0:
CursorMan.showMouse(false);
_optionsFlag = 0;
_selectedMob = -1;
_previousMob = -1;
return;
case 1:
curSurface = _cursor1->getSurface();
break;
case 2:
curSurface = _cursor2;
break;
case 3:
curSurface = _cursor3->getSurface();
Common::Point mousePos = _system->getEventManager()->getMousePos();
mousePos.x = CLIP(mousePos.x, (int16) 315, (int16) 639);
mousePos.y = CLIP(mousePos.y, (int16) 0, (int16) 170);
_system->warpMouse(mousePos.x, mousePos.y);
break;
}
CursorMan.replaceCursorPalette(_roomBmp->getPalette().data(), 0, 255);
CursorMan.replaceCursor(
curSurface->getBasePtr(0, 0),
curSurface->w, curSurface->h,
0, 0,
255, false,
&curSurface->format
);
CursorMan.showMouse(true);
}
void PrinceEngine::makeInvCursor(int itemNr) {
const Graphics::Surface *cur1Surface = _cursor1->getSurface();
int cur1W = cur1Surface->w;
int cur1H = cur1Surface->h;
const Common::Rect cur1Rect(0, 0, cur1W, cur1H);
const Graphics::Surface *itemSurface = _allInvList[itemNr].getSurface();
int itemW = itemSurface->w;
int itemH = itemSurface->h;
int cur2W = cur1W + itemW / 2;
int cur2H = cur1H + itemH / 2;
if (_cursor2 != nullptr) {
_cursor2->free();
delete _cursor2;
}
_cursor2 = new Graphics::Surface();
_cursor2->create(cur2W, cur2H, Graphics::PixelFormat::createFormatCLUT8());
Common::Rect cur2Rect(0, 0, cur2W, cur2H);
_cursor2->fillRect(cur2Rect, 255);
_cursor2->copyRectToSurface(*cur1Surface, 0, 0, cur1Rect);
const byte *src1 = (const byte *)itemSurface->getBasePtr(0, 0);
byte *dst1 = (byte *)_cursor2->getBasePtr(cur1W, cur1H);
if (itemH % 2) {
itemH--;
}
if (itemW % 2) {
itemW--;
}
for (int y = 0; y < itemH; y++) {
const byte *src2 = src1;
byte *dst2 = dst1;
if (y % 2 == 0) {
for (int x = 0; x < itemW; x++, src2++) {
if (x % 2 == 0) {
if (*src2) {
*dst2 = *src2;
} else {
*dst2 = 255;
}
dst2++;
}
}
dst1 += _cursor2->pitch;
}
src1 += itemSurface->pitch;
}
}
} // End of namespace Prince

45
engines/prince/cursor.h Normal file
View File

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

View File

@@ -0,0 +1,44 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace Prince {
const int curveValues[17][4] = {
{ 32768, 0, 0, 0 },
{ 25200, 7200, 480, -112 },
{ 18816, 12544, 1792, -384 },
{ 13520, 16224, 3744, -720 },
{ 9216, 18432, 6144, -1024 },
{ 5808, 19360, 8800, -1200 },
{ 3200, 19200, 11520, -1152 },
{ 1296, 18144, 14112, -784 },
{ 0, 16384, 16384, 0 },
{ -784, 14112, 18144, 1296 },
{ -1152, 11520, 19200, 3200 },
{ -1200, 8800, 19360, 5808 },
{ -1024, 6144, 18432, 9216 },
{ -720, 3744, 16224, 13520 },
{ -384, 1792, 12544, 18816 },
{ -112, 480, 7200, 25200 },
{ 0, 0, 0, 32768 }
};
} // End of namespace Prince

175
engines/prince/debugger.cpp Normal file
View File

@@ -0,0 +1,175 @@
/* 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 "prince/debugger.h"
#include "prince/prince.h"
#include "prince/flags.h"
#include "prince/script.h"
namespace Prince {
Debugger::Debugger(PrinceEngine *vm, InterpreterFlags *flags) : GUI::Debugger(), _vm(vm), _locationNr(0), _flags(flags) {
registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
registerCmd("level", WRAP_METHOD(Debugger, Cmd_DebugLevel));
registerCmd("setflag", WRAP_METHOD(Debugger, Cmd_SetFlag));
registerCmd("getflag", WRAP_METHOD(Debugger, Cmd_GetFlag));
registerCmd("clearflag", WRAP_METHOD(Debugger, Cmd_ClearFlag));
registerCmd("viewflc", WRAP_METHOD(Debugger, Cmd_ViewFlc));
registerCmd("initroom", WRAP_METHOD(Debugger, Cmd_InitRoom));
registerCmd("changecursor", WRAP_METHOD(Debugger, Cmd_ChangeCursor));
registerCmd("additem", WRAP_METHOD(Debugger, Cmd_AddItem));
_cursorNr = 0;
}
static int strToInt(const char *s) {
if (!*s)
// No string at all
return 0;
else if (toupper(s[strlen(s) - 1]) != 'H')
// Standard decimal string
return atoi(s);
// Hexadecimal string
uint tmp = 0;
int read = sscanf(s, "%xh", &tmp);
if (read < 1)
error("strToInt failed on string \"%s\"", s);
return (int)tmp;
}
bool Debugger::Cmd_DebugLevel(int argc, const char **argv) {
if (argc == 1) {
debugPrintf("Debugging is currently set at level %d\n", gDebugLevel);
} else { // set level
gDebugLevel = atoi(argv[1]);
if (0 <= gDebugLevel && gDebugLevel < 11) {
debugPrintf("Debug level set to level %d\n", gDebugLevel);
} else if (gDebugLevel < 0) {
debugPrintf("Debugging is now disabled\n");
} else
debugPrintf("Not a valid debug level (0 - 10)\n");
}
return true;
}
/*
* This command sets a flag
*/
bool Debugger::Cmd_SetFlag(int argc, const char **argv) {
// Check for a flag to set
if (argc != 3) {
debugPrintf("Usage: %s <flag number> <value>\n", argv[0]);
return true;
}
int flagNum = strToInt(argv[1]);
uint16 value = strToInt(argv[2]);
_flags->setFlagValue((Flags::Id)flagNum, value);
return true;
}
/*
* This command gets the value of a flag
*/
bool Debugger::Cmd_GetFlag(int argc, const char **argv) {
// Check for a flag to display
if (argc != 2) {
debugPrintf("Usage: %s <flag number>\n", argv[0]);
return true;
}
int flagNum = strToInt(argv[1]);
debugPrintf("Value: %d\n", _flags->getFlagValue((Flags::Id)flagNum));
return true;
}
/*
* This command clears a flag
*/
bool Debugger::Cmd_ClearFlag(int argc, const char **argv) {
// Check for a flag to clear
if (argc != 2) {
debugPrintf("Usage: %s <flag number>\n", argv[0]);
return true;
}
int flagNum = strToInt(argv[1]);
_flags->setFlagValue((Flags::Id)flagNum, 0);
return true;
}
/*
* This command starts new flc anim
*/
bool Debugger::Cmd_ViewFlc(int argc, const char **argv) {
// Check for a flag to clear
if (argc != 2) {
debugPrintf("Usage: %s <anim number>\n", argv[0]);
return true;
}
int flagNum = strToInt(argv[1]);
_vm->loadAnim(flagNum, false);
return true;
}
bool Debugger::Cmd_InitRoom(int argc, const char **argv) {
// Check for a flag to clear
if (argc != 2) {
debugPrintf("Usage: %s <anim number>\n", argv[0]);
return true;
}
_locationNr = strToInt(argv[1]);
return true;
}
bool Debugger::Cmd_ChangeCursor(int argc, const char **argv) {
// Check for a flag to clear
if (argc != 2) {
debugPrintf("Usage: %s <curId>\n", argv[0]);
return true;
}
_cursorNr = strToInt(argv[1]);
return true;
}
bool Debugger::Cmd_AddItem(int argc, const char **argv) {
if (argc != 2) {
debugPrintf("Usage: %s <itemId>\n", argv[0]);
return true;
}
if (!strcmp(argv[1], "map")) {
_vm->addInv(0, 29, true);
_vm->_flags->setFlagValue(Flags::MapaUsable, 1);
} else {
int itemId = strToInt(argv[1]);
_vm->addInv(0, itemId, true);
}
return true;
}
} // End of namespace Prince

56
engines/prince/debugger.h Normal file
View File

@@ -0,0 +1,56 @@
/* 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 PRINCE_DEBUGGER_H
#define PRINCE_DEBUGGER_H
#include "common/scummsys.h"
#include "gui/debugger.h"
namespace Prince {
class PrinceEngine;
class InterpreterFlags;
class Debugger : public GUI::Debugger {
public:
Debugger(PrinceEngine *vm, InterpreterFlags *flags);
uint8 _locationNr;
uint8 _cursorNr;
private:
bool Cmd_DebugLevel(int argc, const char **argv);
bool Cmd_SetFlag(int argc, const char **argv);
bool Cmd_GetFlag(int argc, const char **argv);
bool Cmd_ClearFlag(int argc, const char **argv);
bool Cmd_ViewFlc(int argc, const char **argv);
bool Cmd_InitRoom(int argc, const char **argv);
bool Cmd_ChangeCursor(int argc, const char **argv);
bool Cmd_AddItem(int argc, const char **argv);
PrinceEngine *_vm;
InterpreterFlags *_flags;
};
} // End of namespace Prince
#endif

View File

@@ -0,0 +1,172 @@
/* 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/>.
*
*/
// John_Doe's implementation
#include "prince/decompress.h"
namespace Prince {
static const uint16 table1[] = {
0x8000, 0x0002,
0x4000, 0x0004,
0x2000, 0x0008,
0x1000, 0x0010,
0x0800, 0x0020,
0x0400, 0x0040,
0x0200, 0x0080,
0x0100, 0x0100,
0x0080, 0x0200,
0x0040, 0x0400
};
static const uint32 table2[] = {
0x0000F000,
0x0020FC00,
0x00A0FF00,
0x02A0FF80,
0x06A0FFC0,
0x0EA0FFE0,
0x1EA0FFF0,
0x3EA0FFF8
};
static const uint16 table3[] = {
0x8000, 0x0000,
0x4000, 0x0002,
0x2000, 0x0006,
0x1000, 0x000E,
0x0800, 0x001E,
0x0400, 0x003E,
0x0200, 0x007E,
0x0100, 0x00FE,
0x0080, 0x01FE,
0x0040, 0x03FE,
0x0020, 0x07FE,
0x0010, 0x0FFE,
0x0008, 0x1FFE,
0x0004, 0x3FFE,
0x0002, 0x7FFE,
0x0001, 0xFFFE
};
void Decompressor::decompress(byte *source, byte *dest, uint32 destSize) {
byte *destEnd = dest + destSize;
int more;
_src = source;
_dst = dest;
_bitBuffer = 0x80;
while (_dst < destEnd) {
uint32 ebp;
uint16 offset, length;
if (getBit()) {
if (getBit()) {
if (getBit()) {
if (getBit()) {
if (getBit()) {
if (getBit()) {
uint32 tableIndex = 0;
while (getBit())
tableIndex++;
length = table3[tableIndex * 2 + 0];
do {
more = !(length & 0x8000);
length = (length << 1) | getBit();
} while (more);
length += table3[tableIndex * 2 + 1];
length++;
memcpy(_dst, _src, length);
_src += length;
_dst += length;
}
*_dst++ = *_src++;
}
*_dst++ = *_src++;
}
*_dst++ = *_src++;
}
*_dst++ = *_src++;
}
*_dst++ = *_src++;
}
if (!getBit()) {
if (getBit()) {
uint32 tableIndex = getBit();
tableIndex = (tableIndex << 1) | getBit();
tableIndex = (tableIndex << 1) | getBit();
ebp = table2[tableIndex];
length = 1;
} else {
ebp = 0x0000FF00;
length = 0;
}
} else {
uint32 tableIndex = 0;
while (getBit())
tableIndex++;
length = table1[tableIndex * 2 + 0];
do {
more = !(length & 0x8000);
length = (length << 1) | getBit();
} while (more);
length += table1[tableIndex * 2 + 1];
tableIndex = getBit();
tableIndex = (tableIndex << 1) | getBit();
tableIndex = (tableIndex << 1) | getBit();
ebp = table2[tableIndex];
}
offset = ebp & 0xFFFF;
do {
if (_bitBuffer == 0x80) {
if (offset >= 0xFF00) {
offset = (offset << 8) | *_src++;
}
}
more = offset & 0x8000;
offset = (offset << 1) | getBit();
} while (more);
offset += (ebp >> 16);
length += 2;
while (length--) {
if (_dst >= destEnd) {
return;
}
if (_dst - offset >= dest)
*_dst = *(_dst - offset);
_dst++;
}
}
}
int Decompressor::getBit() {
int bit = (_bitBuffer & 0x80) >> 7;
_bitBuffer <<= 1;
if (_bitBuffer == 0) {
_bitBuffer = *_src++;
bit = (_bitBuffer & 0x80) >> 7;
_bitBuffer <<= 1;
_bitBuffer |= 1;
}
return bit;
}
} // End of namespace Prince

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/>.
*
*/
// John_Doe's implementation
#ifndef PRINCE_DECOMPRESS_H
#define PRINCE_DECOMPRESS_H
#include "engines/util.h"
namespace Prince {
class Decompressor {
public:
void decompress(byte *source, byte *dest, uint32 destSize);
protected:
byte *_src, *_dst;
byte _bitBuffer;
int _bitsLeft;
int getBit();
};
} // End of namespace Prince
#endif

View File

@@ -0,0 +1,188 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/advancedDetector.h"
#include "prince/detection.h"
#include "prince/prince.h"
static const PlainGameDescriptor princeGames[] = {
{"prince", "The Prince and the Coward"},
{nullptr, nullptr}
};
static const DebugChannelDef debugFlagList[] = {
{Prince::DebugChannel::kScript, "script", "Prince Script debug channel"},
{Prince::DebugChannel::kEngine, "engine", "Prince Engine debug channel"},
DEBUG_CHANNEL_END
};
namespace Prince {
static const PrinceGameDescription gameDescriptions[] = {
{
{
"prince",
"Galador: Der Fluch des Prinzen",
AD_ENTRY1s("databank.ptc", "5fa03833177331214ec1354761b1d2ee", 3565031),
Common::DE_DEU,
Common::kPlatformWindows,
ADGF_USEEXTRAASTITLE | ADGF_DROPPLATFORM,
GUIO2(GAMEOPTION_TTS_OBJECTS, GAMEOPTION_TTS_MISSING_VOICE)
},
kPrinceDataDE
},
{
{
"prince",
"Ksiaze i Tchorz",
AD_ENTRY1s("databank.ptc", "48ec9806bda9d152acbea8ce31c93c49", 3435298),
Common::PL_POL,
Common::kPlatformWindows,
ADGF_USEEXTRAASTITLE | ADGF_DROPPLATFORM,
GUIO2(GAMEOPTION_TTS_OBJECTS, GAMEOPTION_TTS_MISSING_VOICE)
},
kPrinceDataPL
},
{
{
"prince",
"",
AD_ENTRY1s("talktxt.dat", "02bb2372f19aca3c65896ed81b2cefb3", 125702),
Common::RU_RUS,
Common::kPlatformWindows,
GF_EXTRACTED | ADGF_DROPPLATFORM,
GUIO2(GAMEOPTION_TTS_OBJECTS, GAMEOPTION_TTS_MISSING_VOICE)
},
kPrinceDataDE
},
{
{
"prince",
"",
AD_ENTRY1s("databank.ptc", "a67b55730f3d7064921bd2a59e1063a3", 3892982),
Common::RU_RUS,
Common::kPlatformWindows,
GF_NOVOICES | ADGF_DROPPLATFORM,
GUIO2(GAMEOPTION_TTS_OBJECTS, GAMEOPTION_TTS_SPEECH)
},
kPrinceDataDE
},
{
{
"prince",
"",
AD_ENTRY1s("databank.ptc", "eb702d16e88c8c41f963d449287c8023", 3730152),
Common::RU_RUS,
Common::kPlatformWindows,
GF_RUSPROJEDITION | ADGF_USEEXTRAASTITLE | ADGF_DROPPLATFORM,
GUIO2(GAMEOPTION_TTS_OBJECTS, GAMEOPTION_TTS_MISSING_VOICE)
},
kPrinceDataDE
},
{
{
"prince",
"w/translation",
AD_ENTRY2s("databank.ptc", "5fa03833177331214ec1354761b1d2ee", 3565031,
"prince_translation.dat", nullptr, AD_NO_SIZE),
Common::EN_ANY,
Common::kPlatformWindows,
GF_TRANSLATED | ADGF_DROPPLATFORM,
GUIO2(GAMEOPTION_TTS_OBJECTS, GAMEOPTION_TTS_SPEECH)
},
kPrinceDataDE
},
{
{
"prince",
"w/translation",
AD_ENTRY2s("databank.ptc", "48ec9806bda9d152acbea8ce31c93c49", 3435298,
"prince_translation.dat", nullptr, AD_NO_SIZE),
Common::EN_ANY,
Common::kPlatformWindows,
GF_TRANSLATED | ADGF_DROPPLATFORM,
GUIO2(GAMEOPTION_TTS_OBJECTS, GAMEOPTION_TTS_SPEECH)
},
kPrinceDataPL
},
{
{
"prince",
"w/translation",
AD_ENTRY3s("databank.ptc", "5fa03833177331214ec1354761b1d2ee", 3565031,
"FONT1.RAW", "e80c50c8167d4d51c60d93e29bedb779", 27118,
"prince_translation.dat", nullptr, AD_NO_SIZE),
Common::ES_ESP,
Common::kPlatformWindows,
GF_TRANSLATED | ADGF_DROPPLATFORM,
GUIO2(GAMEOPTION_TTS_OBJECTS, GAMEOPTION_TTS_SPEECH)
},
kPrinceDataDE
},
{
{
"prince",
"w/translation",
AD_ENTRY3s("databank.ptc", "48ec9806bda9d152acbea8ce31c93c49", 3435298,
"FONT1.RAW", "e80c50c8167d4d51c60d93e29bedb779", 27118,
"prince_translation.dat", nullptr, AD_NO_SIZE),
Common::ES_ESP,
Common::kPlatformWindows,
GF_TRANSLATED | ADGF_DROPPLATFORM,
GUIO2(GAMEOPTION_TTS_OBJECTS, GAMEOPTION_TTS_SPEECH)
},
kPrinceDataPL
},
{ AD_TABLE_END_MARKER, kPrinceDataUNK }
};
} // End of namespace Prince
const static char *const directoryGlobs[] = {
"all",
nullptr
};
class PrinceMetaEngineDetection : public AdvancedMetaEngineDetection<Prince::PrinceGameDescription> {
public:
PrinceMetaEngineDetection() : AdvancedMetaEngineDetection(Prince::gameDescriptions, princeGames) {
_maxScanDepth = 2;
_directoryGlobs = directoryGlobs;
}
const char *getName() const override {
return "prince";
}
const char *getEngineName() const override {
return "The Prince and the Coward";
}
const char *getOriginalCopyright() const override {
return "The Prince and the Coward (C) 1996-97 Metropolis";
}
const DebugChannelDef *getDebugChannels() const override {
return debugFlagList;
}
};
REGISTER_PLUGIN_STATIC(PRINCE_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, PrinceMetaEngineDetection);

View File

@@ -0,0 +1,55 @@
/* 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 PRINCE_DETECTION_H
#define PRINCE_DETECTION_H
#include "engines/advancedDetector.h"
namespace Prince {
enum PrinceGameType {
kPrinceDataUNK,
kPrinceDataDE,
kPrinceDataPL
};
enum {
GF_TRANSLATED = 1 << 0,
GF_EXTRACTED = 1 << 1,
GF_NOVOICES = 1 << 2,
GF_RUSPROJEDITION = 1 << 3
};
struct PrinceGameDescription {
AD_GAME_DESCRIPTION_HELPERS(desc);
ADGameDescription desc;
PrinceGameType gameType;
};
#define GAMEOPTION_TTS_OBJECTS GUIO_GAMEOPTIONS1
#define GAMEOPTION_TTS_SPEECH GUIO_GAMEOPTIONS2
#define GAMEOPTION_TTS_MISSING_VOICE GUIO_GAMEOPTIONS3
} // End of namespace Prince
#endif // PRINCE_DETECTION_H

777
engines/prince/draw.cpp Normal file
View File

@@ -0,0 +1,777 @@
/* 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/paletteman.h"
#include "prince/prince.h"
#include "prince/animation.h"
#include "prince/graphics.h"
#include "prince/hero.h"
#include "prince/script.h"
namespace Prince {
bool PrinceEngine::spriteCheck(int sprWidth, int sprHeight, int destX, int destY) {
destX -= _picWindowX;
destY -= _picWindowY;
// if x1 is on visible part of screen
if (destX < 0) {
if (destX + sprWidth < 1) {
//x2 is negative - out of window
return false;
}
}
// if x1 is outside of screen on right side
if (destX >= kNormalWidth) {
return false;
}
if (destY < 0) {
if (destY + sprHeight < 1) {
//y2 is negative - out of window
return false;
}
}
if (destY >= kNormalHeight) {
return false;
}
return true;
}
// CheckNak
void PrinceEngine::checkMasks(int x1, int y1, int sprWidth, int sprHeight, int z) {
int x2 = x1 + sprWidth - 1;
int y2 = y1 + sprHeight - 1;
if (x1 < 0) {
x1 = 0;
}
for (uint i = 0; i < _maskList.size(); i++) {
if (!_maskList[i]._state && !_maskList[i]._flags) {
if (_maskList[i]._z > z) {
if (_maskList[i]._x1 <= x2 && _maskList[i]._x2 >= x1) {
if (_maskList[i]._y1 <= y2 && _maskList[i]._y2 >= y1) {
_maskList[i]._state = 1;
}
}
}
}
}
}
// ClsNak
void PrinceEngine::clsMasks() {
for (uint i = 0; i < _maskList.size(); i++) {
if (_maskList[i]._state) {
_maskList[i]._state = 0;
}
}
}
// InsertNakladki
void PrinceEngine::insertMasks(Graphics::Surface *originalRoomSurface) {
for (uint i = 0; i < _maskList.size(); i++) {
if (_maskList[i]._state) {
if (_maskList[i]._data != nullptr) {
showMask(i, originalRoomSurface);
} else {
error("insertMasks() - Wrong mask data- nr %d", i);
}
}
}
}
// ShowNak
void PrinceEngine::showMask(int maskNr, Graphics::Surface *originalRoomSurface) {
if (!_maskList[maskNr]._flags) {
if (spriteCheck(_maskList[maskNr]._width, _maskList[maskNr]._height, _maskList[maskNr]._x1, _maskList[maskNr]._y1)) {
int destX = _maskList[maskNr]._x1 - _picWindowX;
int destY = _maskList[maskNr]._y1 - _picWindowY;
DrawNode newDrawNode;
newDrawNode.posX = destX;
newDrawNode.posY = destY;
newDrawNode.posZ = _maskList[maskNr]._z;
newDrawNode.width = _maskList[maskNr]._width;
newDrawNode.height = _maskList[maskNr]._height;
newDrawNode.s = nullptr;
newDrawNode.originalRoomSurface = originalRoomSurface;
newDrawNode.data = _maskList[maskNr].getMask();
newDrawNode.drawFunction = &_graph->drawMaskDrawNode;
_drawNodeList.push_back(newDrawNode);
}
}
}
void PrinceEngine::showSprite(Graphics::Surface *spriteSurface, int destX, int destY, int destZ) {
if (spriteCheck(spriteSurface->w, spriteSurface->h, destX, destY)) {
destX -= _picWindowX;
destY -= _picWindowY;
DrawNode newDrawNode;
newDrawNode.posX = destX;
newDrawNode.posY = destY;
newDrawNode.posZ = destZ;
newDrawNode.width = 0;
newDrawNode.height = 0;
newDrawNode.s = spriteSurface;
newDrawNode.originalRoomSurface = nullptr;
newDrawNode.data = _transTable;
newDrawNode.drawFunction = &_graph->drawTransparentWithTransDrawNode;
_drawNodeList.push_back(newDrawNode);
}
}
void PrinceEngine::showSpriteShadow(Graphics::Surface *shadowSurface, int destX, int destY, int destZ) {
if (spriteCheck(shadowSurface->w, shadowSurface->h, destX, destY)) {
destX -= _picWindowX;
destY -= _picWindowY;
DrawNode newDrawNode;
newDrawNode.posX = destX;
newDrawNode.posY = destY;
newDrawNode.posZ = destZ;
newDrawNode.width = 0;
newDrawNode.height = 0;
newDrawNode.s = shadowSurface;
newDrawNode.originalRoomSurface = nullptr;
newDrawNode.data = _graph->_shadowTable70;
newDrawNode.drawFunction = &_graph->drawAsShadowDrawNode;
_drawNodeList.push_back(newDrawNode);
}
}
void PrinceEngine::showAnim(Anim &anim) {
//ShowFrameCode
//ShowAnimFrame
int phase = anim._showFrame;
int phaseFrameIndex = anim._animData->getPhaseFrameIndex(phase);
int x = anim._x + anim._animData->getPhaseOffsetX(phase);
int y = anim._y + anim._animData->getPhaseOffsetY(phase);
int animFlag = anim._flags;
int checkMaskFlag = (animFlag & 1);
int maxFrontFlag = (animFlag & 2);
int specialZFlag = anim._nextAnim;
int z = anim._nextAnim;
Graphics::Surface *animSurface = anim._animData->getFrame(phaseFrameIndex);
int frameWidth = animSurface->w;
int frameHeight = animSurface->h;
int shadowZ = 0;
if (checkMaskFlag) {
if (!anim._nextAnim) {
z = y + frameHeight - 1;
}
checkMasks(x, y, frameWidth, frameHeight, z);
}
if (specialZFlag) {
z = specialZFlag;
} else if (maxFrontFlag) {
z = kMaxPicHeight + 1;
} else {
z = y + frameHeight - 1;
}
shadowZ = z;
anim._currX = x;
anim._currY = y;
anim._currW = frameWidth;
anim._currH = frameHeight;
showSprite(animSurface, x, y, z);
// make_special_shadow
if ((anim._flags & 0x80)) {
DrawNode newDrawNode;
newDrawNode.posX = x;
newDrawNode.posY = y + animSurface->h - anim._shadowBack;
newDrawNode.posZ = Hero::kHeroShadowZ;
newDrawNode.width = 0;
newDrawNode.height = 0;
newDrawNode.scaleValue = _scaleValue;
newDrawNode.originalRoomSurface = nullptr;
newDrawNode.data = this;
newDrawNode.drawFunction = &Hero::showHeroShadow;
newDrawNode.s = animSurface;
_drawNodeList.push_back(newDrawNode);
}
//ShowFrameCodeShadow
//ShowAnimFrameShadow
if (anim._shadowData != nullptr) {
int shadowPhaseFrameIndex = anim._shadowData->getPhaseFrameIndex(phase);
int shadowX = anim._shadowData->getBaseX() + anim._shadowData->getPhaseOffsetX(phase);
int shadowY = anim._shadowData->getBaseY() + anim._shadowData->getPhaseOffsetY(phase);
Graphics::Surface *shadowSurface = anim._shadowData->getFrame(shadowPhaseFrameIndex);
int shadowFrameWidth = shadowSurface->w;
int shadowFrameHeight = shadowSurface->h;
if (checkMaskFlag) {
checkMasks(shadowX, shadowY, shadowFrameWidth, shadowFrameHeight, shadowY + shadowFrameWidth - 1);
}
if (!shadowZ) {
if (maxFrontFlag) {
shadowZ = kMaxPicHeight + 1;
} else {
shadowZ = shadowY + shadowFrameWidth - 1;
}
}
showSpriteShadow(shadowSurface, shadowX, shadowY, shadowZ);
}
}
void PrinceEngine::showNormAnims() {
for (int i = 0; i < kMaxNormAnims; i++) {
Anim &anim = _normAnimList[i];
if (anim._animData != nullptr) {
int phaseCount = anim._animData->getPhaseCount();
if (!anim._state) {
if (anim._frame == anim._lastFrame - 1) {
if (anim._loopType) {
if (anim._loopType == 1) {
anim._frame = anim._loopFrame;
} else {
continue;
}
}
} else {
anim._frame++;
}
anim._showFrame = anim._frame;
if (anim._showFrame >= phaseCount) {
anim._showFrame = phaseCount - 1;
}
showAnim(anim);
}
}
}
}
void PrinceEngine::setBackAnim(Anim &backAnim) {
int start = backAnim._basaData._start;
if (start != -1) {
backAnim._frame = start;
backAnim._showFrame = start;
backAnim._loopFrame = start;
}
int end = backAnim._basaData._end;
if (end != -1) {
backAnim._lastFrame = end;
}
backAnim._state = 0;
}
void PrinceEngine::showBackAnims() {
for (int i = 0; i < kMaxBackAnims; i++) {
BAS &seq = _backAnimList[i]._seq;
int activeSubAnim = seq._currRelative;
if (!_backAnimList[i].backAnims.empty()) {
if (_backAnimList[i].backAnims[activeSubAnim]._animData != nullptr) {
if (!_backAnimList[i].backAnims[activeSubAnim]._state) {
seq._counter++;
if (seq._type == 2) {
if (!seq._currRelative) {
if (seq._counter >= seq._data) {
if (seq._anims > 2) {
seq._currRelative = _randomSource.getRandomNumber(seq._anims - 2) + 1;
activeSubAnim = seq._currRelative;
seq._current = _backAnimList[i].backAnims[activeSubAnim]._basaData._num;
}
setBackAnim(_backAnimList[i].backAnims[activeSubAnim]);
seq._counter = 0;
}
}
}
if (seq._type == 3) {
if (!seq._currRelative) {
if (seq._counter < seq._data2) {
continue;
} else {
setBackAnim(_backAnimList[i].backAnims[activeSubAnim]);
}
}
}
if (_backAnimList[i].backAnims[activeSubAnim]._frame == _backAnimList[i].backAnims[activeSubAnim]._lastFrame - 1) {
_backAnimList[i].backAnims[activeSubAnim]._frame = _backAnimList[i].backAnims[activeSubAnim]._loopFrame;
switch (seq._type) {
case 1:
if (seq._anims > 1) {
int rnd;
do {
rnd = _randomSource.getRandomNumber(seq._anims - 1);
} while (rnd == seq._currRelative);
seq._currRelative = rnd;
seq._current = _backAnimList[i].backAnims[rnd]._basaData._num;
activeSubAnim = rnd;
setBackAnim(_backAnimList[i].backAnims[activeSubAnim]);
seq._counter = 0;
}
break;
case 2:
if (seq._currRelative) {
seq._currRelative = 0;
seq._current = _backAnimList[i].backAnims[0]._basaData._num;
activeSubAnim = 0;
setBackAnim(_backAnimList[i].backAnims[activeSubAnim]);
seq._counter = 0;
}
break;
case 3:
seq._currRelative = 0;
seq._current = _backAnimList[i].backAnims[0]._basaData._num;
seq._counter = 0;
seq._data2 = _randomSource.getRandomNumber(seq._data - 1);
continue; // for bug in original game
break;
default:
break;
}
} else {
_backAnimList[i].backAnims[activeSubAnim]._frame++;
}
_backAnimList[i].backAnims[activeSubAnim]._showFrame = _backAnimList[i].backAnims[activeSubAnim]._frame;
showAnim(_backAnimList[i].backAnims[activeSubAnim]);
}
}
}
}
}
void PrinceEngine::removeSingleBackAnim(int slot) {
if (!_backAnimList[slot].backAnims.empty()) {
for (uint j = 0; j < _backAnimList[slot].backAnims.size(); j++) {
if (_backAnimList[slot].backAnims[j]._animData != nullptr) {
delete _backAnimList[slot].backAnims[j]._animData;
_backAnimList[slot].backAnims[j]._animData = nullptr;
}
if (_backAnimList[slot].backAnims[j]._shadowData != nullptr) {
delete _backAnimList[slot].backAnims[j]._shadowData;
_backAnimList[slot].backAnims[j]._shadowData = nullptr;
}
}
_backAnimList[slot].backAnims.clear();
_backAnimList[slot]._seq._currRelative = 0;
}
}
void PrinceEngine::clearBackAnimList() {
for (int i = 0; i < kMaxBackAnims; i++) {
removeSingleBackAnim(i);
}
}
void PrinceEngine::grabMap() {
_graph->_frontScreen->copyFrom(*_roomBmp->getSurface());
showObjects();
runDrawNodes();
_graph->_mapScreen->copyFrom(*_graph->_frontScreen);
}
void PrinceEngine::initZoomIn(int slot) {
freeZoomObject(slot);
Object *object = _objList[slot];
if (object != nullptr) {
Graphics::Surface *zoomSource = object->getSurface();
if (zoomSource != nullptr) {
object->_flags |= 0x8000;
object->_zoomSurface = new Graphics::Surface();
object->_zoomSurface->create(zoomSource->w, zoomSource->h, Graphics::PixelFormat::createFormatCLUT8());
object->_zoomSurface->fillRect(Common::Rect(zoomSource->w, zoomSource->h), 0xFF);
object->_zoomTime = 20;
}
}
}
void PrinceEngine::initZoomOut(int slot) {
freeZoomObject(slot);
Object *object = _objList[slot];
if (object != nullptr) {
Graphics::Surface *zoomSource = object->getSurface();
if (zoomSource != nullptr) {
object->_flags |= 0x4000;
object->_zoomSurface = new Graphics::Surface();
object->_zoomSurface->copyFrom(*zoomSource);
object->_zoomTime = 10;
}
}
}
void PrinceEngine::doZoomIn(int slot) {
Object *object = _objList[slot];
if (object != nullptr) {
Graphics::Surface *orgSurface = object->getSurface();
if (orgSurface != nullptr) {
byte *src1 = (byte *)orgSurface->getBasePtr(0, 0);
byte *dst1 = (byte *)object->_zoomSurface->getBasePtr(0, 0);
int x = 0;
int surfaceHeight = orgSurface->h;
for (int y = 0; y < surfaceHeight; y++) {
byte *src2 = src1;
byte *dst2 = dst1;
int w = orgSurface->w - x;
src2 += x;
dst2 += x;
while (w > 0) {
int randVal = _randomSource.getRandomNumber(zoomInStep - 1);
if (randVal < w) {
*(dst2 + randVal) = *(src2 + randVal);
src2 += zoomInStep;
dst2 += zoomInStep;
} else if (y + 1 != surfaceHeight) {
*(dst1 + orgSurface->pitch + randVal - w) = *(src1 + orgSurface->pitch + randVal - w);
}
w -= zoomInStep;
}
x = -1 * w;
src1 += orgSurface->pitch;
dst1 += orgSurface->pitch;
}
}
}
}
void PrinceEngine::doZoomOut(int slot) {
Object *object = _objList[slot];
if (object != nullptr) {
Graphics::Surface *orgSurface = object->getSurface();
if (orgSurface != nullptr) {
byte *dst1 = (byte *)object->_zoomSurface->getBasePtr(0, 0);
int x = 0;
int surfaceHeight = orgSurface->h;
for (int y = 0; y < surfaceHeight; y++) {
byte *dst2 = dst1;
int w = orgSurface->w - x;
dst2 += x;
while (w > 0) {
int randVal = _randomSource.getRandomNumber(zoomInStep - 1);
if (randVal < w) {
*(dst2 + randVal) = 255;
dst2 += zoomInStep;
} else if (y + 1 != surfaceHeight) {
*(dst1 + orgSurface->pitch + randVal - w) = 255;
}
w -= zoomInStep;
}
x = -1 * w;
dst1 += orgSurface->pitch;
}
}
}
}
void PrinceEngine::freeZoomObject(int slot) {
Object *object = _objList[slot];
if (object != nullptr) {
if (object->_zoomSurface != nullptr) {
object->_zoomSurface->free();
delete object->_zoomSurface;
object->_zoomSurface = nullptr;
}
}
}
void PrinceEngine::showObjects() {
for (int i = 0; i < kMaxObjects; i++) {
int nr = _objSlot[i];
if (nr != 0xFF) {
Graphics::Surface *objSurface = nullptr;
if ((_objList[nr]->_flags & 0x8000)) {
_objList[nr]->_zoomTime--;
if (!_objList[nr]->_zoomTime) {
freeZoomObject(nr);
_objList[nr]->_flags &= 0x7FFF;
objSurface = _objList[nr]->getSurface();
} else {
doZoomIn(nr);
objSurface = _objList[nr]->_zoomSurface;
}
} else if ((_objList[nr]->_flags & 0x4000)) {
_objList[nr]->_zoomTime--;
if (!_objList[nr]->_zoomTime) {
freeZoomObject(nr);
_objList[nr]->_flags &= 0xBFFF;
objSurface = _objList[nr]->getSurface();
} else {
doZoomOut(nr);
objSurface = _objList[nr]->_zoomSurface;
}
} else {
objSurface = _objList[nr]->getSurface();
}
if (objSurface != nullptr) {
if (spriteCheck(objSurface->w, objSurface->h, _objList[nr]->_x, _objList[nr]->_y)) {
int destX = _objList[nr]->_x - _picWindowX;
int destY = _objList[nr]->_y - _picWindowY;
DrawNode newDrawNode;
newDrawNode.posX = destX;
newDrawNode.posY = destY;
newDrawNode.posZ = _objList[nr]->_z;
newDrawNode.width = 0;
newDrawNode.height = 0;
newDrawNode.s = objSurface;
newDrawNode.originalRoomSurface = nullptr;
if ((_objList[nr]->_flags & 0x2000)) {
newDrawNode.data = nullptr;
newDrawNode.drawFunction = &_graph->drawBackSpriteDrawNode;
} else {
newDrawNode.data = _transTable;
if (_flags->getFlagValue(Flags::NOANTIALIAS)) {
newDrawNode.drawFunction = &_graph->drawTransparentDrawNode;
} else {
newDrawNode.drawFunction = &_graph->drawTransparentWithTransDrawNode;
}
}
_drawNodeList.push_back(newDrawNode);
}
if ((_objList[nr]->_flags & 1)) {
checkMasks(_objList[nr]->_x, _objList[nr]->_y, objSurface->w, objSurface->h, _objList[nr]->_z);
}
}
}
}
}
void PrinceEngine::showParallax() {
if (!_pscrList.empty()) {
for (uint i = 0; i < _pscrList.size(); i++) {
Graphics::Surface *pscrSurface = _pscrList[i]->getSurface();
if (pscrSurface != nullptr) {
int x = _pscrList[i]->_x - (_pscrList[i]->_step * _picWindowX / 4);
int y = _pscrList[i]->_y;
int z = PScr::kPScrZ;
if (spriteCheck(pscrSurface->w, pscrSurface->h, x, y)) {
showSprite(pscrSurface, x, y, z);
}
}
}
}
}
bool PrinceEngine::compareDrawNodes(DrawNode d1, DrawNode d2) {
if (d1.posZ < d2.posZ) {
return true;
}
return false;
}
void PrinceEngine::runDrawNodes() {
Common::sort(_drawNodeList.begin(), _drawNodeList.end(), compareDrawNodes);
for (uint i = 0; i < _drawNodeList.size(); i++) {
(*_drawNodeList[i].drawFunction)(_graph->_frontScreen, &_drawNodeList[i]);
}
_graph->change();
}
void PrinceEngine::drawScreen() {
if (!_showInventoryFlag || _inventoryBackgroundRemember) {
clsMasks();
_mainHero->showHero();
_mainHero->scrollHero();
_mainHero->drawHero();
_secondHero->showHero();
_secondHero->_drawX -= _picWindowX;
_secondHero->drawHero();
const Graphics::Surface *roomSurface;
if (_locationNr != 50) {
roomSurface = _roomBmp->getSurface();
} else {
roomSurface = _graph->_mapScreen;
}
Graphics::Surface visiblePart;
if (roomSurface) {
visiblePart = roomSurface->getSubArea(Common::Rect(_picWindowX, 0, roomSurface->w, roomSurface->h));
_graph->draw(_graph->_frontScreen, &visiblePart);
}
showBackAnims();
showNormAnims();
playNextFLCFrame();
showObjects();
if (roomSurface) {
insertMasks(&visiblePart);
}
showParallax();
runDrawNodes();
_drawNodeList.clear();
if (!_inventoryBackgroundRemember && !_dialogFlag) {
if (!_optionsFlag) {
_selectedMob = checkMob(_graph->_frontScreen, _mobList, true);
}
showTexts(_graph->_frontScreen);
checkOptions();
} else {
_inventoryBackgroundRemember = false;
}
showPower();
} else {
displayInventory();
}
}
void PrinceEngine::blackPalette() {
byte *paletteBackup = (byte *)malloc(256 * 3);
byte *blackPalette1 = (byte *)malloc(256 * 3);
int fadeStep = kFadeStep - 1;
for (int i = 0; i < kFadeStep; i++) {
_system->getPaletteManager()->grabPalette(paletteBackup, 0, 256);
for (int j = 0; j < 256; j++) {
blackPalette1[3 * j] = paletteBackup[3 * j] * fadeStep / 4;
blackPalette1[3 * j + 1] = paletteBackup[3 * j + 1] * fadeStep / 4;
blackPalette1[3 * j + 2] = paletteBackup[3 * j + 2] * fadeStep / 4;
}
fadeStep--;
_graph->setPalette(blackPalette1);
_system->updateScreen();
Common::Event event;
Common::EventManager *eventMan = _system->getEventManager();
eventMan->pollEvent(event);
if (shouldQuit()) {
free(paletteBackup);
free(blackPalette1);
return;
}
pausePrinceEngine();
}
free(paletteBackup);
free(blackPalette1);
}
void PrinceEngine::setPalette(const byte *palette) {
if (palette != nullptr) {
byte *blackPalette_ = (byte *)malloc(256 * 3);
int fadeStep = 0;
for (int i = 0; i <= kFadeStep; i++) {
for (int j = 0; j < 256; j++) {
blackPalette_[3 * j] = palette[3 * j] * fadeStep / 4;
blackPalette_[3 * j + 1] = palette[3 * j + 1] * fadeStep / 4;
blackPalette_[3 * j + 2] = palette[3 * j + 2] * fadeStep / 4;
}
fadeStep++;
_graph->setPalette(blackPalette_);
_system->updateScreen();
Common::Event event;
Common::EventManager *eventMan = _system->getEventManager();
eventMan->pollEvent(event);
if (shouldQuit()) {
_graph->setPalette(palette);
free(blackPalette_);
return;
}
pausePrinceEngine();
}
_graph->setPalette(palette);
free(blackPalette_);
}
}
void PrinceEngine::doTalkAnim(int animNumber, int slot, AnimType animType) {
Text &text = _textSlots[slot];
int lines = calcTextLines((const char *)_interpreter->getString());
int time = lines * 30;
if (animType == kNormalAnimation) {
Anim &normAnim = _normAnimList[animNumber];
if (normAnim._animData != nullptr) {
if (!normAnim._state) {
if (normAnim._currW && normAnim._currH) {
text._color = _flags->getFlagValue(Flags::KOLOR);
text._x = normAnim._currX + normAnim._currW / 2;
text._y = normAnim._currY - 10;
}
}
}
} else if (animType == kBackgroundAnimation) {
if (!_backAnimList[animNumber].backAnims.empty()) {
int currAnim = _backAnimList[animNumber]._seq._currRelative;
Anim &backAnim = _backAnimList[animNumber].backAnims[currAnim];
if (backAnim._animData != nullptr) {
if (!backAnim._state) {
if (backAnim._currW && backAnim._currH) {
text._color = _flags->getFlagValue(Flags::KOLOR);
text._x = backAnim._currX + backAnim._currW / 2;
text._y = backAnim._currY - 10;
}
}
}
}
} else {
error("doTalkAnim() - wrong animType: %d", animType);
}
text._time = time;
if (getLanguage() == Common::DE_DEU) {
correctStringDEU((char *)_interpreter->getString());
}
text._str = (const char *)_interpreter->getString();
if (slot == 9) {
// Location 4 has the gambling merchants, who speak frequently and can interrupt the player's
// dialog with other characters, so don't voice their text unless the player isn't in dialog
if ((!_dialogFlag && !_isConversing) || _locationNr != 4) {
setTTSVoice(text._color);
sayText(text._str, true, Common::TextToSpeechManager::QUEUE);
}
} else {
setTTSVoice(text._color);
sayText(text._str, true);
}
_interpreter->increaseString();
}
void PrinceEngine::freeNormAnim(int slot) {
if (!_normAnimList.empty()) {
_normAnimList[slot]._state = 1;
if (_normAnimList[slot]._animData != nullptr) {
delete _normAnimList[slot]._animData;
_normAnimList[slot]._animData = nullptr;
}
if (_normAnimList[slot]._shadowData != nullptr) {
delete _normAnimList[slot]._shadowData;
_normAnimList[slot]._shadowData = nullptr;
}
}
}
void PrinceEngine::freeAllNormAnims() {
for (int i = 0; i < kMaxNormAnims; i++) {
freeNormAnim(i);
}
}
} // End of namespace Prince

414
engines/prince/flags.cpp Normal file
View File

@@ -0,0 +1,414 @@
/* 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 "prince/flags.h"
namespace Prince {
struct FlagDebug {
uint id;
char flagName[30];
} static const flagNames[] = {
{ Flags::FLAGA1, "FLAGA1" },
{ Flags::FLAGA2, "FLAGA2" },
{ Flags::FLAGA3, "FLAGA3" },
{ Flags::DESTX, "DESTX" },
{ Flags::DESTY, "DESTY" },
{ Flags::DESTD, "DESTD" },
{ Flags::DwarfDone, "DwarfDone" },
{ Flags::GRABARZCOUNTER, "GRABARZCOUNTER" },
{ Flags::KIERUNEK, "KIERUNEK" },
{ Flags::BACKFLAG1, "BACKFLAG1" },
{ Flags::BACKFLAG2, "BACKFLAG2" },
{ Flags::BACKFLAG3, "BACKFLAG3" },
{ Flags::BACKFLAG4, "BACKFLAG4" },
{ Flags::MACROFLAG1, "MACROFLAG1" },
{ Flags::MACROFLAG2, "MACROFLAG2" },
{ Flags::MACROFLAG3, "MACROFLAG3" },
{ Flags::HEROLDDONE, "HEROLDDONE" },
{ Flags::BRIDGESET, "BRIDGESET" },
{ Flags::U_BT_1, "U_BT_1" },
{ Flags::U_BT_2, "U_BT_2" },
{ Flags::U_BT_3, "U_BT_3" },
{ Flags::U_BT_4, "U_BT_4" },
{ Flags::U_BT_5, "U_BT_5" },
{ Flags::U_BT_6, "U_BT_6" },
{ Flags::U_BT_7, "U_BT_7" },
{ Flags::U_BT_8, "U_BT_8" },
{ Flags::U_BT_9, "U_BT_9" },
{ Flags::U_BT_COUNTER, "U_BT_COUNTER" },
{ Flags::ARIVALDALIVE, "ARIVALDALIVE" },
{ Flags::TALKCHAR1, "TALKCHAR1" },
{ Flags::TalkType1, "TalkType1" },
{ Flags::TALKROUT1, "TALKROUT1" },
{ Flags::TALKROUT2, "TALKROUT2" },
{ Flags::TALKROUT3, "TALKROUT3" },
{ Flags::TALKROUT4, "TALKROUT4" },
{ Flags::TALKANIM1, "TALKANIM1" },
{ Flags::TALKANIM2, "TALKANIM2" },
{ Flags::TALKCOLOR1, "TALKCOLOR1" },
{ Flags::TALKCOLOR2, "TALKCOLOR2" },
{ Flags::KapciuchTaken, "KapciuchTaken" },
{ Flags::CurrentBeggarA, "CurrentBeggarA" },
{ Flags::TempKapc, "TempKapc" },
{ Flags::HomTaken, "HomTaken" },
{ Flags::WizardTalk, "WizardTalk" },
{ Flags::SunlordTalk, "SunlordTalk" },
{ Flags::HermitTalk, "HermitTalk" },
{ Flags::RunyMode, "RunyMode" },
{ Flags::FatMerchantTalk, "FatMerchantTalk" },
{ Flags::HotDogTalk, "HotDogTalk" },
{ Flags::ThiefTalk, "ThiefTalk" },
{ Flags::BeggarTalk, "BeggarTalk" },
{ Flags::MonkTalk, "MonkTalk" },
{ Flags::BardTalk, "BardTalk" },
{ Flags::BarmanTalk, "BarmanTalk" },
{ Flags::LeftPlayerTalk, "LeftPlayerTalk" },
{ Flags::OczySowy, "OczySowy" },
{ Flags::CzachySpeed1, "CzachySpeed1" },
{ Flags::CzachySpeed2, "CzachySpeed2" },
{ Flags::CzachySpeed3, "CzachySpeed3" },
{ Flags::CzachySlowDown1, "CzachySlowDown1" },
{ Flags::CzachySlowDown2, "CzachySlowDown2" },
{ Flags::CzachySlowDown3, "CzachySlowDown3" },
{ Flags::FjordDane, "FjordDane" },
{ Flags::GKopany1, "GKopany1" },
{ Flags::GKopany2, "GKopany2" },
{ Flags::GKopany3, "GKopany3" },
{ Flags::GKopany4, "GKopany4" },
{ Flags::KnowGodWord, "KnowGodWord" },
{ Flags::TALKROUT21, "TALKROUT21" },
{ Flags::TALKROUT22, "TALKROUT22" },
{ Flags::TALKROUT23, "TALKROUT23" },
{ Flags::TALKROUT24, "TALKROUT24" },
{ Flags::TalkType2, "TalkType2" },
{ Flags::GrabarzTalk, "GrabarzTalk" },
{ Flags::LastTalker, "LastTalker" },
{ Flags::MapaPustelniaEnabled, "MapaPustelniaEnabled" },
{ Flags::MapaTempleEnabled, "MapaTempleEnabled" },
{ Flags::MapaFjordEnabled, "MapaFjordEnabled" },
{ Flags::MapaSilmanionaEnabled, "MapaSilmanionaEnabled" },
{ Flags::MapaKurhanEnabled, "MapaKurhanEnabled" },
{ Flags::MapaDragonEnabled, "MapaDragonEnabled" },
{ Flags::MapaMillEnabled, "MapaMillEnabled" },
{ Flags::DwarfRunning, "DwarfRunning" },
{ Flags::DwarfTalk, "DwarfTalk" },
{ Flags::CurseLift, "CurseLift" },
{ Flags::KosciSwapped, "KosciSwapped" },
{ Flags::BookStolen, "BookStolen" },
{ Flags::MapaUsable, "MapaUsable" },
{ Flags::FjordBoss, "FjordBoss" },
{ Flags::FjordHotDog, "FjordHotDog" },
{ Flags::FjordLewy, "FjordLewy" },
{ Flags::FjordPrawy, "FjordPrawy" },
{ Flags::TalkArivald, "TalkArivald" },
{ Flags::ShootDone, "ShootDone" },
{ Flags::ShootRunning, "ShootRunning" },
{ Flags::ShootKnow, "ShootKnow" },
{ Flags::MirrorKnow, "MirrorKnow" },
{ Flags::Gar1stTime, "Gar1stTime" },
{ Flags::KosciTaken, "KosciTaken" },
{ Flags::ArivGotSpell, "ArivGotSpell" },
{ Flags::BookGiven, "BookGiven" },
{ Flags::Wywieszka, "Wywieszka" },
{ Flags::TalkSheila, "TalkSheila" },
{ Flags::TalkSheila2, "TalkSheila2" },
{ Flags::BackHuman, "BackHuman" },
{ Flags::SkarbiecOpen, "SkarbiecOpen" },
{ Flags::LustroTaken, "LustroTaken" },
{ Flags::GargoyleHom, "GargoyleHom" },
{ Flags::GargoyleBroken, "GargoyleBroken" },
{ Flags::FjordDzien, "FjordDzien" },
{ Flags::GargoyleHom2, "GargoyleHom2" },
{ Flags::RunMonstersRunning, "RunMonstersRunning" },
{ Flags::FoundPaperInCoffin, "FoundPaperInCoffin" },
{ Flags::KnowSunlord, "KnowSunlord" },
{ Flags::KnowSunlordTalk, "KnowSunlordTalk" },
{ Flags::ArivaldCzyta, "ArivaldCzyta" },
{ Flags::TelepX, "TelepX" },
{ Flags::TelepY, "TelepY" },
{ Flags::TelepDir, "TelepDir" },
{ Flags::TelepRoom, "TelepRoom" },
{ Flags::ListStolen, "ListStolen" },
{ Flags::WifeInDoor, "WifeInDoor" },
{ Flags::TalkWifeFlag, "TalkWifeFlag" },
{ Flags::LetterGiven, "LetterGiven" },
{ Flags::LutniaTaken, "LutniaTaken" },
{ Flags::BardHomeOpen, "BardHomeOpen" },
{ Flags::FjordNoMonsters, "FjordNoMonsters" },
{ Flags::ShandriaWallTalking, "ShandriaWallTalking" },
{ Flags::ShandriaWallCounter, "ShandriaWallCounter" },
{ Flags::ShandriaWallDone, "ShandriaWallDone" },
{ Flags::FutureDone, "FutureDone" },
{ Flags::TalkButch, "TalkButch" },
{ Flags::GotSzalik, "GotSzalik" },
{ Flags::GotCzosnek, "GotCzosnek" },
{ Flags::BearDone, "BearDone" },
{ Flags::NekrVisited, "NekrVisited" },
{ Flags::SunRiddle, "SunRiddle" },
{ Flags::PtaszekAway, "PtaszekAway" },
{ Flags::KotGadanie, "KotGadanie" },
{ Flags::SzlafmycaTaken, "SzlafmycaTaken" },
{ Flags::BabkaTalk, "BabkaTalk" },
{ Flags::SellerTalk, "SellerTalk" },
{ Flags::CzosnekDone, "CzosnekDone" },
{ Flags::PriestCounter, "PriestCounter" },
{ Flags::PriestGest1, "PriestGest1" },
{ Flags::PriestGest2, "PriestGest2" },
{ Flags::PriestGest3, "PriestGest3" },
{ Flags::PriestGest4, "PriestGest4" },
{ Flags::PriestAnim, "PriestAnim" },
{ Flags::HolyWaterTaken, "HolyWaterTaken" },
{ Flags::AxeTaken, "AxeTaken" },
{ Flags::BadylTaken1, "BadylTaken1" },
{ Flags::BadylTaken2, "BadylTaken2" },
{ Flags::BadylSharpened, "BadylSharpened" },
{ Flags::PorwanieSmoka, "PorwanieSmoka" },
{ Flags::ShopReOpen, "ShopReOpen" },
{ Flags::LuskaShown, "LuskaShown" },
{ Flags::CudKnow, "CudKnow" },
{ Flags::VampireDead, "VampireDead" },
{ Flags::MapaVisible1, "MapaVisible1" },
{ Flags::MapaVisible2, "MapaVisible2" },
{ Flags::MapaVisible3, "MapaVisible3" },
{ Flags::MapaVisible4, "MapaVisible4" },
{ Flags::MapaVisible5, "MapaVisible5" },
{ Flags::MapaVisible6, "MapaVisible6" },
{ Flags::MapaVisible7, "MapaVisible7" },
{ Flags::MapaVisible8, "MapaVisible8" },
{ Flags::MapaVisible9, "MapaVisible9" },
{ Flags::MapaX, "MapaX" },
{ Flags::MapaY, "MapaY" },
{ Flags::MapaD, "MapaD" },
{ Flags::OldMapaX, "OldMapaX" },
{ Flags::OldMapaY, "OldMapaY" },
{ Flags::OldMapaD, "OldMapaD" },
{ Flags::MovingBack, "MovingBack" },
{ Flags::MapaCount, "MapaCount" },
{ Flags::Pustelnia1st, "Pustelnia1st" },
{ Flags::CzarnePole1st, "CzarnePole1st" },
{ Flags::TalkArivNum, "TalkArivNum" },
{ Flags::Pfui, "Pfui" },
{ Flags::MapaSunlordEnabled, "MapaSunlordEnabled" },
{ Flags::WebDone, "WebDone" },
{ Flags::DragonDone, "DragonDone" },
{ Flags::KanPlay, "KanPlay" },
{ Flags::OldKanPlay, "OldKanPlay" },
{ Flags::LapkiWait, "LapkiWait" },
{ Flags::WebNoCheck, "WebNoCheck" },
{ Flags::Perfumeria, "Perfumeria" },
{ Flags::SmokNoCheck, "SmokNoCheck" },
{ Flags::IluzjaBroken, "IluzjaBroken" },
{ Flags::IluzjaWorking, "IluzjaWorking" },
{ Flags::IluzjaCounter, "IluzjaCounter" },
{ Flags::KurhanOpen1, "KurhanOpen1" },
{ Flags::KastetTaken, "KastetTaken" },
{ Flags::KastetDown, "KastetDown" },
{ Flags::KurhanDone, "KurhanDone" },
{ Flags::SkelCounter, "SkelCounter" },
{ Flags::SkelDial1, "SkelDial1" },
{ Flags::SkelDial2, "SkelDial2" },
{ Flags::SkelDial3, "SkelDial3" },
{ Flags::SkelDial4, "SkelDial4" },
{ Flags::SameTalker, "SameTalker" },
{ Flags::RunMonstersText, "RunMonstersText" },
{ Flags::PiwnicaChecked, "PiwnicaChecked" },
{ Flags::DragonTalked, "DragonTalked" },
{ Flags::ToldAboutBook, "ToldAboutBook" },
{ Flags::SilmanionaDone, "SilmanionaDone" },
{ Flags::ToldBookCount, "ToldBookCount" },
{ Flags::SmrodNoCheck, "SmrodNoCheck" },
{ Flags::RopeTaken, "RopeTaken" },
{ Flags::RopeTime, "RopeTime" },
{ Flags::LaskaFree, "LaskaFree" },
{ Flags::ShanSmokTalked, "ShanSmokTalked" },
{ Flags::SwordTaken, "SwordTaken" },
{ Flags::Mill1st, "Mill1st" },
{ Flags::SawRat, "SawRat" },
{ Flags::KnowRat, "KnowRat" },
{ Flags::DziuraTimer, "DziuraTimer" },
{ Flags::LaskaInside, "LaskaInside" },
{ Flags::HoleBig, "HoleBig" },
{ Flags::EnableWiedzmin, "EnableWiedzmin" },
{ Flags::EnableTrucizna, "EnableTrucizna" },
{ Flags::KnowPoison, "KnowPoison" },
{ Flags::KufelTaken, "KufelTaken" },
{ Flags::BojkaEnabled, "BojkaEnabled" },
{ Flags::BitwaNot1st, "BitwaNot1st" },
{ Flags::BojkaTimer, "BojkaTimer" },
{ Flags::BojkaGirl, "BojkaGirl" },
{ Flags::Look1st, "Look1st" },
{ Flags::RatTaken, "RatTaken" },
{ Flags::LaskaTalkedGr, "LaskaTalkedGr" },
{ Flags::RatusGivus, "RatusGivus" },
{ Flags::MamObole, "MamObole" },
{ Flags::Speed1st, "Speed1st" },
{ Flags::SpeedTimer, "SpeedTimer" },
{ Flags::ProveIt, "ProveIt" },
{ Flags::Proven, "Proven" },
{ Flags::ShowWoalka, "ShowWoalka" },
{ Flags::PoisonTaken, "PoisonTaken" },
{ Flags::HellOpened, "HellOpened" },
{ Flags::HellNoCheck, "HellNoCheck" },
{ Flags::TalAn1, "TalAn1" },
{ Flags::TalAn2, "TalAn2" },
{ Flags::TalAn3, "TalAn3" },
{ Flags::TalkDevilGuard, "TalkDevilGuard" },
{ Flags::Sword1st, "Sword1st" },
{ Flags::IluzjaNoCheck, "IluzjaNoCheck" },
{ Flags::RozdzielniaNumber, "RozdzielniaNumber" },
{ Flags::JailChecked, "JailChecked" },
{ Flags::JailTalked, "JailTalked" },
{ Flags::TrickFailed, "TrickFailed" },
{ Flags::WegielVisible, "WegielVisible" },
{ Flags::WegielTimer1, "WegielTimer1" },
{ Flags::RandomSample, "RandomSample" },
{ Flags::RandomSampleTimer, "RandomSampleTimer" },
{ Flags::SampleTimer, "SampleTimer" },
{ Flags::ZonaSample, "ZonaSample" },
{ Flags::HoleTryAgain, "HoleTryAgain" },
{ Flags::TeleportTimer, "TeleportTimer" },
{ Flags::RozLezy, "RozLezy" },
{ Flags::UdkoTimer, "UdkoTimer" },
{ Flags::ZaworZatkany, "ZaworZatkany" },
{ Flags::ZaworOpened, "ZaworOpened" },
{ Flags::DoorExploded, "DoorExploded" },
{ Flags::SkoraTaken, "SkoraTaken" },
{ Flags::CiezkieByl, "CiezkieByl" },
{ Flags::MamWegiel, "MamWegiel" },
{ Flags::SwiecaAway, "SwiecaAway" },
{ Flags::ITSAVE, "ITSAVE" },
{ Flags::RozpadlSie, "RozpadlSie" },
{ Flags::WegielFullTimer, "WegielFullTimer" },
{ Flags::WegielDown, "WegielDown" },
{ Flags::WegielDownTimer, "WegielDownTimer" },
{ Flags::PaliSie, "PaliSie" },
{ Flags::DiabGuardTalked, "DiabGuardTalked" },
{ Flags::GuardsNoCheck, "GuardsNoCheck" },
{ Flags::TalkedPowloka, "TalkedPowloka" },
{ Flags::JailOpen, "JailOpen" },
{ Flags::PrzytulTimer, "PrzytulTimer" },
{ Flags::JailDone, "JailDone" },
{ Flags::MamMonety, "MamMonety" },
{ Flags::LotTimer, "LotTimer" },
{ Flags::LotObj, "LotObj" },
{ Flags::PtakTimer, "PtakTimer" },
{ Flags::BookTimer, "BookTimer" },
{ Flags::BookGiba, "BookGiba" },
{ Flags::PtakLata, "PtakLata" },
{ Flags::Podej, "Podej" },
{ Flags::GotHint, "GotHint" },
{ Flags::LawaLeci, "LawaLeci" },
{ Flags::PowerKlik, "PowerKlik" },
{ Flags::LucekBad, "LucekBad" },
{ Flags::LucekBad1st, "LucekBad1st" },
{ Flags::IntroDial1, "IntroDial1" },
{ Flags::IntroDial2, "IntroDial2" },
{ Flags::ItsOutro, "ItsOutro" },
{ Flags::KamienComment, "KamienComment" },
{ Flags::KamienSkip, "KamienSkip" },
{ Flags::TesterFlag, "TesterFlag" },
{ Flags::RememberLine, "RememberLine" },
{ Flags::OpisLapek, "OpisLapek" },
{ Flags::TalWait, "TalWait" },
{ Flags::OpisKamienia, "OpisKamienia" },
{ Flags::JumpBox, "JumpBox" },
{ Flags::JumpBox1, "JumpBox1" },
{ Flags::JumpBox2, "JumpBox2" },
{ Flags::JumpBox3, "JumpBox3" },
{ Flags::SpecPiesek, "SpecPiesek" },
{ Flags::SpecPiesekCount, "SpecPiesekCount" },
{ Flags::SpecPiesekGadanie, "SpecPiesekGadanie" },
{ Flags::ZnikaFlag, "ZnikaFlag" },
{ Flags::ZnikaTimer, "ZnikaTimer" },
{ Flags::SowaTimer, "SowaTimer" },
{ Flags::MamrotanieOff, "MamrotanieOff" },
{ Flags::CURRMOB, "CURRMOB" },
{ Flags::KOLOR, "KOLOR" },
{ Flags::MBFLAG, "MBFLAG" },
{ Flags::MXFLAG, "MXFLAG" },
{ Flags::MYFLAG, "MYFLAG" },
{ Flags::SCROLLTYPE, "SCROLLTYPE" },
{ Flags::SCROLLVALUE, "SCROLLVALUE" },
{ Flags::SCROLLVALUE2, "SCROLLVALUE2" },
{ Flags::TALKEXITCODE, "TALKEXITCODE" },
{ Flags::SPECROUTFLAG1, "SPECROUTFLAG1" },
{ Flags::SPECROUTFLAG2, "SPECROUTFLAG2" },
{ Flags::SPECROUTFLAG3, "SPECROUTFLAG3" },
{ Flags::TALKFLAGCODE, "TALKFLAGCODE" },
{ Flags::CURRROOM, "CURRROOM" },
{ Flags::Talker1Init, "Talker1Init" },
{ Flags::Talker2Init, "Talker2Init" },
{ Flags::RESTOREROOM, "RESTOREROOM" },
{ Flags::INVALLOWED, "INVALLOWED" },
{ Flags::BOXSEL, "BOXSEL" },
{ Flags::CURSEBLINK, "CURSEBLINK" },
{ Flags::EXACTMOVE, "EXACTMOVE" },
{ Flags::MOVEDESTX, "MOVEDESTX" },
{ Flags::MOVEDESTY, "MOVEDESTY" },
{ Flags::NOANTIALIAS, "NOANTIALIAS" },
{ Flags::ESCAPED, "ESCAPED" },
{ Flags::ALLOW1OPTION, "ALLOW1OPTION" },
{ Flags::VOICE_H_LINE, "VOICE_H_LINE" },
{ Flags::VOICE_A_LINE, "VOICE_A_LINE" },
{ Flags::VOICE_B_LINE, "VOICE_B_LINE" },
{ Flags::VOICE_C_LINE, "VOICE_C_LINE" },
{ Flags::NOHEROATALL, "NOHEROATALL" },
{ Flags::MOUSEENABLED, "MOUSEENABLED" },
{ Flags::DIALINES, "DIALINES" },
{ Flags::SHANWALK, "SHANWALK" },
{ Flags::SHANDOG, "SHANDOG" },
{ Flags::GETACTIONBACK, "GETACTIONBACK" },
{ Flags::GETACTIONDATA, "GETACTIONDATA" },
{ Flags::GETACTION, "GETACTION" },
{ Flags::HEROFAST, "HEROFAST" },
{ Flags::SELITEM, "SELITEM" },
{ Flags::LMOUSE, "LMOUSE" },
{ Flags::MINMX, "MINMX" },
{ Flags::MAXMX, "MAXMX" },
{ Flags::MINMY, "MINMY" },
{ Flags::MAXMY, "MAXMY" },
{ Flags::TORX1, "TORX1" },
{ Flags::TORY1, "TORY1" },
{ Flags::TORX2, "TORX2" },
{ Flags::TORY2, "TORY2" },
{ Flags::POWER, "POWER" },
{ Flags::POWERENABLED, "POWERENABLED" },
{ Flags::FLCRESTORE, "FLCRESTORE" },
{ Flags::NOCLSTEXT, "NOCLSTEXT" },
{ Flags::ESCAPED2, "ESCAPED2" },
};
Flags::Flags() {
for (uint i = 0; i < ARRAYSIZE(flagNames); i++) {
_flagMap[flagNames[i].id] = flagNames[i].flagName;
}
}
const char *Flags::getFlagName(uint16 flagId) {
if (_flagMap.contains(flagId))
return _flagMap[flagId];
return "unknown_flag";
}
} // End of namespace Prince

416
engines/prince/flags.h Normal file
View File

@@ -0,0 +1,416 @@
/* 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 PRINCE_FLAGS_H
#define PRINCE_FLAGS_H
#include "common/scummsys.h"
#include "common/hashmap.h"
namespace Prince {
class Flags {
public:
Flags();
const char *getFlagName(uint16 flagId);
enum Id {
FLAGA1 = 0x8000,
FLAGA2 = 0x8002,
FLAGA3 = 0x8004,
DESTX = 0x8006,
DESTY = 0x8008,
DESTD = 0x800A,
DwarfDone = 0x800C,
GRABARZCOUNTER = 0x800E,
KIERUNEK = 0x8010,
BACKFLAG1 = 0x8012,
BACKFLAG2 = 0x8014,
BACKFLAG3 = 0x8016,
BACKFLAG4 = 0x8018,
MACROFLAG1 = 0x801A,
MACROFLAG2 = 0x801C,
MACROFLAG3 = 0x801E,
HEROLDDONE = 0x8020,
BRIDGESET = 0x8022,
U_BT_1 = 0x8024,
U_BT_2 = 0x8026,
U_BT_3 = 0x8028,
U_BT_4 = 0x802A,
U_BT_5 = 0x802C,
U_BT_6 = 0x802E,
U_BT_7 = 0x8030,
U_BT_8 = 0x8032,
U_BT_9 = 0x8034,
U_BT_COUNTER = 0x8036,
ARIVALDALIVE = 0x8038,
TALKCHAR1 = 0x803A,
TalkType1 = 0x803C,
TALKROUT1 = 0x803E,
TALKROUT2 = 0x8042,
TALKROUT3 = 0x8046,
TALKROUT4 = 0x804A,
TALKANIM1 = 0x804E,
TALKANIM2 = 0x8050,
TALKCOLOR1 = 0x8052,
TALKCOLOR2 = 0x8054,
KapciuchTaken = 0x8056,
CurrentBeggarA = 0x8058,
TempKapc = 0x805A,
HomTaken = 0x805C,
WizardTalk = 0x805E,
SunlordTalk = 0x8060,
HermitTalk = 0x8062,
RunyMode = 0x8064,
FatMerchantTalk = 0x8066,
HotDogTalk = 0x8068,
ThiefTalk = 0x806A,
BeggarTalk = 0x806C,
// DwarfTalk = 0x806E, // Redefinition
MonkTalk = 0x8070,
BardTalk = 0x8072,
BarmanTalk = 0x8074,
LeftPlayerTalk = 0x8076,
OczySowy = 0x8078,
CzachySpeed1 = 0x807A,
CzachySpeed2 = 0x807C,
CzachySpeed3 = 0x807E,
CzachySlowDown1 = 0x8080,
CzachySlowDown2 = 0x8082,
CzachySlowDown3 = 0x8084,
FjordDane = 0x8086,
GKopany1 = 0x8088,
GKopany2 = 0x808A,
GKopany3 = 0x808C,
GKopany4 = 0x808E,
KnowGodWord = 0x8090,
TALKROUT21 = 0x8092,
TALKROUT22 = 0x8096,
TALKROUT23 = 0x809A,
TALKROUT24 = 0x809E,
TalkType2 = 0x80A2,
GrabarzTalk = 0x80A4,
LastTalker = 0x80A6,
MapaPustelniaEnabled = 0x80A8,
MapaTempleEnabled = 0x80AA,
MapaFjordEnabled = 0x80AC,
MapaSilmanionaEnabled = 0x80AE,
MapaKurhanEnabled = 0x80B0,
MapaDragonEnabled = 0x80B2,
MapaMillEnabled = 0x80B4,
DwarfRunning = 0x80B6,
DwarfTalk = 0x80B8,
CurseLift = 0x80BA,
KosciSwapped = 0x80BC,
BookStolen = 0x80BE,
MapaUsable = 0x80C0,
FjordBoss = 0x80C2,
FjordHotDog = 0x80C4,
FjordLewy = 0x80C6,
FjordPrawy = 0x80C8,
TalkArivald = 0x80CA,
ShootDone = 0x80CC,
ShootRunning = 0x80CE,
ShootKnow = 0x80D0,
MirrorKnow = 0x80D2,
Gar1stTime = 0x80D4,
KosciTaken = 0x80D6,
ArivGotSpell = 0x80D8,
BookGiven = 0x80DA,
Wywieszka = 0x80DC,
TalkSheila = 0x80DE,
TalkSheila2 = 0x80E0,
BackHuman = 0x80E2,
SkarbiecOpen = 0x80E4,
LustroTaken = 0x80E6,
GargoyleHom = 0x80E8,
GargoyleBroken = 0x80EA,
FjordDzien = 0x80EC,
GargoyleHom2 = 0x80EE,
RunMonstersRunning = 0x80F0,
FoundPaperInCoffin = 0x80F2,
KnowSunlord = 0x80F4,
KnowSunlordTalk = 0x80F6,
ArivaldCzyta = 0x80F8,
TelepX = 0x80FA,
TelepY = 0x80FC,
TelepDir = 0x80FE,
TelepRoom = 0x8100,
ListStolen = 0x8102,
WifeInDoor = 0x8104,
TalkWifeFlag = 0x8106,
LetterGiven = 0x8108,
LutniaTaken = 0x810A,
BardHomeOpen = 0x810C,
FjordNoMonsters = 0x810E,
ShandriaWallTalking = 0x8110,
ShandriaWallCounter = 0x8112,
ShandriaWallDone = 0x8114,
FutureDone = 0x8116,
TalkButch = 0x8118,
GotSzalik = 0x811A,
GotCzosnek = 0x811C,
BearDone = 0x811E,
NekrVisited = 0x8120,
SunRiddle = 0x8122,
PtaszekAway = 0x8124,
KotGadanie = 0x8126,
SzlafmycaTaken = 0x8128,
BabkaTalk = 0x812A,
SellerTalk = 0x812C,
CzosnekDone = 0x812E,
PriestCounter = 0x8130,
PriestGest1 = 0x8132,
PriestGest2 = 0x8134,
PriestGest3 = 0x8136,
PriestGest4 = 0x8138,
PriestAnim = 0x813A,
HolyWaterTaken = 0x813C,
AxeTaken = 0x813E,
BadylTaken1 = 0x8140,
BadylTaken2 = 0x8142,
BadylSharpened = 0x8144,
PorwanieSmoka = 0x8146,
ShopReOpen = 0x8148,
LuskaShown = 0x814A,
CudKnow = 0x814C,
VampireDead = 0x814E,
MapaVisible1 = 0x8150,
MapaVisible2 = 0x8152,
MapaVisible3 = 0x8154,
MapaVisible4 = 0x8156,
MapaVisible5 = 0x8158,
MapaVisible6 = 0x815A,
MapaVisible7 = 0x815C,
MapaVisible8 = 0x815E,
MapaVisible9 = 0x8160,
MapaX = 0x8162,
MapaY = 0x8164,
MapaD = 0x8166,
OldMapaX = 0x8168,
OldMapaY = 0x816A,
OldMapaD = 0x816C,
MovingBack = 0x816E,
MapaCount = 0x8170,
Pustelnia1st = 0x8172,
CzarnePole1st = 0x8174,
TalkArivNum = 0x8176,
Pfui = 0x8178,
MapaSunlordEnabled = 0x817A,
WebDone = 0x817C,
DragonDone = 0x817E,
KanPlay = 0x8180,
OldKanPlay = 0x8182,
LapkiWait = 0x8184,
WebNoCheck = 0x8186,
Perfumeria = 0x8188,
SmokNoCheck = 0x818A,
IluzjaBroken = 0x818C,
IluzjaWorking = 0x818E,
IluzjaCounter = 0x8190,
KurhanOpen1 = 0x8192,
KastetTaken = 0x8194,
KastetDown = 0x8196,
KurhanDone = 0x8198,
SkelCounter = 0x819A,
SkelDial1 = 0x819C,
SkelDial2 = 0x819E,
SkelDial3 = 0x81A0,
SkelDial4 = 0x81A2,
SameTalker = 0x81A4,
RunMonstersText = 0x81A6,
PiwnicaChecked = 0x81A8,
DragonTalked = 0x81AA,
ToldAboutBook = 0x81AC,
SilmanionaDone = 0x81AE,
ToldBookCount = 0x81B0,
SmrodNoCheck = 0x81B2,
RopeTaken = 0x81B4,
RopeTime = 0x81B6,
LaskaFree = 0x81B8,
ShanSmokTalked = 0x81BA,
SwordTaken = 0x81BC,
Mill1st = 0x81BE,
SawRat = 0x81C0,
KnowRat = 0x81C2,
DziuraTimer = 0x81C4,
LaskaInside = 0x81C6,
HoleBig = 0x81C8,
EnableWiedzmin = 0x81CA,
EnableTrucizna = 0x81CC,
KnowPoison = 0x81CE,
KufelTaken = 0x81D0,
BojkaEnabled = 0x81D2,
BitwaNot1st = 0x81D4,
BojkaTimer = 0x81D6,
BojkaGirl = 0x81D8,
Look1st = 0x81DA,
RatTaken = 0x81DC,
LaskaTalkedGr = 0x81DE,
RatusGivus = 0x81E0,
MamObole = 0x81E2,
Speed1st = 0x81E4,
SpeedTimer = 0x81E6,
ProveIt = 0x81E8,
Proven = 0x81EA,
ShowWoalka = 0x81EC,
PoisonTaken = 0x81EE,
HellOpened = 0x81F0,
HellNoCheck = 0x81F2,
TalAn1 = 0x81F4,
TalAn2 = 0x81F6,
TalAn3 = 0x81F8,
TalkDevilGuard = 0x81fA,
Sword1st = 0x81FC,
IluzjaNoCheck = 0x81FE,
RozdzielniaNumber = 0x8200,
JailChecked = 0x8202,
JailTalked = 0x8204,
TrickFailed = 0x8206,
WegielVisible = 0x8208,
WegielTimer1 = 0x820A,
RandomSample = 0x820C,
RandomSampleTimer = 0x820E,
SampleTimer = 0x8210,
ZonaSample = 0x8212,
HoleTryAgain = 0x8214,
TeleportTimer = 0x8216,
RozLezy = 0x8218,
UdkoTimer = 0x821A,
ZaworZatkany = 0x821C,
ZaworOpened = 0x821E,
DoorExploded = 0x8220,
SkoraTaken = 0x8222,
CiezkieByl = 0x8224,
MamWegiel = 0x8226,
SwiecaAway = 0x8228,
ITSAVE = 0x822A,
RozpadlSie = 0x822C,
WegielFullTimer = 0x822E,
WegielDown = 0x8230,
WegielDownTimer = 0x8232,
PaliSie = 0x8234,
DiabGuardTalked = 0x8236,
GuardsNoCheck = 0x8238,
TalkedPowloka = 0x823A,
JailOpen = 0x823C,
PrzytulTimer = 0x823E,
JailDone = 0x8240,
MamMonety = 0x8242,
LotTimer = 0x8244,
LotObj = 0x8246,
PtakTimer = 0x8248,
BookTimer = 0x824A,
BookGiba = 0x824C,
PtakLata = 0x824E,
Podej = 0x8250,
GotHint = 0x8252,
LawaLeci = 0x8254,
PowerKlik = 0x8258,
LucekBad = 0x825A,
LucekBad1st = 0x825C,
IntroDial1 = 0x825E,
IntroDial2 = 0x8260,
ItsOutro = 0x8262,
KamienComment = 0x8264,
KamienSkip = 0x8266,
TesterFlag = 0x8268,
RememberLine = 0x826A,
OpisLapek = 0x826C,
//OpisKamienia = 0x826E, // Redefinition
TalWait = 0x8270,
OpisKamienia = 0x8272,
JumpBox = 0x8274,
JumpBox1 = 0x8276,
JumpBox2 = 0x8278,
JumpBox3 = 0x827A,
SpecPiesek = 0x827C,
SpecPiesekCount = 0x827E,
SpecPiesekGadanie = 0x8282,
ZnikaFlag = 0x8284,
ZnikaTimer = 0x8286,
SowaTimer = 0x8288,
MamrotanieOff = 0x828A,
// System flags controlled by script
CURRMOB = 0x8400,
KOLOR = 0x8402,
MBFLAG = 0x8404,
MXFLAG = 0x8406,
MYFLAG = 0x8408,
SCROLLTYPE = 0x840A,
SCROLLVALUE = 0x840C,
SCROLLVALUE2 = 0x840E,
TALKEXITCODE = 0x8410,
SPECROUTFLAG1 = 0x8412,
SPECROUTFLAG2 = 0x8414,
SPECROUTFLAG3 = 0x8416,
TALKFLAGCODE = 0x8418,
CURRROOM = 0x841A,
Talker1Init = 0x841C,
Talker2Init = 0x841E,
RESTOREROOM = 0x8420,
INVALLOWED = 0x8422,
BOXSEL = 0x8424,
CURSEBLINK = 0x8426,
EXACTMOVE = 0x8428,
MOVEDESTX = 0x842A,
MOVEDESTY = 0x842C,
NOANTIALIAS = 0x842E,
ESCAPED = 0x8430,
ALLOW1OPTION = 0x8432,
VOICE_H_LINE = 0x8434,
VOICE_A_LINE = 0x8436,
VOICE_B_LINE = 0x8438,
VOICE_C_LINE = 0x843A,
NOHEROATALL = 0x843C,
MOUSEENABLED = 0x843E,
DIALINES = 0x8440,
//SELITEM = 0x8442, // Redefinition
SHANWALK = 0x8444,
SHANDOG = 0x8446,
GETACTIONBACK = 0x8448,
GETACTIONDATA = 0x844C,
GETACTION = 0x8450,
HEROFAST = 0x8452,
SELITEM = 0x8454,
LMOUSE = 0x8456,
MINMX = 0x8458,
MAXMX = 0x845A,
MINMY = 0x845C,
MAXMY = 0x845E,
TORX1 = 0x8460,
TORY1 = 0x8462,
TORX2 = 0x8464,
TORY2 = 0x8466,
POWER = 0x8468,
POWERENABLED = 0x846A,
FLCRESTORE = 0x846C,
NOCLSTEXT = 0x846E,
ESCAPED2 = 0x8470
};
private:
Common::HashMap<uint, const char *> _flagMap;
};
} // End of namespace Prince
#endif

93
engines/prince/font.cpp Normal file
View File

@@ -0,0 +1,93 @@
/* 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/archive.h"
#include "common/debug.h"
#include "common/stream.h"
#include "prince/font.h"
#include "prince/prince.h"
namespace Prince {
Font::Font() : _fontData(nullptr) {
}
Font::~Font() {
if (_fontData != nullptr) {
free(_fontData);
_fontData = nullptr;
}
}
bool Font::loadStream(Common::SeekableReadStream &stream) {
stream.seek(0);
uint32 dataSize = stream.size();
_fontData = (byte *)malloc(dataSize);
stream.read(_fontData, stream.size());
return true;
}
int Font::getFontHeight() const {
return _fontData[5];
}
int Font::getMaxCharWidth() const {
return 0;
}
Font::ChrData Font::getChrData(byte chr) const {
chr -= 32;
uint16 chrOffset = 4 * chr + 6;
ChrData chrData;
chrData._width = _fontData[chrOffset + 2];
chrData._height = _fontData[chrOffset + 3];
chrData._pixels = _fontData + READ_LE_UINT16(_fontData + chrOffset);
return chrData;
}
int Font::getCharWidth(uint32 chr) const {
return getChrData(chr)._width;
}
void Font::drawChar(Graphics::Surface *dst, uint32 chr, int posX, int posY, uint32 color) const {
const ChrData chrData = getChrData(chr);
Common::Rect screenRect(0, 0, PrinceEngine::kNormalWidth, PrinceEngine::kNormalHeight);
for (int y = 0; y < chrData._height; y++) {
for (int x = 0; x < chrData._width; x++) {
byte d = chrData._pixels[x + (chrData._width * y)];
if (d == 0) d = 255;
else if (d == 1) d = 0;
else if (d == 2) d = color;
else if (d == 3) d = 0;
if (d != 255) {
if (screenRect.contains(posX + x, posY + y)) {
*(byte *)dst->getBasePtr(posX + x, posY + y) = d;
}
}
}
}
}
} // End of namespace Prince

63
engines/prince/font.h Normal file
View File

@@ -0,0 +1,63 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PRINCE_FONT_H
#define PRINCE_FONT_H
#include "graphics/font.h"
#include "graphics/surface.h"
#include "common/str.h"
#include "common/rect.h"
namespace Prince {
class Font : public Graphics::Font {
public:
Font();
~Font() override;
bool loadStream(Common::SeekableReadStream &stream);
int getFontHeight() const override;
int getMaxCharWidth() const override;
int getCharWidth(uint32 chr) const override;
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
int getKerningOffset(uint32 left, uint32 right) const override { return -2; }
private:
struct ChrData {
byte *_pixels;
byte _width;
byte _height;
};
ChrData getChrData(byte chr) const;
byte *_fontData;
};
} // End of namespace Prince
#endif

475
engines/prince/graphics.cpp Normal file
View File

@@ -0,0 +1,475 @@
/* 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 "prince/graphics.h"
#include "prince/prince.h"
#include "prince/mhwanh.h"
#include "graphics/paletteman.h"
#include "common/memstream.h"
namespace Prince {
GraphicsMan::GraphicsMan(PrinceEngine *vm) : _vm(vm), _changed(false) {
initGraphics(640, 480);
_frontScreen = new Graphics::Surface();
_frontScreen->create(640, 480, Graphics::PixelFormat::createFormatCLUT8());
_screenForInventory = new Graphics::Surface();
_screenForInventory->create(640, 480, Graphics::PixelFormat::createFormatCLUT8());
_mapScreen = new Graphics::Surface();
_mapScreen->create(640, 480, Graphics::PixelFormat::createFormatCLUT8());
_shadowTable70 = (byte *)malloc(256);
_shadowTable50 = (byte *)malloc(256);
_roomBackground = nullptr;
}
GraphicsMan::~GraphicsMan() {
_frontScreen->free();
delete _frontScreen;
_screenForInventory->free();
delete _screenForInventory;
_mapScreen->free();
delete _mapScreen;
free(_shadowTable70);
free(_shadowTable50);
}
void GraphicsMan::update(Graphics::Surface *screen) {
if (_changed) {
_vm->_system->copyRectToScreen((byte *)screen->getBasePtr(0, 0), 640, 0, 0, 640, 480);
_vm->_system->updateScreen();
_changed = false;
}
}
void GraphicsMan::setPalette(const byte *palette) {
_vm->_system->getPaletteManager()->setPalette(palette, 0, 256);
}
void GraphicsMan::change() {
_changed = true;
}
void GraphicsMan::draw(Graphics::Surface *screen, const Graphics::Surface *s) {
uint16 w = MIN(screen->w, s->w);
const byte *src = (const byte *)s->getBasePtr(0, 0);
byte *dst = (byte *)screen->getBasePtr(0, 0);
for (int y = 0; y < s->h; y++) {
if (y < screen->h) {
memcpy(dst, src, w);
}
src += s->pitch;
dst += screen->pitch;
}
change();
}
// Black (value = 0) as a primary transparent color, fix for FLC animations
void GraphicsMan::drawTransparentSurface(Graphics::Surface *screen, int32 posX, int32 posY, const Graphics::Surface *s, int secondTransColor) {
const byte *src1 = (const byte *)s->getBasePtr(0, 0);
byte *dst1 = (byte *)screen->getBasePtr(posX, posY);
for (int y = 0; y < s->h; y++) {
if (y + posY < screen->h && y + posY >= 0) {
const byte *src2 = src1;
byte *dst2 = dst1;
for (int x = 0; x < s->w; x++, src2++, dst2++) {
if (*src2 && *src2 != secondTransColor) {
if (x + posX < screen->w && x + posX >= 0) {
*dst2 = *src2;
}
}
}
}
src1 += s->pitch;
dst1 += screen->pitch;
}
change();
}
/**
* Similar to drawTransparentSurface but with use of shadowTable for color recalculation
* and kShadowColor (191) as a transparent color.
*/
void GraphicsMan::drawAsShadowSurface(Graphics::Surface *screen, int32 posX, int32 posY, const Graphics::Surface *s, byte *shadowTable) {
const byte *src1 = (const byte *)s->getBasePtr(0, 0);
byte *dst1 = (byte *)screen->getBasePtr(posX, posY);
for (int y = 0; y < s->h; y++) {
if (y + posY < screen->h && y + posY >= 0) {
const byte *src2 = src1;
byte *dst2 = dst1;
for (int x = 0; x < s->w; x++, src2++, dst2++) {
if (*src2 == kShadowColor) {
if (x + posX < screen->w && x + posX >= 0) {
*dst2 = *(shadowTable + *dst2);
}
}
}
}
src1 += s->pitch;
dst1 += screen->pitch;
}
}
/**
* Used in glowing animation for inventory items. Creates special blendTable array of colors,
* use black (0) as a transparent color.
*/
void GraphicsMan::drawTransparentWithBlendSurface(Graphics::Surface *screen, int32 posX, int32 posY, const Graphics::Surface *s) {
const byte *src1 = (const byte *)s->getBasePtr(0, 0);
byte *dst1 = (byte *)screen->getBasePtr(posX, posY);
byte *blendTable = (byte *)malloc(256);
for (int i = 0; i < 256; i++) {
blendTable[i] = 255;
}
for (int y = 0; y < s->h; y++) {
if (y + posY < screen->h && y + posY >= 0) {
const byte *src2 = src1;
byte *dst2 = dst1;
for (int x = 0; x < s->w; x++, src2++, dst2++) {
if (*src2) {
if (x + posX < screen->w && x + posX >= 0) {
*dst2 = getBlendTableColor(*src2, *dst2, blendTable);
}
}
}
}
src1 += s->pitch;
dst1 += screen->pitch;
}
free(blendTable);
change();
}
/**
* Similar to drawTransparentSurface but with with use of DrawNode as argument for Z axis sorting
* and white (255) as transparent color.
*/
void GraphicsMan::drawTransparentDrawNode(Graphics::Surface *screen, DrawNode *drawNode) {
byte *src1 = (byte *)drawNode->s->getBasePtr(0, 0);
byte *dst1 = (byte *)screen->getBasePtr(drawNode->posX, drawNode->posY);
for (int y = 0; y < drawNode->s->h; y++) {
if (y + drawNode->posY < screen->h && y + drawNode->posY >= 0) {
byte *src2 = src1;
byte *dst2 = dst1;
for (int x = 0; x < drawNode->s->w; x++, src2++, dst2++) {
if (*src2 != 255) {
if (x + drawNode->posX < screen->w && x + drawNode->posX >= 0) {
*dst2 = *src2;
}
}
}
}
src1 += drawNode->s->pitch;
dst1 += screen->pitch;
}
}
/**
* Similar to drawTransparentDrawNode but with additional anti-aliasing code for sprite drawing.
* Edge smoothing is based on 256 x 256 table of colors transition.
* Algorithm is checking if currently drawing pixel is located next to the edge of sprite and if it makes jagged line.
* If it does then this pixel is set with color from transition table calculated of original background pixel color
* and sprite's edge pixel color.
*/
void GraphicsMan::drawTransparentWithTransDrawNode(Graphics::Surface *screen, DrawNode *drawNode) {
// pos of first pixel for each row of source sprite
byte *src1 = (byte *)drawNode->s->getBasePtr(0, 0);
// pos of drawing first pixel for each row on screen surface
byte *dst1 = (byte *)screen->getBasePtr(drawNode->posX, drawNode->posY);
// trasition table for calculating new color value
byte *transTableData = (byte *)drawNode->data;
for (int y = 0; y < drawNode->s->h; y++) {
if (y + drawNode->posY < screen->h && y + drawNode->posY >= 0) {
// current pixel in row of source sprite
byte *src2 = src1;
// current pixel in row of screen surface
byte *dst2 = dst1;
for (int x = 0; x < drawNode->s->w; x++, src2++, dst2++) {
if (x + drawNode->posX < screen->w && x + drawNode->posX >= 0) {
if (*src2 != 255) {
// if source sprite pixel is not mask color than draw it normally
*dst2 = *src2;
} else {
// check for making jagged line
if (x) {
// not first pixel in row
if (*(src2 - 1) == 255) {
// if it has mask color to the left - check right
if (x != drawNode->s->w - 1) {
// not last pixel in row
if (*(src2 + 1) == 255) {
// pixel to the right with mask color - no anti-alias
continue;
}
// it's not mask color to the right - we continue checking
} else {
// last pixel in row, no right check - no anti-alias
continue;
}
}
// it's not mask color to the left - we continue checking
} else if (x != drawNode->s->w - 1) {
// first pixel in row but not last - just right pixel checking
if (*(src2 + 1) == 255) {
// pixel to the right with mask color - no anti-alias
continue;
}
// it's not mask color to the right - we continue checking
} else {
// it's first and last pixel in row at the same time (width = 1) - no anti-alias
continue;
}
byte value = 0;
if (y != drawNode->s->h - 1) {
// not last row
// check pixel below of current src2 pixel
value = *(src2 + drawNode->s->pitch);
if (value == 255) {
// pixel below with mask color - check above
if (y) {
// not first row
value = *(src2 - drawNode->s->pitch);
if (value == 255) {
// pixel above with mask color - no anti-alias
continue;
}
// it's not mask color above - we draw as transition color
} else {
// first row - no anti-alias
continue;
}
}
// it's not mask color below - we draw as transition color
} else if (y) {
// last row - just check above
value = *(src2 - drawNode->s->pitch);
if (value == 255) {
// pixel above with mask color - no anti-alias
continue;
}
// it's not mask color above - we draw as transition color
} else {
// first and last row at the same time (height = 1) - no anti-alias
continue;
}
// new color value based on original screen surface color and sprite's edge pixel color
*dst2 = transTableData[*dst2 * 256 + value];
}
}
}
}
// adding pitch to jump to next row of pixels
src1 += drawNode->s->pitch;
dst1 += screen->pitch;
}
}
void GraphicsMan::drawMaskDrawNode(Graphics::Surface *screen, DrawNode *drawNode) {
byte *maskData = (byte *)drawNode->data;
byte *src1 = (byte *)drawNode->originalRoomSurface->getBasePtr(drawNode->posX, drawNode->posY);
byte *dst1 = (byte *)screen->getBasePtr(drawNode->posX, drawNode->posY);
int maskWidth = drawNode->width >> 3;
int maskPostion = 0;
int maskCounter = 128;
for (int y = 0; y < drawNode->height; y++) {
if (y + drawNode->posY < screen->h && y + drawNode->posY >= 0) {
byte *src2 = src1;
byte *dst2 = dst1;
int tempMaskPostion = maskPostion;
for (int x = 0; x < drawNode->width; x++, src2++, dst2++) {
if (x + drawNode->posX < screen->w && x + drawNode->posX >= 0) {
if ((maskData[tempMaskPostion] & maskCounter) != 0) {
*dst2 = *src2;
}
}
maskCounter >>= 1;
if (maskCounter == 0) {
maskCounter = 128;
tempMaskPostion++;
}
}
}
src1 += drawNode->originalRoomSurface->pitch;
dst1 += screen->pitch;
maskPostion += maskWidth;
maskCounter = 128;
}
}
void GraphicsMan::drawAsShadowDrawNode(Graphics::Surface *screen, DrawNode *drawNode) {
byte *shadowData = (byte *)drawNode->data;
byte *src1 = (byte *)drawNode->s->getBasePtr(0, 0);
byte *dst1 = (byte *)screen->getBasePtr(drawNode->posX, drawNode->posY);
for (int y = 0; y < drawNode->s->h; y++) {
if (y + drawNode->posY < screen->h && y + drawNode->posY >= 0) {
byte *src2 = src1;
byte *dst2 = dst1;
for (int x = 0; x < drawNode->s->w; x++, src2++, dst2++) {
if (*src2 == kShadowColor) {
if (x + drawNode->posX < screen->w && x + drawNode->posX >= 0) {
*dst2 = *(shadowData + *dst2);
}
}
}
}
src1 += drawNode->s->pitch;
dst1 += screen->pitch;
}
}
void GraphicsMan::drawBackSpriteDrawNode(Graphics::Surface *screen, DrawNode *drawNode) {
byte *src1 = (byte *)drawNode->s->getBasePtr(0, 0);
byte *dst1 = (byte *)screen->getBasePtr(drawNode->posX, drawNode->posY);
for (int y = 0; y < drawNode->s->h; y++) {
if (y + drawNode->posY < screen->h && y + drawNode->posY >= 0) {
byte *src2 = src1;
byte *dst2 = dst1;
for (int x = 0; x < drawNode->s->w; x++, src2++, dst2++) {
if (*src2 != 255) {
if (x + drawNode->posX < screen->w && x + drawNode->posX >= 0) {
if (*dst2 == 255) {
*dst2 = *src2;
}
}
}
}
}
src1 += drawNode->s->pitch;
dst1 += screen->pitch;
}
}
byte GraphicsMan::getBlendTableColor(byte pixelColor, byte backgroundPixelColor, byte *blendTable) {
int currColor = 0;
if (blendTable[pixelColor] != 255) {
currColor = blendTable[pixelColor];
} else {
const byte *originalPalette = _vm->_roomBmp->getPalette().data();
int redFirstOrg = originalPalette[pixelColor * 3] * _vm->_mst_shadow / 256;
redFirstOrg = CLIP(redFirstOrg, 0, 255);
if (_vm->_mst_shadow <= 256) {
int redFirstBack = originalPalette[backgroundPixelColor * 3] * (256 - _vm->_mst_shadow) / 256;
redFirstBack = CLIP(redFirstBack, 0, 255);
redFirstOrg += redFirstBack;
redFirstOrg = CLIP(redFirstOrg, 0, 255);
}
int greenFirstOrg = originalPalette[pixelColor * 3 + 1] * _vm->_mst_shadow / 256;
greenFirstOrg = CLIP(greenFirstOrg, 0, 255);
if (_vm->_mst_shadow <= 256) {
int greenFirstBack = originalPalette[backgroundPixelColor * 3 + 1] * (256 - _vm->_mst_shadow) / 256;
greenFirstBack = CLIP(greenFirstBack, 0, 255);
greenFirstOrg += greenFirstBack;
greenFirstOrg = CLIP(greenFirstOrg, 0, 255);
}
int blueFirstOrg = originalPalette[pixelColor * 3 + 2] * _vm->_mst_shadow / 256;
blueFirstOrg = CLIP(blueFirstOrg, 0, 255);
if (_vm->_mst_shadow <= 256) {
int blueFirstBack = originalPalette[backgroundPixelColor * 3 + 2] * (256 - _vm->_mst_shadow) / 256;
blueFirstBack = CLIP(blueFirstBack, 0, 255);
blueFirstOrg += blueFirstBack;
blueFirstOrg = CLIP(blueFirstOrg, 0, 255);
}
int bigValue = PrinceEngine::kIntMax; // infinity
for (int j = 0; j < 256; j++) {
int redSecondOrg = originalPalette[3 * j];
int redNew = redFirstOrg - redSecondOrg;
redNew = redNew * redNew;
int greenSecondOrg = originalPalette[3 * j + 1];
int greenNew = greenFirstOrg - greenSecondOrg;
greenNew = greenNew * greenNew;
int blueSecondOrg = originalPalette[3 * j + 2];
int blueNew = blueFirstOrg - blueSecondOrg;
blueNew = blueNew * blueNew;
int sumOfColorValues = redNew + greenNew + blueNew;
if (sumOfColorValues < bigValue) {
bigValue = sumOfColorValues;
currColor = j;
}
if (sumOfColorValues == 0) {
break;
}
}
blendTable[pixelColor] = currColor;
}
return currColor;
}
void GraphicsMan::makeShadowTable(int brightness, byte *shadowPalette) {
int shadow = brightness * 256 / 100;
const byte *originalPalette = _vm->_roomBmp->getPalette().data();
for (int i = 0; i < 256; i++) {
int redFirstOrg = originalPalette[3 * i] * shadow / 256;
int greenFirstOrg = originalPalette[3 * i + 1] * shadow / 256;
int blueFirstOrg = originalPalette[3 * i + 2] * shadow / 256;
int currColor = 0;
int bigValue = 999999999; // infinity
for (int j = 0; j < 256; j++) {
int redSecondOrg = originalPalette[3 * j];
int redNew = redFirstOrg - redSecondOrg;
redNew = redNew * redNew;
int greenSecondOrg = originalPalette[3 * j + 1];
int greenNew = greenFirstOrg - greenSecondOrg;
greenNew = greenNew * greenNew;
int blueSecondOrg = originalPalette[3 * j + 2];
int blueNew = blueFirstOrg - blueSecondOrg;
blueNew = blueNew * blueNew;
int sumOfColorValues = redNew + greenNew + blueNew;
if (sumOfColorValues < bigValue) {
bigValue = sumOfColorValues;
currColor = j;
}
if (sumOfColorValues == 0) {
break;
}
}
shadowPalette[i] = currColor;
}
}
} // End of namespace Prince

75
engines/prince/graphics.h Normal file
View File

@@ -0,0 +1,75 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PRINCE_GRAPHICS_H
#define PRINCE_GRAPHICS_H
#include "graphics/surface.h"
namespace Prince {
class PrinceEngine;
class MhwanhDecoder;
struct DrawNode;
class GraphicsMan {
public:
GraphicsMan(PrinceEngine *vm);
~GraphicsMan();
void update(Graphics::Surface *screen);
void change();
void setPalette(const byte *palette);
void makeShadowTable(int brightness, byte *shadowTable);
void draw(Graphics::Surface *screen, const Graphics::Surface *s);
void drawTransparentSurface(Graphics::Surface *screen, int32 posX, int32 posY, const Graphics::Surface *s, int secondTransColor = 0);
void drawAsShadowSurface(Graphics::Surface *screen, int32 posX, int32 posY, const Graphics::Surface *s, byte *shadowTable);
void drawTransparentWithBlendSurface(Graphics::Surface *screen, int32 posX, int32 posY, const Graphics::Surface *s);
static void drawTransparentDrawNode(Graphics::Surface *screen, DrawNode *drawNode);
static void drawTransparentWithTransDrawNode(Graphics::Surface *screen, DrawNode *drawNode);
static void drawAsShadowDrawNode(Graphics::Surface *screen, DrawNode *drawNode);
static void drawMaskDrawNode(Graphics::Surface *screen, DrawNode *drawNode);
static void drawBackSpriteDrawNode(Graphics::Surface *screen, DrawNode *drawNode);
byte getBlendTableColor(byte pixelColor, byte backgroundPixelColor, byte *blendTable);
Graphics::Surface *_frontScreen;
Graphics::Surface *_screenForInventory;
Graphics::Surface *_mapScreen;
const Graphics::Surface *_roomBackground;
byte *_shadowTable70;
byte *_shadowTable50;
static const byte kShadowColor = 191;
private:
PrinceEngine *_vm;
bool _changed;
};
} // End of namespace Prince
#endif

1027
engines/prince/hero.cpp Normal file

File diff suppressed because it is too large Load Diff

183
engines/prince/hero.h Normal file
View File

@@ -0,0 +1,183 @@
/* 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 PRINCE_HERO_H
#define PRINCE_HERO_H
#include "common/scummsys.h"
#include "common/array.h"
#include "common/memstream.h"
#include "graphics/surface.h"
#include "graphics/primitives.h"
namespace Prince {
class Animation;
class PrinceEngine;
class GraphicsMan;
struct InventoryItem;
struct DrawNode;
class Hero {
public:
static const uint32 kMoveSetSize = 26;
static const int16 kStepLeftRight = 8;
static const int16 kStepUpDown = 4;
static const int16 kHeroShadowZ = 2;
enum State {
kHeroStateStay,
kHeroStateTurn,
kHeroStateMove,
kHeroStateBore,
kHeroStateSpec,
kHeroStateTalk,
kHeroStateMvan,
kHeroStateTran,
kHeroStateRun,
kHeroStateDelayMove
};
enum Direction {
kHeroDirLeft = 1,
kHeroDirRight = 2,
kHeroDirUp = 3,
kHeroDirDown = 4
};
enum MoveSet {
kMove_SL,
kMove_SR,
kMove_SU,
kMove_SD,
kMove_ML,
kMove_MR,
kMove_MU,
kMove_MD,
kMove_TL,
kMove_TR,
kMove_TU,
kMove_TD,
kMove_MLU,
kMove_MLD,
kMove_MLR,
kMove_MRU,
kMove_MRD,
kMove_MRL,
kMove_MUL,
kMove_MUR,
kMove_MUD,
kMove_MDL,
kMove_MDR,
kMove_MDU,
kMove_BORED1,
kMove_BORED2
};
// Used instead of offset in getData
enum AttrId {
kHeroLastDir = 26,
kHeroAnimSet = 120
};
uint16 getData(AttrId dataId);
Hero(PrinceEngine *vm, GraphicsMan *graph);
~Hero();
bool loadAnimSet(uint32 heroAnimNumber);
Graphics::Surface *getSurface();
void setPos(int16 x, int16 y) { _middleX = x; _middleY = y; }
void setVisible(bool flag) { _visible = flag; }
void showHero();
void drawHero();
void freeZoomedSurface();
void heroStanding();
void heroMoveGotIt(int x, int y, int dir);
int rotateHero(int oldDirection, int newDirection);
void scrollHero();
void setScale(int8 zoomBitmapValue);
int getScaledValue(int size);
void selectZoom();
void countDrawPosition();
Graphics::Surface *zoomSprite(Graphics::Surface *heroFrame);
void line(int x1, int y1, int x2, int y2);
void plotPoint(int x, int y);
static void showHeroShadow(Graphics::Surface *screen, DrawNode *drawNode);
void drawHeroShadow(Graphics::Surface *heroFrame);
void freeOldMove();
void freeHeroAnim();
uint16 _number;
uint16 _visible;
int16 _state;
int16 _middleX; // middle of X
int16 _middleY; // lower part of hero
int16 _moveSetType;
int16 _frameXSize;
int16 _frameYSize;
int16 _scaledFrameXSize;
int16 _scaledFrameYSize;
int16 _drawX;
int16 _drawY;
int16 _drawZ;
byte *_coords; // array of coordinates
byte *_dirTab; // array of directions
byte *_currCoords; // current coordinations
byte *_currDirTab; // current direction
int16 _lastDirection; // previous move direction
int16 _destDirection;
int16 _leftRightMainDir; // left or right - dominant direction
int16 _upDownMainDir; // up or down - dominant direction
int32 _phase; // Phase animation phase
int16 _step; // Step x/y step size depends on direction
int16 _maxBoredom; // stand still timeout
int16 _boredomTime; // Boredom current boredom time in frames
uint16 _boreNum; // Bore anim frame
int16 _talkTime; // TalkTime time of talk anim
Animation *_specAnim; // additional anim
Graphics::Surface *_zoomedHeroSurface;
uint16 _currHeight; // height of current anim phase
Common::Array<byte> _inventory; // Inventory array of items
Common::Array<byte> _inventory2; // Inventory2 array of items
// Font subtitiles font
int _color; // subtitles color
uint32 _animSetNr; // number of animation set
Common::Array<Animation *> _moveSet; // MoveAnims MoveSet
uint32 _moveDelay;
uint32 _shadMinus;
private:
PrinceEngine *_vm;
GraphicsMan *_graph;
};
} // End of namespace Prince
#endif

243
engines/prince/hero_set.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/>.
*
*/
#include "common/scummsys.h"
namespace Prince {
const int heroSetBack[7] = { 0, 0, 10, 0, 6, 0, 0 };
typedef const char *HeroSetAnimNames[26];
static HeroSetAnimNames heroSet5 = {
"SL_DIAB.ANI",
"SR_DIAB.ANI",
"SU_DIAB.ANI",
"SD_DIAB.ANI",
nullptr,
nullptr,
"MU_DIAB.ANI",
"MD_DIAB.ANI",
"TL_DIAB.ANI",
"TR_DIAB.ANI",
"TU_DIAB.ANI",
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr
};
static HeroSetAnimNames heroSet1 = {
"SL_HERO1.ANI",
"SR_HERO1.ANI",
"SU_HERO1.ANI",
"SD_HERO1.ANI",
"ML_HERO1.ANI",
"MR_HERO1.ANI",
"MU_HERO1.ANI",
"MD_HERO1.ANI",
"TL_HERO1.ANI",
"TR_HERO1.ANI",
"TU_HERO1.ANI",
"TD_HERO1.ANI",
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
"KSI_KURZ.ANI",
"KS_WLOSY.ANI"
};
static HeroSetAnimNames heroSet2 = {
"SL_HERO2.ANI",
"SR_HERO2.ANI",
"SU_HERO2.ANI",
"SD_HERO2.ANI",
"ML_HERO2.ANI",
"MR_HERO2.ANI",
"MU_HERO2.ANI",
"MD_HERO2.ANI",
"TL_HERO2.ANI",
"TR_HERO2.ANI",
"TU_HERO2.ANI",
"TD_HERO2.ANI",
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
"KSI_KU_S.ANI",
"KS_WLO_S.ANI"
};
static HeroSetAnimNames heroSet3 = {
"SL_BEAR.ANI",
"SR_BEAR.ANI",
"SU_BEAR.ANI",
"SD_BEAR.ANI",
"NIED-LEW.ANI",
"NIED-PRW.ANI",
"NIED-TYL.ANI",
"NIED-PRZ.ANI",
"SL_BEAR.ANI",
"SR_BEAR.ANI",
"SU_BEAR.ANI",
"SD_BEAR.ANI",
"N_LW-TYL.ANI",
"N_LW-PRZ.ANI",
"N_LW-PR.ANI",
"N_PR-TYL.ANI",
"N_PR-PRZ.ANI",
"N_PR-LW.ANI",
"N_TYL-LW.ANI",
"N_TYL-PR.ANI",
"N_TL-PRZ.ANI",
"N_PRZ-LW.ANI",
"N_PRZ-PR.ANI",
"N_PRZ-TL.ANI",
nullptr,
nullptr,
};
static HeroSetAnimNames shanSet1 = {
"SL_SHAN.ANI",
"SR_SHAN.ANI",
"SU_SHAN.ANI",
"SD_SHAN.ANI",
"ML_SHAN.ANI",
"MR_SHAN.ANI",
"MU_SHAN.ANI",
"MD_SHAN.ANI",
"TL_SHAN.ANI",
"TR_SHAN.ANI",
"TU_SHAN.ANI",
"TD_SHAN.ANI",
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
"B1_SHAN.ANI",
"B2_SHAN.ANI",
};
static HeroSetAnimNames shanSet2 = {
"SL_SHAN2.ANI",
"SR_SHAN2.ANI",
"SU_SHAN.ANI",
"SD_SHAN2.ANI",
"ML_SHAN2.ANI",
"MR_SHAN2.ANI",
"MU_SHAN.ANI",
"MD_SHAN2.ANI",
"TL_SHAN2.ANI",
"TR_SHAN2.ANI",
"TU_SHAN.ANI",
"TD_SHAN2.ANI",
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
"B1_SHAN2.ANI",
"B2_SHAN2.ANI"
};
static HeroSetAnimNames arivSet1 = {
"SL_ARIV.ANI",
"SR_ARIV.ANI",
"SU_ARIV.ANI",
"SD_ARIV.ANI",
"ML_ARIV.ANI",
"MR_ARIV.ANI",
"MU_ARIV.ANI",
"MD_ARIV.ANI",
"TL_ARIV.ANI",
"TR_ARIV.ANI",
"TU_ARIV.ANI",
"TD_ARIV.ANI",
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr
};
const HeroSetAnimNames *heroSetTable[7] = {
&heroSet1,
&heroSet2,
&heroSet3,
&shanSet1,
&arivSet1,
&heroSet5,
&shanSet2,
};
} // End of namespace Prince

View File

@@ -0,0 +1,736 @@
/* 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 "prince/prince.h"
#include "prince/graphics.h"
#include "prince/hero.h"
#include "prince/script.h"
#include "prince/mhwanh.h"
#include "prince/variatxt.h"
#include "prince/option_text.h"
#include "prince/font.h"
namespace Prince {
void PrinceEngine::addInv(int heroId, int item, bool addItemQuiet) {
Hero *hero = nullptr;
if (!heroId) {
hero = _mainHero;
} else if (heroId == 1) {
hero = _secondHero;
}
if (hero != nullptr) {
if (hero->_inventory.size() < kMaxItems) {
if (item != 0x7FFF) {
hero->_inventory.push_back(item);
}
if (!addItemQuiet) {
addInvObj();
}
_interpreter->setResult(0);
} else {
_interpreter->setResult(1);
}
}
}
void PrinceEngine::remInv(int heroId, int item) {
Hero *hero = nullptr;
if (!heroId) {
hero = _mainHero;
} else if (heroId == 1) {
hero = _secondHero;
}
if (hero != nullptr) {
for (uint i = 0; i < hero->_inventory.size(); i++) {
if (hero->_inventory[i] == item) {
hero->_inventory.remove_at(i);
_interpreter->setResult(0);
return;
}
}
}
_interpreter->setResult(1);
}
void PrinceEngine::clearInv(int heroId) {
switch (heroId) {
case 0:
_mainHero->_inventory.clear();
break;
case 1:
_secondHero->_inventory.clear();
break;
default:
error("clearInv() - wrong hero slot");
break;
}
}
void PrinceEngine::swapInv(int heroId) {
Common::Array<int> tempInv;
Hero *hero = nullptr;
if (!heroId) {
hero = _mainHero;
} else if (heroId == 1) {
hero = _secondHero;
}
if (hero != nullptr) {
for (uint i = 0; i < hero->_inventory.size(); i++) {
tempInv.push_back(hero->_inventory[i]);
}
hero->_inventory.clear();
for (uint i = 0; i < hero->_inventory2.size(); i++) {
hero->_inventory.push_back(hero->_inventory2[i]);
}
hero->_inventory2.clear();
for (uint i = 0; i < tempInv.size(); i++) {
hero->_inventory2.push_back(tempInv[i]);
}
tempInv.clear();
}
}
void PrinceEngine::addInvObj() {
changeCursor(0);
prepareInventoryToView();
_inventoryBackgroundRemember = true;
drawScreen();
Graphics::Surface *suitcase = _suitcaseBmp->getSurface();
if (!_flags->getFlagValue(Flags::CURSEBLINK)) {
loadSample(27, "PRZEDMIO.WAV");
playSample(27, 0);
_mst_shadow2 = 1;
while (_mst_shadow2 < 512) {
rememberScreenInv();
_graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
drawInvItems();
_graph->update(_graph->_screenForInventory);
_mst_shadow2 += 50;
Common::Event event;
Common::EventManager *eventMan = _system->getEventManager();
eventMan->pollEvent(event);
if (shouldQuit()) {
return;
}
pausePrinceEngine();
}
while (_mst_shadow2 > 256) {
rememberScreenInv();
_graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
drawInvItems();
_graph->update(_graph->_screenForInventory);
_mst_shadow2 -= 42;
Common::Event event;
Common::EventManager *eventMan = _system->getEventManager();
eventMan->pollEvent(event);
if (shouldQuit()) {
return;
}
pausePrinceEngine();
}
} else {
//CURSEBLINK:
for (int i = 0; i < 3; i++) {
_mst_shadow2 = 256;
while (_mst_shadow2 < 512) {
rememberScreenInv();
_graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
drawInvItems();
_graph->update(_graph->_screenForInventory);
_mst_shadow2 += 50;
Common::Event event;
Common::EventManager *eventMan = _system->getEventManager();
eventMan->pollEvent(event);
if (shouldQuit()) {
return;
}
pausePrinceEngine();
}
while (_mst_shadow2 > 256) {
rememberScreenInv();
_graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
drawInvItems();
_graph->update(_graph->_screenForInventory);
_mst_shadow2 -= 50;
Common::Event event;
Common::EventManager *eventMan = _system->getEventManager();
eventMan->pollEvent(event);
if (shouldQuit()) {
return;
}
pausePrinceEngine();
}
}
}
_mst_shadow2 = 0;
for (int i = 0; i < 20; i++) {
rememberScreenInv();
_graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
drawInvItems();
_graph->update(_graph->_screenForInventory);
Common::Event event;
Common::EventManager *eventMan = _system->getEventManager();
eventMan->pollEvent(event);
if (shouldQuit()) {
return;
}
pausePrinceEngine();
}
}
void PrinceEngine::rememberScreenInv() {
_graph->_screenForInventory->copyFrom(*_graph->_frontScreen);
}
void PrinceEngine::inventoryFlagChange(bool inventoryState) {
if (inventoryState) {
_showInventoryFlag = true;
_inventoryBackgroundRemember = true;
} else {
_showInventoryFlag = false;
}
}
void PrinceEngine::prepareInventoryToView() {
_invMobList.clear();
int invItem = _mainHero->_inventory.size();
_invLine = invItem / 3;
if (invItem % 3) {
_invLine++;
}
if (_invLine < 4) {
_invLine = 4;
}
_maxInvW = (374 - 2 * _invLine) / _invLine;
_invLineW = _maxInvW - 2;
int currInvX = _invLineX;
int currInvY = _invLineY;
Common::MemoryReadStream stream(_invTxt, _invTxtSize);
byte c;
uint item = 0;
for (int i = 0; i < _invLines; i++) {
for (int j = 0; j < _invLine; j++) {
Mob tempMobItem;
if (item < _mainHero->_inventory.size()) {
int itemNr = _mainHero->_inventory[item];
tempMobItem._visible = 0;
tempMobItem._mask = itemNr;
tempMobItem._rect = Common::Rect(currInvX + _picWindowX, currInvY, currInvX + _picWindowX + _invLineW - 1, currInvY + _invLineH - 1);
tempMobItem._type = 0; // to work with checkMob()
tempMobItem._name = "";
tempMobItem._examText = "";
int txtOffset = READ_LE_UINT32(&_invTxt[itemNr * 8]);
int examTxtOffset = READ_LE_UINT32(&_invTxt[itemNr * 8 + 4]);
stream.seek(txtOffset);
while ((c = stream.readByte())) {
tempMobItem._name += c;
}
stream.seek(examTxtOffset);
while ((c = stream.readByte())) {
tempMobItem._examText += c;
}
_invMobList.push_back(tempMobItem);
}
currInvX += _invLineW + _invLineSkipX;
item++;
}
currInvX = _invLineX;
currInvY += _invLineSkipY + _invLineH;
}
}
void PrinceEngine::drawInvItems() {
int currInvX = _invLineX;
int currInvY = _invLineY;
uint item = 0;
for (int i = 0; i < _invLines; i++) {
for (int j = 0; j < _invLine; j++) {
if (item < _mainHero->_inventory.size()) {
int itemNr = _mainHero->_inventory[item];
_mst_shadow = 0;
if (_mst_shadow2) {
if (!_flags->getFlagValue(Flags::CURSEBLINK)) {
if (item + 1 == _mainHero->_inventory.size()) { // last item in inventory
_mst_shadow = 1;
}
} else if (itemNr == 1 || itemNr == 3 || itemNr == 4 || itemNr == 7) {
_mst_shadow = 1;
}
}
int drawX = currInvX;
int drawY = currInvY;
Graphics::Surface *itemSurface = nullptr;
if (itemNr != 68) {
itemSurface = _allInvList[itemNr].getSurface();
if (itemSurface->h < _maxInvH) {
drawY += (_maxInvH - itemSurface->h) / 2;
}
} else {
// candle item:
if (_candleCounter == 8) {
_candleCounter = 0;
}
itemNr = _candleCounter;
_candleCounter++;
itemNr &= 7;
itemNr += 71;
itemSurface = _allInvList[itemNr].getSurface();
drawY += _allInvList[itemNr]._y + (_maxInvH - 76) / 2 - 200;
}
if (itemSurface->w < _maxInvW) {
drawX += (_maxInvW - itemSurface->w) / 2;
}
if (!_mst_shadow) {
_graph->drawTransparentSurface(_graph->_screenForInventory, drawX, drawY, itemSurface);
} else {
_mst_shadow = _mst_shadow2;
_graph->drawTransparentWithBlendSurface(_graph->_screenForInventory, drawX, drawY, itemSurface);
}
}
currInvX += _invLineW + _invLineSkipX;
item++;
}
currInvX = _invLineX;
currInvY += _invLineSkipY + _invLineH;
}
}
void PrinceEngine::inventoryLeftMouseButton() {
if (!_mouseFlag) {
_textSlots[0]._time = 0;
_textSlots[0]._str = nullptr;
stopTextToSpeech();
stopSample(28);
}
if (_optionsFlag == 1) {
if (_selectedMob != -1) {
if (_optionEnabled < _invOptionsNumber) {
_optionsFlag = 0;
} else {
return;
}
} else {
error("PrinceEngine::inventoryLeftMouseButton() - optionsFlag = 1, selectedMob = 0");
if (_currentPointerNumber == 2) {
changeCursor(1);
_currentPointerNumber = 1;
_selectedMob = -1;
_optionsMob = -1;
return;
} else {
return;
}
}
} else {
if (_selectedMob != -1) {
if (_currentPointerNumber != 2) {
if (_invMobList[_selectedMob]._mask != 29) {
_optionEnabled = 0;
} else {
// map item
_optionEnabled = 1;
}
} else {
//use_item_on_item
int invObjUU = _script->scanMobEventsWithItem(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjUU, _selectedItem);
if (invObjUU == -1) {
int textNr = 80011; // "I can't do it."
if (_selectedItem == 31 || _invMobList[_selectedMob]._mask == 31) {
textNr = 80020; // "Nothing is happening."
}
_interpreter->setCurrentString(textNr);
printAt(0, 216, (char *)_variaTxt->getString(textNr - 80000), kNormalWidth / 2, 100);
setVoice(0, 28, 1);
playSample(28, 0);
_selectedMob = -1;
_optionsMob = -1;
return;
} else {
_interpreter->storeNewPC(invObjUU);
_flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask);
_showInventoryFlag = false;
}
}
} else {
return;
}
}
//do_option
if (_optionEnabled == 0) {
int invObjExamEvent = _script->scanMobEvents(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjExam);
if (invObjExamEvent == -1) {
static char buf[256];
strncpy(buf, _invMobList[_selectedMob]._examText.c_str(), 256);
printAt(0, 216, buf, kNormalWidth / 2, _invExamY);
_interpreter->setCurrentString(_invMobList[_selectedMob]._mask + 70000);
setVoice(0, 28, 1);
playSample(28, 0);
// disableuseuse
changeCursor(0);
_currentPointerNumber = 1;
} else {
_interpreter->storeNewPC(invObjExamEvent);
_flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask);
_showInventoryFlag = false;
}
} else if (_optionEnabled == 1) {
// not_examine
int invObjUse = _script->scanMobEvents(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjUse);
if (invObjUse == -1) {
// do_standard_use
_selectedMode = 0;
_selectedItem = _invMobList[_selectedMob]._mask;
makeInvCursor(_invMobList[_selectedMob]._mask);
_currentPointerNumber = 2;
changeCursor(2);
} else {
_interpreter->storeNewPC(invObjUse);
_flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask);
_showInventoryFlag = false;
}
} else if (_optionEnabled == 4) {
// do_standard_give
_selectedMode = 1;
_selectedItem = _invMobList[_selectedMob]._mask;
makeInvCursor(_invMobList[_selectedMob]._mask);
_currentPointerNumber = 2;
changeCursor(2);
} else {
// use_item_on_item
int invObjUU = _script->scanMobEventsWithItem(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjUU, _selectedItem);
if (invObjUU == -1) {
int textNr = 80011; // "I can't do it."
if (_selectedItem == 31 || _invMobList[_selectedMob]._mask == 31) {
textNr = 80020; // "Nothing is happening."
}
_interpreter->setCurrentString(textNr);
printAt(0, 216, (char *)_variaTxt->getString(textNr - 80000), kNormalWidth / 2, 100);
setVoice(0, 28, 1);
playSample(28, 0);
} else {
_interpreter->storeNewPC(invObjUU);
_flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask);
_showInventoryFlag = false;
}
}
_selectedMob = -1;
_optionsMob = -1;
}
void PrinceEngine::inventoryRightMouseButton() {
if (_textSlots[0]._str == nullptr) {
enableOptions(false);
}
}
void PrinceEngine::enableOptions(bool checkType) {
if (_optionsFlag != 1) {
changeCursor(1);
_currentPointerNumber = 1;
if (_selectedMob != -1) {
if (checkType) {
if (_mobList[_selectedMob]._type & 0x100) {
return;
}
}
Common::Point mousePos = _system->getEventManager()->getMousePos();
int x1 = mousePos.x - _optionsWidth / 2;
int x2 = mousePos.x + _optionsWidth / 2;
if (x1 < 0) {
x1 = 0;
x2 = _optionsWidth;
} else if (x2 >= kNormalWidth) {
x1 = kNormalWidth - _optionsWidth;
x2 = kNormalWidth;
}
int y1 = mousePos.y - 10;
if (y1 < 0) {
y1 = 0;
}
if (y1 + _optionsHeight >= kNormalHeight) {
y1 = kNormalHeight - _optionsHeight;
}
_optionsMob = _selectedMob;
_optionsX = x1;
_optionsY = y1;
_optionsFlag = 1;
}
}
}
void PrinceEngine::checkOptions() {
if (_optionsFlag) {
Common::Rect optionsRect(_optionsX, _optionsY, _optionsX + _optionsWidth, _optionsY + _optionsHeight);
Common::Point mousePos = _system->getEventManager()->getMousePos();
if (!optionsRect.contains(mousePos)) {
_optionsFlag = 0;
_selectedMob = -1;
return;
}
_graph->drawAsShadowSurface(_graph->_frontScreen, _optionsX, _optionsY, _optionsPic, _graph->_shadowTable50);
int previousOption = _optionEnabled;
_optionEnabled = -1;
int optionsYCord = mousePos.y - (_optionsY + 16);
if (optionsYCord >= 0) {
int selectedOptionNr = optionsYCord / _optionsStep;
if (selectedOptionNr < _optionsNumber) {
_optionEnabled = selectedOptionNr;
}
}
int optionsColor;
int textY = _optionsY + 16;
for (int i = 0; i < _optionsNumber; i++) {
Common::String optText;
switch(getLanguage()) {
case Common::PL_POL:
optText = optionsTextPL[i];
break;
case Common::DE_DEU:
optText = optionsTextDE[i];
break;
case Common::EN_ANY:
optText = optionsTextEN[i];
break;
case Common::ES_ESP:
optText = optionsTextES[i];
break;
case Common::RU_RUS:
if (getFeatures() & GF_RUSPROJEDITION) {
optText = optionsTextRU2[i];
} else {
optText = optionsTextRU[i];
}
break;
default:
break;
};
if (i != _optionEnabled) {
optionsColor = _optionsColor1;
} else {
optionsColor = _optionsColor2;
if (_optionEnabled != previousOption) {
setTTSVoice(kHeroTextColor);
sayText(optText, false);
}
}
uint16 textW = getTextWidth(optText.c_str());
uint16 textX = _optionsX + _optionsWidth / 2 - textW / 2;
_font->drawString(_graph->_frontScreen, optText, textX, textY, textW, optionsColor);
textY += _optionsStep;
}
}
}
void PrinceEngine::checkInvOptions() {
if (_optionsFlag) {
Common::Rect optionsRect(_optionsX, _optionsY, _optionsX + _invOptionsWidth, _optionsY + _invOptionsHeight);
Common::Point mousePos = _system->getEventManager()->getMousePos();
if (!optionsRect.contains(mousePos)) {
_optionsFlag = 0;
_selectedMob = -1;
return;
}
_graph->drawAsShadowSurface(_graph->_screenForInventory, _optionsX, _optionsY, _optionsPicInInventory, _graph->_shadowTable50);
int previousOption = _optionEnabled;
_optionEnabled = -1;
int optionsYCord = mousePos.y - (_optionsY + 16);
if (optionsYCord >= 0) {
int selectedOptionNr = optionsYCord / _invOptionsStep;
if (selectedOptionNr < _invOptionsNumber) {
_optionEnabled = selectedOptionNr;
}
}
int optionsColor;
int textY = _optionsY + 16;
for (int i = 0; i < _invOptionsNumber; i++) {
Common::String invText;
switch(getLanguage()) {
case Common::PL_POL:
invText = invOptionsTextPL[i];
break;
case Common::DE_DEU:
invText = invOptionsTextDE[i];
break;
case Common::EN_ANY:
invText = invOptionsTextEN[i];
break;
case Common::ES_ESP:
invText = invOptionsTextES[i];
break;
case Common::RU_RUS:
if (getFeatures() & GF_RUSPROJEDITION) {
invText = invOptionsTextRU2[i];
} else {
invText = invOptionsTextRU[i];
}
break;
default:
error("Unknown game language %d", getLanguage());
break;
};
if (i != _optionEnabled) {
optionsColor = _optionsColor1;
} else {
optionsColor = _optionsColor2;
if (_optionEnabled != previousOption) {
setTTSVoice(kHeroTextColor);
sayText(invText, false);
}
}
uint16 textW = getTextWidth(invText.c_str());
uint16 textX = _optionsX + _invOptionsWidth / 2 - textW / 2;
_font->drawString(_graph->_screenForInventory, invText, textX, textY, _graph->_screenForInventory->w, optionsColor);
textY += _invOptionsStep;
}
}
}
void PrinceEngine::displayInventory() {
_mainHero->freeOldMove();
_secondHero->freeOldMove();
_interpreter->setFgOpcodePC(0);
stopAllSamples();
prepareInventoryToView();
while (!shouldQuit()) {
if (_textSlots[0]._str != nullptr) {
changeCursor(0);
} else {
changeCursor(_currentPointerNumber);
Common::Rect inventoryRect(_invX1, _invY1, _invX1 + _invWidth, _invY1 + _invHeight);
Common::Point mousePos = _system->getEventManager()->getMousePos();
if (!_invCurInside && inventoryRect.contains(mousePos)) {
_invCurInside = true;
}
if (_invCurInside && !inventoryRect.contains(mousePos)) {
inventoryFlagChange(false);
_invCurInside = false;
break;
}
}
rememberScreenInv();
Graphics::Surface *suitcase = _suitcaseBmp->getSurface();
_graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
drawInvItems();
showTexts(_graph->_screenForInventory);
if (!_optionsFlag && _textSlots[0]._str == nullptr) {
_selectedMob = checkMob(_graph->_screenForInventory, _invMobList, false);
}
checkInvOptions();
Common::Event event;
Common::EventManager *eventMan = _system->getEventManager();
while (eventMan->pollEvent(event)) {
switch (event.type) {
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
keyHandler(event);
break;
case Common::EVENT_LBUTTONDOWN:
inventoryLeftMouseButton();
break;
case Common::EVENT_RBUTTONDOWN:
inventoryRightMouseButton();
break;
default:
break;
}
}
if (!_showInventoryFlag) {
break;
}
if (shouldQuit())
return;
_graph->update(_graph->_screenForInventory);
pausePrinceEngine();
}
if (_currentPointerNumber == 2) {
_flags->setFlagValue(Flags::SELITEM, _selectedItem);
} else {
_flags->setFlagValue(Flags::SELITEM, 0);
}
}
void PrinceEngine::openInventoryCheck() {
if (!_optionsFlag) {
if (_mouseFlag == 1 || _mouseFlag == 2) {
if (_mainHero->_visible) {
if (!_flags->getFlagValue(Flags::INVALLOWED)) {
// 29 - Basement, 50 - Map
if (_locationNr != 29 && _locationNr != 50) {
Common::Point mousePos = _system->getEventManager()->getMousePos();
if (mousePos.y < 4 && !_showInventoryFlag) {
_invCounter++;
} else {
_invCounter = 0;
}
if (_invCounter >= _invMaxCount) {
inventoryFlagChange(true);
}
}
}
}
}
}
}
} // End of namespace Prince

View File

@@ -0,0 +1,282 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/translation.h"
#include "engines/advancedDetector.h"
#include "prince/prince.h"
#include "prince/detection.h"
#include "backends/keymapper/action.h"
#include "backends/keymapper/keymapper.h"
#include "backends/keymapper/standard-actions.h"
namespace Prince {
#ifdef USE_TTS
static const ADExtraGuiOptionsMap optionsList[] = {
{
GAMEOPTION_TTS_OBJECTS,
{
_s("Enable Text to Speech for Objects and Options"),
_s("Use TTS to read the descriptions (if TTS is available)"),
"tts_enabled_objects",
false,
0,
0
}
},
{
GAMEOPTION_TTS_SPEECH,
{
_s("Enable Text to Speech for Subtitles"),
_s("Use TTS to read the subtitles (if TTS is available)"),
"tts_enabled_speech",
false,
0,
0
}
},
{
GAMEOPTION_TTS_MISSING_VOICE,
{
_s("Enable Text to Speech for Missing Voiceovers"),
_s("Use TTS to read the subtitles of missing voiceovers (if TTS is available)"),
"tts_enabled_missing_voice",
false,
0,
0
}
},
AD_EXTRA_GUI_OPTIONS_TERMINATOR
};
#endif
int PrinceEngine::getGameType() const {
return _gameDescription->gameType;
}
const char *PrinceEngine::getGameId() const {
return _gameDescription->desc.gameId;
}
uint32 PrinceEngine::getFeatures() const {
return _gameDescription->desc.flags;
}
Common::Language PrinceEngine::getLanguage() const {
return _gameDescription->desc.language;
}
} // End of namespace Prince
class PrinceMetaEngine : public AdvancedMetaEngine<Prince::PrinceGameDescription> {
public:
const char *getName() const override {
return "prince";
}
#ifdef USE_TTS
const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override {
return Prince::optionsList;
}
#endif
Common::Error createInstance(OSystem *syst, Engine **engine, const Prince::PrinceGameDescription *desc) const override;
bool hasFeature(MetaEngineFeature f) const override;
int getMaximumSaveSlot() const override { return 99; }
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 PrinceMetaEngine::hasFeature(MetaEngineFeature f) const {
return
(f == kSupportsDeleteSave) ||
(f == kSavesSupportMetaInfo) ||
(f == kSavesSupportThumbnail) ||
(f == kSavesSupportCreationDate) ||
(f == kSavesSupportPlayTime) ||
(f == kSupportsListSaves) ||
(f == kSupportsLoadingDuringStartup) ||
(f == kSimpleSavesNames);
}
bool Prince::PrinceEngine::hasFeature(EngineFeature f) const {
return
(f == kSupportsLoadingDuringRuntime) ||
(f == kSupportsSavingDuringRuntime) ||
(f == kSupportsReturnToLauncher);
}
SaveStateList PrinceMetaEngine::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) {
Prince::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, kSavegameStr, kSavegameStrSize + 1)) {
// Valid savegame
if (Prince::PrinceEngine::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;
}
}
}
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
SaveStateDescriptor PrinceMetaEngine::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) {
Prince::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, kSavegameStr, kSavegameStrSize + 1) &&
Prince::PrinceEngine::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);
desc.setPlayTime(header.playTime * 1000);
return desc;
}
}
return SaveStateDescriptor();
}
bool PrinceMetaEngine::removeSaveState(const char *target, int slot) const {
Common::String fileName = Common::String::format("%s.%03d", target, slot);
return g_system->getSavefileManager()->removeSavefile(fileName);
}
Common::Error PrinceMetaEngine::createInstance(OSystem *syst, Engine **engine, const Prince::PrinceGameDescription *desc) const {
*engine = new Prince::PrinceEngine(syst,desc);
return Common::kNoError;
}
Common::KeymapArray PrinceMetaEngine::initKeymaps(const char *target) const {
using namespace Common;
using namespace Prince;
Keymap *engineKeyMap = new Keymap(Keymap::kKeymapTypeGame, "prince-default", _("Default keymappings"));
Common::Action *act;
act = new Common::Action(kStandardActionLeftClick, _("Move / Interact"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
engineKeyMap->addAction(act);
act = new Common::Action(kStandardActionRightClick, _("Open interaction menu"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
engineKeyMap->addAction(act);
act = new Common::Action("SAVE", _("Save game"));
act->setCustomEngineActionEvent(kActionSave);
act->addDefaultInputMapping("F1");
act->addDefaultInputMapping("JOY_X");
engineKeyMap->addAction(act);
act = new Action("LOAD", _("Load game"));
act->setCustomEngineActionEvent(kActionLoad);
act->addDefaultInputMapping("F2");
act->addDefaultInputMapping("JOY_Y");
engineKeyMap->addAction(act);
// I18N: This refers to the Z key on a keyboard.
act = new Action("Z", _("Z key")); // TODO: Rename this action to better reflect its use in the prison cell minigame near the end of the game.
act->setCustomEngineActionEvent(kActionZ);
act->addDefaultInputMapping("z");
act->addDefaultInputMapping("JOY_LEFT");
engineKeyMap->addAction(act);
// I18N: This refers to the X key on a keyboard.
act = new Action("X", _("X key")); // TODO: Rename this action to better reflect its use in the prison cell minigame near the end of the game.
act->setCustomEngineActionEvent(kActionX);
act->addDefaultInputMapping("x");
act->addDefaultInputMapping("JOY_RIGHT");
engineKeyMap->addAction(act);
act = new Action("SKIP", _("Skip"));
act->setCustomEngineActionEvent(kActionSkip);
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_UP");
engineKeyMap->addAction(act);
return Keymap::arrayOf(engineKeyMap);
}
#if PLUGIN_ENABLED_DYNAMIC(PRINCE)
REGISTER_PLUGIN_DYNAMIC(PRINCE, PLUGIN_TYPE_ENGINE, PrinceMetaEngine);
#else
REGISTER_PLUGIN_STATIC(PRINCE, PLUGIN_TYPE_ENGINE, PrinceMetaEngine);
#endif

68
engines/prince/mhwanh.cpp Normal file
View File

@@ -0,0 +1,68 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/stream.h"
#include "graphics/surface.h"
#include "prince/mhwanh.h"
namespace Prince {
MhwanhDecoder::MhwanhDecoder() : _surface(nullptr), _palette(0) {
}
MhwanhDecoder::~MhwanhDecoder() {
destroy();
}
void MhwanhDecoder::destroy() {
if (_surface != nullptr) {
_surface->free();
delete _surface;
_surface = nullptr;
}
_palette.clear();
}
bool MhwanhDecoder::loadStream(Common::SeekableReadStream &stream) {
destroy();
stream.seek(0);
stream.skip(0x20);
// Read the palette
_palette.resize(kPaletteColorCount, false);
for (uint16 i = 0; i < kPaletteColorCount; i++) {
byte r = stream.readByte();
byte g = stream.readByte();
byte b = stream.readByte();
_palette.set(i, r, g, b);
}
_surface = new Graphics::Surface();
_surface->create(640, 480, Graphics::PixelFormat::createFormatCLUT8());
for (int h = 0; h < 480; h++) {
stream.read(_surface->getBasePtr(0, h), 640);
}
return true;
}
} // End of namespace Prince

54
engines/prince/mhwanh.h Normal file
View File

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

276
engines/prince/mob.cpp Normal file
View File

@@ -0,0 +1,276 @@
/* 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 "prince/prince.h"
#include "prince/mob.h"
#include "prince/animation.h"
#include "prince/font.h"
namespace Prince {
bool Mob::loadFromStream(Common::SeekableReadStream &stream) {
int32 pos = stream.pos();
uint16 visible = stream.readUint16LE();
if (visible == 0xFFFF)
return false;
_visible = visible;
_type = stream.readUint16LE();
_rect.left = stream.readUint16LE();
_rect.top = stream.readUint16LE();
_rect.right = stream.readUint16LE();
_rect.bottom = stream.readUint16LE();
_mask = stream.readUint16LE();
_examPosition.x = stream.readUint16LE();
_examPosition.y = stream.readUint16LE();
_examDirection = (Direction)stream.readUint16LE();
_usePosition.x = stream.readByte();
_usePosition.y = stream.readByte();
_useDirection = (Direction)stream.readUint16LE();
uint32 nameOffset = stream.readUint32LE();
uint32 examTextOffset = stream.readUint32LE();
byte c;
stream.seek(nameOffset);
_name.clear();
while ((c = stream.readByte()))
_name += c;
stream.seek(examTextOffset);
_examText.clear();
c = stream.readByte();
if (c) {
_examText += c;
do {
c = stream.readByte();
_examText += c;
} while (c != 255);
}
stream.seek(pos + 32);
return true;
}
void Mob::setData(AttrId dataId, uint16 value) {
switch (dataId) {
case kMobExamDir:
_examDirection = (Direction)value;
break;
case kMobExamX:
_examPosition.x = value;
break;
case kMobExamY:
_examPosition.y = value;
break;
default:
assert(false);
}
}
uint16 Mob::getData(AttrId dataId) {
switch (dataId) {
case kMobVisible:
return _visible;
case kMobExamDir:
return _examDirection;
case kMobExamX:
return _examPosition.x;
case kMobExamY:
return _examPosition.y;
default:
assert(false);
return 0;
}
}
int PrinceEngine::getMob(Common::Array<Mob> &mobList, bool usePriorityList, int posX, int posY) {
Common::Point pointPos(posX, posY);
int mobListSize;
if (usePriorityList) {
mobListSize = _mobPriorityList.size();
} else {
mobListSize = mobList.size();
}
for (int mobNumber = 0; mobNumber < mobListSize; mobNumber++) {
Mob *mob = nullptr;
if (usePriorityList) {
mob = &mobList[_mobPriorityList[mobNumber]];
} else {
mob = &mobList[mobNumber];
}
if (mob->_visible) {
continue;
}
int type = mob->_type & 7;
switch (type) {
case 0:
case 1:
//normal_mob
if (!mob->_rect.contains(pointPos)) {
continue;
}
break;
case 3:
//mob_obj
if (mob->_mask < kMaxObjects) {
int nr = _objSlot[mob->_mask];
if (nr != 0xFF) {
Object &obj = *_objList[nr];
Common::Rect objectRect(obj._x, obj._y, obj._x + obj._width, obj._y + obj._height);
if (objectRect.contains(pointPos)) {
Graphics::Surface *objSurface = obj.getSurface();
byte *pixel = (byte *)objSurface->getBasePtr(posX - obj._x, posY - obj._y);
if (*pixel != 255) {
break;
}
}
}
}
continue;
break;
case 2:
case 5:
//check_ba_mob
if (!_backAnimList[mob->_mask].backAnims.empty()) {
int currentAnim = _backAnimList[mob->_mask]._seq._currRelative;
Anim &backAnim = _backAnimList[mob->_mask].backAnims[currentAnim];
if (backAnim._animData != nullptr) {
if (!backAnim._state) {
Common::Rect backAnimRect(backAnim._currX, backAnim._currY, backAnim._currX + backAnim._currW, backAnim._currY + backAnim._currH);
if (backAnimRect.contains(pointPos)) {
int phase = backAnim._showFrame;
int phaseFrameIndex = backAnim._animData->getPhaseFrameIndex(phase);
Graphics::Surface *backAnimSurface = backAnim._animData->getFrame(phaseFrameIndex);
byte pixel = *(byte *)backAnimSurface->getBasePtr(posX - backAnim._currX, posY - backAnim._currY);
if (pixel != 255) {
if (type == 5) {
if (mob->_rect.contains(pointPos)) {
break;
}
} else {
break;
}
}
}
}
}
}
continue;
break;
default:
//not_part_ba
continue;
break;
}
if (usePriorityList) {
return _mobPriorityList[mobNumber];
} else {
return mobNumber;
}
}
return -1;
}
int PrinceEngine::checkMob(Graphics::Surface *screen, Common::Array<Mob> &mobList, bool usePriorityList) {
if (_mouseFlag == 0 || _mouseFlag == 3) {
return -1;
}
Common::Point mousePos = _system->getEventManager()->getMousePos();
int mobNumber = getMob(mobList, usePriorityList, mousePos.x + _picWindowX, mousePos.y);
if (mobNumber != -1) {
Common::String mobName = mobList[mobNumber]._name;
if (getLanguage() == Common::DE_DEU) {
for (uint i = 0; i < mobName.size(); i++) {
switch (mobName[i]) {
case '\xc4':
mobName.setChar('\x83', i);
break;
case '\xd6':
mobName.setChar('\x84', i);
break;
case '\xdc':
mobName.setChar('\x85', i);
break;
case '\xdf':
mobName.setChar('\x7f', i);
break;
case '\xe4':
mobName.setChar('\x80', i);
break;
case '\xf6':
mobName.setChar('\x81', i);
break;
case '\xfc':
mobName.setChar('\x82', i);
break;
default:
break;
}
}
}
// _selectedMob can't be used here, as it gets reset when the player clicks, causing the mob
// name to be voiced again
if (mobNumber != _previousMob) {
setTTSVoice(kHeroTextColor);
sayText(mobName, false);
}
uint16 textW = getTextWidth(mobName.c_str());
uint16 x = mousePos.x - textW / 2;
if (x > screen->w) {
x = 0;
}
if (x + textW > screen->w) {
x = screen->w - textW;
}
uint16 y = mousePos.y - _font->getFontHeight();
if (y > screen->h) {
y = _font->getFontHeight() - 2;
}
_font->drawString(screen, mobName, x, y, screen->w, 216);
}
_previousMob = mobNumber;
return mobNumber;
}
} // End of namespace Prince

69
engines/prince/mob.h Normal file
View File

@@ -0,0 +1,69 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PRINCE_MOB_H
#define PRINCE_MOB_H
#include "common/scummsys.h"
#include "common/rect.h"
#include "common/str.h"
#include "common/stream.h"
#include "prince/common.h"
namespace Prince {
class Mob {
public:
Mob() : _name(""), _examText(""), _visible(false), _type(0), _mask(0), _examDirection(kDirL), _useDirection(kDirL) {}
bool loadFromStream(Common::SeekableReadStream &stream);
// Used instead of offset in setData and getData
enum AttrId {
kMobVisible = 0,
kMobExamX = 14,
kMobExamY = 16,
kMobExamDir = 18
};
void setData(AttrId dataId, uint16 value);
uint16 getData(AttrId dataId);
bool _visible;
uint16 _type;
uint16 _mask;
Common::Rect _rect;
Common::Point _examPosition;
Direction _examDirection;
Common::Point _usePosition;
Direction _useDirection;
Common::String _name;
Common::String _examText;
};
} // End of namespace Prince
#endif

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

@@ -0,0 +1,39 @@
MODULE := engines/prince
MODULE_OBJS = \
animation.o \
archive.o \
cursor.o \
debugger.o \
decompress.o \
draw.o \
flags.o \
font.o \
graphics.o \
hero.o \
inventory.o \
metaengine.o \
mhwanh.o \
music.o \
mob.o \
object.o \
prince.o \
pscr.o \
resource.o \
saveload.o \
script.o \
sound.o \
variatxt.o \
videoplayer.o \
walk.o
# This module can be built as a plugin
ifeq ($(ENABLE_PRINCE), DYNAMIC_PLUGIN)
PLUGIN := 1
endif
# Include common rules
include $(srcdir)/rules.mk
# Detection objects
DETECT_OBJS += $(MODULE)/detection.o

86
engines/prince/musNum.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/>.
*
*/
namespace Prince {
enum RoomMus {
ROOM01MUS = 3,
ROOM02MUS = 9,
ROOM03MUS = 9,
ROOM04MUS = 9,
ROOM05MUS = 13,
ROOM06MUS = 9,
ROOM07MUS = 9,
ROOM08MUS = 9,
ROOM09MUS = 14,
ROOM10MUS = 9,
ROOM11MUS = 9,
ROOM12MUS = 9,
ROOM13MUS = 9,
ROOM14MUS = 9,
ROOM15MUS = 5,
ROOM16MUS = 5,
ROOM17MUS = 5,
ROOM18MUS = 5,
ROOM19MUS = 5,
ROOM20MUS = 12,
ROOM21MUS = 9,
ROOM22MUS = 9,
ROOM23MUS = 1,
ROOM24MUS = 1,
ROOM25MUS = 2,
ROOM26MUS = 10,
ROOM27MUS = 7,
ROOM28MUS = 10,
ROOM29MUS = 10,
ROOM30MUS = 11,
ROOM31MUS = 14,
ROOM32MUS = 11,
ROOM33MUS = 7,
ROOM34MUS = 7,
ROOM35MUS = 7,
ROOM36MUS = 7,
ROOM37MUS = 7,
ROOM38MUS = 7,
ROOM39MUS = 7,
ROOM40MUS = 7,
ROOM41MUS = 7,
ROOM42MUS = 7,
ROOM43MUS = 15,
ROOM46MUS = 100,
ROOM47MUS = 100,
ROOM48MUS = 100,
ROOM49MUS = 100,
ROOM50MUS = 100,
ROOM51MUS = 12,
ROOM52MUS = 9,
ROOM53MUS = 5,
ROOM54MUS = 11,
ROOM55MUS = 11,
ROOM56MUS = 11,
ROOM57MUS = 7,
ROOM58MUS = 13,
ROOM59MUS = 16,
ROOM60MUS = 4,
ROOM61MUS = 0
};
} // End of namespace Prince

235
engines/prince/music.cpp Normal file
View File

@@ -0,0 +1,235 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "prince/prince.h"
#include "prince/music.h"
#include "prince/musNum.h"
#include "prince/resource.h"
#include "common/archive.h"
#include "common/debug.h"
#include "audio/mididrv.h"
#include "audio/midiparser.h"
namespace Prince {
const char *MusicPlayer::_musTable[] = {
"",
"Battlfld.mid",
"Cave.mid",
"Cemetery.mid",
"Credits.mid",
"Fjord.mid",
"Guitar.mid",
"Hell.mid",
"Jingle.mid",
"Main.mid",
"Night.mid",
"Reality.mid",
"Sunlord.mid",
"Tavern.mid",
"Temple.mid",
"Boruta.mid",
"Intro.mid"
};
const uint8 MusicPlayer::_musRoomTable[] = {
0,
ROOM01MUS,
ROOM02MUS,
ROOM03MUS,
ROOM04MUS,
ROOM05MUS,
ROOM06MUS,
ROOM07MUS,
ROOM08MUS,
ROOM09MUS,
ROOM10MUS,
ROOM11MUS,
ROOM12MUS,
ROOM13MUS,
ROOM14MUS,
ROOM15MUS,
ROOM16MUS,
ROOM17MUS,
ROOM18MUS,
ROOM19MUS,
ROOM20MUS,
ROOM21MUS,
ROOM22MUS,
ROOM23MUS,
ROOM24MUS,
ROOM25MUS,
ROOM26MUS,
ROOM27MUS,
ROOM28MUS,
ROOM29MUS,
ROOM30MUS,
ROOM31MUS,
ROOM32MUS,
ROOM33MUS,
ROOM34MUS,
ROOM35MUS,
ROOM36MUS,
ROOM37MUS,
ROOM38MUS,
ROOM39MUS,
ROOM40MUS,
ROOM41MUS,
ROOM42MUS,
ROOM43MUS,
0,
0,
ROOM46MUS,
ROOM47MUS,
ROOM48MUS,
ROOM49MUS,
ROOM50MUS,
ROOM51MUS,
ROOM52MUS,
ROOM53MUS,
ROOM54MUS,
ROOM55MUS,
ROOM56MUS,
ROOM57MUS,
ROOM58MUS,
ROOM59MUS,
ROOM60MUS,
ROOM61MUS
};
MusicPlayer::MusicPlayer(PrinceEngine *vm) : _vm(vm) {
_data = nullptr;
_dataSize = 0;
_isGM = false;
MidiPlayer::createDriver();
int ret = _driver->open();
if (ret == 0) {
if (_nativeMT32)
_driver->sendMT32Reset();
else
_driver->sendGMReset();
_driver->setTimerCallback(this, &timerCallback);
}
}
MusicPlayer::~MusicPlayer() {
killMidi();
}
void MusicPlayer::killMidi() {
Audio::MidiPlayer::stop();
free(_data);
_data = nullptr;
}
void MusicPlayer::loadMidi(const char *name) {
Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(name);
if (!stream) {
warning("Can't load midi stream %s", name);
return;
}
stream = Resource::getDecompressedStream(stream);
// Stop any currently playing MIDI file
killMidi();
// Read in the data for the file
_dataSize = stream->size();
_data = (byte *)malloc(_dataSize);
stream->read(_data, _dataSize);
delete stream;
// 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);
}
bool PrinceEngine::loadMusic(int musNumber) {
uint8 midiNumber = MusicPlayer::_musRoomTable[musNumber];
if (midiNumber) {
if (midiNumber != 100) {
if (_currentMidi != midiNumber) {
_currentMidi = midiNumber;
const char *musName = MusicPlayer::_musTable[_currentMidi];
_midiPlayer->loadMidi(musName);
}
}
} else {
stopMusic();
}
return true;
}
void PrinceEngine::stopMusic() {
if (_midiPlayer->isPlaying()) {
_midiPlayer->stop();
}
}
} // End of namespace Prince

60
engines/prince/music.h Normal file
View File

@@ -0,0 +1,60 @@
/* 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 PRINCE_MUSIC_H
#define PRINCE_MUSIC_H
#include "audio/midiplayer.h"
#include "common/memstream.h"
namespace Prince {
class PrinceEngine;
class MusicPlayer: public Audio::MidiPlayer {
private:
PrinceEngine *_vm;
byte *_data;
int _dataSize;
bool _isGM;
// Start MIDI File
void sndMidiStart();
// Stop MIDI File
void sndMidiStop();
public:
MusicPlayer(PrinceEngine *vm);
~MusicPlayer() override;
void loadMidi(const char *);
void killMidi();
void send(uint32 b) override;
void sendToChannel(byte channel, uint32 b) override;
static const char *_musTable[];
static const uint8 _musRoomTable[];
};
} // End of namespace Prince
#endif

115
engines/prince/object.cpp Normal file
View File

@@ -0,0 +1,115 @@
/* 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/archive.h"
#include "common/debug-channels.h"
#include "common/debug.h"
#include "common/stream.h"
#include "graphics/surface.h"
#include "prince/object.h"
#include "prince/resource.h"
namespace Prince {
Object::Object() : _surface(nullptr), _x(0), _y(0), _z(0), _flags(0), _width(0),
_height(0), _zoomTime(0), _zoomSurface(nullptr)
{
}
Object::~Object() {
if (_surface != nullptr) {
_surface->free();
delete _surface;
_surface = nullptr;
}
if (_zoomSurface != nullptr) {
_zoomSurface->free();
delete _zoomSurface;
_zoomSurface = nullptr;
}
}
void Object::loadSurface(Common::SeekableReadStream &stream) {
stream.skip(4);
_width = stream.readUint16LE();
_height = stream.readUint16LE();
_surface = new Graphics::Surface();
_surface->create(_width, _height, Graphics::PixelFormat::createFormatCLUT8());
for (int h = 0; h < _surface->h; h++) {
stream.read(_surface->getBasePtr(0, h), _surface->w);
}
}
bool Object::loadFromStream(Common::SeekableReadStream &stream) {
int32 pos = stream.pos();
uint16 x = stream.readUint16LE();
if (x == 0xFFFF) {
return false;
}
_x = x;
_y = stream.readSint16LE(); // skull mini-game has some signed y coords
const Common::Path obStreamName(Common::String::format("OB%02d", stream.readUint16LE()));
Common::SeekableReadStream *obStream = SearchMan.createReadStreamForMember(obStreamName);
if (obStream) {
obStream = Resource::getDecompressedStream(obStream);
loadSurface(*obStream);
}
delete obStream;
_flags = stream.readUint16LE();
_z = stream.readUint16LE();
stream.seek(pos + 16);
return true;
}
void Object::setData(AttrId dataId, int32 value) {
switch (dataId) {
case kObjectX:
_x = value;
break;
case kObjectY:
_y = value;
break;
default:
assert(false);
}
}
int32 Object::getData(AttrId dataId) {
switch (dataId) {
case kObjectX:
return _x;
case kObjectY:
return _y;
default:
assert(false);
return 0;
}
}
} // End of namespace Prince

69
engines/prince/object.h Normal file
View File

@@ -0,0 +1,69 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PRINCE_OBJECT_H
#define PRINCE_OBJECT_H
#include "image/image_decoder.h"
#include "graphics/surface.h"
namespace Prince {
class Object {
public:
Object();
~Object();
int32 _x;
int32 _y;
int32 _z;
uint16 _width;
uint16 _height;
int32 _flags;
int32 _zoomTime;
Graphics::Surface *_zoomSurface;
// Used instead of offset in setData and getData
enum AttrId {
kObjectAddr = 0,
kObjectX = 4,
kObjectY = 6,
kObjectZ = 8,
kObjectFlags = 10,
kObjectZoomInSource = 12,
kObjectZoomInLen = 16,
kObjectZoomInAddr = 20,
kObjectZoomInTime = 24
};
bool loadFromStream(Common::SeekableReadStream &stream);
Graphics::Surface *getSurface() const { return _surface; }
int32 getData(AttrId dataId);
void setData(AttrId dataId, int32 value);
private:
void loadSurface(Common::SeekableReadStream &stream);
Graphics::Surface *_surface;
};
} // End of namespace Prince
#endif

View File

@@ -0,0 +1,141 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace Prince {
// PL - Mazovia coding
const char invOptionsTextPL[5][18] = {
"Obejrzyj",
"U\xa7""yj",
"Otw\xa2""rz/Pchnij",
"Zamknij/Poci\x86""gnij",
"Daj"
};
const char optionsTextPL[7][18] = {
"Podejd\xa6",
"Obejrzyj",
"Zabierz",
"U\xa7""yj",
"Otw\xa2""rz/Pchnij",
"Zamknij/Poci\x86""gnij",
"Porozmawiaj"
};
// DE - Other font then for PL + ISO 8859-2 or Windows-1250
// + special letter values changing
// Normal value: 196, 214, 220, 223, 228, 246, 252
// Prince change: 131, 132, 133, 127, 128, 129, 130
char invOptionsTextDE[5][17] = {
"Anschauen",
"Benutzen",
"\x84""ffnen/Sto\x7f""en",
("Schlie\x7f""en/Ziehen"),
"Geben"
};
const char optionsTextDE[7][17] = {
"Hingehen",
"Anschauen",
"Wegnehmen",
"Benutzen",
"\x84""ffnen/Sto\x7f""en",
("Schlie\x7f""en/Ziehen"),
"Ansprechen"
};
// EN
const char *invOptionsTextEN[] = {
"Examine",
"Use",
"Open/Push",
"Close/Pull",
"Give"
};
const char *optionsTextEN[] = {
"Walk to",
"Examine",
"Pick up",
"Use",
"Open/Push",
"Close/Pull",
"Talk to"
};
// ES
const char *invOptionsTextES[] = {
"Examinar",
"Usar",
"Abrir/Empujar",
"Cerrar/Tirar de",
"Dar"
};
const char *optionsTextES[] = {
"Ir hacia",
"Examinar",
"Coger",
"Usar",
"Abrir/Empujar",
"Cerrar/Tirar de",
"Hablar a"
};
// RU
const char *invOptionsTextRU[] = {
"Cvjnhtnm",
"Bcgjkmp.",
"Jnrhsnm/""\x83""bnm ",
"Pfrhsnm/Nzyenm ",
"Lfnm "
};
const char *optionsTextRU[] = {
"Gjljqnb",
"Jcvjnhtnm",
"Dpznm ",
"Bcgjkmp.",
"Jnrhsnm/""\x83""bnm ",
"Pfrhsnm/Nzyenm ",
"Ujdjhbnm "
};
// RU localization from "Russian Project"
const char *invOptionsTextRU2[] = {
"n""\x91""\x8c""\x8e""\x92""\x90""\x85""\x92""\x9c",
"h""\x91""\x8f""\x8e""\x8b""\x9c""\x87"".",
"n""\x92""\x8a""\x90""\x9b""\x92""\x9c""/r""\x8e""\x8b""\x8a""\x80""\x92""\x9c",
"g""\x80""\x8a""\x90""\x9b""\x92""\x9c""/r""\x9f""\x8d""\x93""\x92""\x9c",
"d""\x80""\x92""\x9c"
};
const char *optionsTextRU2[] = {
"o""\x8e""\x84""\x8e""\x89""\x92""\x88",
"n""\x91""\x8c""\x8e""\x92""\x90""\x85""\x92""\x9c",
"b""\x87""\x9f""\x92""\x9c",
"h""\x91""\x8f""\x8e""\x8b""\x9c""\x87"".",
"n""\x92""\x8a""\x90""\x9b""\x92""\x9c""/r""\x8e""\x8b""\x8a""\x80""\x92""\x9c",
"g""\x80""\x8a""\x90""\x9b""\x92""\x9c""/r""\x9f""\x8d""\x93""\x92""\x9c",
"c""\x8e""\x82""\x8e""\x90""\x88""\x92""\x9c"
};
} // End of namespace Prince

1526
engines/prince/prince.cpp Normal file

File diff suppressed because it is too large Load Diff

724
engines/prince/prince.h Normal file
View File

@@ -0,0 +1,724 @@
/* 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 PRINCE_PRINCE_H
#define PRINCE_PRINCE_H
#include "common/random.h"
#include "common/system.h"
#include "common/debug.h"
#include "common/debug-channels.h"
#include "common/textconsole.h"
#include "common/text-to-speech.h"
#include "common/rect.h"
#include "common/events.h"
#include "common/endian.h"
#include "common/savefile.h"
#include "common/serializer.h"
#include "image/bmp.h"
#include "gui/debugger.h"
#include "engines/engine.h"
#include "engines/util.h"
#include "audio/mixer.h"
#include "video/flic_decoder.h"
#include "prince/mob.h"
#include "prince/object.h"
#include "prince/pscr.h"
#include "prince/detection.h"
namespace Prince {
enum PRINCEActions {
kActionNone,
kActionSave,
kActionLoad,
kActionZ,
kActionX,
kActionSkip,
};
struct SavegameHeader;
class PrinceEngine;
class GraphicsMan;
class Script;
class Interpreter;
class InterpreterFlags;
class Debugger;
class MusicPlayer;
class VariaTxt;
class Cursor;
class MhwanhDecoder;
class Font;
class Hero;
class Animation;
class Room;
class Pscr;
struct SavegameHeader {
uint8 version;
Common::String saveName;
Graphics::Surface *thumbnail;
int16 saveYear, saveMonth, saveDay;
int16 saveHour, saveMinutes;
uint32 playTime;
};
#define kSavegameStrSize 14
#define kSavegameStr "SCUMMVM_PRINCE"
struct Text {
const char *_str;
uint16 _x, _y;
uint16 _time;
uint32 _color;
Text() {
clear();
}
void clear() {
_str = nullptr;
_x = 0;
_y = 0;
_time = 0;
_color = 255;
}
};
struct AnimListItem {
uint16 _type; // type of animation - for background anims RND of frame
uint16 _fileNumber;
uint16 _startPhase; // first phase number
uint16 _endPhase;
uint16 _loopPhase;
int16 _x;
int16 _y;
uint16 _loopType;
uint16 _nextAnim; // number of animation to do for loop = 3
uint16 _flags; // byte 0 - draw masks, byte 1 - draw in front of mask, byte 2 - load but turn off drawing
bool loadFromStream(Common::SeekableReadStream &stream);
};
struct BAS {
int32 _type; // type of sequence
int32 _data; // additional data
int32 _anims; // number of animations
int32 _current; // actual number of animation
int32 _counter; // time counter for animation
int32 _currRelative; //actual relative number for animation
int32 _data2; // additional data for measurements
};
const int kStructSizeBAS = 28;
struct BASA {
int16 _num; // animation number
int16 _start; // initial frame
int16 _end; // final frame
//int16 _pad; // fulfilment to 8 bytes
};
const int kStructSizeBASA = 8;
// background and normal animation
struct Anim {
BASA _basaData;
int32 _addr; // animation address
int16 _usage;
int16 _state; // state of animation: 0 - turning on, 1 - turning off
int16 _flags;
int16 _frame; // number of phase to show
int16 _lastFrame; // last phase
int16 _loopFrame; // first frame of loop
int16 _showFrame; // actual visible frame of animation
int16 _loopType; // type of loop (0 - last frame; 1 - normal loop (begin from _loopFrame); 2 - no loop; 3 - load new animation)
int16 _nextAnim; // number of next animation to load after actual
int16 _x;
int16 _y;
int32 _currFrame;
int16 _currX;
int16 _currY;
int16 _currW;
int16 _currH;
int16 _packFlag;
int32 _currShadowFrame;
int16 _packShadowFlag;
int32 _shadowBack;
int16 _relX;
int16 _relY;
Animation *_animData;
Animation *_shadowData;
enum AnimOffsets {
kAnimState = 10,
kAnimFrame = 14,
kAnimLastFrame = 16,
kAnimX = 26
};
int16 getAnimData(Anim::AnimOffsets offset) {
switch (offset) {
case kAnimState:
return _state;
case kAnimFrame:
return _frame + 1; // fix for location 30 - man with a dog animation
case kAnimX:
return _x;
default:
error("getAnimData() - Wrong offset type: %d", (int)offset);
}
}
void setAnimData(Anim::AnimOffsets offset, int16 value) {
if (offset == kAnimX) {
_x = value;
} else {
error("setAnimData() - Wrong offset: %d, value: %d", (int)offset, value);
}
}
};
struct BackgroundAnim {
BAS _seq;
Common::Array<Anim> backAnims;
};
enum AnimType {
kBackgroundAnimation,
kNormalAnimation
};
// Nak (PL - Nakladka)
struct Mask {
uint16 _state; // visible / invisible
int16 _flags; // turning on / turning off of a mask
int16 _x1;
int16 _y1;
int16 _x2;
int16 _y2;
int16 _z;
int16 _number; // number of mask for background recreating
int16 _width;
int16 _height;
byte *_data;
int16 getX() const {
return READ_LE_UINT16(_data);
}
int16 getY() const {
return READ_LE_UINT16(_data + 2);
}
int16 getWidth() const {
return READ_LE_UINT16(_data + 4);
}
int16 getHeight() const {
return READ_LE_UINT16(_data + 6);
}
byte *getMask() const {
return (byte *)(_data + 8);
}
};
struct InvItem {
int _x;
int _y;
Graphics::Surface *_surface;
Graphics::Surface *getSurface() const { return _surface; }
};
struct DrawNode {
int posX;
int posY;
int posZ;
int32 width;
int32 height;
int32 scaleValue;
Graphics::Surface *s;
Graphics::Surface *originalRoomSurface;
void *data;
void (*drawFunction)(Graphics::Surface *, DrawNode *);
};
struct DebugChannel {
enum Type {
kScript = 1 << 0,
kEngine = 1 << 1
};
};
static const uint8 kHeroTextColor = 220;
class PrinceEngine : public Engine {
protected:
Common::Error run() override;
public:
PrinceEngine(OSystem *syst, const PrinceGameDescription *gameDesc);
~PrinceEngine() override;
bool scummVMSaveLoadDialog(bool isSave);
bool hasFeature(EngineFeature f) const override;
void pauseEngineIntern(bool pause) override;
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
Common::Error loadGameState(int slot) override;
void playVideo(const Common::Path &videoFilename);
WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail = true);
void writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header);
void syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream);
bool loadGame(int slotNumber);
void resetGame();
int32 _creditsDataSize;
byte *_creditsData;
void scrollCredits();
int getGameType() const;
const char *getGameId() const;
uint32 getFeatures() const;
Common::Language getLanguage() const;
const PrinceGameDescription *_gameDescription;
Video::FlicDecoder _flicPlayer;
const Graphics::Surface *_flcFrameSurface;
VariaTxt *_variaTxt;
uint32 _talkTxtSize;
byte *_talkTxt;
uint32 _mobTranslationSize;
byte *_mobTranslationData;
bool _missingVoice;
bool loadLocation(uint16 locationNr);
bool loadAnim(uint16 animNr, bool loop);
bool loadVoice(uint32 textSlot, uint32 sampleSlot, const Common::String &name);
bool loadSample(uint32 sampleSlot, const Common::String &name);
bool loadZoom(byte *zoomBitmap, uint32 dataSize, const char *resourceName);
bool loadShadow(byte *shadowBitmap, uint32 dataSize, const char *resourceName1, const char *resourceName2);
bool loadTrans(byte *transTable, const char *resourceName);
bool loadMobPriority(const char *resourceName);
void loadMobTranslationTexts();
void setMobTranslationTexts();
bool loadMusic(int musNumber);
void stopMusic();
void playSample(uint16 sampleId, uint16 loopType);
void stopSample(uint16 sampleId);
void stopAllSamples();
void freeSample(uint16 sampleId);
void freeAllSamples();
void setVoice(uint16 slot, uint32 sampleSlot, uint16 flag);
void changeCursor(uint16 curId);
void printAt(uint32 slot, uint8 color, char *s, uint16 x, uint16 y);
int calcTextLines(const char *s);
int calcTextTime(int numberOfLines);
void correctStringDEU(char *s);
void sayText(const Common::String &text, bool isSpeech, Common::TextToSpeechManager::Action action = Common::TextToSpeechManager::INTERRUPT);
#ifdef USE_TTS
Common::U32String convertText(const Common::String &text) const;
bool checkConversionTable(const byte *character, int &index, byte *convertedBytes, const uint16 *table) const;
#endif
void setTTSVoice(uint8 textColor) const;
void stopTextToSpeech() const;
static const uint8 kMaxTexts = 32;
Text _textSlots[kMaxTexts];
Hero *_mainHero;
Hero *_secondHero;
enum HeroId {
kMainHero,
kSecondHero
};
int _mouseFlag;
uint32 _currentTime;
uint16 _locationNr;
uint16 _sceneWidth;
int32 _picWindowX;
int32 _picWindowY;
bool _printMapNotification;
bool _intro;
bool _credits;
Image::BitmapDecoder *_roomBmp;
MhwanhDecoder *_suitcaseBmp;
Room *_room;
Script *_script;
InterpreterFlags *_flags;
Interpreter *_interpreter;
GraphicsMan *_graph;
uint8 _currentMidi;
byte *_zoomBitmap;
byte *_shadowBitmap;
byte *_transTable;
int16 _scaleValue; // scale for hero or special shadow animation
int16 _lightX; // for hero shadow
int16 _lightY;
int32 _shadScaleValue;
int32 _shadLineLen;
byte *_shadowLine;
void setShadowScale(int32 shadowScale);
static const int16 kFPS = 15;
static const int32 kIntMax = 2147483647;
static const int16 kMaxPicWidth = 1280;
static const int16 kMaxPicHeight = 480;
static const int16 kZoomStep = 4;
static const int32 kZoomBitmapLen = kMaxPicHeight / kZoomStep * kMaxPicWidth / kZoomStep;
static const int32 kShadowBitmapSize = kMaxPicWidth * kMaxPicHeight / 8;
static const int16 kShadowLineArraySize = 2 * 1280 * 4;
static const int16 kZoomBitmapWidth = kMaxPicWidth / kZoomStep;
static const int16 kZoomBitmapHeight = kMaxPicHeight / kZoomStep;
static const int16 kNormalWidth = 640;
static const int16 kNormalHeight = 480;
static const uint32 kTransTableSize = 256 * 256;
static const int kMaxNormAnims = 64;
static const int kMaxBackAnims = 64;
static const int kMaxObjects = 64;
static const int kMaxMobs = 64;
Common::Array<DrawNode> _drawNodeList;
Common::Array<AnimListItem> _animList;
Common::Array<BackgroundAnim> _backAnimList;
Common::Array<Anim> _normAnimList;
Common::Array<Mob> _mobList;
Common::Array<uint32> _mobPriorityList;
Common::Array<Mask> _maskList;
Common::Array<Object *> _objList;
uint16 *_objSlot;
void freeNormAnim(int slot);
void freeAllNormAnims();
void removeSingleBackAnim(int slot);
Common::RandomSource _randomSource;
void checkMasks(int x1, int y1, int sprWidth, int sprHeight, int z);
void insertMasks(Graphics::Surface *originalRoomSurface);
void showMask(int maskNr, Graphics::Surface *originalRoomSurface);
void clsMasks();
void grabMap();
int _selectedMob; // number of selected Mob / inventory item
int _previousMob;
int _dialogMob;
int _selectedItem; // number of item on mouse cursor
int _selectedMode;
int _currentPointerNumber;
static const int16 kMaxInv = 90; // max amount of inventory items in whole game
static const uint16 kMaxItems = 30; // size of inventory
uint32 _invTxtSize;
byte *_invTxt;
Graphics::Surface *_optionsPic;
Graphics::Surface *_optionsPicInInventory;
bool _optionsFlag;
int _optionEnabled;
int _optionsMob;
int _optionsX;
int _optionsY;
int _optionsWidth;
int _optionsHeight;
int _invOptionsWidth;
int _invOptionsHeight;
int _optionsStep;
int _invOptionsStep;
int _optionsNumber;
int _invOptionsNumber;
int _optionsColor1; // color for non-selected options
int _optionsColor2; // color for selected option
bool _showInventoryFlag;
int _invExamY;
bool _inventoryBackgroundRemember;
int _invLineX;
int _invLineY;
int _invLine; // number of items in one line
int _invLines; // number of lines with inventory items
int _invLineW;
int _invLineH;
int _maxInvW;
int _maxInvH;
int _invLineSkipX;
int _invLineSkipY;
int _invX1;
int _invY1;
int _invWidth;
int _invHeight;
bool _invCurInside;
int _mst_shadow;
int _mst_shadow2; // blinking after adding new item
int _candleCounter; // special counter for candle inventory item
int _invMaxCount; // time to turn inventory on
int _invCounter; // turning on counter
void inventoryFlagChange(bool inventoryState);
bool loadAllInv();
void rememberScreenInv();
void prepareInventoryToView();
void drawInvItems();
void displayInventory();
void addInv(int heroId, int item, bool addItemQuiet);
void remInv(int heroId, int item);
void clearInv(int heroId);
void swapInv(int heroId);
void addInvObj();
void makeInvCursor(int itemNr);
void enableOptions(bool checkType);
void checkOptions();
void checkInvOptions();
void openInventoryCheck();
void leftMouseButton();
void rightMouseButton();
void inventoryLeftMouseButton();
void inventoryRightMouseButton();
void dialogLeftMouseButton(byte *string, int dialogSelected);
uint32 _dialogDatSize;
byte *_dialogDat;
byte *_dialogData; // on, off flags for lines of dialog text
byte *_dialogBoxAddr[32]; // adresses of dialog windows
byte *_dialogOptAddr[32]; // adresses of dialog options
int _dialogOptLines[4 * 32]; // numbers of initial dialog lines
byte *_dialogText;
int _dialogLines;
bool _dialogFlag;
int _dialogWidth;
int _dialogHeight;
int _dialogLineSpace;
int _dialogColor1; // color for non-selected options
int _dialogColor2; // color for selected option
int _previousSelectedDialog;
bool _isConversing;
Graphics::Surface *_dialogImage;
void createDialogBox(int dialogBoxNr);
void dialogRun();
void talkHero(int slot);
void doTalkAnim(int animNumber, int slot, AnimType animType);
static const uint8 zoomInStep = 8;
void initZoomIn(int slot);
void initZoomOut(int slot);
void doZoomIn(int slot);
void doZoomOut(int slot);
void freeZoomObject(int slot);
static const uint8 kFadeStep = 4;
void blackPalette();
void setPalette(const byte *palette);
int getMob(Common::Array<Mob> &mobList, bool usePriorityList, int posX, int posY);
// 'Throw a rock' mini-game:
static const int16 kCurveLen = 17;
static const int kCelStep = 4;
int16 *_curveData;
int _curvPos;
void makeCurve();
void getCurve();
void mouseWeirdo();
static const uint16 kPowerBarPosX = 288;
static const uint16 kPowerBarPosY = 430;
static const uint8 kPowerBarWidth = 64;
static const uint8 kPowerBarHeight = 16;
static const uint8 kPowerBarBackgroundColor = 0;
static const uint16 kPowerBarGreenPosY = 434;
static const uint8 kPowerBarGreenColor1 = 202;
static const uint8 kPowerBarGreenColor2 = 235;
static const uint8 kPowerBarGreenHeight = 8;
void showPower();
// Pathfinding
static const int16 kPathGridStep = 2;
static const uint32 kPathBitmapLen = (kMaxPicHeight / kPathGridStep * kMaxPicWidth / kPathGridStep) / 8;
static const int32 kTracePts = 8000;
static const int32 kPBW = kMaxPicWidth / 16; // PathBitmapWidth
static const int kMinDistance = 2500;
byte *_roomPathBitmap; // PL - Sala
byte *_roomPathBitmapTemp; // PL - SSala
byte *_coordsBufEnd;
byte *_coordsBuf; // optimal path
byte *_coords; // last path point address from coordsBuf
byte *_coordsBuf2;
byte *_coords2;
byte *_coordsBuf3;
byte *_coords3;
int _traceLineLen;
bool _traceLineFirstPointFlag; // if plotTraceLine after first point
bool _tracePointFirstPointFlag; // if plotTracePoint after first point
byte *_directionTable;
int _shanLen;
byte *_checkBitmapTemp;
byte *_checkBitmap;
int _checkMask;
int _checkX;
int _checkY;
byte *_rembBitmapTemp;
byte *_rembBitmap;
int _rembMask;
int _rembX;
int _rembY;
int _fpX;
int _fpY;
int drawLine(int x0, int y0, int x1, int y1, int (*plotProc)(int, int, void *), void *data);
bool loadPath(const char *resourceName);
byte *makePath(int heroId, int currX, int currY, int destX, int destY);
void findPoint(int x, int y);
int getPixelAddr(byte *pathBitmap, int x, int y);
static int plotTraceLine(int x, int y, void *data);
void specialPlotInside(int x, int y);
bool tracePath(int x1, int y1, int x2, int y2);
Direction makeDirection(int x1, int y1, int x2, int y2);
void specialPlot(int x, int y);
void specialPlot2(int x, int y);
void allocCoords2();
void freeCoords2();
void freeCoords3();
static int plotTracePoint(int x, int y, void *data);
void specialPlotInside2(int x, int y);
void approxPath();
void freeDirectionTable();
void scanDirections();
int scanDirectionsFindNext(byte *coords, int xDiff, int yDiff);
void moveShandria();
void walkTo();
void moveRunHero(int heroId, int x, int y, int dir, bool runHeroFlag);
int leftDownDir();
int leftDir();
int leftUpDir();
int rightDownDir();
int rightDir();
int rightUpDir();
int upLeftDir();
int upDir();
int upRightDir();
int downLeftDir();
int downDir();
int downRightDir();
int cpe();
int checkLeftDownDir();
int checkLeftDir();
int checkDownDir();
int checkUpDir();
int checkRightDir();
int checkLeftUpDir();
int checkRightDownDir();
int checkRightUpDir();
private:
bool playNextFLCFrame();
void keyHandler(Common::Event event);
int checkMob(Graphics::Surface *screen, Common::Array<Mob> &mobList, bool usePriorityList);
void drawScreen();
void showTexts(Graphics::Surface *screen);
void init();
void showLogo();
void showAnim(Anim &anim);
void showNormAnims();
void setBackAnim(Anim &backAnim);
void showBackAnims();
void clearBackAnimList();
bool spriteCheck(int sprWidth, int sprHeight, int destX, int destY);
void showSprite(Graphics::Surface *spriteSurface, int destX, int destY, int destZ);
void showSpriteShadow(Graphics::Surface *shadowSurface, int destX, int destY, int destZ);
void showObjects();
void showParallax();
static bool compareDrawNodes(DrawNode d1, DrawNode d2);
void runDrawNodes();
void makeShadowTable(int brightness);
void pausePrinceEngine(int fps = kFPS);
uint32 getTextWidth(const char *s);
void debugEngine(const char *s, ...);
uint8 _cursorNr;
Common::RandomSource *_rnd;
Cursor *_cursor1;
Graphics::Surface *_cursor2;
Cursor *_cursor3;
Debugger *_debugger;
Font *_font;
MusicPlayer *_midiPlayer;
static const int kMaxSamples = 60;
Audio::RewindableAudioStream *_audioStream[kMaxSamples];
Audio::SoundHandle _soundHandle[kMaxSamples];
Common::Array<PScr *> _pscrList;
Common::Array<InvItem> _allInvList;
Common::Array<Mob> _invMobList;
bool _flicLooped;
void mainLoop();
};
} // End of namespace Prince
#endif

77
engines/prince/pscr.cpp Normal file
View File

@@ -0,0 +1,77 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/archive.h"
#include "common/stream.h"
#include "prince/pscr.h"
#include "prince/resource.h"
namespace Prince {
PScr::PScr() : _x(0), _y(0), _step(0), _surface(nullptr)
{
}
PScr::~PScr() {
if (_surface != nullptr) {
_surface->free();
delete _surface;
_surface = nullptr;
}
}
void PScr::loadSurface(Common::SeekableReadStream &stream) {
stream.skip(4);
int width = stream.readUint16LE();
int height = stream.readUint16LE();
_surface = new Graphics::Surface();
_surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
for (int h = 0; h < _surface->h; h++) {
stream.read(_surface->getBasePtr(0, h), _surface->w);
}
}
bool PScr::loadFromStream(Common::SeekableReadStream &stream) {
int32 pos = stream.pos();
uint16 file = stream.readUint16LE();
if (file == 0xFFFF) {
return false;
}
_x = stream.readUint16LE();
_y = stream.readUint16LE();
_step = stream.readUint16LE();
const Common::Path pscrStreamName(Common::String::format("PS%02d", file));
Common::SeekableReadStream *pscrStream = SearchMan.createReadStreamForMember(pscrStreamName);
if (pscrStream != nullptr) {
pscrStream = Resource::getDecompressedStream(pscrStream);
loadSurface(*pscrStream);
}
delete pscrStream;
stream.seek(pos + 12); // size of PScrList struct
return true;
}
} // End of namespace Prince

47
engines/prince/pscr.h 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/>.
*
*/
#ifndef PRINCE_PSCR_H
#define PRINCE_PSCR_H
#include "graphics/surface.h"
namespace Prince {
class PScr {
public:
PScr();
~PScr();
int16 _x;
int16 _y;
int16 _step;
static const int16 kPScrZ = 1000;
bool loadFromStream(Common::SeekableReadStream &stream);
Graphics::Surface *getSurface() const { return _surface; }
private:
void loadSurface(Common::SeekableReadStream &stream);
Graphics::Surface *_surface;
};
} // End of namespace Prince
#endif

366
engines/prince/resource.cpp Normal file
View File

@@ -0,0 +1,366 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/fs.h"
#include "common/config-manager.h"
#include "prince/prince.h"
#include "prince/graphics.h"
#include "prince/debugger.h"
#include "prince/script.h"
#include "prince/hero.h"
#include "prince/resource.h"
#include "prince/archive.h"
namespace Prince {
Common::SeekableReadStream *Resource::getDecompressedStream(Common::SeekableReadStream *stream) {
if (!(((PrinceEngine *)g_engine)->getFeatures() & GF_EXTRACTED))
return stream;
byte header[4];
stream->read(header, 4);
stream->seek(0);
if (READ_BE_UINT32(header) == MKTAG('M', 'A', 'S', 'M')) {
byte *buffer = (byte *)malloc(stream->size());
stream->read(buffer, stream->size());
Decompressor dec;
uint32 decompLen = READ_BE_UINT32(buffer + 14);
byte *decompData = (byte *)malloc(decompLen);
dec.decompress(buffer + 18, decompData, decompLen);
free(buffer);
debug(8, "Resource::getDecompressedStream: decompressed %d to %d bytes", (int)stream->size(), decompLen);
return new Common::MemoryReadStream(decompData, decompLen, DisposeAfterUse::YES);
} else {
return stream;
}
}
bool AnimListItem::loadFromStream(Common::SeekableReadStream &stream) {
int32 pos = stream.pos();
uint16 type = stream.readUint16LE();
if (type == 0xFFFF) {
return false;
}
_type = type;
_fileNumber = stream.readUint16LE();
_startPhase = stream.readUint16LE();
_endPhase = stream.readUint16LE();
_loopPhase = stream.readUint16LE();
_x = stream.readSint16LE();
_y = stream.readSint16LE();
_loopType = stream.readUint16LE();
_nextAnim = stream.readUint16LE();
_flags = stream.readUint16LE();
debug(7, "AnimListItem type %d, fileNumber %d, x %d, y %d, flags %d", _type, _fileNumber, _x, _y, _flags);
debug(7, "startPhase %d, endPhase %d, loopPhase %d", _startPhase, _endPhase, _loopPhase);
// 32 byte aligment
stream.seek(pos + 32);
return true;
}
bool PrinceEngine::loadLocation(uint16 locationNr) {
blackPalette();
_flicPlayer.close();
for (uint i = 0; i < ARRAYSIZE(_textSlots); i++) {
_textSlots[i].clear();
_textSlots[i]._color = 0; // FIXME: Can be left at default of 255?
}
freeAllSamples();
debugEngine("PrinceEngine::loadLocation %d", locationNr);
const Common::FSNode gameDataDir(ConfMan.getPath("path"));
SearchMan.remove(Common::String::format("%02d", _locationNr));
_locationNr = locationNr;
_debugger->_locationNr = locationNr;
_flags->setFlagValue(Flags::CURRROOM, _locationNr);
_interpreter->stopBg();
changeCursor(0);
const Common::String locationNrStr = Common::String::format("%02d", _locationNr);
debugEngine("loadLocation %s", locationNrStr.c_str());
if (!(getFeatures() & GF_EXTRACTED)) {
PtcArchive *locationArchive = new PtcArchive();
if (!locationArchive->open(Common::Path(locationNrStr).appendComponent("databank.ptc")))
error("Can't open location %s", locationNrStr.c_str());
SearchMan.add(locationNrStr, locationArchive);
} else {
SearchMan.addSubDirectoryMatching(gameDataDir, locationNrStr);
}
loadMusic(_locationNr);
// load location background, replace old one
Resource::loadResource(_roomBmp, "room", true);
if (_roomBmp->getSurface()) {
_sceneWidth = _roomBmp->getSurface()->w;
}
loadZoom(_zoomBitmap, kZoomBitmapLen, "zoom");
loadShadow(_shadowBitmap, kShadowBitmapSize, "shadow", "shadow2");
loadTrans(_transTable, "trans");
loadPath("path");
for (uint32 i = 0; i < _pscrList.size(); i++) {
delete _pscrList[i];
}
_pscrList.clear();
Resource::loadResource(_pscrList, "pscr.lst", false);
loadMobPriority("mobpri");
_mobList.clear();
if (getGameType() == kPrinceDataDE) {
const Common::String mobLstName = Common::String::format("mob%02d.lst", _locationNr);
debug(3, "moblist name: %s", mobLstName.c_str());
Resource::loadResource(_mobList, mobLstName.c_str(), false);
} else if (getGameType() == kPrinceDataPL) {
Resource::loadResource(_mobList, "mob.lst", false);
}
if (getFeatures() & GF_TRANSLATED) {
// update Mob texts for translated version
setMobTranslationTexts();
}
_animList.clear();
Resource::loadResource(_animList, "anim.lst", false);
for (uint32 i = 0; i < _objList.size(); i++) {
delete _objList[i];
}
_objList.clear();
Resource::loadResource(_objList, "obj.lst", false);
_room->loadRoom(_script->getRoomOffset(_locationNr));
for (uint i = 0; i < _maskList.size(); i++) {
free(_maskList[i]._data);
}
_maskList.clear();
_script->loadAllMasks(_maskList, _room->_nak);
_picWindowX = 0;
_lightX = _script->getLightX(_locationNr);
_lightY = _script->getLightY(_locationNr);
setShadowScale(_script->getShadowScale(_locationNr));
for (uint i = 0; i < _mobList.size(); i++) {
_mobList[i]._visible = _script->getMobVisible(_room->_mobs, i);
}
_script->installObjects(_room->_obj);
freeAllNormAnims();
clearBackAnimList();
_script->installBackAnims(_backAnimList, _room->_backAnim);
_graph->makeShadowTable(70, _graph->_shadowTable70);
_graph->makeShadowTable(50, _graph->_shadowTable50);
_mainHero->freeOldMove();
_secondHero->freeOldMove();
_mainHero->scrollHero();
return true;
}
bool PrinceEngine::loadAnim(uint16 animNr, bool loop) {
Common::Path streamName(Common::String::format("AN%02d", animNr));
Common::SeekableReadStream *flicStream = SearchMan.createReadStreamForMember(streamName);
if (!flicStream) {
error("Can't open %s", streamName.toString().c_str());
return false;
}
flicStream = Resource::getDecompressedStream(flicStream);
if (!_flicPlayer.loadStream(flicStream)) {
error("Can't load flic stream %s", streamName.toString().c_str());
}
debugEngine("%s loaded", streamName.toString().c_str());
_flicLooped = loop;
_flicPlayer.start();
playNextFLCFrame();
return true;
}
bool PrinceEngine::loadZoom(byte *zoomBitmap, uint32 dataSize, const char *resourceName) {
Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
if (!stream) {
return false;
}
stream = Resource::getDecompressedStream(stream);
if (stream->read(zoomBitmap, dataSize) != dataSize) {
free(zoomBitmap);
delete stream;
return false;
}
delete stream;
return true;
}
bool PrinceEngine::loadShadow(byte *shadowBitmap, uint32 dataSize, const char *resourceName1, const char *resourceName2) {
Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName1);
if (!stream) {
return false;
}
stream = Resource::getDecompressedStream(stream);
if (stream->read(shadowBitmap, dataSize) != dataSize) {
free(shadowBitmap);
delete stream;
return false;
}
Common::SeekableReadStream *stream2 = SearchMan.createReadStreamForMember(resourceName2);
if (!stream2) {
delete stream;
return false;
}
stream2 = Resource::getDecompressedStream(stream2);
byte *shadowBitmap2 = shadowBitmap + dataSize;
if (stream2->read(shadowBitmap2, dataSize) != dataSize) {
free(shadowBitmap);
delete stream;
delete stream2;
return false;
}
delete stream;
delete stream2;
return true;
}
bool PrinceEngine::loadTrans(byte *transTable, const char *resourceName) {
Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
if (!stream) {
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 256; j++) {
transTable[i * 256 + j] = j;
}
}
return true;
}
stream = Resource::getDecompressedStream(stream);
if (stream->read(transTable, kTransTableSize) != kTransTableSize) {
delete stream;
return false;
}
delete stream;
return true;
}
bool PrinceEngine::loadPath(const char *resourceName) {
Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
if (!stream) {
return false;
}
stream = Resource::getDecompressedStream(stream);
if (stream->read(_roomPathBitmap, kPathBitmapLen) != kPathBitmapLen) {
delete stream;
return false;
}
delete stream;
return true;
}
bool PrinceEngine::loadAllInv() {
for (int i = 0; i < kMaxInv; i++) {
InvItem tempInvItem;
const Common::Path invStreamName(Common::String::format("INV%02d", i));
Common::SeekableReadStream *invStream = SearchMan.createReadStreamForMember(invStreamName);
if (!invStream) {
return true;
}
invStream = Resource::getDecompressedStream(invStream);
tempInvItem._x = invStream->readUint16LE();
tempInvItem._y = invStream->readUint16LE();
int width = invStream->readUint16LE();
int height = invStream->readUint16LE();
tempInvItem._surface = new Graphics::Surface();
tempInvItem._surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
for (int h = 0; h < tempInvItem._surface->h; h++) {
invStream->read(tempInvItem._surface->getBasePtr(0, h), tempInvItem._surface->w);
}
_allInvList.push_back(tempInvItem);
delete invStream;
}
return true;
}
bool PrinceEngine::loadMobPriority(const char *resourceName) {
Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
if (!stream) {
return false;
}
stream = Resource::getDecompressedStream(stream);
_mobPriorityList.clear();
uint mobId;
while (1) {
mobId = stream->readUint32LE();
if (mobId == 0xFFFFFFFF) {
break;
}
_mobPriorityList.push_back(mobId);
}
delete stream;
return true;
}
} // End of namespace Prince

110
engines/prince/resource.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/>.
*
*/
#ifndef PRINCE_RESOURCE_H
#define PRINCE_RESOURCE_H
#include "common/stream.h"
#include "common/memstream.h"
#include "common/archive.h"
#include "common/debug-channels.h"
#include "common/ptr.h"
#include "prince/decompress.h"
namespace Prince {
namespace Resource {
Common::SeekableReadStream *getDecompressedStream(Common::SeekableReadStream *stream);
template <typename T>
bool loadFromStream(T &resource, Common::SeekableReadStream &stream) {
return resource.loadStream(stream);
}
template<typename T>
bool loadResource(T *resource, const char *resourceName, bool required) {
Common::SeekableReadStream *stream_(SearchMan.createReadStreamForMember(resourceName));
if (!stream_) {
if (required)
error("Can't load %s", resourceName);
return false;
}
Common::ScopedPtr<Common::SeekableReadStream> stream(getDecompressedStream(stream_));
return loadFromStream(*resource, *stream);
}
template <typename T>
bool loadResource(Common::Array<T> &array, Common::SeekableReadStream &stream, bool required = true) {
T t;
while (t.loadFromStream(stream))
array.push_back(t);
return true;
}
template <typename T>
bool loadResource(Common::Array<T> &array, const char *resourceName, bool required = true) {
Common::SeekableReadStream *stream_(SearchMan.createReadStreamForMember(resourceName));
if (!stream_) {
if (required)
error("Can't load %s", resourceName);
return false;
}
Common::ScopedPtr<Common::SeekableReadStream> stream(getDecompressedStream(stream_));
return loadResource(array, *stream, required);
}
template <typename T>
bool loadResource(Common::Array<T *> &array, const char *resourceName, bool required = true) {
Common::SeekableReadStream *stream_(SearchMan.createReadStreamForMember(resourceName));
if (!stream_) {
if (required)
error("Can't load %s", resourceName);
return false;
}
Common::ScopedPtr<Common::SeekableReadStream> stream(getDecompressedStream(stream_));
// FIXME: This is stupid. Maybe loadFromStream should be helper method that returns initialized object
while (true) {
T* t = new T();
if (!t->loadFromStream(*stream)) {
delete t;
break;
}
array.push_back(t);
}
return true;
}
}
} // End of namespace Prince
#endif

471
engines/prince/saveload.cpp Normal file
View File

@@ -0,0 +1,471 @@
/* 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 "prince/prince.h"
#include "prince/graphics.h"
#include "prince/flags.h"
#include "prince/script.h"
#include "prince/hero.h"
#include "common/savefile.h"
#include "common/system.h"
#include "common/config-manager.h"
#include "common/memstream.h"
#include "common/translation.h"
#include "graphics/thumbnail.h"
#include "graphics/surface.h"
#include "graphics/paletteman.h"
#include "graphics/scaler.h"
#include "gui/saveload.h"
namespace Prince {
#define kSavegameVersion 1
class InterpreterFlags;
class Interpreter;
bool PrinceEngine::scummVMSaveLoadDialog(bool isSave) {
GUI::SaveLoadChooser *dialog;
Common::String desc;
int slot;
if (isSave) {
dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
slot = dialog->runModalWithCurrentTarget();
desc = dialog->getResultString();
if (desc.empty()) {
desc = dialog->createDefaultSaveDescription(slot);
}
} else {
dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
slot = dialog->runModalWithCurrentTarget();
}
delete dialog;
if (slot < 0)
return false;
if (isSave) {
return saveGameState(slot, desc).getCode() == Common::kNoError;
} else {
return loadGameState(slot).getCode() == Common::kNoError;
}
}
WARN_UNUSED_RESULT bool PrinceEngine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail) {
header.version = 0;
header.saveName.clear();
header.thumbnail = nullptr;
header.saveYear = 0;
header.saveMonth = 0;
header.saveDay = 0;
header.saveHour = 0;
header.saveMinutes = 0;
header.playTime = 0;
// Get the savegame version
header.version = in->readByte();
if (header.version > kSavegameVersion)
return false;
// Read in the string
char ch;
while ((ch = (char)in->readByte()) != '\0')
header.saveName += ch;
// Get the thumbnail
if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) {
return false;
}
// Read in save date/time
header.saveYear = in->readSint16LE();
header.saveMonth = in->readSint16LE();
header.saveDay = in->readSint16LE();
header.saveHour = in->readSint16LE();
header.saveMinutes = in->readSint16LE();
header.playTime = in->readUint32LE();
return true;
}
bool PrinceEngine::canSaveGameStateCurrently(Common::U32String *msg) {
if (_mouseFlag && _mouseFlag != 3) {
if (_mainHero->_visible) {
// 29 - Basement
if (_locationNr != 29) {
// No dialog box and not in inventory
if (!_dialogFlag && !_showInventoryFlag) {
return true;
}
}
}
}
return false;
}
bool PrinceEngine::canLoadGameStateCurrently(Common::U32String *msg) {
if (_mouseFlag && _mouseFlag != 3) {
if (_mainHero->_visible) {
// 29 - Basement
if (_locationNr != 29) {
// No dialog box and not in inventory
if (!_dialogFlag && !_showInventoryFlag) {
return true;
}
}
}
}
return false;
}
Common::Error PrinceEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
// Set up the serializer
Common::String slotName = getSaveStateName(slot);
Common::OutSaveFile *saveFile = g_system->getSavefileManager()->openForSaving(slotName);
// Write out the ScummVM savegame header
SavegameHeader header;
header.saveName = desc;
header.version = kSavegameVersion;
writeSavegameHeader(saveFile, header);
// Write out the data of the savegame
syncGame(nullptr, saveFile);
// Finish writing out game data
saveFile->finalize();
delete saveFile;
return Common::kNoError;
}
void PrinceEngine::writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header) {
// Write out a savegame header
out->write(kSavegameStr, kSavegameStrSize + 1);
out->writeByte(kSavegameVersion);
// Write savegame name
out->write(header.saveName.c_str(), header.saveName.size() + 1);
// Get the active palette
uint8 thumbPalette[256 * 3];
_system->getPaletteManager()->grabPalette(thumbPalette, 0, 256);
// Create a thumbnail and save it
Graphics::Surface *thumb = new Graphics::Surface();
Graphics::Surface *s = _graph->_frontScreen; // check inventory / map etc..
::createThumbnail(thumb, (const byte *)s->getPixels(), s->w, s->h, thumbPalette);
Graphics::saveThumbnail(*out, *thumb);
thumb->free();
delete thumb;
// Write out the save date/time
TimeDate td;
g_system->getTimeAndDate(td);
out->writeSint16LE(td.tm_year + 1900);
out->writeSint16LE(td.tm_mon + 1);
out->writeSint16LE(td.tm_mday);
out->writeSint16LE(td.tm_hour);
out->writeSint16LE(td.tm_min);
out->writeUint32LE(g_engine->getTotalPlayTime() / 1000);
}
void PrinceEngine::syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream) {
int emptyRoom = 0x00;
int normRoom = 0xFF;
byte endInv = 0xFF;
Common::Serializer s(readStream, writeStream);
if (s.isSaving()) {
// Flag values
for (int i = 0; i < _flags->kMaxFlags; i++) {
uint32 value = _flags->getFlagValue((Flags::Id)(_flags->kFlagMask + i));
s.syncAsUint32LE(value);
}
// Dialog data
for (uint32 i = 0; i < _dialogDatSize; i++) {
byte value = _dialogDat[i];
s.syncAsByte(value);
}
// Location number
s.syncAsUint16LE(_locationNr);
// Rooms
for (int roomId = 0; roomId < _script->kMaxRooms; roomId++) {
Room *room = new Room();
room->loadRoom(_script->getRoomOffset(roomId));
if (room->_mobs) {
s.syncAsByte(normRoom);
} else {
s.syncAsByte(emptyRoom);
delete room;
continue;
}
// Mobs
for (int mobId = 0; mobId < kMaxMobs; mobId++) {
byte value = _script->getMobVisible(room->_mobs, mobId);
s.syncAsByte(value);
}
// Background animations
for (int backAnimSlot = 0; backAnimSlot < kMaxBackAnims; backAnimSlot++) {
uint32 value = _script->getBackAnimId(room->_backAnim, backAnimSlot);
s.syncAsUint32LE(value);
}
// Objects
for (int objectSlot = 0; objectSlot < kMaxObjects; objectSlot++) {
byte value = _script->getObjId(room->_obj, objectSlot);
s.syncAsByte(value);
}
delete room;
}
// Main hero
s.syncAsUint16LE(_mainHero->_visible);
s.syncAsUint16LE(_mainHero->_middleX);
s.syncAsUint16LE(_mainHero->_middleY);
s.syncAsUint16LE(_mainHero->_lastDirection);
s.syncAsUint32LE(_mainHero->_color);
s.syncAsUint16LE(_mainHero->_maxBoredom);
s.syncAsUint32LE(_mainHero->_animSetNr);
for (uint inv1Slot = 0; inv1Slot < _mainHero->_inventory.size(); inv1Slot++) {
s.syncAsByte(_mainHero->_inventory[inv1Slot]);
}
s.syncAsByte(endInv);
for (uint inv2Slot = 0; inv2Slot < _mainHero->_inventory2.size(); inv2Slot++) {
s.syncAsByte(_mainHero->_inventory2[inv2Slot]);
}
s.syncAsByte(endInv);
// Second hero
s.syncAsUint16LE(_secondHero->_visible);
s.syncAsUint16LE(_secondHero->_middleX);
s.syncAsUint16LE(_secondHero->_middleY);
s.syncAsUint16LE(_secondHero->_lastDirection);
s.syncAsUint32LE(_secondHero->_color);
s.syncAsUint16LE(_secondHero->_maxBoredom);
s.syncAsUint32LE(_secondHero->_animSetNr);
for (uint inv1Slot = 0; inv1Slot < _secondHero->_inventory.size(); inv1Slot++) {
s.syncAsByte(_secondHero->_inventory[inv1Slot]);
}
s.syncAsByte(endInv);
for (uint inv2Slot = 0; inv2Slot < _secondHero->_inventory2.size(); inv2Slot++) {
s.syncAsByte(_secondHero->_inventory2[inv2Slot]);
}
s.syncAsByte(endInv);
} else {
// Cursor reset
changeCursor(1);
_currentPointerNumber = 1;
// Flag values
for (int i = 0; i < _flags->kMaxFlags; i++) {
uint32 value = 0;
s.syncAsUint32LE(value);
_flags->setFlagValue((Flags::Id)(_flags->kFlagMask + i), value);
}
// Dialog data
for (uint32 i = 0; i < _dialogDatSize; i++) {
byte value = 0;
s.syncAsByte(value);
_dialogDat[i] = value;
}
// Location number
int restoreRoom = 0;
s.syncAsUint16LE(restoreRoom);
_flags->setFlagValue(Flags::RESTOREROOM, restoreRoom);
// Rooms
for (int roomId = 0; roomId < _script->kMaxRooms; roomId++) {
Room *room = new Room();
room->loadRoom(_script->getRoomOffset(roomId));
byte roomType = emptyRoom;
s.syncAsByte(roomType);
if (roomType == emptyRoom) {
delete room;
continue;
}
// Mobs
for (int mobId = 0; mobId < kMaxMobs; mobId++) {
byte value = 0;
s.syncAsByte(value);
_script->setMobVisible(room->_mobs, mobId, value);
}
// Background animations
for (int backAnimSlot = 0; backAnimSlot < kMaxBackAnims; backAnimSlot++) {
uint32 value = 0;
s.syncAsUint32LE(value);
_script->setBackAnimId(room->_backAnim, backAnimSlot, value);
}
// Objects
for (int objectSlot = 0; objectSlot < kMaxObjects; objectSlot++) {
byte value = 0;
s.syncAsByte(value);
_script->setObjId(room->_obj, objectSlot, value);
}
delete room;
}
// Main hero
s.syncAsUint16LE(_mainHero->_visible);
s.syncAsUint16LE(_mainHero->_middleX);
s.syncAsUint16LE(_mainHero->_middleY);
s.syncAsUint16LE(_mainHero->_lastDirection);
s.syncAsUint32LE(_mainHero->_color);
s.syncAsUint16LE(_mainHero->_maxBoredom);
s.syncAsUint32LE(_mainHero->_animSetNr);
_mainHero->loadAnimSet(_mainHero->_animSetNr);
_mainHero->_inventory.clear();
byte invId = endInv;
while (1) {
s.syncAsByte(invId);
if (invId == endInv) {
break;
}
_mainHero->_inventory.push_back(invId);
}
_mainHero->_inventory2.clear();
invId = endInv;
while (1) {
s.syncAsByte(invId);
if (invId == endInv) {
break;
}
_mainHero->_inventory2.push_back(invId);
}
// Second hero
s.syncAsUint16LE(_secondHero->_visible);
s.syncAsUint16LE(_secondHero->_middleX);
s.syncAsUint16LE(_secondHero->_middleY);
s.syncAsUint16LE(_secondHero->_lastDirection);
s.syncAsUint32LE(_secondHero->_color);
s.syncAsUint16LE(_secondHero->_maxBoredom);
s.syncAsUint32LE(_secondHero->_animSetNr);
_secondHero->loadAnimSet(_secondHero->_animSetNr);
_secondHero->_inventory.clear();
invId = endInv;
while (1) {
s.syncAsByte(invId);
if (invId == endInv) {
break;
}
_secondHero->_inventory.push_back(invId);
}
_secondHero->_inventory2.clear();
invId = endInv;
while (1) {
s.syncAsByte(invId);
if (invId == endInv) {
break;
}
_secondHero->_inventory2.push_back(invId);
}
// Script
_interpreter->setBgOpcodePC(0);
_interpreter->setFgOpcodePC(_script->_scriptInfo.restoreGame);
}
}
Common::Error PrinceEngine::loadGameState(int slot) {
if (!loadGame(slot)) {
return Common::kReadingFailed;
}
return Common::kNoError;
}
bool PrinceEngine::loadGame(int slotNumber) {
Common::MemoryReadStream *readStream;
// Open up the savegame file
Common::String slotName = getSaveStateName(slotNumber);
Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(slotName);
if (!saveFile)
return false;
// Read the data into a data buffer
int size = saveFile->size();
byte *dataBuffer = (byte *)malloc(size);
saveFile->read(dataBuffer, size);
readStream = new Common::MemoryReadStream(dataBuffer, size, DisposeAfterUse::YES);
delete saveFile;
// Check to see if it's a ScummVM savegame or not
char buffer[kSavegameStrSize + 1];
readStream->read(buffer, kSavegameStrSize + 1);
if (strncmp(buffer, kSavegameStr, kSavegameStrSize + 1) != 0) {
delete readStream;
return false;
} else {
SavegameHeader saveHeader;
if (!readSavegameHeader(readStream, saveHeader)) {
delete readStream;
return false;
}
g_engine->setTotalPlayTime(saveHeader.playTime * 1000);
}
// Get in the savegame
syncGame(readStream, nullptr);
delete readStream;
return true;
}
} // End of namespace Prince

2113
engines/prince/script.cpp Normal file

File diff suppressed because it is too large Load Diff

400
engines/prince/script.h Normal file
View File

@@ -0,0 +1,400 @@
/* 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 PRINCE_SCRIPT_H
#define PRINCE_SCRIPT_H
#include "common/random.h"
#include "common/endian.h"
#include "common/array.h"
#include "common/stream.h"
#include "prince/flags.h"
namespace Prince {
class PrinceEngine;
class Animation;
class Object;
struct Anim;
struct BackgroundAnim;
struct Mask;
class Room {
public:
Room();
int _mobs; // mob flag offset
int _backAnim; // offset to array of animation numbers
int _obj; // offset to array of object numbers
int _nak; // offset to array of masks
int _itemUse;
int _itemGive;
int _walkTo; // offset to array of WALKTO events or 0
int _examine; // offset to array of EXAMINE events or 0
int _pickup;
int _use;
int _pushOpen;
int _pullClose;
int _talk;
int _give;
bool loadStream(Common::SeekableReadStream &stream);
bool loadRoom(byte *roomData);
int getOptionOffset(int option);
private:
typedef void (Room::*LoadingStep)(Common::SeekableReadStream &stream);
void nextLoadStep(Common::SeekableReadStream &stream, LoadingStep step);
void loadMobs(Common::SeekableReadStream &stream);
void loadBackAnim(Common::SeekableReadStream &stream);
void loadObj(Common::SeekableReadStream &stream);
void loadNak(Common::SeekableReadStream &stream);
void loadItemUse(Common::SeekableReadStream &stream);
void loadItemGive(Common::SeekableReadStream &stream);
void loadWalkTo(Common::SeekableReadStream &stream);
void loadExamine(Common::SeekableReadStream &stream);
void loadPickup(Common::SeekableReadStream &stream);
void loadUse(Common::SeekableReadStream &stream);
void loadPushOpen(Common::SeekableReadStream &stream);
void loadPullClose(Common::SeekableReadStream &stream);
void loadTalk(Common::SeekableReadStream &stream);
void loadGive(Common::SeekableReadStream &stream);
};
class Script {
public:
static const int16 kMaxRooms = 60;
Script(PrinceEngine *vm);
~Script();
struct ScriptInfo {
int rooms;
int startGame;
int restoreGame;
int stdExamine;
int stdPickup;
int stdUse;
int stdOpen;
int stdClose;
int stdTalk;
int stdGive;
int usdCode;
int invObjExam;
int invObjUse;
int invObjUU;
int stdUseItem;
int lightSources;
int specRout;
int invObjGive;
int stdGiveItem;
int goTester;
};
ScriptInfo _scriptInfo;
bool loadStream(Common::SeekableReadStream &stream);
uint16 readScript16(uint32 address);
uint32 readScript32(uint32 address);
uint32 getStartGameOffset();
uint32 getLocationInitScript(int initRoomTableOffset, int roomNr);
int16 getLightX(int locationNr);
int16 getLightY(int locationNr);
int32 getShadowScale(int locationNr);
uint8 *getRoomOffset(int locationNr);
int32 getOptionStandardOffset(int option);
uint8 *getHeroAnimName(int offset);
void installBackAnims(Common::Array<BackgroundAnim> &backAnimList, int roomBackAnimOffset);
void installSingleBackAnim(Common::Array<BackgroundAnim> &backAnimList, int slot, int roomBackAnimOffset);
void installObjects(int offset);
bool loadAllMasks(Common::Array<Mask> &maskList, int offset);
int scanMobEvents(int mobMask, int dataEventOffset);
int scanMobEventsWithItem(int mobMask, int dataEventOffset, int itemMask);
byte getMobVisible(int roomMobOffset, uint16 mob);
void setMobVisible(int roomMobOffset, uint16 mob, byte value);
uint32 getBackAnimId(int roomBackAnimOffset, int slot);
void setBackAnimId(int roomBackAnimOffset, int slot, int animId);
byte getObjId(int roomObjOffset, int slot);
void setObjId(int roomObjOffset, int slot, byte objectId);
const char *getString(uint32 offset) {
return (const char *)(&_data[offset]);
}
private:
PrinceEngine *_vm;
uint8 *_data;
uint32 _dataSize;
Common::Array<Room> _roomList;
};
class InterpreterFlags {
public:
InterpreterFlags();
void setFlagValue(Flags::Id flag, int32 value);
int32 getFlagValue(Flags::Id flag);
void resetAllFlags();
static const uint16 kFlagMask = 0x8000;
static const uint16 kMaxFlags = 2000;
private:
int32 _flags[kMaxFlags];
};
class Interpreter {
public:
Interpreter(PrinceEngine *vm, Script *script, InterpreterFlags *flags);
void stopBg() { _bgOpcodePC = 0; }
void stepBg();
void stepFg();
void storeNewPC(int opcodePC);
int getLastOPCode();
int getFgOpcodePC();
void setBgOpcodePC(uint32 value);
void setFgOpcodePC(uint32 value);
uint32 getCurrentString();
void setCurrentString(uint32 value);
byte *getString();
void setString(byte *newString);
void increaseString();
void setResult(byte value);
private:
PrinceEngine *_vm;
Script *_script;
InterpreterFlags *_flags;
uint32 _currentInstruction;
uint32 _bgOpcodePC;
uint32 _fgOpcodePC;
uint16 _lastOpcode;
uint32 _lastInstruction;
byte _result;
bool _opcodeNF; // break interpreter loop
bool _opcodeEnd; // end of a game flag
static const uint32 _STACK_SIZE = 500;
uint32 _stack[_STACK_SIZE];
struct stringStack {
byte *string;
byte *dialogData;
uint32 currentString;
} _stringStack;
uint8 _stacktop;
uint32 _waitFlag;
byte *_string;
byte _stringBuf[1024];
uint32 _currentString;
const char *_mode;
Flags _flagMap;
// Helper functions
uint32 step(uint32 opcodePC);
uint16 readScript16();
uint32 readScript32();
int32 readScriptFlagValue();
Flags::Id readScriptFlagId();
int checkSeq(byte *string);
void debugInterpreter(const char *s, ...);
typedef void (Interpreter::*OpcodeFunc)();
static OpcodeFunc _opcodes[];
static const uint kGiveLetterScriptFix = 79002;
static const uint kSecondBirdAnimationScriptFix = 45658;
// Keep opcode handlers names as they are in original code
// making it easier to switch back and forth
void O_WAITFOREVER();
void O_BLACKPALETTE();
void O_SETUPPALETTE();
void O_INITROOM();
void O_SETSAMPLE();
void O_FREESAMPLE();
void O_PLAYSAMPLE();
void O_PUTOBJECT();
void O_REMOBJECT();
void O_SHOWANIM();
void O_CHECKANIMEND();
void O_FREEANIM();
void O_CHECKANIMFRAME();
void O_PUTBACKANIM();
void O_REMBACKANIM();
void O_CHECKBACKANIMFRAME();
void O_FREEALLSAMPLES();
void O_SETMUSIC();
void O_STOPMUSIC();
void O__WAIT();
void O_UPDATEOFF();
void O_UPDATEON();
void O_UPDATE ();
void O_CLS();
void O__CALL();
void O_RETURN();
void O_GO();
void O_BACKANIMUPDATEOFF();
void O_BACKANIMUPDATEON();
void O_CHANGECURSOR();
void O_CHANGEANIMTYPE();
void O__SETFLAG();
void O_COMPARE();
void O_JUMPZ();
void O_JUMPNZ();
void O_EXIT();
void O_ADDFLAG();
void O_TALKANIM();
void O_SUBFLAG();
void O_SETSTRING();
void O_ANDFLAG();
void O_GETMOBDATA();
void O_ORFLAG();
void O_SETMOBDATA();
void O_XORFLAG();
void O_GETMOBTEXT();
void O_MOVEHERO();
void O_WALKHERO();
void O_SETHERO();
void O_HEROOFF();
void O_HEROON();
void O_CLSTEXT();
void O_CALLTABLE();
void O_CHANGEMOB();
void O_ADDINV();
void O_REMINV();
void O_REPINV();
void O_OBSOLETE_GETACTION();
void O_ADDWALKAREA();
void O_REMWALKAREA();
void O_RESTOREWALKAREA();
void O_WAITFRAME();
void O_SETFRAME();
void O_RUNACTION();
void O_COMPAREHI();
void O_COMPARELO();
void O_PRELOADSET();
void O_FREEPRELOAD();
void O_CHECKINV();
void O_TALKHERO();
void O_WAITTEXT();
void O_SETHEROANIM();
void O_WAITHEROANIM();
void O_GETHERODATA();
void O_GETMOUSEBUTTON();
void O_CHANGEFRAMES();
void O_CHANGEBACKFRAMES();
void O_GETBACKANIMDATA();
void O_GETANIMDATA();
void O_SETBGCODE();
void O_SETBACKFRAME();
void O_GETRND();
void O_TALKBACKANIM();
void O_LOADPATH();
void O_GETCHAR();
void O_SETDFLAG();
void O_CALLDFLAG();
void O_PRINTAT();
void O_ZOOMIN();
void O_ZOOMOUT();
void O_SETSTRINGOFFSET();
void O_GETOBJDATA();
void O_SETOBJDATA();
void O_SWAPOBJECTS();
void O_CHANGEHEROSET();
void O_ADDSTRING();
void O_SUBSTRING();
void O_INITDIALOG();
void O_ENABLEDIALOGOPT();
void O_DISABLEDIALOGOPT();
void O_SHOWDIALOGBOX();
void O_STOPSAMPLE();
void O_BACKANIMRANGE();
void O_CLEARPATH();
void O_SETPATH();
void O_GETHEROX();
void O_GETHEROY();
void O_GETHEROD();
void O_PUSHSTRING();
void O_POPSTRING();
void O_SETFGCODE();
void O_STOPHERO();
void O_ANIMUPDATEOFF();
void O_ANIMUPDATEON();
void O_FREECURSOR();
void O_ADDINVQUIET();
void O_RUNHERO();
void O_SETBACKANIMDATA();
void O_VIEWFLC();
void O_CHECKFLCFRAME();
void O_CHECKFLCEND();
void O_FREEFLC();
void O_TALKHEROSTOP();
void O_HEROCOLOR();
void O_GRABMAPA();
void O_ENABLENAK();
void O_DISABLENAK();
void O_GETMOBNAME();
void O_SWAPINVENTORY();
void O_CLEARINVENTORY();
void O_SKIPTEXT();
void O_SETVOICEH();
void O_SETVOICEA();
void O_SETVOICEB();
void O_SETVOICEC();
void O_VIEWFLCLOOP();
void O_FLCSPEED();
void O_OPENINVENTORY();
void O_KRZYWA();
void O_GETKRZYWA();
void O_GETMOB();
void O_INPUTLINE();
void O_SETVOICED();
void O_BREAK_POINT();
};
} // End of namespace Prince
#endif

180
engines/prince/sound.cpp Normal file
View File

@@ -0,0 +1,180 @@
/* 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/archive.h"
#include "common/config-manager.h"
#include "audio/audiostream.h"
#include "audio/decoders/wave.h"
#include "prince/prince.h"
#include "prince/hero.h"
#include "prince/script.h"
namespace Prince {
void PrinceEngine::playSample(uint16 sampleId, uint16 loopType) {
if (_audioStream[sampleId]) {
if (_mixer->isSoundIDActive(sampleId)) {
return;
}
_audioStream[sampleId]->rewind();
if (sampleId < 28) {
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle[sampleId], _audioStream[sampleId], sampleId, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
} else {
_mixer->playStream(Audio::Mixer::kSpeechSoundType, &_soundHandle[sampleId], _audioStream[sampleId], sampleId, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
}
}
}
void PrinceEngine::stopSample(uint16 sampleId) {
_mixer->stopID(sampleId);
}
void PrinceEngine::stopAllSamples() {
_mixer->stopAll();
}
void PrinceEngine::freeSample(uint16 sampleId) {
stopSample(sampleId);
if (_audioStream[sampleId] != nullptr) {
delete _audioStream[sampleId];
_audioStream[sampleId] = nullptr;
}
}
void PrinceEngine::freeAllSamples() {
for (int sampleId = 0; sampleId < kMaxSamples; sampleId++) {
freeSample(sampleId);
}
}
bool PrinceEngine::loadSample(uint32 sampleSlot, const Common::String &streamName) {
// FIXME: This is just a workaround streamName is a path
// SOUND\\SCIERKA1.WAV for now only last path component is used
Common::String normalizedPath = lastPathComponent(streamName, '\\');
// WALKAROUND: Wrong name in script, not existing sound in data files
if (!normalizedPath.compareTo("9997BEKA.WAV")) {
return 0;
}
debugEngine("loadSample slot %d, name %s", sampleSlot, normalizedPath.c_str());
freeSample(sampleSlot);
Common::SeekableReadStream *sampleStream = SearchMan.createReadStreamForMember(Common::Path(normalizedPath));
if (sampleStream == nullptr) {
error("Can't load sample %s to slot %d", normalizedPath.c_str(), sampleSlot);
}
_audioStream[sampleSlot] = Audio::makeWAVStream(sampleStream->readStream(sampleStream->size()), DisposeAfterUse::YES);
delete sampleStream;
return true;
}
bool PrinceEngine::loadVoice(uint32 slot, uint32 sampleSlot, const Common::String &streamName) {
if (getFeatures() & GF_NOVOICES)
return false;
_missingVoice = false;
debugEngine("Loading wav %s slot %d", streamName.c_str(), slot);
if (slot >= kMaxTexts) {
error("Text slot bigger than MAXTEXTS %d", kMaxTexts - 1);
return false;
}
freeSample(sampleSlot);
Common::SeekableReadStream *sampleStream = SearchMan.createReadStreamForMember(Common::Path(streamName));
if (sampleStream == nullptr) {
warning("loadVoice: Can't open %s", streamName.c_str());
_missingVoice = true; // Insert END tag if needed
_textSlots[slot]._time = 1; // Set phrase time to none
_mainHero->_talkTime = 1;
// Speak missing voice clips like objects
if (_textSlots[slot]._str && (ConfMan.getBool("tts_enabled_missing_voice") || ConfMan.getBool("tts_enabled_speech"))) {
sayText(_textSlots[slot]._str, false);
}
return false;
}
uint32 id = sampleStream->readUint32LE();
if (id != MKTAG('F', 'F', 'I', 'R')) {
error("It's not RIFF file %s", streamName.c_str());
return false;
}
sampleStream->skip(0x20);
id = sampleStream->readUint32LE();
if (id != MKTAG('a', 't', 'a', 'd')) {
error("No data section in %s id %04x", streamName.c_str(), id);
return false;
}
id = sampleStream->readUint32LE();
debugEngine("SetVoice slot %d time %04x", slot, id);
id <<= 3;
id /= 22050;
id += 2;
_textSlots[slot]._time = id;
if (!slot) {
_mainHero->_talkTime = id;
} else if (slot == 1) {
_secondHero->_talkTime = id;
}
debugEngine("SetVoice slot %d time %04x", slot, id);
sampleStream->seek(SEEK_SET);
_audioStream[sampleSlot] = Audio::makeWAVStream(sampleStream->readStream(sampleStream->size()), DisposeAfterUse::YES);
delete sampleStream;
return true;
}
void PrinceEngine::setVoice(uint16 slot, uint32 sampleSlot, uint16 flag) {
Common::String sampleName;
uint32 currentString = _interpreter->getCurrentString();
if (currentString >= 80000) {
uint32 nr = currentString - 80000;
sampleName = Common::String::format("%02d0%02d-%02d.WAV", nr / 100, nr % 100, flag);
} else if (currentString >= 70000) {
sampleName = Common::String::format("inv%02d-01.WAV", currentString - 70000);
} else if (currentString >= 60000) {
sampleName = Common::String::format("M%04d-%02d.WAV", currentString - 60000, flag);
// String 316.
// Fixes PRINCE: conversation with the priest bug #11771
// When Galador starts conversation with the priest with any gesture,
// the priest sits down to his place and conversation cannot be continued.
} else if (currentString == 316 || currentString >= 2000) {
return;
} else if (flag >= 100) {
sampleName = Common::String::format("%03d-%03d.WAV", currentString, flag);
} else {
sampleName = Common::String::format("%03d-%02d.WAV", currentString, flag);
}
loadVoice(slot, sampleSlot, sampleName);
}
} // End of namespace Prince

View File

@@ -0,0 +1,54 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "prince/variatxt.h"
#include "common/debug.h"
namespace Prince {
VariaTxt::VariaTxt() : _dataSize(0), _data(nullptr) {
}
VariaTxt::~VariaTxt() {
_dataSize = 0;
if (_data != nullptr) {
free(_data);
_data = nullptr;
}
}
bool VariaTxt::loadStream(Common::SeekableReadStream &stream) {
_dataSize = stream.size();
_data = (byte *)malloc(_dataSize);
stream.read(_data, _dataSize);
return true;
}
byte *VariaTxt::getString(uint32 stringId) {
uint32 stringOffset = READ_LE_UINT32(_data + stringId * 4);
if (stringOffset > _dataSize) {
assert(false);
}
return _data + stringOffset;
}
} // End of namespace Prince

39
engines/prince/variatxt.h Normal file
View File

@@ -0,0 +1,39 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/stream.h"
namespace Prince {
class VariaTxt {
public:
VariaTxt();
~VariaTxt();
bool loadStream(Common::SeekableReadStream &stream);
byte *getString(uint32 stringId);
private:
uint32 _dataSize;
byte *_data;
};
} // End of namespace Prince

View File

@@ -0,0 +1,82 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "prince/prince.h"
#include "engines/util.h"
#include "graphics/surface.h"
#include "video/avi_decoder.h"
namespace Prince {
void PrinceEngine::playVideo(const Common::Path &videoFilename) {
// Set the correct video mode
initGraphics(640, 480, nullptr);
if (_system->getScreenFormat().bytesPerPixel == 1) {
warning("Couldn't switch to a RGB color video mode to play a video.");
return;
}
debug(2, "Screen format: %s", _system->getScreenFormat().toString().c_str());
Video::VideoDecoder *videoDecoder = new Video::AVIDecoder();
if (!videoDecoder->loadFile(videoFilename)) {
delete videoDecoder;
warning("Unable to open video %s", videoFilename.toString().c_str());
initGraphics(640, 480);
return;
}
videoDecoder->start();
bool skipVideo = false;
while (!shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) {
if (videoDecoder->needsUpdate()) {
const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
if (frame) {
if (frame->format.bytesPerPixel > 1) {
Graphics::Surface *frame1 = frame->convertTo(_system->getScreenFormat());
_system->copyRectToScreen(frame1->getPixels(), frame1->pitch, 0, 0, frame1->w, frame1->h);
frame1->free();
delete frame1;
} else {
_system->copyRectToScreen(frame->getPixels(), frame->pitch, 0, 0, frame->w, frame->h);
}
_system->updateScreen();
}
}
Common::Event event;
while (_system->getEventManager()->pollEvent(event)) {
if ((event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_START && event.customType == kActionSkip) ||
event.type == Common::EVENT_LBUTTONUP)
skipVideo = true;
}
_system->delayMillis(10);
}
delete videoDecoder;
initGraphics(640, 480);
}
} // End of namespace Prince

1609
engines/prince/walk.cpp Normal file

File diff suppressed because it is too large Load Diff