Initial commit

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

View File

@@ -0,0 +1,268 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/system.h"
#include "petka/interfaces/dialog_interface.h"
#include "petka/interfaces/main.h"
#include "petka/petka.h"
#include "petka/objects/object_cursor.h"
#include "petka/objects/object_star.h"
#include "petka/objects/heroes.h"
#include "petka/q_system.h"
#include "petka/big_dialogue.h"
#include "petka/sound.h"
#include "petka/flc.h"
#include "petka/q_manager.h"
namespace Petka {
DialogInterface::DialogInterface() {
_dialog = g_vm->getBigDialogue();
_qsys = g_vm->getQSystem();
_state = kIdle;
_id = -1;
_isUserMsg = false;
_afterUserMsg = false;
_talker = nullptr;
_sender = nullptr;
_reaction = nullptr;
_firstTime = true;
_savedCursorId = _savedCursorActType = 0;
_wasCursorAnim = _wasCursorShown = false;
}
DialogInterface::~DialogInterface() {
delete _reaction;
}
void DialogInterface::start(uint id, QMessageObject *sender) {
_id = id;
_isUserMsg = false;
_afterUserMsg = false;
_talker = nullptr;
_firstTime = true;
_state = kIdle;
_sender = sender;
_soundName.clear();
initCursor();
next(-2);
}
void DialogInterface::initCursor() {
QObjectCursor *cursor = _qsys->getCursor();
_savedCursorId = cursor->_resourceId;
_savedCursorActType = cursor->_actionType;
_wasCursorAnim = cursor->_animate;
_wasCursorShown = cursor->_isShown;
cursor->show(false);
cursor->_animate = true;
cursor->_resourceId = 5006;
cursor->_actionType = kActionTalk;
}
void DialogInterface::restoreCursor() {
QObjectCursor *cursor = _qsys->getCursor();
cursor->_isShown = _wasCursorShown;
cursor->_animate = _wasCursorAnim;
cursor->_resourceId = _savedCursorId;
cursor->_actionType = _savedCursorActType;
// original bug fix
g_vm->pushMouseMoveEvent();
}
void DialogInterface::next(int choice) {
if (_id == -1)
return;
if ((choice == -1 && _state == kMenu) || (choice != -1 && _state == kPlaying))
return;
int prevTalkerId = -1;
if (choice == -1 && !_afterUserMsg) {
_dialog->getSpeechInfo(&prevTalkerId, nullptr, -1);
}
_afterUserMsg = _isUserMsg;
_qsys->getCursor()->_isShown = false;
if (_isUserMsg)
return;
if (_firstTime)
_firstTime = false;
else
_dialog->next(choice);
switch (_dialog->opcode()) {
case kOpcodePlay:
onPlayOpcode(prevTalkerId);
break;
case kOpcodeMenu:
onMenuOpcode();
break;
case kOpcodeEnd:
onEndOpcode();
break;
case kOpcodeUserMessage:
onUserMsgOpcode();
break;
default:
break;
}
}
void DialogInterface::sendMsg(uint16 opcode) {
if (_talker) {
_talker->processMessage(QMessage(_talker->_id, opcode, 0, 0, 0, nullptr, 0));
}
}
void DialogInterface::onEndOpcode() {
g_vm->soundMgr()->removeSound(_soundName);
sendMsg(kSaid);
_talker = nullptr;
_state = kIdle;
_id = -1;
_qsys->_currInterface->removeTexts();
restoreCursor();
if (_reaction) {
QReaction *reaction = _reaction;
_reaction = nullptr;
_sender->processReaction(reaction);
}
_sender = nullptr;
}
void DialogInterface::endUserMsg() {
_isUserMsg = false;
initCursor();
next(-1);
}
void DialogInterface::startUserMsg(uint16 arg) {
sendMsg(kSaid);
_isUserMsg = true;
restoreCursor();
_qsys->addMessage(_qsys->getChapay()->_id, kUserMsg, arg);
}
bool DialogInterface::isActive() {
return _state != kIdle;
}
void DialogInterface::setSender(QMessageObject *sender) {
_sender = sender;
}
Sound *DialogInterface::findSound() {
return g_vm->soundMgr()->findSound(_soundName);
}
void DialogInterface::removeSound() {
g_vm->soundMgr()->removeSound(_soundName);
_soundName.clear();
}
void DialogInterface::setReaction(QReaction *reaction) {
delete _reaction;
_reaction = reaction;
}
void DialogInterface::playSound(const Common::String &name) {
removeSound();
_soundName = name;
Sound *s = g_vm->soundMgr()->addSound(name, Audio::Mixer::kSpeechSoundType);
if (s) {
FlicDecoder *flc = g_vm->resMgr()->getFlic(_talker->_resourceId);
if (flc) {
Common::Rect bounds = flc->getBounds();
s->setBalance(bounds.left + _talker->_x + bounds.width(), _qsys->_sceneWidth);
}
s->play(false);
}
}
void DialogInterface::setPhrase(const Common::U32String *text) {
uint16 textColor;
uint16 outlineColor;
if (_talker->_dialogColor == -1) {
textColor = g_system->getScreenFormat().RGBToColor(0xA, 0xA, 0xA);
outlineColor = 0xFFFF;
} else {
textColor = _talker->_dialogColor;
outlineColor = g_system->getScreenFormat().RGBToColor(0x7F, 0, 0);
}
_qsys->_currInterface->setTextPhrase(*text, textColor, outlineColor);
}
void DialogInterface::onPlayOpcode(int prevTalkerId) {
int currTalkerId;
const char *soundName = nullptr;
const Common::U32String *text = _dialog->getSpeechInfo(&currTalkerId, &soundName, -1);
if (prevTalkerId != currTalkerId) {
sendMsg(kSaid);
}
_talker = _qsys->findObject(currTalkerId);
playSound(g_vm->getSpeechPath() + soundName);
setPhrase(text);
if (prevTalkerId != currTalkerId) {
sendMsg(kSay);
}
_state = kPlaying;
}
void DialogInterface::onMenuOpcode() {
removeSound();
sendMsg(kSaid);
_talker = nullptr;
Common::Array<Common::U32String> choices;
_dialog->getMenuChoices(choices);
_qsys->_mainInterface->setTextChoice(choices,
g_system->getScreenFormat().RGBToColor(0xFF, 0xFF, 0xFF),
g_system->getScreenFormat().RGBToColor(0xA, 0xA, 0xA),
g_system->getScreenFormat().RGBToColor(0, 0, 0xFF));
_qsys->getCursor()->_isShown = true;
_state = kMenu;
}
void DialogInterface::onUserMsgOpcode() {
_qsys->_currInterface->setTextPhrase(Common::U32String(), 0, 0);
removeSound();
_talker = nullptr;
_state = kPlaying;
}
void DialogInterface::fixCursor() {
_isUserMsg = false;
_qsys->getCursor()->show(true);
_qsys->getStar()->_isActive = true;
}
} // End of namespace Petka

View File

@@ -0,0 +1,96 @@
/* 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 PETKA_DIALOG_INTERFACE_H
#define PETKA_DIALOG_INTERFACE_H
#include "common/str.h"
namespace Petka {
enum DialogState {
kPlaying = 1,
kMenu = 2,
kIdle = 3
};
class Sound;
class QMessageObject;
class BigDialogue;
class QSystem;
struct QReaction;
class DialogInterface {
public:
DialogInterface();
~DialogInterface();
void start(uint id, QMessageObject *sender);
void next(int choice);
void startUserMsg(uint16 arg);
void endUserMsg();
bool isActive();
Sound *findSound();
void setSender(QMessageObject *sender);
void setReaction(QReaction *reaction);
void fixCursor();
private:
void onPlayOpcode(int prevTalkerId);
void onMenuOpcode();
void onEndOpcode();
void onUserMsgOpcode();
void removeSound();
void sendMsg(uint16 opcode);
void setPhrase(const Common::U32String *text);
void playSound(const Common::String &name);
void initCursor();
void restoreCursor();
private:
BigDialogue *_dialog;
QSystem *_qsys;
bool _isUserMsg;
bool _afterUserMsg;
bool _firstTime;
int _id;
DialogState _state;
Common::String _soundName;
QMessageObject *_talker;
QMessageObject *_sender;
QReaction *_reaction;
int16 _savedCursorActType;
int16 _savedCursorId;
bool _wasCursorShown;
bool _wasCursorAnim;
};
} // End of namespace Petka
#endif

View File

@@ -0,0 +1,154 @@
/* 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 "petka/objects/text.h"
#include "petka/interfaces/interface.h"
#include "petka/q_system.h"
#include "petka/petka.h"
#include "petka/objects/object_cursor.h"
#include "petka/q_manager.h"
#include "petka/video.h"
namespace Petka {
Interface::Interface()
: _objUnderCursor(nullptr), _startIndex(0) {}
void Interface::stop() {
setText(Common::U32String(), 0, 0);
g_vm->videoSystem()->makeAllDirty();
}
void Interface::setText(const Common::U32String &text, uint16 textColor, uint16 outlineColor) {
removeTexts();
if (!text.empty())
_objs.push_back(new QText(text, textColor, outlineColor));
}
void Interface::setTextPhrase(const Common::U32String &text, uint16 textColor, uint16 outlineColor) {
removeTexts();
_objUnderCursor = nullptr;
_objs.push_back(new QTextPhrase(text, textColor, outlineColor));
}
QVisibleObject *Interface::findObject(int resourceId) {
for (uint i = 0; i < _objs.size(); ++i) {
if (_objs[i]->_resourceId == resourceId) {
return _objs[i];
}
}
return nullptr;
}
void Interface::initCursor(int id, bool show, bool animate) {
QObjectCursor *cursor = g_vm->getQSystem()->getCursor();
_objs.push_back(cursor);
cursor->_resourceId = id;
cursor->_isShown = show;
cursor->_animate = animate;
cursor->_actionType = kActionLook;
cursor->setPos(Common::Point(cursor->_x, cursor->_y), false);
}
void Interface::removeTexts() {
for (uint i = 0; i < _objs.size();) {
if (_objs[i]->_resourceId == -2) {
g_vm->videoSystem()->addDirtyRect(((QText *)_objs[i])->getRect());
g_vm->resMgr()->removeResource((uint32)-2);
delete _objs[i];
_objs.remove_at(i);
} else {
++i;
}
}
}
void Interface::update(uint time) {
for (uint i = _startIndex; i < _objs.size(); ++i) {
_objs[i]->update(time);
}
for (uint i = 0; i < _objs.size(); ++i) {
_objs[i]->updateZ();
}
sort();
}
void Interface::draw() {
for (uint i = 0; i < _objs.size(); ++i) {
_objs[i]->draw();
}
}
void Interface::sort() {
for (uint i = 0; i < _objs.size() - 1; ++i) {
uint minIndex = i;
for (uint j = i + 1; j < _objs.size(); ++j) {
if (_objs[j]->_z < _objs[minIndex]->_z) {
minIndex = j;
}
}
if (i != minIndex) {
SWAP(_objs[i], _objs[minIndex]);
}
}
}
void SubInterface::start(int id) {
QSystem *sys = g_vm->getQSystem();
QObjectCursor *cursor = sys->getCursor();
_savedCursorId = cursor->_resourceId;
_savedCursorType = cursor->_actionType;
initCursor(4901, true, false);
_savedXOffset = sys->_xOffset;
_savedSceneWidth = sys->_sceneWidth;
sys->_xOffset = 0;
sys->_sceneWidth = 640;
g_vm->getQSystem()->_currInterface = this;
g_vm->videoSystem()->updateTime();
g_vm->videoSystem()->makeAllDirty();
}
void SubInterface::stop() {
QSystem *sys = g_vm->getQSystem();
QObjectCursor *cursor = sys->getCursor();
sys->_xOffset = _savedXOffset;
sys->_sceneWidth = _savedSceneWidth;
cursor->_resourceId = _savedCursorId;
cursor->_actionType = _savedCursorType;
sys->_currInterface = g_vm->getQSystem()->_prevInterface;
sys->_currInterface->onMouseMove(Common::Point(cursor->_x, cursor->_y));
_objs.clear();
Interface::stop();
}
} // End of namespace Petka

View File

@@ -0,0 +1,81 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PETKA_INTERFACE_H
#define PETKA_INTERFACE_H
#include "common/ustr.h"
#include "common/rect.h"
#include "common/array.h"
namespace Petka {
class QVisibleObject;
class QText;
class Interface {
public:
Interface();
virtual ~Interface() {}
virtual void start(int id) {};
virtual void stop();
virtual void update(uint time);
void draw();
virtual void onLeftButtonDown(Common::Point p) {};
virtual void onRightButtonDown(Common::Point p) {};
virtual void onMouseMove(Common::Point p) {};
void setText(const Common::U32String &text, uint16 textColor, uint16 outlineColor);
void setTextPhrase(const Common::U32String &text, uint16 textColor, uint16 outlineColor);
void removeTexts();
QVisibleObject *findObject(int resourceId);
void initCursor(int id, bool show, bool animate);
private:
void sort();
public:
Common::Array<QVisibleObject *> _objs;
QVisibleObject *_objUnderCursor;
uint _startIndex;
};
class SubInterface : public Interface {
public:
void start(int id) override;
void stop() override;
private:
int _savedXOffset;
int _savedSceneWidth;
int _savedCursorId;
int _savedCursorType;
};
} // End of namespace Petka
#endif

View File

@@ -0,0 +1,305 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/system.h"
#include "common/stream.h"
#include "common/events.h"
#include "common/formats/ini-file.h"
#include "petka/flc.h"
#include "petka/objects/object_case.h"
#include "petka/objects/object_cursor.h"
#include "petka/objects/object_star.h"
#include "petka/interfaces/main.h"
#include "petka/q_system.h"
#include "petka/q_manager.h"
#include "petka/sound.h"
#include "petka/petka.h"
#include "petka/video.h"
#include "petka/objects/object_case.h"
#include "petka/objects/heroes.h"
#include "petka/objects/text.h"
#include "petka/walk.h"
namespace Petka {
InterfaceMain::InterfaceMain() {
Common::ScopedPtr<Common::SeekableReadStream> stream(g_vm->openFile("backgrnd.bg", true));
_hasTextDesc = false;
_roomId = 0;
if (!stream)
return;
_bgs.resize(stream->readUint32LE());
for (uint i = 0; i < _bgs.size(); ++i) {
_bgs[i].objId = stream->readUint16LE();
_bgs[i].attachedObjIds.resize(stream->readUint32LE());
for (uint j = 0; j < _bgs[i].attachedObjIds.size(); ++j) {
_bgs[i].attachedObjIds[j] = stream->readUint16LE();
QMessageObject *obj = g_vm->getQSystem()->findObject(_bgs[i].attachedObjIds[j]);
obj->_x = stream->readSint32LE();
obj->_y = stream->readSint32LE();
obj->_z = stream->readSint32LE();
obj->_walkX = stream->readSint32LE();
obj->_walkY = stream->readSint32LE();
}
}
_objs.push_back(g_vm->getQSystem()->getCursor());
_objs.push_back(g_vm->getQSystem()->getCase());
_objs.push_back(g_vm->getQSystem()->getStar());
}
void InterfaceMain::start(int id) {
_objs.push_back(g_vm->getQSystem()->getPetka());
_objs.push_back(g_vm->getQSystem()->getChapay());
Common::ScopedPtr<Common::SeekableReadStream> bgsStream(g_vm->openFile("BGs.ini", true));
Common::INIFile bgsIni;
bgsIni.allowNonEnglishCharacters();
bgsIni.loadFromStream(*bgsStream);
Common::String startRoom;
bgsIni.getKey("StartRoom", "Settings", startRoom);
if (g_vm->getSaveSlot() == -1)
loadRoom(g_vm->getQSystem()->findObject(startRoom)->_id, false);
}
void InterfaceMain::loadRoom(int id, bool fromSave) {
QSystem *sys = g_vm->getQSystem();
sys->_currInterface->stop();
if (_roomId == id)
return;
unloadRoom(fromSave);
const BGInfo *info = findBGInfo(id);
QObjectBG *room = (QObjectBG *)sys->findObject(id);
QManager *resMgr = g_vm->resMgr();
_roomId = id;
sys->_room = room;
_objs.push_back(room);
const auto *surface = resMgr->getSurface(room->_resourceId);
if (surface) {
assert(surface->w >= 640);
sys->_sceneWidth = MAX<int>(surface->w, 640);
sys->_xOffset = 0;
}
for (uint i = 0; i < info->attachedObjIds.size(); ++i) {
QMessageObject *obj = sys->findObject(info->attachedObjIds[i]);
obj->loadSound();
if (obj->_isShown || obj->_isActive)
g_vm->resMgr()->getFlic(obj->_resourceId);
_objs.push_back(obj);
}
auto petka = sys->getPetka();
auto chapay = sys->getChapay();
auto bkgName = resMgr->findResourceName(room->_resourceId);
petka->_walk->setBackground(bkgName);
chapay->_walk->setBackground(bkgName);
petka->setPos(Common::Point(petka->_x, petka->_y), false);
chapay->setPos(Common::Point(chapay->_x, chapay->_y), false);
playSound(room->_musicId, Audio::Mixer::kMusicSoundType);
playSound(room->_fxId, Audio::Mixer::kSFXSoundType);
if (!fromSave)
sys->addMessageForAllObjects(kInitBG, 0, 0, 0, 0, room);
g_vm->videoSystem()->updateTime();
}
void InterfaceMain::playSound(int id, Audio::Mixer::SoundType type) {
int *sysId = (type == Audio::Mixer::kMusicSoundType) ? &g_vm->getQSystem()->_musicId : &g_vm->getQSystem()->_fxId;
if (*sysId != id) {
g_vm->soundMgr()->removeSound(g_vm->resMgr()->findSoundName(*sysId));
Sound *sound = g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(id), Audio::Mixer::kMusicSoundType); // kMusicSoundType intended
if (sound) {
sound->play(true);
}
*sysId = id;
}
}
const BGInfo *InterfaceMain::findBGInfo(int id) const {
for (uint i = 0; i < _bgs.size(); ++i) {
if (_bgs[i].objId == id)
return &_bgs[i];
}
return nullptr;
}
void InterfaceMain::unloadRoom(bool fromSave) {
if (_roomId == -1)
return;
QSystem *sys = g_vm->getQSystem();
QObjectBG *room = (QObjectBG *)sys->findObject(_roomId);
if (!room)
return;
if (!fromSave)
sys->addMessageForAllObjects(kLeaveBG, 0, 0, 0, 0, room);
g_vm->soundMgr()->removeSoundsWithType(Audio::Mixer::kSFXSoundType);
g_vm->resMgr()->clearUnneeded();
_objs.clear();
_objs.push_back(sys->getCursor());
_objs.push_back(sys->getCase());
_objs.push_back(sys->getStar());
_objs.push_back(sys->getPetka());
_objs.push_back(sys->getChapay());
}
void InterfaceMain::onLeftButtonDown(Common::Point p) {
QObjectCursor *cursor = g_vm->getQSystem()->getCursor();
if (!cursor->_isShown) {
_dialog.next(-1);
return;
}
for (int i = _objs.size() - 1; i >= 0; --i) {
if (_objs[i]->isInPoint(p)) {
_objs[i]->onClick(p);
return;
}
}
switch (cursor->_actionType) {
case kActionWalk: {
QObjectPetka *petka = g_vm->getQSystem()->getPetka();
if (petka->_heroReaction) {
for (uint i = 0; i < petka->_heroReaction->messages.size(); ++i) {
if (petka->_heroReaction->messages[i].opcode == kGoTo) {
QObjectChapayev *chapay = g_vm->getQSystem()->getChapay();
chapay->stopWalk();
break;
}
}
delete petka->_heroReaction;
petka->_heroReaction = nullptr;
}
petka->walk(p.x, p.y);
break;
}
case kActionObjUseChapayev: {
QObjectChapayev *chapay = g_vm->getQSystem()->getChapay();
chapay->walk(p.x, p.y);
break;
}
default:
break;
}
}
void InterfaceMain::onRightButtonDown(Common::Point p) {
QObjectStar *star = g_vm->getQSystem()->getStar();
QObjectCase *objCase = g_vm->getQSystem()->getCase();
QObjectCursor *cursor = g_vm->getQSystem()->getCursor();
if (!star->_isActive)
return;
if (objCase->_isShown && cursor->_actionType == kActionObjUse) {
cursor->setAction(kActionTake);
} else {
star->setPos(p, false);
star->show(star->_isShown == 0);
}
}
void InterfaceMain::onMouseMove(Common::Point p) {
QMessageObject *prevObj = (QMessageObject *)_objUnderCursor;
_objUnderCursor = nullptr;
QObjectCursor *cursor = g_vm->getQSystem()->getCursor();
if (cursor->_isShown) {
for (int i = _objs.size() - 1; i >= 0; --i) {
if (_objs[i]->isInPoint(p)) {
_objs[i]->onMouseMove(p);
break;
}
}
}
cursor->_animate = _objUnderCursor != nullptr;
cursor->setPos(p, true);
if (prevObj != _objUnderCursor && _objUnderCursor && !_dialog.isActive()) {
Graphics::PixelFormat fmt = g_system->getScreenFormat();
QMessageObject *obj = (QMessageObject *)_objUnderCursor;
if (!obj->_nameOnScreen.empty()) {
setText(Common::convertToU32String(obj->_nameOnScreen.c_str(), Common::kWindows1251), fmt.RGBToColor(0xC0, 0xFF, 0xFF), fmt.RGBToColor(0xA, 0xA, 0xA));
} else {
setText(Common::convertToU32String(obj->_name.c_str(), Common::kWindows1251), fmt.RGBToColor(0x80, 0, 0), fmt.RGBToColor(0xA, 0xA, 0xA));
}
} else if (prevObj && !_objUnderCursor && !_dialog.isActive()) {
setText(Common::U32String(), 0, 0);
}
}
void InterfaceMain::setTextChoice(const Common::Array<Common::U32String> &choices, uint16 color, uint16 outlineColor, uint16 selectedColor) {
removeTexts();
_objUnderCursor = nullptr;
_objs.push_back(new QTextChoice(choices, color, outlineColor, selectedColor));
}
void InterfaceMain::setTextDescription(const Common::U32String &text, int frame) {
removeTexts();
QObjectStar *star = g_vm->getQSystem()->getStar();
star->_isActive = false;
_objUnderCursor = nullptr;
_hasTextDesc = true;
_objs.push_back(new QTextDescription(text, frame));
}
void InterfaceMain::removeTextDescription() {
_hasTextDesc = false;
_objUnderCursor = nullptr;
g_vm->getQSystem()->getStar()->_isActive = true;
removeTexts();
}
void InterfaceMain::update(uint time) {
QSystem *sys = g_vm->getQSystem();
int xOff = sys->_xOffset;
int reqOffset = sys->_reqOffset;
if (xOff != reqOffset && ((xOff != sys->_sceneWidth - 640 && xOff < reqOffset) || (xOff > 0 && xOff > reqOffset))) {
if (xOff <= reqOffset) {
xOff += 8;
xOff = MIN<int>(xOff, reqOffset);
} else {
xOff -= 8;
xOff = MAX<int>(xOff, reqOffset);
}
sys->_xOffset = CLIP(xOff, 0, sys->_sceneWidth - 640);
g_vm->videoSystem()->makeAllDirty();
}
Interface::update(time);
}
} // End of namespace Petka

View File

@@ -0,0 +1,74 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PETKA_MAIN_H
#define PETKA_MAIN_H
#include "audio/mixer.h"
#include "petka/interfaces/interface.h"
#include "petka/interfaces/dialog_interface.h"
namespace Petka {
struct BGInfo {
uint16 objId;
Common::Array<uint16> attachedObjIds;
};
class Sound;
class InterfaceMain : public Interface {
public:
InterfaceMain();
void start(int id) override;
void update(uint time) override;
void loadRoom(int id, bool fromSave);
const BGInfo *findBGInfo(int id) const;
void unloadRoom(bool fromSave);
void onLeftButtonDown(Common::Point p) override;
void onRightButtonDown(Common::Point p) override;
void onMouseMove(Common::Point p) override;
void setTextChoice(const Common::Array<Common::U32String> &choices, uint16 color, uint16 outlineColor, uint16 selectedColor);
void setTextDescription(const Common::U32String &text, int frame);
void removeTextDescription();
private:
void playSound(int id, Audio::Mixer::SoundType type);
public:
DialogInterface _dialog;
Common::Array<BGInfo> _bgs;
int _roomId;
bool _hasTextDesc;
};
} // End of namespace Petka
#endif

View File

@@ -0,0 +1,126 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/system.h"
#include "common/str-enc.h"
#include "petka/q_manager.h"
#include "petka/flc.h"
#include "petka/petka.h"
#include "petka/q_system.h"
#include "petka/interfaces/main.h"
#include "petka/interfaces/map.h"
#include "petka/objects/object_cursor.h"
#include "petka/video.h"
namespace Petka {
const char *const mapName = "\xCA\xC0\xD0\xD2\xC0"; // КАРТА
void InterfaceMap::start(int id) {
QSystem *sys = g_vm->getQSystem();
if (!sys->_room->_showMap)
return;
QObjectBG *bg = (QObjectBG *)sys->findObject(mapName);
_roomResID = bg->_resourceId;
_objs.push_back(bg);
const BGInfo *info = g_vm->getQSystem()->_mainInterface->findBGInfo(bg->_id);
for (uint i = 0; i < info->attachedObjIds.size(); ++i) {
QMessageObject *obj = sys->findObject(info->attachedObjIds[i]);
FlicDecoder *flc = g_vm->resMgr()->getFlic(obj->_resourceId);
if (flc) {
flc->setFrame(1);
}
obj->_z = 1;
obj->_x = 0;
obj->_y = 0;
obj->_frame = 1;
obj->_animate = obj->_isShown;
_objs.push_back(obj);
}
sys->addMessageForAllObjects(kInitBG, 0, 0, 0, 0, bg);
SubInterface::start(id);
}
void InterfaceMap::stop() {
if (_objUnderCursor)
((QMessageObject *)_objUnderCursor)->_isShown = false;
SubInterface::stop();
}
void InterfaceMap::onLeftButtonDown(Common::Point p) {
for (int i = _objs.size() - 1; i >= 0; --i) {
if (_objs[i]->isInPoint(p)) {
_objs[i]->onClick(p);
break;
}
}
}
void InterfaceMap::onMouseMove(Common::Point p) {
QVisibleObject *oldObj = _objUnderCursor;
_objUnderCursor = nullptr;
bool found = false;
for (int i = _objs.size() - 1; i > 0; --i) {
QMessageObject *obj = (QMessageObject *)_objs[i];
if (obj->_resourceId != 4901 && obj->_resourceId != _roomResID) {
FlicDecoder *flc = g_vm->resMgr()->getFlic(obj->_resourceId);
if (flc) {
bool show = false;
if (!found && obj->isInPoint(p)) {
found = true;
show = true;
_objUnderCursor = obj;
}
if (obj->_isShown != show)
obj->show(obj->_isShown == 0);
}
}
}
QObjectCursor *cursor = g_vm->getQSystem()->getCursor();
cursor->_animate = _objUnderCursor != nullptr;
cursor->_isShown = true;
cursor->setPos(p, false);
if (_objUnderCursor != oldObj && _objUnderCursor) {
Graphics::PixelFormat fmt = g_system->getScreenFormat();
QMessageObject *obj = (QMessageObject *)_objUnderCursor;
if (!obj->_nameOnScreen.empty()) {
setText(Common::convertToU32String(obj->_nameOnScreen.c_str(), Common::kWindows1251), fmt.RGBToColor(0xC0, 0xFF, 0xFF), fmt.RGBToColor(0xA, 0xA, 0xA));
} else {
setText(Common::convertToU32String(obj->_name.c_str(), Common::kWindows1251), fmt.RGBToColor(0x80, 0, 0), fmt.RGBToColor(0xA, 0xA, 0xA));
}
} else if (oldObj && !_objUnderCursor) {
setText(Common::U32String(), 0, 0);
}
}
void InterfaceMap::onRightButtonDown(Common::Point p) {
stop();
}
} // End of namespace Petka

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 PETKA_MAP_H
#define PETKA_MAP_H
#include "petka/interfaces/interface.h"
namespace Petka {
class InterfaceMap: public SubInterface {
public:
InterfaceMap() : _roomResID(0) {}
void start(int id) override;
void stop() override;
void onLeftButtonDown(Common::Point p) override;
void onRightButtonDown(Common::Point p) override;
void onMouseMove(Common::Point p) override;
private:
int _roomResID;
};
} // End of namespace Petka
#endif

View File

@@ -0,0 +1,346 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/config-manager.h"
#include "common/system.h"
#include "petka/objects/object_cursor.h"
#include "petka/objects/object_case.h"
#include "petka/petka.h"
#include "petka/q_system.h"
#include "petka/flc.h"
#include "petka/video.h"
#include "petka/q_manager.h"
#include "petka/interfaces/main.h"
#include "petka/interfaces/save_load.h"
#include "petka/interfaces/panel.h"
namespace {
// ПАНЕЛЬ УПРАВЛЕНИЯ
const char *const kPanelObjName = "\xCF\xC0\xCD\xC5\xCB\xDC\x20\xD3\xCF\xD0\xC0\xC2\xCB\xC5\xCD\xC8\xDF";
const uint kNewGameButtonIndex = 1;
const uint kLoadButtonIndex = 2;
const uint kContinueButtonIndex = 3;
const uint kExitButtonIndex = 4;
const uint kSaveButtonIndex = 5;
const uint kSafeObjectIndex = 6;
const uint kSfxLabelIndex = 7;
const uint kSubtitleButtonIndex = 8;
const uint kSfxVolumeSliderIndex = 9;
const uint kSpeedSliderIndex = 10;
const uint kMusicLabelIndex = 11;
const uint kSubtitleLabelIndex = 12;
const uint kSpeechLabelIndex = 13;
const uint kSpeedLabelIndex = 14;
const uint kSpeechVolumeSliderIndex = 15;
const uint kMusicVolumeSliderIndex = 16;
const uint kDecSpeechButtonIndex = 17;
const uint kIncSpeechButtonIndex = 18;
const uint kDecMusicButtonIndex = 19;
const uint kIncMusicButtonIndex = 20;
const uint kDecSfxButtonIndex = 21;
const uint kIncSfxButtonIndex = 22;
const uint kDecSpeedButtonIndex = 23;
const uint kIncSpeedButtonIndex = 24;
Common::Point getObjectPos(uint index)
{
switch (index) {
case kNewGameButtonIndex:
return {0, 2};
case kLoadButtonIndex:
return {5, 70};
case kContinueButtonIndex:
return {5, 136};
case kExitButtonIndex:
return {22, 328};
case kSaveButtonIndex:
return {87, 224};
case kSafeObjectIndex:
return {118, 395};
case kSfxLabelIndex:
return {467, 71};
case kSubtitleButtonIndex:
return {432, 144};
case kSfxVolumeSliderIndex:
return {428, 29};
case kSpeedSliderIndex:
return {434, 170};
case kMusicLabelIndex:
return {297, 214};
case kSubtitleLabelIndex:
return {470, 139};
case kSpeechLabelIndex:
return {318, 87};
case kSpeedLabelIndex:
return {468, 172};
case kSpeechVolumeSliderIndex:
return {262, 31};
case kMusicVolumeSliderIndex:
return {231, 137};
// case kDecSpeechButtonIndex:
// case kIncSpeechButtonIndex:
// case kDecMusicButtonIndex:
// case kIncMusicButtonIndex:
// case kDecSfxButtonIndex:
// case kIncSfxButtonIndex:
// case kDecSpeedButtonIndex:
// case kIncSpeedButtonIndex:
default:
return {0, 0};
}
}
}
namespace Petka {
InterfacePanel::InterfacePanel() {
readSettings();
}
void InterfacePanel::start(int id) {
QSystem *sys = g_vm->getQSystem();
sys->getCase()->show(false);
g_vm->videoSystem()->makeAllDirty();
g_vm->videoSystem()->update();
InterfaceSaveLoad::saveScreen();
QObjectBG *bg = (QObjectBG *)sys->findObject(kPanelObjName);
const BGInfo *info = sys->_mainInterface->findBGInfo(bg->_id);
_objs.reserve(info->attachedObjIds.size() + 1);
_objs.push_back(bg);
for (uint i = 0; i < info->attachedObjIds.size(); ++i) {
QMessageObject *obj = sys->findObject(info->attachedObjIds[i]);
FlicDecoder *flc = g_vm->resMgr()->getFlic(obj->_resourceId);
flc->setFrame(1);
const auto pos = getObjectPos(i + 1);
obj->_x = pos.x;
obj->_y = pos.y;
obj->_z = 1;
obj->_frame = 1;
obj->_animate = false;
_objs.push_back(obj);
}
SubInterface::start(id);
onSettingsChanged();
sys->getCursor()->_animate = true;
}
void InterfacePanel::onLeftButtonDown(Common::Point p) {
int i = 0;
for (i = _objs.size() - 1; i > 0; --i) {
if (_objs[i]->isInPoint(p)) {
break;
}
}
switch (i) {
case kNewGameButtonIndex:
g_vm->loadPart(1);
break;
case kLoadButtonIndex:
stop();
g_vm->getQSystem()->_saveLoadInterface->start(kLoadMode);
break;
case kContinueButtonIndex:
stop();
break;
case kExitButtonIndex:
g_system->quit();
break;
case kSaveButtonIndex:
stop();
g_vm->getQSystem()->_saveLoadInterface->start(kSaveMode);
break;
case kSubtitleButtonIndex:
_subtitles = !_subtitles;
updateSubtitles();
break;
case kDecSpeechButtonIndex:
_speechFrame -= 5;
updateSliders();
break;
case kIncSpeechButtonIndex:
_speechFrame += 5;
updateSliders();
break;
case kDecMusicButtonIndex:
_musicFrame -= 5;
updateSliders();
break;
case kIncMusicButtonIndex:
_musicFrame += 5;
updateSliders();
break;
case kDecSfxButtonIndex:
_sfxFrame -= 5;
updateSliders();
break;
case kIncSfxButtonIndex:
_sfxFrame += 5;
updateSliders();
break;
case kDecSpeedButtonIndex:
_speedFrame -= 5;
updateSliders();
break;
case kIncSpeedButtonIndex:
_speedFrame += 5;
updateSliders();
break;
default:
break;
}
}
void InterfacePanel::onMouseMove(Common::Point p) {
bool found = false;
for (uint i = _objs.size() - 1; i > 0; --i) {
QMessageObject *obj = (QMessageObject *)_objs[i];
byte frame = 1;
if (!found && obj->isInPoint(p)) {
found = true;
if ((i >= kNewGameButtonIndex && i <= kSaveButtonIndex) || (i >= kDecSpeechButtonIndex && i <= kIncSpeedButtonIndex)) {
frame = 2;
}
}
if (obj->_frame == frame)
continue;
obj->_frame = frame;
switch (i) {
case kDecSpeechButtonIndex:
case kIncSpeechButtonIndex:
updateSprite(kSpeechLabelIndex, frame);
break;
case kDecMusicButtonIndex:
case kIncMusicButtonIndex:
updateSprite(kMusicLabelIndex, frame);
break;
case kDecSfxButtonIndex:
case kIncSfxButtonIndex:
updateSprite(kSfxLabelIndex, frame);
break;
case kIncSpeedButtonIndex:
case kDecSpeedButtonIndex:
updateSprite(kSpeedLabelIndex, frame);
break;
default:
updateSprite(i, frame);
break;
}
}
QObjectCursor *cursor = g_vm->getQSystem()->getCursor();
cursor->_isShown = true;
cursor->setPos(p, false);
}
void InterfacePanel::updateSliders() {
applySettings();
updateSprite(kSpeechVolumeSliderIndex, _speechFrame);
updateSprite(kMusicVolumeSliderIndex, _musicFrame);
updateSprite(kSfxVolumeSliderIndex, _sfxFrame);
updateSprite(kSpeedSliderIndex, _speedFrame);
}
void InterfacePanel::updateSubtitles() {
applySettings();
updateSprite(kSubtitleButtonIndex, _subtitles == 0 ? 1 : 7);
updateSprite(kSubtitleLabelIndex, _subtitles == 0 ? 1 : 2);
}
void InterfacePanel::readSettings() {
_speechFrame = 1 + 30 * ConfMan.getInt("speech_volume") / 255;
_musicFrame = 1 + 40 * ConfMan.getInt("music_volume") / 255;
_sfxFrame = 1 + 30 * ConfMan.getInt("sfx_volume") / 255;
_subtitles = ConfMan.getBool("subtitles");
_speedFrame = 1 + ConfMan.getInt("petka_speed") / 4;
}
void InterfacePanel::applySettings() {
_speechFrame = CLIP<int>(_speechFrame, 1, 31);
_musicFrame = CLIP<int>(_musicFrame, 1, 41);
_sfxFrame = CLIP<int>(_sfxFrame, 1, 31);
_speedFrame = CLIP<int>(_speedFrame, 1, 26);
const auto speechFrame = _speechFrame;
const auto musicFrame = _musicFrame;
const auto sfxFrame = _sfxFrame;
const auto speedFrame = _speedFrame;
const auto subtitles = _subtitles;
readSettings();
if (speechFrame != _speechFrame) {
ConfMan.setInt("speech_volume", 255 * (speechFrame - 1) / (31 - 1));
}
if (musicFrame != _musicFrame) {
ConfMan.setInt("music_volume", 255 * (musicFrame - 1) / (41 - 1));
}
if (sfxFrame != _sfxFrame) {
ConfMan.setInt("sfx_volume", 255 * (sfxFrame - 1) / (31 - 1));
}
ConfMan.setBool("subtitles", subtitles);
if (speedFrame != _speedFrame) {
ConfMan.setInt("petka_speed", 4 * (speedFrame - 1));
}
readSettings();
ConfMan.flushToDisk();
g_vm->syncSoundSettings();
}
void InterfacePanel::onRightButtonDown(Common::Point p) {
stop();
}
void InterfacePanel::updateSprite(uint index, uint frame) const {
const auto *object = (QMessageObject *)(_objs[index]);
FlicDecoder *flc = g_vm->resMgr()->getFlic(object->_resourceId);
flc->setFrame(frame);
g_vm->videoSystem()->addDirtyRect(Common::Point(object->_x, object->_y), *flc);
}
int InterfacePanel::getHeroSpeed() {
return (_speedFrame * 100 - 100) / 25;
}
void InterfacePanel::onSettingsChanged() {
readSettings();
updateSliders();
updateSubtitles();
}
} // End of namespace Petka

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 PETKA_PANEL_H
#define PETKA_PANEL_H
#include "petka/interfaces/interface.h"
namespace Petka {
class InterfacePanel : public SubInterface {
public:
InterfacePanel();
void start(int id) override;
void onLeftButtonDown(Common::Point p) override;
void onRightButtonDown(Common::Point p) override;
void onMouseMove(Common::Point p) override;
void onSettingsChanged();
int getHeroSpeed();
bool showSubtitles() const { return _subtitles; }
private:
void readSettings();
void applySettings();
void updateSliders();
void updateSubtitles();
void updateSprite(uint index, uint frame) const;
private:
bool _subtitles;
int _speechFrame;
int _musicFrame;
int _sfxFrame;
int _speedFrame;
};
} // End of namespace Petka
#endif

View File

@@ -0,0 +1,149 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/system.h"
#include "engines/advancedDetector.h"
#include "graphics/fonts/ttf.h"
#include "graphics/font.h"
#include "graphics/thumbnail.h"
#include "petka/petka.h"
#include "petka/q_system.h"
#include "petka/q_manager.h"
#include "petka/video.h"
#include "petka/objects/object_cursor.h"
#include "petka/interfaces/save_load.h"
namespace Petka {
const uint kFirstSaveLoadPageId = 4990;
InterfaceSaveLoad::InterfaceSaveLoad() {
_page = 0;
_loadMode = false;
_saveRects[0] = Common::Rect(43, 84, 151, 166);
_saveRects[1] = Common::Rect(43, 209, 151, 291);
_saveRects[2] = Common::Rect(43, 335, 151, 417);
_saveRects[3] = Common::Rect(358, 75, 466, 157);
_saveRects[4] = Common::Rect(360, 200, 468, 282);
_saveRects[5] = Common::Rect(359, 325, 467, 407);
_nextPageRect = Common::Rect(596, 403, 624, 431);
_prevPageRect = Common::Rect(10, 414, 38, 442);
}
void InterfaceSaveLoad::start(int id) {
QSystem *sys = g_vm->getQSystem();
QManager *resMgr = g_vm->resMgr();
QObjectBG *bg = (QObjectBG *)sys->findObject("SAVELOAD");
_loadMode = (id == kLoadMode);
_objs.push_back(bg);
bg->_resourceId = kFirstSaveLoadPageId + _page + (_loadMode ? 0 : 5);
resMgr->removeResource(bg->_resourceId);
auto bmp = resMgr->getSurface(bg->_resourceId);
Graphics::ManagedSurface surf(bmp->w, bmp->h, bmp->format);
surf.blitFrom(*bmp);
// TODO: Which font did the original game use?
Common::ScopedPtr<Graphics::Font> font(Graphics::loadTTFFontFromArchive("LiberationSans-Regular.ttf", 18));
MetaEngine *metaEngine = g_engine->getMetaEngine();
for (int i = 0, j = _page * 6; i < 6; ++i, ++j) {
SaveStateDescriptor save = metaEngine->querySaveMetaInfos(g_vm->_desc->gameId, j);
auto surface = save.getThumbnail();
if (!surface)
continue;
Common::ScopedPtr<Graphics::Surface, Graphics::SurfaceDeleter> thumbnail(surface->scale(108, 82, true));
thumbnail.reset(thumbnail->convertTo(g_system->getOverlayFormat()));
surf.blitFrom(*thumbnail, Common::Point(_saveRects[i].left, _saveRects[i].top));
Common::Rect textRect(240, 30);
textRect.translate(_saveRects[i].left, _saveRects[i].bottom + 1);
Common::ScopedPtr<Graphics::Surface, Graphics::SurfaceDeleter> text(new Graphics::Surface);
text->create(textRect.width(), textRect.height(), g_system->getScreenFormat());
font->drawString(text.get(), save.getSaveDate() + " " + save.getSaveTime(), 0, 0, textRect.width(), text->format.RGBToColor(0, 0x7F, 00));
surf.transBlitFrom(*text, Common::Point(textRect.left, textRect.top));
}
bmp->copyFrom(surf.rawSurface());
SubInterface::start(id);
}
void InterfaceSaveLoad::onLeftButtonDown(Common::Point p) {
int index = findSaveLoadRectIndex(p);
if (index == -1) {
if (_prevPageRect.contains(p) && _page > 0) {
_page--;
stop();
start(_loadMode ? kLoadMode : kSaveMode);
} else if (_nextPageRect.contains(p) && _page < 2) {
_page++;
stop();
start(_loadMode ? kLoadMode : kSaveMode);
}
} else {
stop();
const uint slot = _page * 6 + index;
_loadMode ? g_vm->loadGameState(slot) : g_vm->saveGameState(slot, Common::String::format("Save %d", slot + 1), false);
}
}
void InterfaceSaveLoad::onRightButtonDown(Common::Point p) {
stop();
}
void InterfaceSaveLoad::onMouseMove(Common::Point p) {
QObjectCursor *cursor = g_vm->getQSystem()->getCursor();
cursor->_animate = findSaveLoadRectIndex(p) != -1 || _nextPageRect.contains(p) || _prevPageRect.contains(p);
cursor->setPos(p, false);
}
int InterfaceSaveLoad::findSaveLoadRectIndex(Common::Point p) {
for (uint i = 0; i < ARRAYSIZE(_saveRects); ++i) {
if (_saveRects[i].contains(p)) {
return i;
}
}
return -1;
}
void InterfaceSaveLoad::saveScreen() {
Common::ScopedPtr<Common::MemoryWriteStreamDynamic> thumbnail(new Common::MemoryWriteStreamDynamic(DisposeAfterUse::NO));
Graphics::saveThumbnail(*thumbnail);
g_vm->_thumbnail.reset(new Common::MemoryReadStream(thumbnail->getData(), thumbnail->size(), DisposeAfterUse::YES));
}
} // End of namespace Petka

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 PETKA_SAVE_LOAD_H
#define PETKA_SAVE_LOAD_H
#include "petka/interfaces/interface.h"
namespace Petka {
enum {
kSaveMode,
kLoadMode
};
class InterfaceSaveLoad : public SubInterface {
public:
InterfaceSaveLoad();
void start(int id) override;
bool loadMode() { return _loadMode; }
void onLeftButtonDown(Common::Point p) override;
void onRightButtonDown(Common::Point p) override;
void onMouseMove(Common::Point p) override;
static void saveScreen();
private:
int findSaveLoadRectIndex(Common::Point p);
private:
bool _loadMode;
uint _page;
Common::Rect _saveRects[6];
Common::Rect _nextPageRect;
Common::Rect _prevPageRect;
};
} // End of namespace Petka
#endif

View File

@@ -0,0 +1,127 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/system.h"
#include "petka/q_system.h"
#include "petka/q_manager.h"
#include "petka/sound.h"
#include "petka/petka.h"
#include "petka/video.h"
#include "petka/objects/object.h"
#include "petka/interfaces/main.h"
#include "petka/interfaces/sequence.h"
namespace Petka {
InterfaceSequence::InterfaceSequence() {
_fxId = 0;
_musicId = 0;
}
void InterfaceSequence::start(int id) {
// original bug fix
g_vm->getQSystem()->_mainInterface->removeTexts();
removeObjects();
g_system->getMixer()->pauseAll(true);
QObjectBG* bg = (QObjectBG *)g_vm->getQSystem()->findObject(id);
_objs.push_back(bg);
const auto *surface = g_vm->resMgr()->getSurface(bg->_resourceId);
if (surface) {
assert(surface->w >= 640);
g_vm->getQSystem()->_sceneWidth = MAX<int>(surface->w, 640);
g_vm->getQSystem()->_xOffset = 0;
}
playSound(bg->_musicId, Audio::Mixer::kMusicSoundType);
playSound(bg->_fxId, Audio::Mixer::kSFXSoundType);
const BGInfo *info = g_vm->getQSystem()->_mainInterface->findBGInfo(id);
if (info) {
for (uint i = 0; i < info->attachedObjIds.size(); ++i) {
QMessageObject *obj = g_vm->getQSystem()->findObject(info->attachedObjIds[i]);
g_vm->resMgr()->getFlic(obj->_resourceId);
obj->loadSound();
_objs.push_back(obj);
}
}
g_vm->getQSystem()->_currInterface = this;
g_vm->videoSystem()->makeAllDirty();
}
void InterfaceSequence::stop() {
removeObjects();
// original bug fix
QObjectBG *room = g_vm->getQSystem()->_room;
if (!room || room->_fxId != _fxId)
g_vm->soundMgr()->removeSound(g_vm->resMgr()->findSoundName(_fxId));
if (!room || room->_musicId != _musicId)
g_vm->soundMgr()->removeSound(g_vm->resMgr()->findSoundName(_musicId));
_fxId = 0;
_musicId = 0;
g_system->getMixer()->pauseAll(false);
g_vm->getQSystem()->_currInterface = g_vm->getQSystem()->_mainInterface.get();
Interface::stop();
}
void InterfaceSequence::onLeftButtonDown(Common::Point p) {
QVisibleObject *obj = findObject(-2);
if (obj) {
obj->onClick(p);
}
}
void InterfaceSequence::removeObjects() {
removeTexts();
for (uint i = 0; i < _objs.size(); ++i) {
QMessageObject *obj = (QMessageObject *)_objs[i];
obj->removeSound();
}
_objs.clear();
}
void InterfaceSequence::playSound(int id, Audio::Mixer::SoundType type) {
int *soundId = (type == Audio::Mixer::kSFXSoundType) ? &_fxId : &_musicId;
if (*soundId == id) {
Sound *s = g_vm->soundMgr()->findSound(g_vm->resMgr()->findSoundName(id));
if (s) {
s->pause(false);
}
} else {
g_vm->soundMgr()->removeSound(g_vm->resMgr()->findSoundName(*soundId));
Sound *sound = g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(id), type);
if (sound) {
sound->play(true);
}
*soundId = id;
}
}
} // End of namespace Petka

View File

@@ -0,0 +1,51 @@
/* 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 PETKA_SEQUENCE_H
#define PETKA_SEQUENCE_H
#include "audio/mixer.h"
#include "petka/interfaces/interface.h"
namespace Petka {
class InterfaceSequence : public Interface {
public:
InterfaceSequence();
void start(int id) override;
void stop() override;
void onLeftButtonDown(Common::Point p) override;
private:
void removeObjects();
void playSound(int id, Audio::Mixer::SoundType type);
private:
int _fxId;
int _musicId;
};
} // End of namespace Petka
#endif

View File

@@ -0,0 +1,129 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/system.h"
#include "common/stream.h"
#include "common/events.h"
#include "petka/flc.h"
#include "petka/objects/object_cursor.h"
#include "petka/interfaces/main.h"
#include "petka/interfaces/save_load.h"
#include "petka/interfaces/startup.h"
#include "petka/q_system.h"
#include "petka/q_manager.h"
#include "petka/sound.h"
#include "petka/petka.h"
#include "petka/video.h"
namespace Petka {
const char *const kStartupObjName = "STARTUP";
const char *const kCreditsVideoName = "credits.avi";
enum {
kExit = 4981,
kCredits = 4982,
kLoad = 4983,
kNewGame = 4984,
kStartupCursorId = 4901,
kBackgroundId = 4980
};
void InterfaceStartup::start(int id) {
QSystem *sys = g_vm->getQSystem();
QObjectBG *bg = (QObjectBG *)sys->findObject(kStartupObjName);
_objs.push_back(bg);
Sound *s = g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(bg->_musicId), Audio::Mixer::kMusicSoundType);
s->play(true);
const BGInfo *info = sys->_mainInterface->findBGInfo(bg->_id);
for (uint i = 0; i < info->attachedObjIds.size(); ++i) {
QMessageObject *obj = sys->findObject(info->attachedObjIds[i]);
obj->_z = 1;
obj->_x = 0;
obj->_y = 0;
obj->_frame = 1;
obj->_animate = false;
obj->_isShown = false;
_objs.push_back(obj);
}
initCursor(kStartupCursorId, true, false);
g_vm->videoSystem()->updateTime();
}
void InterfaceStartup::onLeftButtonDown(Common::Point p) {
if (!_objUnderCursor)
return;
switch (_objUnderCursor->_resourceId) {
case kExit:
Engine::quitGame();
break;
case kCredits:
g_vm->playVideo(g_vm->openFile(kCreditsVideoName, false));
break;
case kLoad:
g_vm->getQSystem()->_saveLoadInterface->start(kLoadMode);
break;
case kNewGame:
g_vm->loadPart(1);
break;
default:
break;
}
}
void InterfaceStartup::onMouseMove(Common::Point p) {
_objUnderCursor = nullptr;
bool found = false;
for (int i = _objs.size() - 1; i > 0; --i) {
QMessageObject *obj = (QMessageObject *)_objs[i];
if (obj->_resourceId != kStartupCursorId && obj->_resourceId != kBackgroundId) {
FlicDecoder *flc = g_vm->resMgr()->getFlic(obj->_resourceId);
if (flc) {
bool show = false;
if (!found && obj->isInPoint(p)) {
found = true;
show = true;
_objUnderCursor = obj;
}
if (obj->_isShown != show)
obj->show(obj->_isShown == 0);
}
}
}
QObjectCursor *cursor = g_vm->getQSystem()->getCursor();
cursor->_animate = _objUnderCursor != nullptr;
cursor->_isShown = true;
cursor->setPos(p, false);
}
void InterfaceStartup::stop() {
QObjectBG *bg = (QObjectBG *)g_vm->getQSystem()->findObject(kStartupObjName);
Common::String sound = g_vm->resMgr()->findSoundName(bg->_musicId);
g_vm->soundMgr()->removeSound(sound);
Interface::stop();
}
} // End of namespace Petka

View File

@@ -0,0 +1,40 @@
/* 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 PETKA_STARTUP_H
#define PETKA_STARTUP_H
#include "petka/interfaces/interface.h"
namespace Petka {
class InterfaceStartup : public Interface {
public:
void start(int id) override;
void stop() override;
void onLeftButtonDown(Common::Point p) override;
void onMouseMove(Common::Point p) override;
};
} // End of namespace Petka
#endif