[Scummvm-git-logs] scummvm master -> 158a18b42b0994d5f14d46cadfac25e83f2f3410

sev- sev at scummvm.org
Sat May 16 20:39:36 UTC 2020


This automated email contains information about 153 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
32dd96e6ca PETKA: Initial engine commit
46c5784481 PETKA: implemented file manager
e83c69bdb4 PETKA: simplified loading stores
4fcf080de7 PETKA: added basic structures
26ed615432 PETKA: added Resource Manager
d607eaccdc PETKA: changed console ptr to smart
749dbee5a5 PETKA: added QVisibleObject, QMessageObject, QObject and QObjectBG
9b6984d544 PETKA: JANITORIAL: fixed formatting
9143cc38dc PETKA: fixed include in q_object.h
cd439b1fe2 PETKA: added QSystem
dbff81f8d5 PETKA: added QObjectCursor
9c0909b9b8 PETKA: added QObjectCase
1b22c08da1 PETKA: added QObjectStar
95abfb168d PETKA: added QInterface
93980436aa PETKA: renamed unknown fields in QReaction
ab76b44ce0 PETKA: renamed unknown field in QMessage
1e25b941e0 PETKA: added partial implementation of processing messages in QMessageObject
081e19bd7b PETKA: added partial implementation of processing messages in QObjectBG
b2a532ded1 PETKA: implemented QSystem update method
fac55cf185 PETKA: implemented playing intro videos
8f61c3e611 PETKA: added screen class
4811d22143 PETKA: added QInterfaceMain
9f3bd28fc6 PETKA: implemented sound system
137fca0d9b PETKA: fixed loading attached objects from backgrnd.bg
38b6434130 PETKA: fixed compiling
a207cef914 PETKA: fixed BMP pixel fmt
5b7119f3bb PETKA: implemented menu loading
a5ea8881ec PETKA: implemented startup menu
cf7cbd06e2 PETKA: added missing object file to modulek.mk
c0bcc30612 PETKA: moved interface classes to separate files
dc3335308f PETKA: removed unneeded commented code
a2b4cdaf21 PETKA: fixed drawing cursor when its trans color is not black
1e11c80040 PETKA: added some constants to startup class
d24f8c52cc PETKA: JANITORIAL: fixed formatting
b2432a3d09 PETKA: made loop condition in InterfaceStartup equal to disasm
c05ad40eca PETKA: fixed compilation
72b0685fa9 PETKA: added saveload interface
a3761ab0fb PETKA: added partial implementation of settings interface
974fb205b3 PETKA: implemented reading and applying settings in menu
ea159a4f19 PETKA: fixed setting frame in panel interface
56dcd053ce PETKA: implemented mouse move event handling in settings interface
f3538539e9 PETKA: moved game object classes to separate files
313b3b5d31 PETKA: implemented AVI opcode
47984f1471 PETKA: implemented starting a new game
6ed94fc08d PETKA: implemented MUSIC and BGsFX opcodes
d4979f659a PETKA: implemented ON and OFF opcodes
c2e4d284bb PETKA: added ZBUFFER opcode
1cf2d82276 PETKA: implemented STOP opcode
81ebc4193f PETKA: added basic implementation of GoTo opcode(change room)
22abfc0245 PETKA: implemented handling z coordinate of objects
586cbd970f PETKA: implemented cursor show method
703a0efe0c PETKA: implemented object show method
06d99e210f PETKA: reworked object updating
48a8318285 PETKA: implemented update method for QObject
6f1161f9b1 PETKA: added SET and PLAY opcodes implementation
26b411c688 PETKA: implementing adding sounds to objects when room loads
b135735d8a PETKA: implemented removing old room
e0b52484fe PETKA: fixed opening files with relative path
55daf01e31 PETKA: fixed opening files with empty name
bef655aabb PETKA: implemented loading bitmaps with bpp other than 16
acdbda77ce PETKA: fixed SIGSEGV when sound is being played 2nd time
1bc8ba189e PETKA: rewrote update method of QSystem
a022df3b5d PETKA: changed z coord to unsigned
ae51caefc4 PETKA: fixed isInPoint method of QObject
e984d7a526 PETKA: added makeAllDirty method to video system
1e21a56c2d PETKA: added initialization of QMessageObject fields according to disasm
c38082e60b PETKA: added ctor for QObject
71d72f6df5 PETKA: fixed compilation
94a66f09ab PETKA: load right part when running demo
050d3d5dd3 PETKA: detect StartRoom from ini file rather than hardcoded name
3201b6f485 PETKA: implemented SHOW and HIDE opcodes
2a99a2a766 PETKA: added PASSIVE and ACTIVE opcodes
feca9cf9c8 PETKA: fixed CHECK opcode
a4bdc33c28 PETKA: implemented proper handling of PLAY opcode in handlers
bb10d42a33 PETKA: implemented SETPOS opcode
4cebc88106 PETKA: fixed adding sound in PLAY opcode
46fd290d8f PETKA: fixed removing looped sounds
38db7a8a8b PETKA: split loadingRoom method
6b079e8575 PETKA: fixed playing previously stopped sounds
76c587a700 PETKA: fixed adding sound which has null file stream
cd066fa2de PETKA: disabled updating QObject with sprites which have 1 frame
d78926d79d PETKA: fixed checking time when to update sprites
10a2ea1f10 PETKA: fixed frame time of video system
f434be2bf5 PETKA: fixed starting game when ini files aren't needed
8d9ce6cd60 PETKA: temporarily disabled usage of ini file with names
dbb71b3e80 PETKA: started dialogs implementation
d7cf76087b PETKA: partial implementation of dialogs
25b6c21992 PETKA: hack to continue dialog after phrase ends
c001172f62 PETKA: added misssing opcode to dialogs
9f9210b236 PETKA: added implementation of dialog opcode
b89b0930f5 PETKA: send SAID opcode after dialog ends
38f2679266 PETKA: some refactoring of dialog interface
f94ba47d84 PETKA: disabled walk opcodes because of no implementation
5e34a2a507 PETKA: added hero classes
2f4c710797 PETKA: implemented dialog opcode 0x09
0148ee59ed PETKA: added missing object file to module.mk
c1815c18e5 PETKA: added Text class
42a90418f3 PETKA: removed unnecessary variable
f3a2cd951a PETKA: implemented dialog opcode 0x10
75bb3c85c9 PETKA: implemented dialog opcode 0x08
a366e65aad PETKA: implemented dialog opcode 0x02
464718e896 PETKA: implemented handling dialog opcode 0x2 when engine needs speech info
0559732e05 PETKA: added engine description
d8aa134025 PETKA: added debug log to Engine class
26d6f04fbe PETKA: added debug log to FileMgr
c485b77229 PETKA: added debug log to SoundMgr
e4c51ddf1d PETKA: enabled saving speed variable in settings
8bb12711cb PETKA: implemented QObjectStar
7b7268acfb PETKA: implemented QObjectCase
196fb7884d PETKA: implemented events handling in InterfaceMain
6ba552e0a9 PETKA: fixed onMouseMove method of ObjectStar
bbfa139d9b PETKA: fixed crash and endless lopp in ObjectCase
ea4f10f4fa PETKA: implemented CONTINUE opcode
f2b9a451a6 PETKA: fixed crash when dialog is in process
1a61fd4c59 PETKA: add heroes before starting InterfaceMain
541368979e PETKA: overrode cursor's isInPoint method
c50093da2e PETKA: fixed handling left button click
e1bcf2711b PETKA: enabled case and cursor in main interface
8f08804aed PETKA: fixed choosing action type in star object
2763c22a9f PETKA: implemented clicking on objects depending on action type
6b39e634d8 PETKA: implemented switching to panel interface from case object
0dc8c459b7 PETKA: implemented map
9e7beac5d1 PETKA: implemented inventory opcodes
50e65957dc PETKA: implemented jump opcodes
66261efac3 PETKA: renamed unknown fields
527488d228 PETKA: added CURSOR opcode
4a88f993ff PETKA: implemented changing hero to chapayev
49fd19e969 PETKA: fixed handling rbutton click
db52ecd907 PETKA: implemented saving/loading system
5e2e4596d5 PETKA: reimplemented show method of QObject
7c14d49398 PETKA: added constants to startup interface
b973ec372f PETKA: added initCursor function to interface class
eb0d3a546d PETKA: added fields to hero class
afa777da2a PETKA: implemented processing messages by heroes
1599f21861 PETKA: added heroes implementation without walking system
139bb33f32 PETKA: fixed compilation
4fcb585065 PETKA: fixed compilation on newer revision of ScummVM
8e7ffaa0be PETKA: enabled reading of russian ini files
91cfe96da1 PETKA: Add 16bit to configure.engine
e0d0aa1e84 PETKA: removed goto
6b93465bc4 PETKA: reworked dialogs handling
edb68a7697 PETKA: removed global objects
c994d6bc81 PETKA: JANITORIAL: fixed compiler warnings about newline
7a5a39fa22 PETKA: JANITORIAL: removed comma at the end of enumerator list
b0e6db5909 PETKA: removed cast warnings
ea296c6ad7 PETKA: renamed RTL event
ee9a09e005 PETKA: fixed setting musicId in ObjectBG
ef65600429 PETKA: fixed drawing save/load interface
5a5208666f PETKA: minor fixes to dialog system
dc3427c505 PETKA: rewrote search of rectangle in SaveLoad interface
1b7e691f25 PETKA: renamed method in DialogInterface
a6cb15bd62 PETKA: new text subsystem implementation
158a18b42b PETKA: removed tracking sound by global variable


Commit: 32dd96e6ca677faaf4e28f1529423cdcb7b03704
    https://github.com/scummvm/scummvm/commit/32dd96e6ca677faaf4e28f1529423cdcb7b03704
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: Initial engine commit

Changed paths:
  A engines/petka/configure.engine
  A engines/petka/detection.cpp
  A engines/petka/detection_tables.h
  A engines/petka/module.mk
  A engines/petka/petka.cpp
  A engines/petka/petka.h


diff --git a/engines/petka/configure.engine b/engines/petka/configure.engine
new file mode 100644
index 0000000000..d9811acc47
--- /dev/null
+++ b/engines/petka/configure.engine
@@ -0,0 +1,3 @@
+# This file is included from the main "configure" script
+# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
+add_engine petka "Red Comrades" no "" "" "highres"
diff --git a/engines/petka/detection.cpp b/engines/petka/detection.cpp
new file mode 100644
index 0000000000..97f4f9d210
--- /dev/null
+++ b/engines/petka/detection.cpp
@@ -0,0 +1,65 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "engines/advancedDetector.h"
+
+#include "petka/petka.h"
+
+static const PlainGameDescriptor petkaGames[] = {
+	{"petka_demo", "Red Comrades Demo"},
+	{"petka1", "Red Comrades 1: Save the Galaxy"},
+	{"petka2", "Red Comrades 2: For the Great Justice"},
+	{0, 0}
+};
+
+#include "detection_tables.h"
+
+class PetkaMetaEngine : public AdvancedMetaEngine {
+public:
+	PetkaMetaEngine() : AdvancedMetaEngine(Petka::gameDescriptions, sizeof(ADGameDescription), petkaGames) {
+		_gameIds = petkaGames;
+		_maxScanDepth = 2;
+	}
+
+	virtual const char *getName() const {
+		return "Red Comrades";
+	}
+
+	virtual const char *getOriginalCopyright() const {
+		return "Red Comrades (C) S.K.I.F";
+	}
+
+	virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+};
+
+bool PetkaMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+	if (desc)
+		*engine = new Petka::PetkaEngine(syst, desc);
+
+	return desc != 0;
+}
+
+#if PLUGIN_ENABLED_DYNAMIC(PETKA)
+	REGISTER_PLUGIN_DYNAMIC(PETKA, PLUGIN_TYPE_ENGINE, PetkaMetaEngine);
+#else
+	REGISTER_PLUGIN_STATIC(PETKA, PLUGIN_TYPE_ENGINE, PetkaMetaEngine);
+#endif
diff --git a/engines/petka/detection_tables.h b/engines/petka/detection_tables.h
new file mode 100644
index 0000000000..c8b1e91707
--- /dev/null
+++ b/engines/petka/detection_tables.h
@@ -0,0 +1,70 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_DETECTION_TABLES_H
+#define PETKA_DETECTION_TABLES_H
+
+namespace Petka {
+
+static const ADGameDescription gameDescriptions[] = {
+
+	// Red Comrades Demo
+	{
+		"petka_demo",
+		0,
+		AD_ENTRY1s("DEMO.EXE", "5ef1ceaba05413d04fd733a81e6adbae", 888832),
+		Common::RU_RUS,
+		Common::kPlatformWindows,
+		ADGF_UNSTABLE | ADGF_DROPPLATFORM,
+		GUIO1(GUIO_NONE)
+
+	},
+
+	// Red Comrades 1: Save the Galaxy
+	{
+		"petka1",
+		0,
+		AD_ENTRY1s("MAIN.STR", "2523bf402ac8b7b2bf54e6e29a79831d", 27414919),
+		Common::RU_RUS,
+		Common::kPlatformWindows,
+		ADGF_UNSTABLE | ADGF_DROPPLATFORM,
+		GUIO1(GUIO_NONE)
+
+	},
+
+	// Red Comrades 2: For the Great Justice
+	{
+		"petka2",
+		0,
+		AD_ENTRY1s("main.str", "4e515669c343609518277cab6e7d8c8f", 18992879),
+		Common::RU_RUS,
+		Common::kPlatformWindows,
+		ADGF_UNSTABLE | ADGF_DROPPLATFORM,
+		GUIO1(GUIO_NONE)
+	},
+
+	AD_TABLE_END_MARKER
+};
+
+} // End of namespace Petka
+
+#endif
diff --git a/engines/petka/module.mk b/engines/petka/module.mk
new file mode 100644
index 0000000000..3a352528cf
--- /dev/null
+++ b/engines/petka/module.mk
@@ -0,0 +1,13 @@
+MODULE := engines/petka
+
+MODULE_OBJS = \
+    detection.o \
+    petka.o
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_PETKA), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
new file mode 100644
index 0000000000..cf4b2c8637
--- /dev/null
+++ b/engines/petka/petka.cpp
@@ -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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/debug-channels.h"
+#include "common/error.h"
+
+#include "engines/util.h"
+
+#include "petka/petka.h"
+
+namespace Petka {
+
+PetkaEngine::PetkaEngine(OSystem *system, const ADGameDescription *desc)
+	: Engine(system), _console(nullptr), _desc(desc) {
+	DebugMan.addDebugChannel(kPetkaDebugGeneral, "general", "General issues");
+}
+
+PetkaEngine::~PetkaEngine() {
+	DebugMan.clearAllDebugChannels();
+	delete _console;
+}
+
+Common::Error PetkaEngine::run() {
+	const Graphics::PixelFormat format(2, 5, 6, 5, 0, 11, 5, 0, 0);
+	initGraphics(640, 480, &format);
+
+	_console = new Console(this);
+
+	return Common::kNoError;
+}
+
+} // End of namespace Petka
diff --git a/engines/petka/petka.h b/engines/petka/petka.h
new file mode 100644
index 0000000000..5f9dec63a3
--- /dev/null
+++ b/engines/petka/petka.h
@@ -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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_PETKA_H
+#define PETKA_PETKA_H
+
+#include "engines/engine.h"
+
+#include "gui/debugger.h"
+
+struct ADGameDescription;
+
+namespace Petka {
+
+class Console;
+
+enum {
+	kPetkaDebugGeneral = 1 << 0,
+};
+
+class PetkaEngine : public Engine {
+public:
+	PetkaEngine(OSystem *syst, const ADGameDescription *desc);
+	~PetkaEngine();
+
+	virtual Common::Error run();
+
+private:
+	Console *_console;
+	const ADGameDescription *_desc;
+};
+
+class Console : public GUI::Debugger {
+public:
+	Console(PetkaEngine *vm) {}
+	virtual ~Console() {}
+};
+
+} // End of namespace Petka
+
+#endif


Commit: 46c5784481d998a19800b92d98e77468e62564c9
    https://github.com/scummvm/scummvm/commit/46c5784481d998a19800b92d98e77468e62564c9
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented file manager

Changed paths:
  A engines/petka/file_mgr.cpp
  A engines/petka/file_mgr.h
    engines/petka/module.mk
    engines/petka/petka.cpp
    engines/petka/petka.h


diff --git a/engines/petka/file_mgr.cpp b/engines/petka/file_mgr.cpp
new file mode 100644
index 0000000000..731f32609e
--- /dev/null
+++ b/engines/petka/file_mgr.cpp
@@ -0,0 +1,100 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/debug.h"
+#include "common/file.h"
+#include "common/substream.h"
+
+#include "petka/file_mgr.h"
+
+namespace Petka {
+
+FileMgr::~FileMgr() {
+	closeAll();
+}
+
+bool FileMgr::openStore(const Common::String &name) {
+	Common::ScopedPtr<Common::File> file(new Common::File());
+	if (name.empty() || !file->open(name) || file->readUint32BE() != MKTAG('S', 't', 'O', 'R')) {
+		return false;
+	}
+
+	const uint32 tableOffset = file->readUint32LE();
+	if (!file->seek(tableOffset)) {
+		return false;
+	}
+
+	_stores.push_back(Store());
+	Store &store = _stores.back();
+	store.descriptions.resize(file->readUint32LE());
+
+	for (uint i = 0; i < store.descriptions.size(); ++i) {
+		file->skip(4);
+		store.descriptions[i].offset = file->readUint32LE();
+		store.descriptions[i].size = file->readUint32LE();
+	}
+
+	for (uint i = 0; i < store.descriptions.size(); ++i) {
+		char ch;
+		while ((ch = file->readByte()) != 0) {
+			store.descriptions[i].name += ch;
+		}
+	}
+	store.file = file.release();
+	return true;
+}
+
+void FileMgr::closeStore(const Common::String &name) {
+	for (uint i = 0; i < _stores.size(); ++i) {
+		if (_stores[i].file->getName() == name) {
+			delete _stores[i].file;
+			_stores.remove_at(i);
+			return;
+		}
+	}
+}
+
+void FileMgr::closeAll() {
+	for (uint i = 0; i < _stores.size(); ++i) {
+		delete _stores[i].file;
+	}
+	_stores.clear();
+}
+
+Common::SeekableReadStream *FileMgr::getFileStream(const Common::String &name) {
+	Common::ScopedPtr<Common::File> file(new Common::File());
+	if (file->open(name)) {
+		return file.release();
+	}
+	for (uint i = 0; i < _stores.size(); ++i) {
+		for (uint j = 0; j < _stores[i].descriptions.size(); ++j) {
+			const Description &desc = _stores[i].descriptions[j];
+			if (desc.name.compareToIgnoreCase(name) == 0) {
+				return new Common::SafeSeekableSubReadStream(_stores[i].file, desc.offset, desc.offset + desc.size);
+			}
+
+		}
+	}
+	return nullptr;
+}
+
+} // End of namespace Pink
diff --git a/engines/petka/file_mgr.h b/engines/petka/file_mgr.h
new file mode 100644
index 0000000000..ad2b1e6f25
--- /dev/null
+++ b/engines/petka/file_mgr.h
@@ -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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_FILE_MGR_H
+#define PETKA_FILE_MGR_H
+
+#include "common/array.h"
+
+namespace Common {
+	class File;
+	class SeekableReadStream;
+}
+
+namespace Petka {
+
+class FileMgr {
+public:
+	~FileMgr();
+
+	bool openStore(const Common::String &name);
+	void closeStore(const Common::String &name);
+	void closeAll();
+
+	Common::SeekableReadStream *getFileStream(const Common::String &name);
+
+private:
+	struct Description {
+		Common::String name;
+		uint32 offset;
+		uint32 size;
+	};
+	struct Store {
+		Common::File *file;
+		Common::Array<Description> descriptions;
+	};
+	Common::Array<Store> _stores;
+};
+
+} // End of namespace Petka
+
+#endif
diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index 3a352528cf..66331b84bb 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -2,6 +2,7 @@ MODULE := engines/petka
 
 MODULE_OBJS = \
     detection.o \
+    file_mgr.o \
     petka.o
 
 # This module can be built as a plugin
diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
index cf4b2c8637..9c5cd47d42 100644
--- a/engines/petka/petka.cpp
+++ b/engines/petka/petka.cpp
@@ -22,16 +22,21 @@
 
 #include "common/debug-channels.h"
 #include "common/error.h"
+#include "common/ini-file.h"
+#include "common/stream.h"
 
 #include "engines/util.h"
 
+#include "petka/file_mgr.h"
 #include "petka/petka.h"
 
 namespace Petka {
 
 PetkaEngine::PetkaEngine(OSystem *system, const ADGameDescription *desc)
-	: Engine(system), _console(nullptr), _desc(desc) {
+	: Engine(system), _console(nullptr), _fileMgr(nullptr), _desc(desc) {
 	DebugMan.addDebugChannel(kPetkaDebugGeneral, "general", "General issues");
+	_part = 0;
+	_chapter = 0;
 }
 
 PetkaEngine::~PetkaEngine() {
@@ -44,8 +49,53 @@ Common::Error PetkaEngine::run() {
 	initGraphics(640, 480, &format);
 
 	_console = new Console(this);
+	_fileMgr.reset(new FileMgr());
+	loadStores();
 
 	return Common::kNoError;
 }
 
+void PetkaEngine::loadStores() {
+	_fileMgr->closeAll();
+
+	_fileMgr->openStore("patch.str");
+	_fileMgr->openStore("main.str");
+
+	Common::INIFile parts;
+	Common::ScopedPtr<Common::SeekableReadStream> stream(_fileMgr->getFileStream("PARTS.INI"));
+
+	if (!stream || !parts.loadFromStream(*stream)) {
+		return;
+	}
+
+	Common::String backgroundStoreName;
+	Common::String flcStoreName;
+	Common::String wavStoreName;
+	Common::String sfxStoreName;
+	Common::String musicStoreName;
+	Common::String speechStoreName;
+
+	const Common::String section = Common::String::format("Part %d", _part);
+
+	parts.getKey("CurrentPath", section, _currentPath);
+	parts.getKey("PathSpeech", section, _speechPath);
+
+	parts.getKey("Background", section, backgroundStoreName);
+	parts.getKey("Flics", section, flcStoreName);
+	parts.getKey("Wavs", section, wavStoreName);
+	parts.getKey("SFX", section, sfxStoreName);
+	parts.getKey("Music", section, musicStoreName);
+	parts.getKey("Speech", section, speechStoreName);
+
+	parts.getKey("Chapter", Common::String::format("Part %d Chapter %d", _part, _chapter), _chapterStoreName);
+
+	_fileMgr->openStore(backgroundStoreName);
+	_fileMgr->openStore(flcStoreName);
+	_fileMgr->openStore(wavStoreName);
+	_fileMgr->openStore(sfxStoreName);
+	_fileMgr->openStore(musicStoreName);
+	_fileMgr->openStore(speechStoreName);
+	_fileMgr->openStore(_chapterStoreName);
+}
+
 } // End of namespace Petka
diff --git a/engines/petka/petka.h b/engines/petka/petka.h
index 5f9dec63a3..b87f27b8d6 100644
--- a/engines/petka/petka.h
+++ b/engines/petka/petka.h
@@ -32,6 +32,7 @@ struct ADGameDescription;
 namespace Petka {
 
 class Console;
+class FileMgr;
 
 enum {
 	kPetkaDebugGeneral = 1 << 0,
@@ -44,9 +45,21 @@ public:
 
 	virtual Common::Error run();
 
+private:
+	void loadStores();
+
 private:
 	Console *_console;
+	Common::ScopedPtr<FileMgr> _fileMgr;
 	const ADGameDescription *_desc;
+
+	Common::String _currentPath;
+	Common::String _speechPath;
+
+	Common::String _chapterStoreName;
+
+	uint8 _part;
+	uint8 _chapter;
 };
 
 class Console : public GUI::Debugger {


Commit: e83c69bdb47a0accbb1c51a00bbb777cc905bb46
    https://github.com/scummvm/scummvm/commit/e83c69bdb47a0accbb1c51a00bbb777cc905bb46
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: simplified loading stores

Changed paths:
    engines/petka/petka.cpp


diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
index 9c5cd47d42..d0a50d14a6 100644
--- a/engines/petka/petka.cpp
+++ b/engines/petka/petka.cpp
@@ -68,33 +68,19 @@ void PetkaEngine::loadStores() {
 		return;
 	}
 
-	Common::String backgroundStoreName;
-	Common::String flcStoreName;
-	Common::String wavStoreName;
-	Common::String sfxStoreName;
-	Common::String musicStoreName;
-	Common::String speechStoreName;
-
+	const char *const names[] = {"Background", "Flics", "Wavs", "SFX", "Music", "Speech"};
 	const Common::String section = Common::String::format("Part %d", _part);
 
 	parts.getKey("CurrentPath", section, _currentPath);
 	parts.getKey("PathSpeech", section, _speechPath);
 
-	parts.getKey("Background", section, backgroundStoreName);
-	parts.getKey("Flics", section, flcStoreName);
-	parts.getKey("Wavs", section, wavStoreName);
-	parts.getKey("SFX", section, sfxStoreName);
-	parts.getKey("Music", section, musicStoreName);
-	parts.getKey("Speech", section, speechStoreName);
+	Common::String storeName;
+	for (uint i = 0; i < sizeof(names) / sizeof(char *); ++i) {
+		parts.getKey(names[i], section, storeName);
+		_fileMgr->openStore(storeName);
+	}
 
 	parts.getKey("Chapter", Common::String::format("Part %d Chapter %d", _part, _chapter), _chapterStoreName);
-
-	_fileMgr->openStore(backgroundStoreName);
-	_fileMgr->openStore(flcStoreName);
-	_fileMgr->openStore(wavStoreName);
-	_fileMgr->openStore(sfxStoreName);
-	_fileMgr->openStore(musicStoreName);
-	_fileMgr->openStore(speechStoreName);
 	_fileMgr->openStore(_chapterStoreName);
 }
 


Commit: 4fcf080de7e6c6d3a9957c1c29e7fbcc7112fc23
    https://github.com/scummvm/scummvm/commit/4fcf080de7e6c6d3a9957c1c29e7fbcc7112fc23
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added basic structures

Changed paths:
  A engines/petka/base.h


diff --git a/engines/petka/base.h b/engines/petka/base.h
new file mode 100644
index 0000000000..925c73c262
--- /dev/null
+++ b/engines/petka/base.h
@@ -0,0 +1,116 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_BASE_H
+#define PETKA_BASE_H
+
+#include "common/array.h"
+
+namespace Petka {
+
+enum Opcode {
+	kZero = 0,
+	kUse = 1,
+	kSetPos = 2,
+	kGoTo = 3,
+	kLook = 4,
+	kSay = 5,
+	kTake = 6,
+	kQMUse = 7,
+	kVasiliyIvanovich = 8,
+	kWalk = 9,
+	kTalk = 10,
+	kEnd = 11,
+	kSetAnimation = 12,
+	kForceMove = 13,
+	kSet = 14,
+	kShow = 15,
+	kHide = 16,
+	kDialog = 17,
+	kZBuffer = 18,
+	kTotalInit = 19,
+	kAnimate = 20,
+	kStatus = 21,
+	kAddInv = 22,
+	kDelInv = 23,
+	kStop = 24,
+	kCursor = 25,
+	kObjectUse = 26,
+	kActive = 27,
+	kSaid = 28,
+	kSetSeq = 29,
+	kEndSeq = 30,
+	kCheck = 31,
+	kIf = 32,
+	kDescription = 33,
+	kHalf = 34,
+	kWalked = 35,
+	kWalkTo = 36,
+	kWalkVich = 37,
+	kInitBG = 38,
+	kUserMsg = 39,
+	kSystem = 40,
+	kSetZBuffer = 41, // ??? Reserved1
+	kContinue = 42,
+	kMap = 43,
+	kPassive = 44,
+	kNoMap = 45,
+	kSetInv = 46,
+	kBGsFX = 47,
+	kMusic = 48,
+	kImage = 49,
+	kStand = 50,
+	kOn = 51,
+	kOff = 52,
+	kPlay = 53,
+	kLeaveBG = 54,
+	kShake = 55,
+	kSP = 56,
+	kRandom = 57,
+	kJump = 58,
+	kJumpVich = 59,
+	kPart = 60,
+	kChapter = 61,
+	kAvi = 62,
+	kToMap = 63 // ??? MessageNumber
+};
+
+struct QMessage {
+	uint16 objId;
+	uint16 opcode;
+	int16 arg1;
+	int16 arg2;
+	int16 arg3;
+	int32 unk1;
+	int32 unk2;
+};
+
+struct QReaction {
+	uint16 opcode;
+	byte unk1;
+	uint16 unk2;
+	Common::Array<QMessage> _messages;
+};
+
+} // End of namespace Petka
+
+#endif


Commit: 26ed61543284202641054eca5a2d77b6dd552812
    https://github.com/scummvm/scummvm/commit/26ed61543284202641054eca5a2d77b6dd552812
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added Resource Manager

Changed paths:
  A engines/petka/q_manager.cpp
  A engines/petka/q_manager.h
    engines/petka/module.mk
    engines/petka/petka.cpp
    engines/petka/petka.h


diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index 66331b84bb..3459d4773e 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -3,7 +3,8 @@ MODULE := engines/petka
 MODULE_OBJS = \
     detection.o \
     file_mgr.o \
-    petka.o
+    petka.o \
+    q_manager.o
 
 # This module can be built as a plugin
 ifeq ($(ENABLE_PETKA), DYNAMIC_PLUGIN)
diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
index d0a50d14a6..d4ae8b23ec 100644
--- a/engines/petka/petka.cpp
+++ b/engines/petka/petka.cpp
@@ -29,11 +29,12 @@
 
 #include "petka/file_mgr.h"
 #include "petka/petka.h"
+#include "petka/q_manager.h"
 
 namespace Petka {
 
 PetkaEngine::PetkaEngine(OSystem *system, const ADGameDescription *desc)
-	: Engine(system), _console(nullptr), _fileMgr(nullptr), _desc(desc) {
+	: Engine(system), _console(nullptr), _fileMgr(nullptr), _resMgr(nullptr), _desc(desc) {
 	DebugMan.addDebugChannel(kPetkaDebugGeneral, "general", "General issues");
 	_part = 0;
 	_chapter = 0;
@@ -51,10 +52,17 @@ Common::Error PetkaEngine::run() {
 	_console = new Console(this);
 	_fileMgr.reset(new FileMgr());
 	loadStores();
+	_resMgr.reset(new QManager(*this));
+	if (!_resMgr->init())
+		return Common::kNoGameDataFoundError;
 
 	return Common::kNoError;
 }
 
+Common::SeekableReadStream *PetkaEngine::openFile(const Common::String &name, bool addCurrentPath) {
+	return _fileMgr->getFileStream(addCurrentPath ? _currentPath + name : name);
+}
+
 void PetkaEngine::loadStores() {
 	_fileMgr->closeAll();
 
diff --git a/engines/petka/petka.h b/engines/petka/petka.h
index b87f27b8d6..18cf71b78d 100644
--- a/engines/petka/petka.h
+++ b/engines/petka/petka.h
@@ -33,6 +33,7 @@ namespace Petka {
 
 class Console;
 class FileMgr;
+class QManager;
 
 enum {
 	kPetkaDebugGeneral = 1 << 0,
@@ -44,6 +45,7 @@ public:
 	~PetkaEngine();
 
 	virtual Common::Error run();
+	Common::SeekableReadStream *openFile(const Common::String &name, bool addCurrentPath);
 
 private:
 	void loadStores();
@@ -51,6 +53,7 @@ private:
 private:
 	Console *_console;
 	Common::ScopedPtr<FileMgr> _fileMgr;
+	Common::ScopedPtr<QManager> _resMgr;
 	const ADGameDescription *_desc;
 
 	Common::String _currentPath;
diff --git a/engines/petka/q_manager.cpp b/engines/petka/q_manager.cpp
new file mode 100644
index 0000000000..1c8934a067
--- /dev/null
+++ b/engines/petka/q_manager.cpp
@@ -0,0 +1,230 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/system.h"
+#include "common/substream.h"
+#include "common/tokenizer.h"
+
+#include "graphics/surface.h"
+
+#include "petka/petka.h"
+#include "petka/q_manager.h"
+
+#include "video/flic_decoder.h"
+
+namespace Petka {
+
+QManager::QManager(PetkaEngine &vm)
+	: _vm(vm) {}
+
+QManager::~QManager() {
+	for (Common::HashMap<uint32, QResource>::iterator it = _resourceMap.begin(); it != _resourceMap.end(); ++it) {
+		destructResourceContent(it->_value);
+	}
+}
+
+bool QManager::init() {
+	clear();
+	Common::ScopedPtr<Common::SeekableReadStream> stream(_vm.openFile("resource.qrc", true));
+	if (!stream) {
+		return false;
+	}
+
+	while (!stream->eos()) {
+		Common::StringTokenizer tokenizer(stream->readLine());
+		if (tokenizer.empty()) {
+			continue;
+		}
+
+		const uint32 id = (uint32)atoi(tokenizer.nextToken().c_str());
+		_isAlwaysNeededMap.setVal(id, tokenizer.nextToken() == "==");
+		_nameMap.setVal(id, tokenizer.nextToken());
+
+	}
+	return true;
+}
+
+Common::String QManager::findResourceName(uint32 id) const {
+	if (_nameMap.contains(id)) {
+		return _nameMap.getVal(id);
+	}
+	return "";
+}
+
+Common::String QManager::findSoundName(uint32 id) const {
+	Common::String name = findResourceName(id);
+	name.toUppercase();
+	if (name.empty() || name.hasSuffix(".WAV")) {
+		return name;
+	}
+	name.erase(name.size() - 3, 3);
+	return name += "WAV";
+}
+
+void QManager::removeResource(uint32 id) {
+	if (_resourceMap.contains(id)) {
+		destructResourceContent(_resourceMap.getVal(id));
+		_resourceMap.erase(id);
+	}
+}
+
+void QManager::clearUnneeded() {
+	for (Common::HashMap<uint32, QResource>::iterator it = _resourceMap.begin(); it != _resourceMap.end(); ++it) {
+		if (!_isAlwaysNeededMap.getVal(it->_key)) {
+			destructResourceContent(it->_value);
+			_resourceMap.erase(it);
+		}
+	}
+}
+
+Graphics::Surface *QManager::findOrCreateSurface(uint32 id, uint16 w, uint16 h) {
+	if (_resourceMap.contains(id)) {
+		QResource &res = _resourceMap.getVal(id);
+		if (res.type != QResource::kSurface) {
+			return nullptr;
+		}
+		return res.surface;
+	}
+
+	QResource &res = _resourceMap.getVal(id);
+	res.type = QResource::kSurface;
+	res.surface = new Graphics::Surface;
+	res.surface->create(w, h, _vm._system->getScreenFormat());
+	return res.surface;
+}
+
+void QManager::destructResourceContent(QResource &res) {
+	if (res.type == QResource::kSurface) {
+		res.surface->free();
+		delete res.surface;
+	} else {
+		delete res.flcDecoder;
+	}
+}
+
+Common::SeekableReadStream *QManager::loadFileStream(uint32 id) const {
+	const Common::String &name = findResourceName(id);
+	return name.empty() ? nullptr : _vm.openFile(name, false);
+}
+
+Graphics::Surface *QManager::loadBitmap(uint32 id) {
+	if (_resourceMap.contains(id)) {
+		QResource &res = _resourceMap.getVal(id);
+		if (res.type != QResource::kSurface) {
+			return nullptr;
+		}
+		return res.surface;
+	}
+
+	Common::ScopedPtr<Common::SeekableReadStream> stream(loadFileStream(id));
+	if (!stream) {
+		return nullptr;
+	}
+
+	Graphics::Surface *s = loadBitmapSurface(*stream);
+	if (s) {
+		QResource &res = _resourceMap.getVal(id);
+		res.type = QResource::kSurface;
+		res.surface = s;
+		return res.surface;
+	}
+	return nullptr;
+}
+
+Video::FlicDecoder *QManager::loadFlic(uint32 id) {
+	if (_resourceMap.contains(id)) {
+		QResource &res = _resourceMap.getVal(id);
+		if (res.type != QResource::kFlic) {
+			return nullptr;
+		}
+		return res.flcDecoder;
+	}
+
+	Common::ScopedPtr<Common::SeekableReadStream> stream(loadFileStream(id));
+	if (!stream) {
+		return nullptr;
+	}
+
+	Common::ScopedPtr<Video::FlicDecoder> flc (new Video::FlicDecoder);
+	if (flc->loadStream(stream.release())) {
+		QResource &res = _resourceMap.getVal(id);
+		res.type = QResource::kFlic;
+		res.flcDecoder = flc.release();
+		return res.flcDecoder;
+	}
+	return nullptr;
+}
+
+void QManager::clear() {
+	for (Common::HashMap<uint32, QResource>::iterator it = _resourceMap.begin(); it != _resourceMap.end(); ++it) {
+		destructResourceContent(it->_value);
+	}
+	_resourceMap.clear();
+	_nameMap.clear();
+	_isAlwaysNeededMap.clear();
+}
+
+Graphics::Surface *QManager::loadBitmapSurface(Common::SeekableReadStream &stream) {
+	if (stream.readByte() != 'B')
+		return nullptr;
+
+	if (stream.readByte() != 'M')
+		return nullptr;
+
+	stream.skip(12);
+
+	uint32 infoSize = stream.readUint32LE();
+	assert(infoSize == 40);
+
+	uint32 width = stream.readUint32LE();
+	uint32 height = stream.readUint32LE();
+	stream.skip(2);
+	uint16 bitsPerPixel = stream.readUint16LE();
+	assert(bitsPerPixel == 16);
+
+	/* uint32 compression = stream.readUint32BE(); */
+	/* uint32 imageSize = stream.readUint32LE(); */
+	/* uint32 pixelsPerMeterX = stream.readUint32LE(); */
+	/* uint32 pixelsPerMeterY = stream.readUint32LE(); */
+	/* uint32 paletteColorCount = stream.readUint32LE(); */
+	/* uint32 colorsImportant = stream.readUint32LE(); */
+	/* uint32 unk = stream.readUint32LE(); */
+	/* uint32 fileSize_ = stream.readUint32LE(); */
+	stream.skip(32);
+
+	int srcPitch = width * (bitsPerPixel >> 3);
+	int extraDataLength = (srcPitch % 4) ? 4 - (srcPitch % 4) : 0;
+
+	Graphics::Surface *s = new Graphics::Surface;
+	s->create(width, height, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
+
+	uint16 *dst = (uint16 *)s->getPixels();
+	for (uint i = 0; i < height; ++i) {
+		for (uint j = 0; j < width; ++j) {
+			dst[(height - i - 1) * width + j] = stream.readUint16BE();
+		}
+		stream.skip(extraDataLength);
+	}
+	return s;
+}
+
+} // End of namespace Petka
diff --git a/engines/petka/q_manager.h b/engines/petka/q_manager.h
new file mode 100644
index 0000000000..a12e45540c
--- /dev/null
+++ b/engines/petka/q_manager.h
@@ -0,0 +1,88 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_QMANAGER_H
+#define PETKA_QMANAGER_H
+
+#include "common/hashmap.h"
+
+namespace Common {
+	class SeekableReadStream;
+}
+
+namespace Graphics {
+	struct Surface;
+}
+
+namespace Video {
+	class FlicDecoder;
+}
+
+namespace Petka {
+
+class PetkaEngine;
+
+struct QResource {
+	union {
+		Graphics::Surface *surface;
+		Video::FlicDecoder *flcDecoder;
+	};
+	enum ResType {
+		kSurface,
+		kFlic
+	} type;
+};
+
+class QManager {
+public:
+	explicit QManager(PetkaEngine &vm);
+	~QManager();
+
+	bool init();
+
+	Common::String findResourceName(uint32 id) const;
+	Common::String findSoundName(uint32 id) const;
+
+	Graphics::Surface *findOrCreateSurface(uint32 id, uint16 w, uint16 h);
+	Graphics::Surface *loadBitmap(uint32 id);
+	Video::FlicDecoder *loadFlic(uint32 id);
+
+	void removeResource(uint32 id);
+	void clearUnneeded();
+	void clear();
+
+private:
+	Common::SeekableReadStream *loadFileStream(uint32 id) const;
+
+	static void destructResourceContent(QResource &resource);
+	static Graphics::Surface *loadBitmapSurface(Common::SeekableReadStream &stream);
+
+private:
+	PetkaEngine &_vm;
+	Common::HashMap<uint32, QResource> _resourceMap;
+	Common::HashMap<uint32, Common::String> _nameMap;
+	Common::HashMap<uint32, bool> _isAlwaysNeededMap;
+};
+
+} // End of namespace Petka
+
+#endif


Commit: d607eaccdc1b4574e725d97d4d5395ab345dd9f0
    https://github.com/scummvm/scummvm/commit/d607eaccdc1b4574e725d97d4d5395ab345dd9f0
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: changed console ptr to smart

Changed paths:
    engines/petka/petka.cpp
    engines/petka/petka.h


diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
index d4ae8b23ec..8885bb8d92 100644
--- a/engines/petka/petka.cpp
+++ b/engines/petka/petka.cpp
@@ -42,17 +42,17 @@ PetkaEngine::PetkaEngine(OSystem *system, const ADGameDescription *desc)
 
 PetkaEngine::~PetkaEngine() {
 	DebugMan.clearAllDebugChannels();
-	delete _console;
 }
 
 Common::Error PetkaEngine::run() {
 	const Graphics::PixelFormat format(2, 5, 6, 5, 0, 11, 5, 0, 0);
 	initGraphics(640, 480, &format);
 
-	_console = new Console(this);
+	_console.reset(new Console(this));
 	_fileMgr.reset(new FileMgr());
-	loadStores();
 	_resMgr.reset(new QManager(*this));
+
+	loadStores();
 	if (!_resMgr->init())
 		return Common::kNoGameDataFoundError;
 
diff --git a/engines/petka/petka.h b/engines/petka/petka.h
index 18cf71b78d..08b823d565 100644
--- a/engines/petka/petka.h
+++ b/engines/petka/petka.h
@@ -51,7 +51,7 @@ private:
 	void loadStores();
 
 private:
-	Console *_console;
+	Common::ScopedPtr<Console> _console;
 	Common::ScopedPtr<FileMgr> _fileMgr;
 	Common::ScopedPtr<QManager> _resMgr;
 	const ADGameDescription *_desc;


Commit: 749dbee5a580855afa0b99ad64c5efa1a6bf9d2f
    https://github.com/scummvm/scummvm/commit/749dbee5a580855afa0b99ad64c5efa1a6bf9d2f
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added QVisibleObject, QMessageObject, QObject and QObjectBG

Changed paths:
  A engines/petka/q_message_object.cpp
  A engines/petka/q_message_object.h
  A engines/petka/q_object.cpp
  A engines/petka/q_object.h
  A engines/petka/q_object_bg.cpp
  A engines/petka/q_object_bg.h
    engines/petka/base.h
    engines/petka/module.mk


diff --git a/engines/petka/base.h b/engines/petka/base.h
index 925c73c262..5af59b7a4c 100644
--- a/engines/petka/base.h
+++ b/engines/petka/base.h
@@ -108,7 +108,7 @@ struct QReaction {
 	uint16 opcode;
 	byte unk1;
 	uint16 unk2;
-	Common::Array<QMessage> _messages;
+	Common::Array<QMessage> messages;
 };
 
 } // End of namespace Petka
diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index 3459d4773e..23d66cb432 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -4,7 +4,10 @@ MODULE_OBJS = \
     detection.o \
     file_mgr.o \
     petka.o \
-    q_manager.o
+    q_manager.o \
+    q_message_object.o \
+    q_object.o \
+    q_object_bg.o \
 
 # This module can be built as a plugin
 ifeq ($(ENABLE_PETKA), DYNAMIC_PLUGIN)
diff --git a/engines/petka/q_message_object.cpp b/engines/petka/q_message_object.cpp
new file mode 100644
index 0000000000..028179ac08
--- /dev/null
+++ b/engines/petka/q_message_object.cpp
@@ -0,0 +1,73 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/stream.h"
+
+#include "petka/q_message_object.h"
+
+namespace Petka {
+
+QVisibleObject::QVisibleObject()
+	: _resourceId(-1), _z(240) {}
+
+QMessageObject::QMessageObject()
+	: _id(-1), _dialogColor(-1) {}
+
+static Common::String readString(Common::ReadStream &readStream) {
+	uint32 stringSize = readStream.readUint32LE();
+	byte *data = (byte *)malloc(stringSize + 1);
+	readStream.read(data, stringSize);
+	data[stringSize] = '\0';
+	Common::String str((char *)data);
+	return str;
+}
+
+void QMessageObject::deserialize(Common::SeekableReadStream &stream) {
+	_id = stream.readUint16LE();
+	_name = readString(stream);
+	_reactions.resize(stream.readUint32LE());
+	for (uint i = 0; i < _reactions.size(); ++i) {
+		QReaction *reaction = &_reactions[i];
+		reaction->opcode = stream.readUint16LE();
+		reaction->unk1 = stream.readByte();
+		reaction->unk2 = stream.readUint16LE();
+		reaction->messages.resize(stream.readUint32LE());
+		for (uint j = 0; j < reaction->messages.size(); ++j) {
+			QMessage *msg = &reaction->messages[j];
+			msg->objId = stream.readUint16LE();
+			msg->opcode = stream.readUint16LE();
+			msg->arg1 = stream.readUint16LE();
+			msg->arg2 = stream.readUint16LE();
+			msg->arg3 = stream.readUint16LE();
+		}
+	}
+}
+
+void QMessageObject::setDialogColor(int32 color) {
+	_dialogColor = color;
+}
+
+void QMessageObject::setNameOnScreen(const Common::String &name) {
+	_nameOnScreen = name;
+}
+
+} // End of namespace Petka
diff --git a/engines/petka/q_message_object.h b/engines/petka/q_message_object.h
new file mode 100644
index 0000000000..fdaff44157
--- /dev/null
+++ b/engines/petka/q_message_object.h
@@ -0,0 +1,59 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_Q_MESSAGE_OBJECT_H
+#define PETKA_Q_MESSAGE_OBJECT_H
+
+#include "petka/base.h"
+
+namespace Common {
+	class SeekableReadStream;
+}
+
+namespace Petka {
+
+class QVisibleObject {
+public:
+	QVisibleObject();
+protected:
+	int32 _resourceId;
+	int32 _z;
+};
+
+class QMessageObject : public QVisibleObject {
+public:
+	QMessageObject();
+	void deserialize(Common::SeekableReadStream &stream);
+    void setDialogColor(int32 color);
+    void setNameOnScreen(const Common::String &name);
+
+protected:
+	int16 _id;
+	Common::String _name;
+	Common::String _nameOnScreen;
+	int32 _dialogColor;
+	Common::Array<QReaction> _reactions;
+};
+
+} // End of namespace Petka
+
+#endif
diff --git a/engines/petka/q_object.cpp b/engines/petka/q_object.cpp
new file mode 100644
index 0000000000..ccf7f0ec73
--- /dev/null
+++ b/engines/petka/q_object.cpp
@@ -0,0 +1,30 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "petka/q_object.h"
+
+namespace Petka {
+
+
+
+} // End of namespace Petka
+
diff --git a/engines/petka/q_object.h b/engines/petka/q_object.h
new file mode 100644
index 0000000000..42850b3d91
--- /dev/null
+++ b/engines/petka/q_object.h
@@ -0,0 +1,36 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_Q_OBJECT_H
+#define PETKA_Q_OBJECT_H
+
+#include "petka/q_object.h"
+
+namespace Petka {
+
+class QObject : public QMessageObject {
+
+};
+
+} // End of namespace Petka
+
+#endif
diff --git a/engines/petka/q_object_bg.cpp b/engines/petka/q_object_bg.cpp
new file mode 100644
index 0000000000..ae8555de73
--- /dev/null
+++ b/engines/petka/q_object_bg.cpp
@@ -0,0 +1,29 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "petka/q_object_bg.h"
+
+namespace Petka {
+
+
+
+} // End of namespace Petka
diff --git a/engines/petka/q_object_bg.h b/engines/petka/q_object_bg.h
new file mode 100644
index 0000000000..8562082e26
--- /dev/null
+++ b/engines/petka/q_object_bg.h
@@ -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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_Q_OBJECT_BG_H
+#define PETKA_Q_OBJECT_BG_H
+
+#include "petka/q_message_object.h"
+
+namespace Petka {
+
+class QObjectBG : public QMessageObject {
+public:
+
+private:
+
+};
+
+} // End of namespace Petka
+
+#endif
+


Commit: 9b6984d544b1fdb3cf24bb5ccf6b656a49ce7d21
    https://github.com/scummvm/scummvm/commit/9b6984d544b1fdb3cf24bb5ccf6b656a49ce7d21
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: JANITORIAL: fixed formatting

Changed paths:
    engines/petka/q_message_object.h


diff --git a/engines/petka/q_message_object.h b/engines/petka/q_message_object.h
index fdaff44157..cc049da97d 100644
--- a/engines/petka/q_message_object.h
+++ b/engines/petka/q_message_object.h
@@ -43,8 +43,8 @@ class QMessageObject : public QVisibleObject {
 public:
 	QMessageObject();
 	void deserialize(Common::SeekableReadStream &stream);
-    void setDialogColor(int32 color);
-    void setNameOnScreen(const Common::String &name);
+	void setDialogColor(int32 color);
+	void setNameOnScreen(const Common::String &name);
 
 protected:
 	int16 _id;


Commit: 9143cc38dca78c2fb4e711f32e8c2d8ceed286fc
    https://github.com/scummvm/scummvm/commit/9143cc38dca78c2fb4e711f32e8c2d8ceed286fc
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed include in q_object.h

Changed paths:
    engines/petka/q_object.h


diff --git a/engines/petka/q_object.h b/engines/petka/q_object.h
index 42850b3d91..d38931e7fe 100644
--- a/engines/petka/q_object.h
+++ b/engines/petka/q_object.h
@@ -23,7 +23,7 @@
 #ifndef PETKA_Q_OBJECT_H
 #define PETKA_Q_OBJECT_H
 
-#include "petka/q_object.h"
+#include "petka/q_message_object.h"
 
 namespace Petka {
 


Commit: cd439b1fe2d8c3db70760e95371c1afe465625ee
    https://github.com/scummvm/scummvm/commit/cd439b1fe2d8c3db70760e95371c1afe465625ee
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added QSystem

Changed paths:
  A engines/petka/q_system.cpp
  A engines/petka/q_system.h
    engines/petka/module.mk
    engines/petka/petka.cpp
    engines/petka/petka.h
    engines/petka/q_message_object.cpp
    engines/petka/q_message_object.h


diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index 23d66cb432..707e1d8ca8 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -8,6 +8,7 @@ MODULE_OBJS = \
     q_message_object.o \
     q_object.o \
     q_object_bg.o \
+    q_system.o
 
 # This module can be built as a plugin
 ifeq ($(ENABLE_PETKA), DYNAMIC_PLUGIN)
diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
index 8885bb8d92..66c28c54ea 100644
--- a/engines/petka/petka.cpp
+++ b/engines/petka/petka.cpp
@@ -30,11 +30,12 @@
 #include "petka/file_mgr.h"
 #include "petka/petka.h"
 #include "petka/q_manager.h"
+#include "petka/q_system.h"
 
 namespace Petka {
 
 PetkaEngine::PetkaEngine(OSystem *system, const ADGameDescription *desc)
-	: Engine(system), _console(nullptr), _fileMgr(nullptr), _resMgr(nullptr), _desc(desc) {
+	: Engine(system), _console(nullptr), _fileMgr(nullptr), _resMgr(nullptr), _gsystem(nullptr), _desc(desc) {
 	DebugMan.addDebugChannel(kPetkaDebugGeneral, "general", "General issues");
 	_part = 0;
 	_chapter = 0;
@@ -51,10 +52,12 @@ Common::Error PetkaEngine::run() {
 	_console.reset(new Console(this));
 	_fileMgr.reset(new FileMgr());
 	_resMgr.reset(new QManager(*this));
+	_gsystem.reset(new QSystem(*this));
 
 	loadStores();
 	if (!_resMgr->init())
 		return Common::kNoGameDataFoundError;
+	_gsystem->init();
 
 	return Common::kNoError;
 }
diff --git a/engines/petka/petka.h b/engines/petka/petka.h
index 08b823d565..f8f998a162 100644
--- a/engines/petka/petka.h
+++ b/engines/petka/petka.h
@@ -34,6 +34,7 @@ namespace Petka {
 class Console;
 class FileMgr;
 class QManager;
+class QSystem;
 
 enum {
 	kPetkaDebugGeneral = 1 << 0,
@@ -54,6 +55,7 @@ private:
 	Common::ScopedPtr<Console> _console;
 	Common::ScopedPtr<FileMgr> _fileMgr;
 	Common::ScopedPtr<QManager> _resMgr;
+	Common::ScopedPtr<QSystem> _gsystem;
 	const ADGameDescription *_desc;
 
 	Common::String _currentPath;
diff --git a/engines/petka/q_message_object.cpp b/engines/petka/q_message_object.cpp
index 028179ac08..3d7c03f02c 100644
--- a/engines/petka/q_message_object.cpp
+++ b/engines/petka/q_message_object.cpp
@@ -20,8 +20,11 @@
  *
  */
 
+#include "common/ini-file.h"
 #include "common/stream.h"
 
+#include "graphics/colormasks.h"
+
 #include "petka/q_message_object.h"
 
 namespace Petka {
@@ -41,10 +44,11 @@ static Common::String readString(Common::ReadStream &readStream) {
 	return str;
 }
 
-void QMessageObject::deserialize(Common::SeekableReadStream &stream) {
+void QMessageObject::deserialize(Common::SeekableReadStream &stream, const Common::INIFile &namesIni, const Common::INIFile &castIni) {
 	_id = stream.readUint16LE();
 	_name = readString(stream);
 	_reactions.resize(stream.readUint32LE());
+
 	for (uint i = 0; i < _reactions.size(); ++i) {
 		QReaction *reaction = &_reactions[i];
 		reaction->opcode = stream.readUint16LE();
@@ -60,14 +64,19 @@ void QMessageObject::deserialize(Common::SeekableReadStream &stream) {
 			msg->arg3 = stream.readUint16LE();
 		}
 	}
-}
 
-void QMessageObject::setDialogColor(int32 color) {
-	_dialogColor = color;
+	namesIni.getKey(_name, "all", _nameOnScreen);
+
+	Common::String rgbString;
+	if (castIni.getKey(_name, "all", rgbString)) {
+		int r, g, b;
+		sscanf(rgbString.c_str(), "%d %d %d", &r, &g, &b);
+		_dialogColor = Graphics::RGBToColor<Graphics::ColorMasks<888>>((byte)r, (byte)g, (byte)b);
+	}
 }
 
-void QMessageObject::setNameOnScreen(const Common::String &name) {
-	_nameOnScreen = name;
+uint16 QMessageObject::getId() {
+	return _id;
 }
 
 } // End of namespace Petka
diff --git a/engines/petka/q_message_object.h b/engines/petka/q_message_object.h
index cc049da97d..9bc176ef3c 100644
--- a/engines/petka/q_message_object.h
+++ b/engines/petka/q_message_object.h
@@ -27,6 +27,7 @@
 
 namespace Common {
 	class SeekableReadStream;
+	class INIFile;
 }
 
 namespace Petka {
@@ -42,12 +43,11 @@ protected:
 class QMessageObject : public QVisibleObject {
 public:
 	QMessageObject();
-	void deserialize(Common::SeekableReadStream &stream);
-	void setDialogColor(int32 color);
-	void setNameOnScreen(const Common::String &name);
+	void deserialize(Common::SeekableReadStream &stream, const Common::INIFile &namesIni, const Common::INIFile &castIni);
+	uint16 getId();
 
 protected:
-	int16 _id;
+	uint16 _id;
 	Common::String _name;
 	Common::String _nameOnScreen;
 	int32 _dialogColor;
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
new file mode 100644
index 0000000000..459c2fd186
--- /dev/null
+++ b/engines/petka/q_system.cpp
@@ -0,0 +1,98 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/ini-file.h"
+#include "common/substream.h"
+
+#include "petka/petka.h"
+#include "petka/q_system.h"
+
+namespace Petka {
+
+QSystem::QSystem(PetkaEngine &vm)
+	: _vm(vm) {}
+
+QSystem::~QSystem() {
+
+}
+
+Common::String readString(Common::ReadStream &readStream) {
+	uint32 stringSize = readStream.readUint32LE();
+	byte *data = (byte *)malloc(stringSize + 1);
+	readStream.read(data, stringSize);
+	data[stringSize] = '\0';
+	Common::String str((char *)data);
+	return str;
+}
+
+bool QSystem::init() {
+	Common::ScopedPtr<Common::SeekableReadStream> stream(_vm.openFile("script.dat", true));
+	if (!stream)
+		return false;
+	Common::ScopedPtr<Common::SeekableReadStream> namesStream(_vm.openFile("Names.ini", false));
+	Common::ScopedPtr<Common::SeekableReadStream> castStream(_vm.openFile("Cast.ini", false));
+	Common::ScopedPtr<Common::SeekableReadStream> bgsStream(_vm.openFile("BGs.ini", false));
+
+	Common::INIFile namesIni;
+	Common::INIFile castIni;
+	Common::INIFile bgsIni;
+
+	// fails because ini is broken for Russian letters
+	namesIni.loadFromStream(*namesStream);
+	castIni.loadFromStream(*castStream);
+	bgsIni.loadFromStream(*bgsStream);
+
+	uint32 objsCount = stream->readUint32LE();
+	uint32 bgsCount = stream->readUint32LE();
+
+	_objs.resize(objsCount);
+	_bgs.resize(bgsCount);
+
+	Common::String name;
+	for (uint i = 0; i < objsCount; ++i) {
+		_objs[i].deserialize(*stream, namesIni, castIni);
+		_allObjects.push_back(&_objs[i]);
+	}
+	for (uint i = 0; i < bgsCount; ++i) {
+		_bgs[i].deserialize(*stream, namesIni, castIni);
+		_allObjects.push_back(&_bgs[i]);
+	}
+
+	addMessageForAllObjects(kTotalInit);
+	return true;
+}
+
+void QSystem::addMessage(const QMessage &msg) {
+	_messages.push_back(msg);
+}
+
+void QSystem::addMessage(uint16 objId, uint16 opcode, int16 arg1, int16 arg2, int16 arg3, int16 unk1, int16 unk2) {
+	_messages.push_back({objId, opcode, arg1, arg2, arg3, unk1, unk2});
+}
+
+void QSystem::addMessageForAllObjects(uint16 opcode, int16 arg1, int16 arg2, int16 arg3, int16 unk1, int16 unk2) {
+	for (uint i = 0; i < _allObjects.size(); ++i) {
+		_messages.push_back({_allObjects[i]->getId(), opcode, arg1, arg2, arg3, unk1, unk2});
+	}
+}
+
+}
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
new file mode 100644
index 0000000000..d82970e169
--- /dev/null
+++ b/engines/petka/q_system.h
@@ -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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_Q_SYSTEM_H
+#define PETKA_Q_SYSTEM_H
+
+#include "petka/q_object.h"
+#include "petka/q_object_bg.h"
+
+namespace Petka {
+
+class PetkaEngine;
+
+class QSystem {
+public:
+	explicit QSystem(PetkaEngine &vm);
+	~QSystem();
+
+	bool init();
+
+	void addMessage(const QMessage &msg);
+	void addMessage(uint16 objId, uint16 opcode, int16 arg1 = 0, int16 arg2 = 0, int16 arg3 = 0, int16 unk1 = 0, int16 unk2 = 0);
+	void addMessageForAllObjects(uint16 opcode, int16 arg1 = 0, int16 arg2 = 0, int16 arg3 = 0, int16 unk1 = 0, int16 unk2 = 0);
+
+private:
+	PetkaEngine &_vm;
+	Common::Array<QObject> _objs;
+	Common::Array<QObjectBG> _bgs;
+	Common::Array<QMessageObject *> _allObjects;
+	Common::Array<QMessage> _messages;
+};
+
+} // End of namespace Petka
+
+#endif


Commit: dbff81f8d59d42ee779a08b9769dc6a59f461936
    https://github.com/scummvm/scummvm/commit/dbff81f8d59d42ee779a08b9769dc6a59f461936
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added QObjectCursor

Changed paths:
  A engines/petka/q_object_cursor.cpp
  A engines/petka/q_object_cursor.h
    engines/petka/module.mk
    engines/petka/q_system.cpp
    engines/petka/q_system.h


diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index 707e1d8ca8..0daa432703 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -8,6 +8,7 @@ MODULE_OBJS = \
     q_message_object.o \
     q_object.o \
     q_object_bg.o \
+    q_object_cursor.o \
     q_system.o
 
 # This module can be built as a plugin
diff --git a/engines/petka/q_object_cursor.cpp b/engines/petka/q_object_cursor.cpp
new file mode 100644
index 0000000000..6596280289
--- /dev/null
+++ b/engines/petka/q_object_cursor.cpp
@@ -0,0 +1,28 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "petka/q_object_cursor.h"
+
+namespace Petka {
+
+
+} // End of namespace Petka
\ No newline at end of file
diff --git a/engines/petka/q_object_cursor.h b/engines/petka/q_object_cursor.h
new file mode 100644
index 0000000000..7af696f3f5
--- /dev/null
+++ b/engines/petka/q_object_cursor.h
@@ -0,0 +1,36 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_Q_OBJECT_CURSOR_H
+#define PETKA_Q_OBJECT_CURSOR_H
+
+#include "petka/q_object.h"
+
+namespace Petka {
+
+class QObjectCursor : public QObject {
+
+};
+
+} // End of namespace Petka
+
+#endif
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 459c2fd186..1d0035d880 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -24,12 +24,13 @@
 #include "common/substream.h"
 
 #include "petka/petka.h"
+#include "petka/q_object_cursor.h"
 #include "petka/q_system.h"
 
 namespace Petka {
 
 QSystem::QSystem(PetkaEngine &vm)
-	: _vm(vm) {}
+	: _vm(vm), _cursor(nullptr) {}
 
 QSystem::~QSystem() {
 
@@ -78,6 +79,9 @@ bool QSystem::init() {
 	}
 
 	addMessageForAllObjects(kTotalInit);
+
+	_cursor.reset(new QObjectCursor());
+	_allObjects.push_back(_cursor.get());
 	return true;
 }
 
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index d82970e169..696216140e 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -29,6 +29,7 @@
 namespace Petka {
 
 class PetkaEngine;
+class QObjectCursor;
 
 class QSystem {
 public:
@@ -47,6 +48,7 @@ private:
 	Common::Array<QObjectBG> _bgs;
 	Common::Array<QMessageObject *> _allObjects;
 	Common::Array<QMessage> _messages;
+	Common::ScopedPtr<QObjectCursor> _cursor;
 };
 
 } // End of namespace Petka


Commit: 9c0909b9b8ea0630882e413918a5ea2548cbcc34
    https://github.com/scummvm/scummvm/commit/9c0909b9b8ea0630882e413918a5ea2548cbcc34
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added QObjectCase

Changed paths:
  A engines/petka/q_object_case.cpp
  A engines/petka/q_object_case.h
    engines/petka/module.mk
    engines/petka/q_system.cpp
    engines/petka/q_system.h


diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index 0daa432703..029839a6ed 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -8,6 +8,7 @@ MODULE_OBJS = \
     q_message_object.o \
     q_object.o \
     q_object_bg.o \
+    q_object_case.o \
     q_object_cursor.o \
     q_system.o
 
diff --git a/engines/petka/q_object_case.cpp b/engines/petka/q_object_case.cpp
new file mode 100644
index 0000000000..4bf813d84d
--- /dev/null
+++ b/engines/petka/q_object_case.cpp
@@ -0,0 +1,29 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "petka/q_object_case.h"
+
+namespace Petka {
+
+
+
+} // End of namespace Petka
diff --git a/engines/petka/q_object_case.h b/engines/petka/q_object_case.h
new file mode 100644
index 0000000000..059809c872
--- /dev/null
+++ b/engines/petka/q_object_case.h
@@ -0,0 +1,36 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_Q_OBJECT_CASE_H
+#define PETKA_Q_OBJECT_CASE_H
+
+#include "petka/q_object.h"
+
+namespace Petka {
+
+class QObjectCase : public QObject {
+
+};
+
+} // End of namespace Petka
+
+#endif
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 1d0035d880..1c7daa7fe9 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -24,13 +24,14 @@
 #include "common/substream.h"
 
 #include "petka/petka.h"
+#include "petka/q_object_case.h"
 #include "petka/q_object_cursor.h"
 #include "petka/q_system.h"
 
 namespace Petka {
 
 QSystem::QSystem(PetkaEngine &vm)
-	: _vm(vm), _cursor(nullptr) {}
+	: _vm(vm), _cursor(nullptr), _case(nullptr) {}
 
 QSystem::~QSystem() {
 
@@ -81,7 +82,9 @@ bool QSystem::init() {
 	addMessageForAllObjects(kTotalInit);
 
 	_cursor.reset(new QObjectCursor());
+	_case.reset(new QObjectCase());
 	_allObjects.push_back(_cursor.get());
+	_allObjects.push_back(_case.get());
 	return true;
 }
 
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index 696216140e..317f410e1f 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -29,6 +29,7 @@
 namespace Petka {
 
 class PetkaEngine;
+class QObjectCase;
 class QObjectCursor;
 
 class QSystem {
@@ -49,6 +50,7 @@ private:
 	Common::Array<QMessageObject *> _allObjects;
 	Common::Array<QMessage> _messages;
 	Common::ScopedPtr<QObjectCursor> _cursor;
+	Common::ScopedPtr<QObjectCase> _case;
 };
 
 } // End of namespace Petka


Commit: 1b22c08da1cd88aa130cb91d2bb825924d02b5a4
    https://github.com/scummvm/scummvm/commit/1b22c08da1cd88aa130cb91d2bb825924d02b5a4
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added QObjectStar

Changed paths:
  A engines/petka/q_object_star.cpp
  A engines/petka/q_object_star.h
    engines/petka/module.mk
    engines/petka/q_system.cpp
    engines/petka/q_system.h


diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index 029839a6ed..c9d35f424d 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -10,6 +10,7 @@ MODULE_OBJS = \
     q_object_bg.o \
     q_object_case.o \
     q_object_cursor.o \
+    q_object_star. o \
     q_system.o
 
 # This module can be built as a plugin
diff --git a/engines/petka/q_object_star.cpp b/engines/petka/q_object_star.cpp
new file mode 100644
index 0000000000..5a8104b2c8
--- /dev/null
+++ b/engines/petka/q_object_star.cpp
@@ -0,0 +1,28 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "petka/q_object_star.h"
+
+namespace Petka {
+
+
+} // End of namespace Petka
\ No newline at end of file
diff --git a/engines/petka/q_object_star.h b/engines/petka/q_object_star.h
new file mode 100644
index 0000000000..62c8209ad7
--- /dev/null
+++ b/engines/petka/q_object_star.h
@@ -0,0 +1,36 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_Q_OBJECT_STAR_H
+#define PETKA_Q_OBJECT_STAR_H
+
+#include "petka/q_object.h"
+
+namespace Petka {
+
+class QObjectStar : public QObject {
+
+};
+
+} // End of namespace Petka
+
+#endif
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 1c7daa7fe9..7bcb4954d5 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -26,12 +26,13 @@
 #include "petka/petka.h"
 #include "petka/q_object_case.h"
 #include "petka/q_object_cursor.h"
+#include "petka/q_object_star.h"
 #include "petka/q_system.h"
 
 namespace Petka {
 
 QSystem::QSystem(PetkaEngine &vm)
-	: _vm(vm), _cursor(nullptr), _case(nullptr) {}
+	: _vm(vm), _cursor(nullptr), _case(nullptr), _star(nullptr) {}
 
 QSystem::~QSystem() {
 
@@ -83,8 +84,11 @@ bool QSystem::init() {
 
 	_cursor.reset(new QObjectCursor());
 	_case.reset(new QObjectCase());
+	_star.reset(new QObjectStar());
+
 	_allObjects.push_back(_cursor.get());
 	_allObjects.push_back(_case.get());
+	_allObjects.push_back(_star.get());
 	return true;
 }
 
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index 317f410e1f..9ab440d750 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -31,6 +31,7 @@ namespace Petka {
 class PetkaEngine;
 class QObjectCase;
 class QObjectCursor;
+class QObjectStar;
 
 class QSystem {
 public:
@@ -51,6 +52,7 @@ private:
 	Common::Array<QMessage> _messages;
 	Common::ScopedPtr<QObjectCursor> _cursor;
 	Common::ScopedPtr<QObjectCase> _case;
+	Common::ScopedPtr<QObjectStar> _star;
 };
 
 } // End of namespace Petka


Commit: 95abfb168d4d62e3229ae4eebb8d6cb71c22565f
    https://github.com/scummvm/scummvm/commit/95abfb168d4d62e3229ae4eebb8d6cb71c22565f
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added QInterface

Changed paths:
  A engines/petka/q_interface.cpp
  A engines/petka/q_interface.h
    engines/petka/module.mk
    engines/petka/q_system.cpp
    engines/petka/q_system.h


diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index c9d35f424d..60d4e40697 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -4,6 +4,7 @@ MODULE_OBJS = \
     detection.o \
     file_mgr.o \
     petka.o \
+    q_interface.o \
     q_manager.o \
     q_message_object.o \
     q_object.o \
diff --git a/engines/petka/q_interface.cpp b/engines/petka/q_interface.cpp
new file mode 100644
index 0000000000..07f5fa5788
--- /dev/null
+++ b/engines/petka/q_interface.cpp
@@ -0,0 +1,30 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "petka/q_interface.h"
+
+namespace Petka {
+
+QInterface::QInterface()
+	: _objUnderCursor(nullptr) {}
+
+} // End of namespace Petka
diff --git a/engines/petka/q_interface.h b/engines/petka/q_interface.h
new file mode 100644
index 0000000000..915deb578b
--- /dev/null
+++ b/engines/petka/q_interface.h
@@ -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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_Q_INTERFACE_H
+#define PETKA_Q_INTERFACE_H
+
+#include "common/array.h"
+
+namespace Petka {
+
+class QVisibleObject;
+
+class QInterface {
+public:
+	QInterface();
+
+private:
+	Common::Array<QVisibleObject *> _objs;
+	QVisibleObject *_objUnderCursor;
+};
+
+} // End of namespace Petka
+
+#endif
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 7bcb4954d5..d6bacba83d 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -32,7 +32,8 @@
 namespace Petka {
 
 QSystem::QSystem(PetkaEngine &vm)
-	: _vm(vm), _cursor(nullptr), _case(nullptr), _star(nullptr) {}
+	: _vm(vm), _cursor(nullptr), _case(nullptr), _star(nullptr),
+	_currInterface(nullptr), _prevInterface(nullptr) {}
 
 QSystem::~QSystem() {
 
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index 9ab440d750..79ae675284 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -32,6 +32,7 @@ class PetkaEngine;
 class QObjectCase;
 class QObjectCursor;
 class QObjectStar;
+class QInterface;
 
 class QSystem {
 public:
@@ -53,6 +54,8 @@ private:
 	Common::ScopedPtr<QObjectCursor> _cursor;
 	Common::ScopedPtr<QObjectCase> _case;
 	Common::ScopedPtr<QObjectStar> _star;
+	QInterface *_currInterface;
+	QInterface *_prevInterface;
 };
 
 } // End of namespace Petka


Commit: 93980436aa323508adb11fbb06b0ac42a47b4ab4
    https://github.com/scummvm/scummvm/commit/93980436aa323508adb11fbb06b0ac42a47b4ab4
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: renamed unknown fields in QReaction

Changed paths:
    engines/petka/base.h
    engines/petka/q_message_object.cpp


diff --git a/engines/petka/base.h b/engines/petka/base.h
index 5af59b7a4c..a1d6a1e1af 100644
--- a/engines/petka/base.h
+++ b/engines/petka/base.h
@@ -106,8 +106,8 @@ struct QMessage {
 
 struct QReaction {
 	uint16 opcode;
-	byte unk1;
-	uint16 unk2;
+	byte status;
+	uint16 senderId;
 	Common::Array<QMessage> messages;
 };
 
diff --git a/engines/petka/q_message_object.cpp b/engines/petka/q_message_object.cpp
index 3d7c03f02c..a471eb5ea3 100644
--- a/engines/petka/q_message_object.cpp
+++ b/engines/petka/q_message_object.cpp
@@ -52,8 +52,8 @@ void QMessageObject::deserialize(Common::SeekableReadStream &stream, const Commo
 	for (uint i = 0; i < _reactions.size(); ++i) {
 		QReaction *reaction = &_reactions[i];
 		reaction->opcode = stream.readUint16LE();
-		reaction->unk1 = stream.readByte();
-		reaction->unk2 = stream.readUint16LE();
+		reaction->status = stream.readByte();
+		reaction->senderId = stream.readUint16LE();
 		reaction->messages.resize(stream.readUint32LE());
 		for (uint j = 0; j < reaction->messages.size(); ++j) {
 			QMessage *msg = &reaction->messages[j];


Commit: ab76b44ce0b14ffe6ac64726ef57e300e06fe2bf
    https://github.com/scummvm/scummvm/commit/ab76b44ce0b14ffe6ac64726ef57e300e06fe2bf
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: renamed unknown field in QMessage

Changed paths:
    engines/petka/base.h
    engines/petka/q_system.cpp
    engines/petka/q_system.h


diff --git a/engines/petka/base.h b/engines/petka/base.h
index a1d6a1e1af..0fc6eaa859 100644
--- a/engines/petka/base.h
+++ b/engines/petka/base.h
@@ -94,14 +94,16 @@ enum Opcode {
 	kToMap = 63 // ??? MessageNumber
 };
 
+class QMessageObject;
+
 struct QMessage {
 	uint16 objId;
 	uint16 opcode;
 	int16 arg1;
 	int16 arg2;
 	int16 arg3;
-	int32 unk1;
-	int32 unk2;
+	QMessageObject *sender;
+	int32 unk;
 };
 
 struct QReaction {
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index d6bacba83d..1dc29a6546 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -97,13 +97,13 @@ void QSystem::addMessage(const QMessage &msg) {
 	_messages.push_back(msg);
 }
 
-void QSystem::addMessage(uint16 objId, uint16 opcode, int16 arg1, int16 arg2, int16 arg3, int16 unk1, int16 unk2) {
-	_messages.push_back({objId, opcode, arg1, arg2, arg3, unk1, unk2});
+void QSystem::addMessage(uint16 objId, uint16 opcode, int16 arg1, int16 arg2, int16 arg3, int16 unk, QMessageObject *sender) {
+	_messages.push_back({objId, opcode, arg1, arg2, arg3, sender, unk});
 }
 
-void QSystem::addMessageForAllObjects(uint16 opcode, int16 arg1, int16 arg2, int16 arg3, int16 unk1, int16 unk2) {
+void QSystem::addMessageForAllObjects(uint16 opcode, int16 arg1, int16 arg2, int16 arg3, int16 unk, QMessageObject *sender) {
 	for (uint i = 0; i < _allObjects.size(); ++i) {
-		_messages.push_back({_allObjects[i]->getId(), opcode, arg1, arg2, arg3, unk1, unk2});
+		_messages.push_back({_allObjects[i]->getId(), opcode, arg1, arg2, arg3, sender, unk});
 	}
 }
 
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index 79ae675284..e3b0e0ed6c 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -42,8 +42,8 @@ public:
 	bool init();
 
 	void addMessage(const QMessage &msg);
-	void addMessage(uint16 objId, uint16 opcode, int16 arg1 = 0, int16 arg2 = 0, int16 arg3 = 0, int16 unk1 = 0, int16 unk2 = 0);
-	void addMessageForAllObjects(uint16 opcode, int16 arg1 = 0, int16 arg2 = 0, int16 arg3 = 0, int16 unk1 = 0, int16 unk2 = 0);
+	void addMessage(uint16 objId, uint16 opcode, int16 arg1 = 0, int16 arg2 = 0, int16 arg3 = 0, int16 unk = 0, QMessageObject *sender = nullptr);
+	void addMessageForAllObjects(uint16 opcode, int16 arg1 = 0, int16 arg2 = 0, int16 arg3 = 0, int16 unk = 0, QMessageObject *sender = nullptr);
 
 private:
 	PetkaEngine &_vm;


Commit: 1e25b941e0ed1f6dc8a9fc6531910b0848c0775f
    https://github.com/scummvm/scummvm/commit/1e25b941e0ed1f6dc8a9fc6531910b0848c0775f
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added partial implementation of processing messages in QMessageObject

Changed paths:
    engines/petka/base.h
    engines/petka/petka.cpp
    engines/petka/petka.h
    engines/petka/q_message_object.cpp
    engines/petka/q_message_object.h
    engines/petka/q_system.cpp
    engines/petka/q_system.h


diff --git a/engines/petka/base.h b/engines/petka/base.h
index 0fc6eaa859..e71a655db1 100644
--- a/engines/petka/base.h
+++ b/engines/petka/base.h
@@ -108,8 +108,8 @@ struct QMessage {
 
 struct QReaction {
 	uint16 opcode;
-	byte status;
-	uint16 senderId;
+	int8 status;
+	int16 senderId;
 	Common::Array<QMessage> messages;
 };
 
diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
index 66c28c54ea..f761502dcb 100644
--- a/engines/petka/petka.cpp
+++ b/engines/petka/petka.cpp
@@ -34,11 +34,15 @@
 
 namespace Petka {
 
+PetkaEngine *g_vm;
+
 PetkaEngine::PetkaEngine(OSystem *system, const ADGameDescription *desc)
-	: Engine(system), _console(nullptr), _fileMgr(nullptr), _resMgr(nullptr), _gsystem(nullptr), _desc(desc) {
+	: Engine(system), _console(nullptr), _fileMgr(nullptr), _resMgr(nullptr),
+	_qsystem(nullptr), _desc(desc), _rnd("petka") {
 	DebugMan.addDebugChannel(kPetkaDebugGeneral, "general", "General issues");
 	_part = 0;
 	_chapter = 0;
+	g_vm = this;
 }
 
 PetkaEngine::~PetkaEngine() {
@@ -52,12 +56,12 @@ Common::Error PetkaEngine::run() {
 	_console.reset(new Console(this));
 	_fileMgr.reset(new FileMgr());
 	_resMgr.reset(new QManager(*this));
-	_gsystem.reset(new QSystem(*this));
+	_qsystem.reset(new QSystem(*this));
 
 	loadStores();
 	if (!_resMgr->init())
 		return Common::kNoGameDataFoundError;
-	_gsystem->init();
+	_qsystem->init();
 
 	return Common::kNoError;
 }
@@ -95,4 +99,12 @@ void PetkaEngine::loadStores() {
 	_fileMgr->openStore(_chapterStoreName);
 }
 
+QSystem *PetkaEngine::getQSystem() const {
+	return _qsystem.get();
+}
+
+Common::RandomSource &PetkaEngine::getRnd() {
+	return _rnd;
+}
+
 } // End of namespace Petka
diff --git a/engines/petka/petka.h b/engines/petka/petka.h
index f8f998a162..f876f5370a 100644
--- a/engines/petka/petka.h
+++ b/engines/petka/petka.h
@@ -23,6 +23,8 @@
 #ifndef PETKA_PETKA_H
 #define PETKA_PETKA_H
 
+#include "common/random.h"
+
 #include "engines/engine.h"
 
 #include "gui/debugger.h"
@@ -48,6 +50,9 @@ public:
 	virtual Common::Error run();
 	Common::SeekableReadStream *openFile(const Common::String &name, bool addCurrentPath);
 
+	QSystem *getQSystem() const;
+	Common::RandomSource &getRnd();
+
 private:
 	void loadStores();
 
@@ -55,9 +60,11 @@ private:
 	Common::ScopedPtr<Console> _console;
 	Common::ScopedPtr<FileMgr> _fileMgr;
 	Common::ScopedPtr<QManager> _resMgr;
-	Common::ScopedPtr<QSystem> _gsystem;
+	Common::ScopedPtr<QSystem> _qsystem;
 	const ADGameDescription *_desc;
 
+	Common::RandomSource _rnd;
+
 	Common::String _currentPath;
 	Common::String _speechPath;
 
@@ -73,6 +80,8 @@ public:
 	virtual ~Console() {}
 };
 
+extern PetkaEngine *g_vm;
+
 } // End of namespace Petka
 
 #endif
diff --git a/engines/petka/q_message_object.cpp b/engines/petka/q_message_object.cpp
index a471eb5ea3..02dce34f54 100644
--- a/engines/petka/q_message_object.cpp
+++ b/engines/petka/q_message_object.cpp
@@ -25,6 +25,8 @@
 
 #include "graphics/colormasks.h"
 
+#include "petka/petka.h"
+#include "petka/q_system.h"
 #include "petka/q_message_object.h"
 
 namespace Petka {
@@ -75,8 +77,64 @@ void QMessageObject::deserialize(Common::SeekableReadStream &stream, const Commo
 	}
 }
 
-uint16 QMessageObject::getId() {
+uint16 QMessageObject::getId() const {
 	return _id;
 }
 
+const Common::String &QMessageObject::getName() const {
+	return _name;
+}
+
+void QMessageObject::processMessage(const QMessage &msg) {
+	for (uint i = 0; i < _reactions.size(); ++i) {
+		QReaction &r = _reactions[i];
+		if (r.opcode != msg.opcode ||
+		(r.status != -1 && r.status != _status) ||
+		(r.senderId != -1 && r.senderId != msg.sender->_id)) {
+			continue;
+		}
+		for (uint j = 0; j < r.messages.size(); ++j) {
+			QMessage &rMsg = r.messages[j];
+			if (r.opcode == kCheck && g_vm->getQSystem()->findObject(rMsg.objId)->_status != rMsg.arg1) {
+				break;
+			}
+			if (rMsg.opcode == kIf &&
+			(rMsg.arg1 == -1 || rMsg.arg1 != msg.arg1) &&
+			(rMsg.arg2 == -1 || rMsg.arg2 != msg.arg2) &&
+			(rMsg.arg3 == -1 || rMsg.arg3 != msg.arg3)) {
+				break;
+			}
+			if (rMsg.opcode == kRandom && rMsg.arg2 != -1) {
+				rMsg.arg1 = (int16)g_vm->getRnd().getRandomNumber((uint)(rMsg.arg2 - 1));
+			}
+			g_vm->getQSystem()->addMessage(rMsg.objId, rMsg.opcode, rMsg.arg1, rMsg.arg2, rMsg.arg3, rMsg.unk, rMsg.sender);
+
+			switch (rMsg.opcode) {
+			case kPlay:
+				break;
+			case kWalk:
+			case kWalkTo:
+				break;
+			case kWalkVich:
+				break;
+			}
+		}
+	}
+
+	switch (msg.opcode) {
+	case kSet:
+		break;
+	case kStatus:
+		_status = (int8)msg.arg1;
+		break;
+	case kHide:
+		break;
+	case kZBuffer:
+		break;
+	case kPassive:
+		break;
+	}
+
+}
+
 } // End of namespace Petka
diff --git a/engines/petka/q_message_object.h b/engines/petka/q_message_object.h
index 9bc176ef3c..8287a4c0b3 100644
--- a/engines/petka/q_message_object.h
+++ b/engines/petka/q_message_object.h
@@ -35,6 +35,8 @@ namespace Petka {
 class QVisibleObject {
 public:
 	QVisibleObject();
+	virtual ~QVisibleObject() {};
+
 protected:
 	int32 _resourceId;
 	int32 _z;
@@ -43,11 +45,17 @@ protected:
 class QMessageObject : public QVisibleObject {
 public:
 	QMessageObject();
+
 	void deserialize(Common::SeekableReadStream &stream, const Common::INIFile &namesIni, const Common::INIFile &castIni);
-	uint16 getId();
+
+	uint16 getId() const;
+	const Common::String &getName() const;
+
+	virtual void processMessage(const QMessage &msg);
 
 protected:
 	uint16 _id;
+	int8 _status;
 	Common::String _name;
 	Common::String _nameOnScreen;
 	int32 _dialogColor;
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 1dc29a6546..f351895c5a 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -97,14 +97,30 @@ void QSystem::addMessage(const QMessage &msg) {
 	_messages.push_back(msg);
 }
 
-void QSystem::addMessage(uint16 objId, uint16 opcode, int16 arg1, int16 arg2, int16 arg3, int16 unk, QMessageObject *sender) {
+void QSystem::addMessage(uint16 objId, uint16 opcode, int16 arg1, int16 arg2, int16 arg3, int32 unk, QMessageObject *sender) {
 	_messages.push_back({objId, opcode, arg1, arg2, arg3, sender, unk});
 }
 
-void QSystem::addMessageForAllObjects(uint16 opcode, int16 arg1, int16 arg2, int16 arg3, int16 unk, QMessageObject *sender) {
+void QSystem::addMessageForAllObjects(uint16 opcode, int16 arg1, int16 arg2, int16 arg3, int32 unk, QMessageObject *sender) {
 	for (uint i = 0; i < _allObjects.size(); ++i) {
 		_messages.push_back({_allObjects[i]->getId(), opcode, arg1, arg2, arg3, sender, unk});
 	}
 }
 
+QMessageObject *QSystem::findObject(int16 id) {
+	for (uint i = 0; i < _allObjects.size(); ++i) {
+		if (_allObjects[i]->getId() == id)
+			return _allObjects[i];
+	}
+	return nullptr;
+}
+
+QMessageObject *QSystem::findObject(const Common::String &name) {
+	for (uint i = 0; i < _allObjects.size(); ++i) {
+		if (_allObjects[i]->getName() == name)
+			return _allObjects[i];
+	}
+	return nullptr;
+}
+
 }
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index e3b0e0ed6c..1f4424ccef 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -42,8 +42,11 @@ public:
 	bool init();
 
 	void addMessage(const QMessage &msg);
-	void addMessage(uint16 objId, uint16 opcode, int16 arg1 = 0, int16 arg2 = 0, int16 arg3 = 0, int16 unk = 0, QMessageObject *sender = nullptr);
-	void addMessageForAllObjects(uint16 opcode, int16 arg1 = 0, int16 arg2 = 0, int16 arg3 = 0, int16 unk = 0, QMessageObject *sender = nullptr);
+	void addMessage(uint16 objId, uint16 opcode, int16 arg1 = 0, int16 arg2 = 0, int16 arg3 = 0, int32 unk = 0, QMessageObject *sender = nullptr);
+	void addMessageForAllObjects(uint16 opcode, int16 arg1 = 0, int16 arg2 = 0, int16 arg3 = 0, int32 unk = 0, QMessageObject *sender = nullptr);
+
+	QMessageObject *findObject(int16 id);
+	QMessageObject *findObject(const Common::String &name);
 
 private:
 	PetkaEngine &_vm;


Commit: 081e19bd7b741b339c8a08e201c1cbd2748cca80
    https://github.com/scummvm/scummvm/commit/081e19bd7b741b339c8a08e201c1cbd2748cca80
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added partial implementation of processing messages in QObjectBG

Changed paths:
    engines/petka/q_object_bg.cpp
    engines/petka/q_object_bg.h


diff --git a/engines/petka/q_object_bg.cpp b/engines/petka/q_object_bg.cpp
index ae8555de73..88eb406ed0 100644
--- a/engines/petka/q_object_bg.cpp
+++ b/engines/petka/q_object_bg.cpp
@@ -24,6 +24,31 @@
 
 namespace Petka {
 
+void QObjectBG::processMessage(const QMessage &msg) {
+	QMessageObject::processMessage(msg);
+	switch (msg.opcode) {
+	case kSet:
+		_resourceId = msg.arg1;
+	case kMusic:
+		_musicId = msg.arg1;
+		break;
+	case kBGsFX:
+		_fxId = msg.arg1;
+		break;
+	case kMap:
+		_showMap = msg.arg1 != 0;
+		break;
+	case kNoMap:
+		_showMap = 0;
+		break;
+	case kGoTo:
+		break;
+	case kSetSeq:
+		break;
+	case kEndSeq:
+		break;
+	}
 
+}
 
 } // End of namespace Petka
diff --git a/engines/petka/q_object_bg.h b/engines/petka/q_object_bg.h
index 8562082e26..d2cb2bcada 100644
--- a/engines/petka/q_object_bg.h
+++ b/engines/petka/q_object_bg.h
@@ -29,9 +29,12 @@ namespace Petka {
 
 class QObjectBG : public QMessageObject {
 public:
+	void processMessage(const QMessage &msg) override;
 
 private:
-
+	int _showMap;
+	int _fxId;
+	int _musicId;
 };
 
 } // End of namespace Petka


Commit: b2a532ded138f554260048eab8b98be5fa59d0fa
    https://github.com/scummvm/scummvm/commit/b2a532ded138f554260048eab8b98be5fa59d0fa
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented QSystem update method

Changed paths:
    engines/petka/q_system.cpp
    engines/petka/q_system.h


diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index f351895c5a..3f65b22312 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -123,4 +123,22 @@ QMessageObject *QSystem::findObject(const Common::String &name) {
 	return nullptr;
 }
 
+void QSystem::update() {
+	for (Common::List<QMessage>::iterator it = _messages.begin(); it != _messages.end();) {
+		bool removeMsg = false;
+		for (uint j = 0; j < _allObjects.size(); ++j) {
+			if (it->objId == _allObjects[j]->getId()) {
+				_allObjects[j]->processMessage(*it);
+				removeMsg = true;
+				break;
+			}
+		}
+		if (removeMsg) {
+			it = _messages.erase(it);
+		} else {
+			++it;
+		}
+	}
+}
+
 }
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index 1f4424ccef..5da21976b4 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -41,6 +41,8 @@ public:
 
 	bool init();
 
+	void update();
+
 	void addMessage(const QMessage &msg);
 	void addMessage(uint16 objId, uint16 opcode, int16 arg1 = 0, int16 arg2 = 0, int16 arg3 = 0, int32 unk = 0, QMessageObject *sender = nullptr);
 	void addMessageForAllObjects(uint16 opcode, int16 arg1 = 0, int16 arg2 = 0, int16 arg3 = 0, int32 unk = 0, QMessageObject *sender = nullptr);
@@ -53,7 +55,7 @@ private:
 	Common::Array<QObject> _objs;
 	Common::Array<QObjectBG> _bgs;
 	Common::Array<QMessageObject *> _allObjects;
-	Common::Array<QMessage> _messages;
+	Common::List<QMessage> _messages;
 	Common::ScopedPtr<QObjectCursor> _cursor;
 	Common::ScopedPtr<QObjectCase> _case;
 	Common::ScopedPtr<QObjectStar> _star;


Commit: fac55cf185f54ad932f1bcc12ef0d568c213cfef
    https://github.com/scummvm/scummvm/commit/fac55cf185f54ad932f1bcc12ef0d568c213cfef
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented playing intro videos

Changed paths:
    engines/petka/petka.cpp
    engines/petka/petka.h


diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
index f761502dcb..fb5624b364 100644
--- a/engines/petka/petka.cpp
+++ b/engines/petka/petka.cpp
@@ -22,11 +22,18 @@
 
 #include "common/debug-channels.h"
 #include "common/error.h"
+#include "common/events.h"
 #include "common/ini-file.h"
 #include "common/stream.h"
+#include "common/system.h"
+#include "common/file.h"
 
 #include "engines/util.h"
 
+#include "graphics/surface.h"
+
+#include "video/avi_decoder.h"
+
 #include "petka/file_mgr.h"
 #include "petka/petka.h"
 #include "petka/q_manager.h"
@@ -53,6 +60,16 @@ Common::Error PetkaEngine::run() {
 	const Graphics::PixelFormat format(2, 5, 6, 5, 0, 11, 5, 0, 0);
 	initGraphics(640, 480, &format);
 
+	const char *const videos[] = {"buka.avi", "skif.avi", "adv.avi"};
+	for (uint i = 0; i < sizeof(videos) / sizeof(char *); ++i) {
+		Common::File *file = new Common::File;
+		if (file->open(videos[i])) {
+			playVideo(file);
+		} else {
+			delete file;
+		}
+	}
+
 	_console.reset(new Console(this));
 	_fileMgr.reset(new FileMgr());
 	_resMgr.reset(new QManager(*this));
@@ -107,4 +124,40 @@ Common::RandomSource &PetkaEngine::getRnd() {
 	return _rnd;
 }
 
+void PetkaEngine::playVideo(Common::SeekableReadStream *stream) {
+	Graphics::PixelFormat fmt = _system->getScreenFormat();
+
+	Video::AVIDecoder decoder;
+	if (!decoder.loadStream(stream)) {
+		return;
+	}
+
+	decoder.start();
+	while (!decoder.endOfVideo()) {
+		Common::Event event;
+		while (_eventMan->pollEvent(event)) {
+			switch (event.type) {
+			case Common::EVENT_LBUTTONDOWN:
+			case Common::EVENT_RBUTTONDOWN:
+			case Common::EVENT_KEYDOWN:
+				decoder.close();
+				break;
+			default:
+				break;
+			}
+		}
+
+		if (decoder.needsUpdate()) {
+			const Graphics::Surface *frame = decoder.decodeNextFrame();
+			if (frame) {
+				Common::ScopedPtr<Graphics::Surface> f(frame->convertTo(fmt));
+				_system->copyRectToScreen(f->getPixels(), f->pitch, 0, 0, f->w, f->h);
+			}
+		}
+
+		_system->updateScreen();
+		_system->delayMillis(50);
+	}
+}
+
 } // End of namespace Petka
diff --git a/engines/petka/petka.h b/engines/petka/petka.h
index f876f5370a..539b5289ff 100644
--- a/engines/petka/petka.h
+++ b/engines/petka/petka.h
@@ -48,8 +48,11 @@ public:
 	~PetkaEngine();
 
 	virtual Common::Error run();
+
 	Common::SeekableReadStream *openFile(const Common::String &name, bool addCurrentPath);
 
+	void playVideo(Common::SeekableReadStream *stream);
+
 	QSystem *getQSystem() const;
 	Common::RandomSource &getRnd();
 


Commit: 8f61c3e611d837f483cc9e70283ad2072c443945
    https://github.com/scummvm/scummvm/commit/8f61c3e611d837f483cc9e70283ad2072c443945
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added screen class

Changed paths:
  A engines/petka/screen.cpp
  A engines/petka/screen.h


diff --git a/engines/petka/screen.cpp b/engines/petka/screen.cpp
new file mode 100644
index 0000000000..5e375578eb
--- /dev/null
+++ b/engines/petka/screen.cpp
@@ -0,0 +1,73 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/system.h"
+
+#include "petka/petka.h"
+#include "petka/screen.h"
+
+namespace Petka {
+
+Screen::Screen() :
+	_shake(false), _shift(false),
+	_shakeTime(0), _interface(nullptr) {}
+
+void Screen::update() {
+	if (_shake) {
+		int width = w;
+		int x =  0;
+
+		if (_shift) {
+			Graphics::Surface s;
+			s.create(3, 480, g_system->getScreenFormat());
+			g_system->copyRectToScreen(s.getPixels(), s.pitch, 0, 0, s.w, s.h);
+			w -= 3;
+			x = 3;
+		}
+
+		uint32 time = g_system->getMillis();
+		if (time - _shakeTime > 30) {
+			_shift = !_shift;
+			_shakeTime = time;
+		}
+
+		_dirtyRects.clear();
+		g_system->copyRectToScreen(getPixels(), pitch, x, 0, width, h);
+		g_system->updateScreen();
+	} else {
+		Screen::update();
+	}
+}
+
+void Screen::setShake(bool shake) {
+	_shake = true;
+}
+
+void Screen::setInterface(QInterface *interface) {
+	_interface = interface;
+}
+
+const Common::List<Common::Rect> &Screen::dirtyRects() const {
+	return _dirtyRects;
+}
+
+}
\ No newline at end of file
diff --git a/engines/petka/screen.h b/engines/petka/screen.h
new file mode 100644
index 0000000000..a5be44ba11
--- /dev/null
+++ b/engines/petka/screen.h
@@ -0,0 +1,52 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_SCREEN_H
+#define PETKA_SCREEN_H
+
+#include "graphics/screen.h"
+
+namespace Petka {
+
+class QInterface;
+
+class Screen : public Graphics::Screen {
+public:
+	Screen();
+
+	void update() override;
+
+	void setShake(bool shake);
+	void setInterface(QInterface *interface);
+
+	const Common::List<Common::Rect> &dirtyRects() const;
+
+private:
+	QInterface *_interface;
+	uint32 _shakeTime;
+	bool _shake;
+	bool _shift;
+};
+
+}
+
+#endif


Commit: 4811d22143bf97aa93af79b3c75b805b217f7763
    https://github.com/scummvm/scummvm/commit/4811d22143bf97aa93af79b3c75b805b217f7763
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added QInterfaceMain

Changed paths:
    engines/petka/petka.h
    engines/petka/q_interface.cpp
    engines/petka/q_interface.h
    engines/petka/q_message_object.cpp
    engines/petka/q_message_object.h
    engines/petka/q_system.cpp
    engines/petka/q_system.h


diff --git a/engines/petka/petka.h b/engines/petka/petka.h
index 539b5289ff..1ef9644dab 100644
--- a/engines/petka/petka.h
+++ b/engines/petka/petka.h
@@ -31,6 +31,10 @@
 
 struct ADGameDescription;
 
+namespace Common {
+class SeekableReadStream;
+}
+
 namespace Petka {
 
 class Console;
diff --git a/engines/petka/q_interface.cpp b/engines/petka/q_interface.cpp
index 07f5fa5788..0f0c25dff8 100644
--- a/engines/petka/q_interface.cpp
+++ b/engines/petka/q_interface.cpp
@@ -20,11 +20,30 @@
  *
  */
 
+#include "common/stream.h"
+
 #include "petka/q_interface.h"
+#include "petka/q_system.h"
+#include "petka/petka.h"
 
 namespace Petka {
 
 QInterface::QInterface()
 	: _objUnderCursor(nullptr) {}
 
+QInterfaceMain::QInterfaceMain() {
+	Common::ScopedPtr<Common::SeekableReadStream> stream(g_vm->openFile("backgrnd.bg", true));
+	if (!stream)
+		return;
+	_bgs.resize(stream->readUint32LE());
+	for (uint i = 0; i < _bgs.size(); ++i) {
+		_bgs[i].attachedObjIds.resize(stream->readUint32LE());
+		for (uint j = 0; j < _bgs[i].attachedObjIds.size(); ++j) {
+			_bgs[i].attachedObjIds[i] = stream->readUint16LE();
+			QMessageObject *obj = g_vm->getQSystem()->findObject(_bgs[i].attachedObjIds[i]);
+			obj->readFromBackgrndBg(*stream);
+		}
+	}
+}
+
 } // End of namespace Petka
diff --git a/engines/petka/q_interface.h b/engines/petka/q_interface.h
index 915deb578b..35e54d66c9 100644
--- a/engines/petka/q_interface.h
+++ b/engines/petka/q_interface.h
@@ -23,6 +23,7 @@
 #ifndef PETKA_Q_INTERFACE_H
 #define PETKA_Q_INTERFACE_H
 
+#include "common/rect.h"
 #include "common/array.h"
 
 namespace Petka {
@@ -32,10 +33,32 @@ class QVisibleObject;
 class QInterface {
 public:
 	QInterface();
+	virtual ~QInterface() {}
 
-private:
+	virtual void start() {};
+	virtual void stop() {};
+
+	virtual void onLeftButtonDown(const Common::Point p) {};
+	virtual void onRightButtonDown(const Common::Point p) {};
+	virtual void onMouseMove(const Common::Point p) {};
+
+protected:
 	Common::Array<QVisibleObject *> _objs;
 	QVisibleObject *_objUnderCursor;
+	uint _startIndex;
+};
+
+struct BGInfo {
+	uint16 objId;
+	Common::Array<uint16> attachedObjIds;
+};
+
+class QInterfaceMain : public QInterface {
+public:
+	QInterfaceMain();
+
+private:
+	Common::Array<BGInfo> _bgs;
 };
 
 } // End of namespace Petka
diff --git a/engines/petka/q_message_object.cpp b/engines/petka/q_message_object.cpp
index 02dce34f54..6049691d24 100644
--- a/engines/petka/q_message_object.cpp
+++ b/engines/petka/q_message_object.cpp
@@ -137,4 +137,12 @@ void QMessageObject::processMessage(const QMessage &msg) {
 
 }
 
+void QMessageObject::readFromBackgrndBg(Common::SeekableReadStream &stream) {
+	_x = stream.readSint32LE();
+	_y = stream.readSint32LE();
+	_z = stream.readSint32LE();
+	_field14 = stream.readSint32LE();
+	_field18 = stream.readSint32LE();
+}
+
 } // End of namespace Petka
diff --git a/engines/petka/q_message_object.h b/engines/petka/q_message_object.h
index 8287a4c0b3..2cfe9cfa2a 100644
--- a/engines/petka/q_message_object.h
+++ b/engines/petka/q_message_object.h
@@ -47,6 +47,7 @@ public:
 	QMessageObject();
 
 	void deserialize(Common::SeekableReadStream &stream, const Common::INIFile &namesIni, const Common::INIFile &castIni);
+	void readFromBackgrndBg(Common::SeekableReadStream &stream);
 
 	uint16 getId() const;
 	const Common::String &getName() const;
@@ -54,6 +55,10 @@ public:
 	virtual void processMessage(const QMessage &msg);
 
 protected:
+	int32 _x;
+	int32 _y;
+	int32 _field14;
+	int32 _field18;
 	uint16 _id;
 	int8 _status;
 	Common::String _name;
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 3f65b22312..117b84e8aa 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -24,6 +24,7 @@
 #include "common/substream.h"
 
 #include "petka/petka.h"
+#include "petka/q_interface.h"
 #include "petka/q_object_case.h"
 #include "petka/q_object_cursor.h"
 #include "petka/q_object_star.h"
@@ -33,7 +34,7 @@ namespace Petka {
 
 QSystem::QSystem(PetkaEngine &vm)
 	: _vm(vm), _cursor(nullptr), _case(nullptr), _star(nullptr),
-	_currInterface(nullptr), _prevInterface(nullptr) {}
+	_mainInterface(nullptr), _currInterface(nullptr), _prevInterface(nullptr) {}
 
 QSystem::~QSystem() {
 
@@ -90,6 +91,9 @@ bool QSystem::init() {
 	_allObjects.push_back(_cursor.get());
 	_allObjects.push_back(_case.get());
 	_allObjects.push_back(_star.get());
+
+	_mainInterface.reset(new QInterfaceMain());
+
 	return true;
 }
 
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index 5da21976b4..d23f55c2c8 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -23,6 +23,9 @@
 #ifndef PETKA_Q_SYSTEM_H
 #define PETKA_Q_SYSTEM_H
 
+#include "common/ptr.h"
+#include "common/list.h"
+
 #include "petka/q_object.h"
 #include "petka/q_object_bg.h"
 
@@ -32,6 +35,7 @@ class PetkaEngine;
 class QObjectCase;
 class QObjectCursor;
 class QObjectStar;
+class QInterfaceMain;
 class QInterface;
 
 class QSystem {
@@ -59,6 +63,7 @@ private:
 	Common::ScopedPtr<QObjectCursor> _cursor;
 	Common::ScopedPtr<QObjectCase> _case;
 	Common::ScopedPtr<QObjectStar> _star;
+	Common::ScopedPtr<QInterfaceMain> _mainInterface;
 	QInterface *_currInterface;
 	QInterface *_prevInterface;
 };


Commit: 9f3bd28fc6d9b85162d8420582dbad057777b7fd
    https://github.com/scummvm/scummvm/commit/9f3bd28fc6d9b85162d8420582dbad057777b7fd
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented sound system

Changed paths:
  A engines/petka/sound.cpp
  A engines/petka/sound.h
    engines/petka/petka.cpp
    engines/petka/petka.h


diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
index fb5624b364..43fc934773 100644
--- a/engines/petka/petka.cpp
+++ b/engines/petka/petka.cpp
@@ -35,6 +35,7 @@
 #include "video/avi_decoder.h"
 
 #include "petka/file_mgr.h"
+#include "petka/sound.h"
 #include "petka/petka.h"
 #include "petka/q_manager.h"
 #include "petka/q_system.h"
@@ -73,6 +74,7 @@ Common::Error PetkaEngine::run() {
 	_console.reset(new Console(this));
 	_fileMgr.reset(new FileMgr());
 	_resMgr.reset(new QManager(*this));
+	_soundMgr.reset(new SoundMgr());
 	_qsystem.reset(new QSystem(*this));
 
 	loadStores();
@@ -160,4 +162,8 @@ void PetkaEngine::playVideo(Common::SeekableReadStream *stream) {
 	}
 }
 
+SoundMgr *PetkaEngine::soundMgr() const {
+	return _soundMgr.get();
+}
+
 } // End of namespace Petka
diff --git a/engines/petka/petka.h b/engines/petka/petka.h
index 1ef9644dab..a069172b8d 100644
--- a/engines/petka/petka.h
+++ b/engines/petka/petka.h
@@ -39,6 +39,7 @@ namespace Petka {
 
 class Console;
 class FileMgr;
+class SoundMgr;
 class QManager;
 class QSystem;
 
@@ -58,6 +59,8 @@ public:
 	void playVideo(Common::SeekableReadStream *stream);
 
 	QSystem *getQSystem() const;
+	SoundMgr *soundMgr() const;
+
 	Common::RandomSource &getRnd();
 
 private:
@@ -67,6 +70,7 @@ private:
 	Common::ScopedPtr<Console> _console;
 	Common::ScopedPtr<FileMgr> _fileMgr;
 	Common::ScopedPtr<QManager> _resMgr;
+	Common::ScopedPtr<SoundMgr> _soundMgr;
 	Common::ScopedPtr<QSystem> _qsystem;
 	const ADGameDescription *_desc;
 
diff --git a/engines/petka/sound.cpp b/engines/petka/sound.cpp
new file mode 100644
index 0000000000..19083a6f38
--- /dev/null
+++ b/engines/petka/sound.cpp
@@ -0,0 +1,108 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "audio/audiostream.h"
+#include "audio/decoders/wave.h"
+
+#include "common/substream.h"
+#include "common/system.h"
+
+#include "petka/petka.h"
+#include "petka/sound.h"
+#include "sound.h"
+
+
+namespace Petka {
+
+Sound::Sound(Common::SeekableReadStream *stream, Audio::Mixer::SoundType type)
+	: _stream(stream), _type(type) {}
+
+Sound::~Sound() {
+	stop();
+}
+
+void Sound::play(bool isLoop) {
+	stop();
+
+	Audio::AudioStream *audioStream;
+	Audio::SeekableAudioStream *wavStream = Audio::makeWAVStream(_stream, DisposeAfterUse::YES);
+	if (isLoop)
+		audioStream = Audio::makeLoopingAudioStream(wavStream, 0, 0, 0);
+	else
+		audioStream = wavStream;
+
+	g_system->getMixer()->playStream(_type, &_handle , audioStream);
+}
+
+bool Sound::isPlaying() {
+	return g_system->getMixer()->isSoundHandleActive(_handle);
+}
+
+void Sound::stop() {
+	g_system->getMixer()->stopHandle(_handle);
+}
+
+void Sound::setBalance(uint16 x, uint16 width) {
+	g_system->getMixer()->setChannelBalance(_handle, (int8)(255 * (2 * x - width) / (2 * width)));
+}
+
+Audio::Mixer::SoundType Sound::type() {
+	return _type;
+}
+
+void Sound::pause(bool p) {
+	g_system->getMixer()->pauseHandle(_handle, p);
+}
+
+Sound *SoundMgr::addSound(const Common::String &name, Audio::Mixer::SoundType type) {
+	Sound *sound = findSound(name);
+	if (sound)
+		return sound;
+	sound = new Sound(g_vm->openFile(name, false), type);
+	_sounds.getVal(name).reset(sound);
+	return sound;
+}
+
+Sound *SoundMgr::findSound(const Common::String &name) const {
+	Common::HashMap<Common::String, Common::ScopedPtr<Sound>>::iterator it = _sounds.find(name);
+	return it != _sounds.end() ? it->_value.get() : nullptr;
+}
+
+void SoundMgr::removeSound(const Common::String &name) {
+	_sounds.erase(name);
+}
+
+void SoundMgr::removeAll() {
+	_sounds.clear(0);
+}
+
+void SoundMgr::removeSoundsWithType(Audio::Mixer::SoundType type) {
+	Common::HashMap<Common::String, Common::ScopedPtr<Sound>>::iterator it;
+	for (it = _sounds.begin(); it != _sounds.end(); ++it) {
+		Sound *s = it->_value.get();
+		if (s->type() == type && !s->isPlaying()) {
+			_sounds.erase(it);
+		}
+	}
+}
+
+} // End of namespace Petka
diff --git a/engines/petka/sound.h b/engines/petka/sound.h
new file mode 100644
index 0000000000..0ba9ab1c2c
--- /dev/null
+++ b/engines/petka/sound.h
@@ -0,0 +1,73 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_SOUND_H
+#define PETKA_SOUND_H
+
+#include "audio/mixer.h"
+
+#include "common/hashmap.h"
+
+namespace Common {
+class SeekableReadStream;
+}
+
+namespace Petka {
+
+class Sound {
+public:
+	Sound(Common::SeekableReadStream *stream, Audio::Mixer::SoundType type);
+	~Sound();
+
+	Audio::Mixer::SoundType type();
+
+	void play(bool isLoop = false);
+	void stop();
+
+	void pause(bool p);
+
+	bool isPlaying();
+
+	void setBalance(uint16 x, uint16 width);
+
+private:
+	Common::SeekableReadStream *_stream;
+	Audio::Mixer::SoundType _type;
+	Audio::SoundHandle _handle;
+};
+
+class SoundMgr {
+public:
+	Sound *addSound(const Common::String &name, Audio::Mixer::SoundType type);
+	Sound *findSound(const Common::String &name) const;
+
+	void removeSound(const Common::String &name);
+	void removeSoundsWithType(Audio::Mixer::SoundType type);
+	void removeAll();
+
+private:
+	Common::HashMap<Common::String, Common::ScopedPtr<Sound>> _sounds;
+};
+
+} // End of namespace Pink
+
+#endif


Commit: 137fca0d9b9d21084da701b00f2694f9f5a027cc
    https://github.com/scummvm/scummvm/commit/137fca0d9b9d21084da701b00f2694f9f5a027cc
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed loading attached objects from backgrnd.bg

Changed paths:
    engines/petka/q_interface.cpp


diff --git a/engines/petka/q_interface.cpp b/engines/petka/q_interface.cpp
index 0f0c25dff8..58f7c36f7d 100644
--- a/engines/petka/q_interface.cpp
+++ b/engines/petka/q_interface.cpp
@@ -37,6 +37,7 @@ QInterfaceMain::QInterfaceMain() {
 		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[i] = stream->readUint16LE();


Commit: 38b643413028fe92c139a57ce7fa9edc7be7a484
    https://github.com/scummvm/scummvm/commit/38b643413028fe92c139a57ce7fa9edc7be7a484
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed compiling

Changed paths:
    engines/petka/sound.cpp
    engines/petka/sound.h


diff --git a/engines/petka/sound.cpp b/engines/petka/sound.cpp
index 19083a6f38..47b9a04606 100644
--- a/engines/petka/sound.cpp
+++ b/engines/petka/sound.cpp
@@ -28,8 +28,6 @@
 
 #include "petka/petka.h"
 #include "petka/sound.h"
-#include "sound.h"
-
 
 namespace Petka {
 
@@ -73,6 +71,7 @@ void Sound::pause(bool p) {
 	g_system->getMixer()->pauseHandle(_handle, p);
 }
 
+
 Sound *SoundMgr::addSound(const Common::String &name, Audio::Mixer::SoundType type) {
 	Sound *sound = findSound(name);
 	if (sound)
@@ -83,7 +82,7 @@ Sound *SoundMgr::addSound(const Common::String &name, Audio::Mixer::SoundType ty
 }
 
 Sound *SoundMgr::findSound(const Common::String &name) const {
-	Common::HashMap<Common::String, Common::ScopedPtr<Sound>>::iterator it = _sounds.find(name);
+	SoundsMap::iterator it = _sounds.find(name);
 	return it != _sounds.end() ? it->_value.get() : nullptr;
 }
 
@@ -96,7 +95,7 @@ void SoundMgr::removeAll() {
 }
 
 void SoundMgr::removeSoundsWithType(Audio::Mixer::SoundType type) {
-	Common::HashMap<Common::String, Common::ScopedPtr<Sound>>::iterator it;
+	SoundsMap::iterator it;
 	for (it = _sounds.begin(); it != _sounds.end(); ++it) {
 		Sound *s = it->_value.get();
 		if (s->type() == type && !s->isPlaying()) {
diff --git a/engines/petka/sound.h b/engines/petka/sound.h
index 0ba9ab1c2c..e76003d9f3 100644
--- a/engines/petka/sound.h
+++ b/engines/petka/sound.h
@@ -25,7 +25,7 @@
 
 #include "audio/mixer.h"
 
-#include "common/hashmap.h"
+#include "common/hash-str.h"
 
 namespace Common {
 class SeekableReadStream;
@@ -65,7 +65,8 @@ public:
 	void removeAll();
 
 private:
-	Common::HashMap<Common::String, Common::ScopedPtr<Sound>> _sounds;
+	typedef Common::HashMap<Common::String, Common::ScopedPtr<Sound>, Common::CaseSensitiveString_Hash> SoundsMap;
+	SoundsMap _sounds;
 };
 
 } // End of namespace Pink


Commit: a207cef9143e96d96dda5dc5e95122629bda459b
    https://github.com/scummvm/scummvm/commit/a207cef9143e96d96dda5dc5e95122629bda459b
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed BMP pixel fmt

Changed paths:
    engines/petka/q_manager.cpp


diff --git a/engines/petka/q_manager.cpp b/engines/petka/q_manager.cpp
index 1c8934a067..cf4747cacc 100644
--- a/engines/petka/q_manager.cpp
+++ b/engines/petka/q_manager.cpp
@@ -215,7 +215,7 @@ Graphics::Surface *QManager::loadBitmapSurface(Common::SeekableReadStream &strea
 	int extraDataLength = (srcPitch % 4) ? 4 - (srcPitch % 4) : 0;
 
 	Graphics::Surface *s = new Graphics::Surface;
-	s->create(width, height, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
+	s->create(width, height, Graphics::PixelFormat(2, 5, 6, 5, 0, 0, 5, 11, 0));
 
 	uint16 *dst = (uint16 *)s->getPixels();
 	for (uint i = 0; i < height; ++i) {


Commit: 5b7119f3bb1465893d624443c4f4234311920890
    https://github.com/scummvm/scummvm/commit/5b7119f3bb1465893d624443c4f4234311920890
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented menu loading

Changed paths:
  A engines/petka/obj.cpp
  A engines/petka/obj.h
  A engines/petka/video.cpp
  A engines/petka/video.h
  R engines/petka/q_message_object.cpp
  R engines/petka/q_message_object.h
  R engines/petka/q_object.cpp
  R engines/petka/q_object.h
  R engines/petka/q_object_bg.cpp
  R engines/petka/q_object_bg.h
  R engines/petka/q_object_case.cpp
  R engines/petka/q_object_case.h
  R engines/petka/q_object_cursor.cpp
  R engines/petka/q_object_cursor.h
  R engines/petka/q_object_star.cpp
  R engines/petka/q_object_star.h
  R engines/petka/screen.cpp
  R engines/petka/screen.h
    engines/petka/module.mk
    engines/petka/petka.cpp
    engines/petka/petka.h
    engines/petka/q_interface.cpp
    engines/petka/q_interface.h
    engines/petka/q_manager.cpp
    engines/petka/q_system.cpp
    engines/petka/q_system.h


diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index 60d4e40697..1fad7b26c6 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -3,16 +3,13 @@ MODULE := engines/petka
 MODULE_OBJS = \
     detection.o \
     file_mgr.o \
+    obj.o \
     petka.o \
     q_interface.o \
     q_manager.o \
-    q_message_object.o \
-    q_object.o \
-    q_object_bg.o \
-    q_object_case.o \
-    q_object_cursor.o \
-    q_object_star. o \
-    q_system.o
+    q_system.o \
+    sound.o \
+    video.o
 
 # This module can be built as a plugin
 ifeq ($(ENABLE_PETKA), DYNAMIC_PLUGIN)
diff --git a/engines/petka/q_message_object.cpp b/engines/petka/obj.cpp
similarity index 59%
rename from engines/petka/q_message_object.cpp
rename to engines/petka/obj.cpp
index 6049691d24..957e427809 100644
--- a/engines/petka/q_message_object.cpp
+++ b/engines/petka/obj.cpp
@@ -22,12 +22,16 @@
 
 #include "common/ini-file.h"
 #include "common/stream.h"
+#include "common/system.h"
 
 #include "graphics/colormasks.h"
+#include "graphics/surface.h"
 
 #include "petka/petka.h"
+#include "petka/video.h"
 #include "petka/q_system.h"
-#include "petka/q_message_object.h"
+#include "petka/q_manager.h"
+#include "petka/obj.h"
 
 namespace Petka {
 
@@ -37,54 +41,6 @@ QVisibleObject::QVisibleObject()
 QMessageObject::QMessageObject()
 	: _id(-1), _dialogColor(-1) {}
 
-static Common::String readString(Common::ReadStream &readStream) {
-	uint32 stringSize = readStream.readUint32LE();
-	byte *data = (byte *)malloc(stringSize + 1);
-	readStream.read(data, stringSize);
-	data[stringSize] = '\0';
-	Common::String str((char *)data);
-	return str;
-}
-
-void QMessageObject::deserialize(Common::SeekableReadStream &stream, const Common::INIFile &namesIni, const Common::INIFile &castIni) {
-	_id = stream.readUint16LE();
-	_name = readString(stream);
-	_reactions.resize(stream.readUint32LE());
-
-	for (uint i = 0; i < _reactions.size(); ++i) {
-		QReaction *reaction = &_reactions[i];
-		reaction->opcode = stream.readUint16LE();
-		reaction->status = stream.readByte();
-		reaction->senderId = stream.readUint16LE();
-		reaction->messages.resize(stream.readUint32LE());
-		for (uint j = 0; j < reaction->messages.size(); ++j) {
-			QMessage *msg = &reaction->messages[j];
-			msg->objId = stream.readUint16LE();
-			msg->opcode = stream.readUint16LE();
-			msg->arg1 = stream.readUint16LE();
-			msg->arg2 = stream.readUint16LE();
-			msg->arg3 = stream.readUint16LE();
-		}
-	}
-
-	namesIni.getKey(_name, "all", _nameOnScreen);
-
-	Common::String rgbString;
-	if (castIni.getKey(_name, "all", rgbString)) {
-		int r, g, b;
-		sscanf(rgbString.c_str(), "%d %d %d", &r, &g, &b);
-		_dialogColor = Graphics::RGBToColor<Graphics::ColorMasks<888>>((byte)r, (byte)g, (byte)b);
-	}
-}
-
-uint16 QMessageObject::getId() const {
-	return _id;
-}
-
-const Common::String &QMessageObject::getName() const {
-	return _name;
-}
-
 void QMessageObject::processMessage(const QMessage &msg) {
 	for (uint i = 0; i < _reactions.size(); ++i) {
 		QReaction &r = _reactions[i];
@@ -137,12 +93,41 @@ void QMessageObject::processMessage(const QMessage &msg) {
 
 }
 
-void QMessageObject::readFromBackgrndBg(Common::SeekableReadStream &stream) {
-	_x = stream.readSint32LE();
-	_y = stream.readSint32LE();
-	_z = stream.readSint32LE();
-	_field14 = stream.readSint32LE();
-	_field18 = stream.readSint32LE();
+void QObjectBG::processMessage(const QMessage &msg) {
+	QMessageObject::processMessage(msg);
+	switch (msg.opcode) {
+	case kSet:
+		_resourceId = msg.arg1;
+	case kMusic:
+		_musicId = msg.arg1;
+		break;
+	case kBGsFX:
+		_fxId = msg.arg1;
+		break;
+	case kMap:
+		_showMap = msg.arg1 != 0;
+		break;
+	case kNoMap:
+		_showMap = 0;
+		break;
+	case kGoTo:
+		break;
+	case kSetSeq:
+		break;
+	case kEndSeq:
+		break;
+	}
+
+}
+
+void QObjectBG::draw() {
+	Graphics::Surface *s = g_vm->resMgr()->loadBitmap(_resourceId);
+	if (s) {
+		const Common::List<Common::Rect> &dirty = g_vm->videoSystem()->rects();
+		for (Common::List<Common::Rect>::const_iterator it = dirty.begin(); it != dirty.end(); ++it) {
+			g_vm->videoSystem()->screen().blitFrom(*s, *it, Common::Point(it->top, it->left));
+		}
+	}
 }
 
 } // End of namespace Petka
diff --git a/engines/petka/q_message_object.h b/engines/petka/obj.h
similarity index 74%
rename from engines/petka/q_message_object.h
rename to engines/petka/obj.h
index 2cfe9cfa2a..2420e93730 100644
--- a/engines/petka/q_message_object.h
+++ b/engines/petka/obj.h
@@ -25,40 +25,39 @@
 
 #include "petka/base.h"
 
-namespace Common {
-	class SeekableReadStream;
-	class INIFile;
-}
-
 namespace Petka {
 
+class Screen;
+
 class QVisibleObject {
 public:
 	QVisibleObject();
 	virtual ~QVisibleObject() {};
 
-protected:
+	virtual void draw() {};
+
+public:
 	int32 _resourceId;
 	int32 _z;
 };
 
+
 class QMessageObject : public QVisibleObject {
 public:
 	QMessageObject();
 
-	void deserialize(Common::SeekableReadStream &stream, const Common::INIFile &namesIni, const Common::INIFile &castIni);
-	void readFromBackgrndBg(Common::SeekableReadStream &stream);
-
-	uint16 getId() const;
-	const Common::String &getName() const;
-
 	virtual void processMessage(const QMessage &msg);
 
-protected:
+public:
 	int32 _x;
 	int32 _y;
 	int32 _field14;
 	int32 _field18;
+	int32 _field20;
+	int32 _field24;
+	int32 _field28;
+	int32 _isShown;
+	int32 _animate;
 	uint16 _id;
 	int8 _status;
 	Common::String _name;
@@ -67,6 +66,33 @@ protected:
 	Common::Array<QReaction> _reactions;
 };
 
-} // End of namespace Petka
+class QObjectBG : public QMessageObject {
+public:
+	void processMessage(const QMessage &msg) override;
+	void draw() override;
+
+public:
+	int _showMap;
+	int _fxId;
+	int _musicId;
+};
+
+class QObject : public QMessageObject {
+
+};
+
+class QObjectCase : public QObject {
+
+};
+
+class QObjectStar : public QObject {
+
+};
+
+class QObjectCursor : public QObject {
+
+};
+
+} // End of naespace Petka
 
 #endif
diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
index 43fc934773..7d99fa45d3 100644
--- a/engines/petka/petka.cpp
+++ b/engines/petka/petka.cpp
@@ -35,6 +35,7 @@
 #include "video/avi_decoder.h"
 
 #include "petka/file_mgr.h"
+#include "petka/video.h"
 #include "petka/sound.h"
 #include "petka/petka.h"
 #include "petka/q_manager.h"
@@ -46,7 +47,7 @@ PetkaEngine *g_vm;
 
 PetkaEngine::PetkaEngine(OSystem *system, const ADGameDescription *desc)
 	: Engine(system), _console(nullptr), _fileMgr(nullptr), _resMgr(nullptr),
-	_qsystem(nullptr), _desc(desc), _rnd("petka") {
+	_qsystem(nullptr), _vsys(nullptr), _desc(desc), _rnd("petka") {
 	DebugMan.addDebugChannel(kPetkaDebugGeneral, "general", "General issues");
 	_part = 0;
 	_chapter = 0;
@@ -75,13 +76,38 @@ Common::Error PetkaEngine::run() {
 	_fileMgr.reset(new FileMgr());
 	_resMgr.reset(new QManager(*this));
 	_soundMgr.reset(new SoundMgr());
-	_qsystem.reset(new QSystem(*this));
+	_vsys.reset(new VideoSystem());
+	_qsystem.reset(new QSystem());
 
 	loadStores();
 	if (!_resMgr->init())
 		return Common::kNoGameDataFoundError;
 	_qsystem->init();
 
+	while (!shouldQuit()) {
+		Common::Event event;
+		while (_eventMan->pollEvent(event)) {
+			switch (event.type) {
+			case Common::EVENT_QUIT:
+			case Common::EVENT_RTL:
+				return Common::kNoError;
+			case Common::EVENT_MOUSEMOVE:
+				break;
+			case Common::EVENT_LBUTTONDOWN:
+				break;
+			case Common::EVENT_LBUTTONUP:
+				break;
+			case Common::EVENT_RBUTTONDOWN:
+				break;
+			case Common::EVENT_KEYDOWN:
+				break;
+			default:
+				break;
+			}
+		}
+		_vsys->update();
+		_system->delayMillis(15);
+	}
 	return Common::kNoError;
 }
 
@@ -166,4 +192,12 @@ SoundMgr *PetkaEngine::soundMgr() const {
 	return _soundMgr.get();
 }
 
+QManager *PetkaEngine::resMgr() const {
+	return _resMgr.get();
+}
+
+VideoSystem *PetkaEngine::videoSystem() const {
+	return _vsys.get();
+}
+
 } // End of namespace Petka
diff --git a/engines/petka/petka.h b/engines/petka/petka.h
index a069172b8d..c556644951 100644
--- a/engines/petka/petka.h
+++ b/engines/petka/petka.h
@@ -42,6 +42,7 @@ class FileMgr;
 class SoundMgr;
 class QManager;
 class QSystem;
+class VideoSystem;
 
 enum {
 	kPetkaDebugGeneral = 1 << 0,
@@ -60,6 +61,8 @@ public:
 
 	QSystem *getQSystem() const;
 	SoundMgr *soundMgr() const;
+	QManager *resMgr() const;
+	VideoSystem *videoSystem() const;
 
 	Common::RandomSource &getRnd();
 
@@ -72,6 +75,7 @@ private:
 	Common::ScopedPtr<QManager> _resMgr;
 	Common::ScopedPtr<SoundMgr> _soundMgr;
 	Common::ScopedPtr<QSystem> _qsystem;
+	Common::ScopedPtr<VideoSystem> _vsys;
 	const ADGameDescription *_desc;
 
 	Common::RandomSource _rnd;
diff --git a/engines/petka/q_interface.cpp b/engines/petka/q_interface.cpp
index 58f7c36f7d..81af3a8d86 100644
--- a/engines/petka/q_interface.cpp
+++ b/engines/petka/q_interface.cpp
@@ -22,8 +22,11 @@
 
 #include "common/stream.h"
 
+#include "petka/obj.h"
 #include "petka/q_interface.h"
 #include "petka/q_system.h"
+#include "petka/q_manager.h"
+#include "petka/sound.h"
 #include "petka/petka.h"
 
 namespace Petka {
@@ -42,9 +45,45 @@ QInterfaceMain::QInterfaceMain() {
 		for (uint j = 0; j < _bgs[i].attachedObjIds.size(); ++j) {
 			_bgs[i].attachedObjIds[i] = stream->readUint16LE();
 			QMessageObject *obj = g_vm->getQSystem()->findObject(_bgs[i].attachedObjIds[i]);
-			obj->readFromBackgrndBg(*stream);
+			obj->_x = stream->readSint32LE();
+			obj->_y = stream->readSint32LE();
+			obj->_z = stream->readSint32LE();
+			obj->_field14 = stream->readSint32LE();
+			obj->_field18 = stream->readSint32LE();
 		}
 	}
 }
 
+const Common::Array<BGInfo> QInterfaceMain::bgInfos() {
+	return _bgs;
+}
+
+void QInterfaceStartup::start() {
+	g_vm->getQSystem()->update();
+
+	QObjectBG *bg = (QObjectBG *)g_vm->getQSystem()->findObject("STARTUP");
+	_objs.push_back(bg);
+
+	Sound *s = g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(bg->_musicId), Audio::Mixer::SoundType::kMusicSoundType);
+	s->play(true);
+
+	const Common::Array<BGInfo> infos = g_vm->getQSystem()->_mainInterface->_bgs;
+
+	for (uint i = 0; i < infos.size(); ++i) {
+		if (infos[i].objId != bg->_id) {
+			continue;
+		}
+		QMessageObject *obj = g_vm->getQSystem()->findObject(infos[i].objId);
+		obj->_z = 1;
+		obj->_x = 0;
+		obj->_y = 0;
+		obj->_field24 = 1;
+		obj->_field20 = 1;
+		obj->_field28 = 1;
+		obj->_animate = 1;
+		obj->_isShown = 0;
+		_objs.push_back(obj);
+	}
+}
+
 } // End of namespace Petka
diff --git a/engines/petka/q_interface.h b/engines/petka/q_interface.h
index 35e54d66c9..2d5a2383e7 100644
--- a/engines/petka/q_interface.h
+++ b/engines/petka/q_interface.h
@@ -42,7 +42,7 @@ public:
 	virtual void onRightButtonDown(const Common::Point p) {};
 	virtual void onMouseMove(const Common::Point p) {};
 
-protected:
+public:
 	Common::Array<QVisibleObject *> _objs;
 	QVisibleObject *_objUnderCursor;
 	uint _startIndex;
@@ -57,10 +57,21 @@ class QInterfaceMain : public QInterface {
 public:
 	QInterfaceMain();
 
-private:
+	const Common::Array<BGInfo> bgInfos();
+
+public:
 	Common::Array<BGInfo> _bgs;
 };
 
+class QInterfaceStartup : public QInterface {
+public:
+	//QInterfaceStartup();
+
+	void start() override;
+
+
+};
+
 } // End of namespace Petka
 
 #endif
diff --git a/engines/petka/q_manager.cpp b/engines/petka/q_manager.cpp
index cf4747cacc..f8b8120b88 100644
--- a/engines/petka/q_manager.cpp
+++ b/engines/petka/q_manager.cpp
@@ -142,6 +142,7 @@ Graphics::Surface *QManager::loadBitmap(uint32 id) {
 
 	Graphics::Surface *s = loadBitmapSurface(*stream);
 	if (s) {
+		s->convertToInPlace(g_system->getScreenFormat());
 		QResource &res = _resourceMap.getVal(id);
 		res.type = QResource::kSurface;
 		res.surface = s;
diff --git a/engines/petka/q_object.cpp b/engines/petka/q_object.cpp
deleted file mode 100644
index ccf7f0ec73..0000000000
--- a/engines/petka/q_object.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "petka/q_object.h"
-
-namespace Petka {
-
-
-
-} // End of namespace Petka
-
diff --git a/engines/petka/q_object.h b/engines/petka/q_object.h
deleted file mode 100644
index d38931e7fe..0000000000
--- a/engines/petka/q_object.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef PETKA_Q_OBJECT_H
-#define PETKA_Q_OBJECT_H
-
-#include "petka/q_message_object.h"
-
-namespace Petka {
-
-class QObject : public QMessageObject {
-
-};
-
-} // End of namespace Petka
-
-#endif
diff --git a/engines/petka/q_object_bg.cpp b/engines/petka/q_object_bg.cpp
deleted file mode 100644
index 88eb406ed0..0000000000
--- a/engines/petka/q_object_bg.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "petka/q_object_bg.h"
-
-namespace Petka {
-
-void QObjectBG::processMessage(const QMessage &msg) {
-	QMessageObject::processMessage(msg);
-	switch (msg.opcode) {
-	case kSet:
-		_resourceId = msg.arg1;
-	case kMusic:
-		_musicId = msg.arg1;
-		break;
-	case kBGsFX:
-		_fxId = msg.arg1;
-		break;
-	case kMap:
-		_showMap = msg.arg1 != 0;
-		break;
-	case kNoMap:
-		_showMap = 0;
-		break;
-	case kGoTo:
-		break;
-	case kSetSeq:
-		break;
-	case kEndSeq:
-		break;
-	}
-
-}
-
-} // End of namespace Petka
diff --git a/engines/petka/q_object_bg.h b/engines/petka/q_object_bg.h
deleted file mode 100644
index d2cb2bcada..0000000000
--- a/engines/petka/q_object_bg.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef PETKA_Q_OBJECT_BG_H
-#define PETKA_Q_OBJECT_BG_H
-
-#include "petka/q_message_object.h"
-
-namespace Petka {
-
-class QObjectBG : public QMessageObject {
-public:
-	void processMessage(const QMessage &msg) override;
-
-private:
-	int _showMap;
-	int _fxId;
-	int _musicId;
-};
-
-} // End of namespace Petka
-
-#endif
-
diff --git a/engines/petka/q_object_case.cpp b/engines/petka/q_object_case.cpp
deleted file mode 100644
index 4bf813d84d..0000000000
--- a/engines/petka/q_object_case.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "petka/q_object_case.h"
-
-namespace Petka {
-
-
-
-} // End of namespace Petka
diff --git a/engines/petka/q_object_case.h b/engines/petka/q_object_case.h
deleted file mode 100644
index 059809c872..0000000000
--- a/engines/petka/q_object_case.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef PETKA_Q_OBJECT_CASE_H
-#define PETKA_Q_OBJECT_CASE_H
-
-#include "petka/q_object.h"
-
-namespace Petka {
-
-class QObjectCase : public QObject {
-
-};
-
-} // End of namespace Petka
-
-#endif
diff --git a/engines/petka/q_object_cursor.cpp b/engines/petka/q_object_cursor.cpp
deleted file mode 100644
index 6596280289..0000000000
--- a/engines/petka/q_object_cursor.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "petka/q_object_cursor.h"
-
-namespace Petka {
-
-
-} // End of namespace Petka
\ No newline at end of file
diff --git a/engines/petka/q_object_cursor.h b/engines/petka/q_object_cursor.h
deleted file mode 100644
index 7af696f3f5..0000000000
--- a/engines/petka/q_object_cursor.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef PETKA_Q_OBJECT_CURSOR_H
-#define PETKA_Q_OBJECT_CURSOR_H
-
-#include "petka/q_object.h"
-
-namespace Petka {
-
-class QObjectCursor : public QObject {
-
-};
-
-} // End of namespace Petka
-
-#endif
diff --git a/engines/petka/q_object_star.cpp b/engines/petka/q_object_star.cpp
deleted file mode 100644
index 5a8104b2c8..0000000000
--- a/engines/petka/q_object_star.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "petka/q_object_star.h"
-
-namespace Petka {
-
-
-} // End of namespace Petka
\ No newline at end of file
diff --git a/engines/petka/q_object_star.h b/engines/petka/q_object_star.h
deleted file mode 100644
index 62c8209ad7..0000000000
--- a/engines/petka/q_object_star.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef PETKA_Q_OBJECT_STAR_H
-#define PETKA_Q_OBJECT_STAR_H
-
-#include "petka/q_object.h"
-
-namespace Petka {
-
-class QObjectStar : public QObject {
-
-};
-
-} // End of namespace Petka
-
-#endif
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 117b84e8aa..ec89de02cc 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -23,24 +23,23 @@
 #include "common/ini-file.h"
 #include "common/substream.h"
 
+#include "graphics/colormasks.h"
+
 #include "petka/petka.h"
 #include "petka/q_interface.h"
-#include "petka/q_object_case.h"
-#include "petka/q_object_cursor.h"
-#include "petka/q_object_star.h"
 #include "petka/q_system.h"
 
 namespace Petka {
 
-QSystem::QSystem(PetkaEngine &vm)
-	: _vm(vm), _cursor(nullptr), _case(nullptr), _star(nullptr),
+QSystem::QSystem()
+	: _cursor(nullptr), _case(nullptr), _star(nullptr),
 	_mainInterface(nullptr), _currInterface(nullptr), _prevInterface(nullptr) {}
 
 QSystem::~QSystem() {
 
 }
 
-Common::String readString(Common::ReadStream &readStream) {
+static Common::String readString(Common::ReadStream &readStream) {
 	uint32 stringSize = readStream.readUint32LE();
 	byte *data = (byte *)malloc(stringSize + 1);
 	readStream.read(data, stringSize);
@@ -49,13 +48,46 @@ Common::String readString(Common::ReadStream &readStream) {
 	return str;
 }
 
+static void readObject(QMessageObject &obj, Common::SeekableReadStream &stream,
+	const Common::INIFile &namesIni, const Common::INIFile &castIni) {
+	obj._id = stream.readUint16LE();
+	obj._name = readString(stream);
+	obj._reactions.resize(stream.readUint32LE());
+
+	for (uint i = 0; i < obj._reactions.size(); ++i) {
+		QReaction *reaction = &obj._reactions[i];
+		reaction->opcode = stream.readUint16LE();
+		reaction->status = stream.readByte();
+		reaction->senderId = stream.readUint16LE();
+		reaction->messages.resize(stream.readUint32LE());
+		for (uint j = 0; j < reaction->messages.size(); ++j) {
+			QMessage *msg = &reaction->messages[j];
+			msg->objId = stream.readUint16LE();
+			msg->opcode = stream.readUint16LE();
+			msg->arg1 = stream.readUint16LE();
+			msg->arg2 = stream.readUint16LE();
+			msg->arg3 = stream.readUint16LE();
+		}
+	}
+
+	namesIni.getKey(obj._name, "all", obj._nameOnScreen);
+
+	Common::String rgbString;
+	if (castIni.getKey(obj._name, "all", rgbString)) {
+		int r, g, b;
+		sscanf(rgbString.c_str(), "%d %d %d", &r, &g, &b);
+		obj._dialogColor = Graphics::RGBToColor<Graphics::ColorMasks<888>>((byte)r, (byte)g, (byte)b);
+	}
+}
+
+
 bool QSystem::init() {
-	Common::ScopedPtr<Common::SeekableReadStream> stream(_vm.openFile("script.dat", true));
+	Common::ScopedPtr<Common::SeekableReadStream> stream(g_vm->openFile("script.dat", true));
 	if (!stream)
 		return false;
-	Common::ScopedPtr<Common::SeekableReadStream> namesStream(_vm.openFile("Names.ini", false));
-	Common::ScopedPtr<Common::SeekableReadStream> castStream(_vm.openFile("Cast.ini", false));
-	Common::ScopedPtr<Common::SeekableReadStream> bgsStream(_vm.openFile("BGs.ini", false));
+	Common::ScopedPtr<Common::SeekableReadStream> namesStream(g_vm->openFile("Names.ini", false));
+	Common::ScopedPtr<Common::SeekableReadStream> castStream(g_vm->openFile("Cast.ini", false));
+	Common::ScopedPtr<Common::SeekableReadStream> bgsStream(g_vm->openFile("BGs.ini", false));
 
 	Common::INIFile namesIni;
 	Common::INIFile castIni;
@@ -74,11 +106,11 @@ bool QSystem::init() {
 
 	Common::String name;
 	for (uint i = 0; i < objsCount; ++i) {
-		_objs[i].deserialize(*stream, namesIni, castIni);
+		readObject(_objs[i], *stream, namesIni, castIni);
 		_allObjects.push_back(&_objs[i]);
 	}
 	for (uint i = 0; i < bgsCount; ++i) {
-		_bgs[i].deserialize(*stream, namesIni, castIni);
+		readObject(_bgs[i], *stream, namesIni, castIni);
 		_allObjects.push_back(&_bgs[i]);
 	}
 
@@ -93,7 +125,9 @@ bool QSystem::init() {
 	_allObjects.push_back(_star.get());
 
 	_mainInterface.reset(new QInterfaceMain());
-
+	_startupInterface.reset(new QInterfaceStartup());
+	_startupInterface->start();
+	_currInterface = _startupInterface.get();
 	return true;
 }
 
@@ -107,13 +141,13 @@ void QSystem::addMessage(uint16 objId, uint16 opcode, int16 arg1, int16 arg2, in
 
 void QSystem::addMessageForAllObjects(uint16 opcode, int16 arg1, int16 arg2, int16 arg3, int32 unk, QMessageObject *sender) {
 	for (uint i = 0; i < _allObjects.size(); ++i) {
-		_messages.push_back({_allObjects[i]->getId(), opcode, arg1, arg2, arg3, sender, unk});
+		_messages.push_back({_allObjects[i]->_id, opcode, arg1, arg2, arg3, sender, unk});
 	}
 }
 
 QMessageObject *QSystem::findObject(int16 id) {
 	for (uint i = 0; i < _allObjects.size(); ++i) {
-		if (_allObjects[i]->getId() == id)
+		if (_allObjects[i]->_id == id)
 			return _allObjects[i];
 	}
 	return nullptr;
@@ -121,7 +155,7 @@ QMessageObject *QSystem::findObject(int16 id) {
 
 QMessageObject *QSystem::findObject(const Common::String &name) {
 	for (uint i = 0; i < _allObjects.size(); ++i) {
-		if (_allObjects[i]->getName() == name)
+		if (_allObjects[i]->_name == name)
 			return _allObjects[i];
 	}
 	return nullptr;
@@ -131,7 +165,7 @@ void QSystem::update() {
 	for (Common::List<QMessage>::iterator it = _messages.begin(); it != _messages.end();) {
 		bool removeMsg = false;
 		for (uint j = 0; j < _allObjects.size(); ++j) {
-			if (it->objId == _allObjects[j]->getId()) {
+			if (it->objId == _allObjects[j]->_id) {
 				_allObjects[j]->processMessage(*it);
 				removeMsg = true;
 				break;
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index d23f55c2c8..0aac88347b 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -26,8 +26,7 @@
 #include "common/ptr.h"
 #include "common/list.h"
 
-#include "petka/q_object.h"
-#include "petka/q_object_bg.h"
+#include "petka/obj.h"
 
 namespace Petka {
 
@@ -36,11 +35,12 @@ class QObjectCase;
 class QObjectCursor;
 class QObjectStar;
 class QInterfaceMain;
+class QInterfaceStartup;
 class QInterface;
 
 class QSystem {
 public:
-	explicit QSystem(PetkaEngine &vm);
+	explicit QSystem();
 	~QSystem();
 
 	bool init();
@@ -54,8 +54,7 @@ public:
 	QMessageObject *findObject(int16 id);
 	QMessageObject *findObject(const Common::String &name);
 
-private:
-	PetkaEngine &_vm;
+public:
 	Common::Array<QObject> _objs;
 	Common::Array<QObjectBG> _bgs;
 	Common::Array<QMessageObject *> _allObjects;
@@ -64,6 +63,7 @@ private:
 	Common::ScopedPtr<QObjectCase> _case;
 	Common::ScopedPtr<QObjectStar> _star;
 	Common::ScopedPtr<QInterfaceMain> _mainInterface;
+	Common::ScopedPtr<QInterfaceStartup> _startupInterface;
 	QInterface *_currInterface;
 	QInterface *_prevInterface;
 };
diff --git a/engines/petka/screen.cpp b/engines/petka/video.cpp
similarity index 63%
rename from engines/petka/screen.cpp
rename to engines/petka/video.cpp
index 5e375578eb..ed4b76028e 100644
--- a/engines/petka/screen.cpp
+++ b/engines/petka/video.cpp
@@ -23,24 +23,37 @@
 #include "common/system.h"
 
 #include "petka/petka.h"
-#include "petka/screen.h"
+#include "petka/q_system.h"
+#include "petka/q_interface.h"
+#include "petka/obj.h"
+#include "petka/video.h"
 
 namespace Petka {
 
-Screen::Screen() :
-	_shake(false), _shift(false),
-	_shakeTime(0), _interface(nullptr) {}
+VideoSystem::VideoSystem() :
+	_shake(false), _shift(false), _shakeTime(0) {
+	addDirtyRect({0, 0, 640, 480});
+}
+
+void VideoSystem::update() {
+	QInterface *interface = g_vm->getQSystem()->_currInterface;
+	if (interface) {
+		for (uint i = 0; i < interface->_objs.size(); ++i) {
+			interface->_objs[i]->draw();
+		}
+	}
+
+	_rects.clear();
 
-void Screen::update() {
 	if (_shake) {
-		int width = w;
+		int width = _screen.w;
 		int x =  0;
 
 		if (_shift) {
 			Graphics::Surface s;
 			s.create(3, 480, g_system->getScreenFormat());
 			g_system->copyRectToScreen(s.getPixels(), s.pitch, 0, 0, s.w, s.h);
-			w -= 3;
+			width -= 3;
 			x = 3;
 		}
 
@@ -50,24 +63,23 @@ void Screen::update() {
 			_shakeTime = time;
 		}
 
-		_dirtyRects.clear();
-		g_system->copyRectToScreen(getPixels(), pitch, x, 0, width, h);
+		g_system->copyRectToScreen(_screen.getPixels(), _screen.pitch, x, 0, width, _screen.h);
 		g_system->updateScreen();
 	} else {
-		Screen::update();
+		_screen.update();
 	}
 }
 
-void Screen::setShake(bool shake) {
-	_shake = true;
+void VideoSystem::addDirtyRect(const Common::Rect &rect) {
+	_rects.push_back(rect);
 }
 
-void Screen::setInterface(QInterface *interface) {
-	_interface = interface;
+const Common::List<Common::Rect> VideoSystem::rects() const {
+	return _rects;
 }
 
-const Common::List<Common::Rect> &Screen::dirtyRects() const {
-	return _dirtyRects;
+Graphics::Screen &VideoSystem::screen() {
+	return _screen;
 }
 
 }
\ No newline at end of file
diff --git a/engines/petka/screen.h b/engines/petka/video.h
similarity index 81%
rename from engines/petka/screen.h
rename to engines/petka/video.h
index a5be44ba11..4ea4168d83 100644
--- a/engines/petka/screen.h
+++ b/engines/petka/video.h
@@ -27,21 +27,19 @@
 
 namespace Petka {
 
-class QInterface;
-
-class Screen : public Graphics::Screen {
+class VideoSystem {
 public:
-	Screen();
-
-	void update() override;
+	VideoSystem();
 
-	void setShake(bool shake);
-	void setInterface(QInterface *interface);
+	void update();
 
-	const Common::List<Common::Rect> &dirtyRects() const;
+	void addDirtyRect(const Common::Rect &rect);
+	const Common::List<Common::Rect> rects() const;
+	Graphics::Screen &screen();
 
 private:
-	QInterface *_interface;
+	Graphics::Screen _screen;
+	Common::List<Common::Rect> _rects;
 	uint32 _shakeTime;
 	bool _shake;
 	bool _shift;


Commit: a5ea8881ec54ba8c8fa9969fa36cef741c907100
    https://github.com/scummvm/scummvm/commit/a5ea8881ec54ba8c8fa9969fa36cef741c907100
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented startup menu

Changed paths:
  A engines/petka/flc.cpp
  A engines/petka/flc.h
    engines/petka/obj.cpp
    engines/petka/obj.h
    engines/petka/petka.cpp
    engines/petka/q_interface.cpp
    engines/petka/q_interface.h
    engines/petka/q_manager.cpp
    engines/petka/q_manager.h
    engines/petka/q_system.cpp
    engines/petka/q_system.h
    engines/petka/video.cpp


diff --git a/engines/petka/flc.cpp b/engines/petka/flc.cpp
new file mode 100644
index 0000000000..bd532001a2
--- /dev/null
+++ b/engines/petka/flc.cpp
@@ -0,0 +1,147 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/stream.h"
+
+#include "graphics/surface.h"
+
+#include "petka/flc.h"
+#include "flc.h"
+
+
+namespace Petka {
+
+const Graphics::Surface *FlicDecoder::getCurrentFrame() const {
+	const Track *track = getTrack(0);
+	if (track)
+		return ((const FlicVideoTrack *)track)->getSurface();
+	return nullptr;
+}
+
+void FlicDecoder::load(Common::SeekableReadStream *stream, Common::SeekableReadStream *mskStream) {
+	close();
+
+	/* uint32 frameSize = */ stream->readUint32LE();
+	uint16 frameType = stream->readUint16LE();
+
+	// Check FLC magic number
+	if (frameType != 0xAF12) {
+		warning("FlicDecoder::loadStream(): attempted to load non-FLC data (type = 0x%04X)", frameType);
+	}
+
+	uint16 frameCount = stream->readUint16LE();
+	uint16 width = stream->readUint16LE();
+	uint16 height = stream->readUint16LE();
+	uint16 colorDepth = stream->readUint16LE();
+	if (colorDepth != 8) {
+		warning("FlicDecoder::loadStream(): attempted to load an FLC with a palette of color depth %d. Only 8-bit color palettes are supported", colorDepth);
+	}
+
+	FlicVideoTrack *track = new FlicVideoTrack(stream, frameCount, width, height);
+	addTrack(track);
+	decodeNextFrame();
+	assert(track->getPalette());
+	if (mskStream)
+		track->loadMsk(*mskStream);
+	delete mskStream;
+}
+
+const Common::Rect &FlicDecoder::getBounds() const {
+	const Track *track = getTrack(0);
+	if (track)
+		return ((FlicVideoTrack *)track)->getBounds();
+}
+
+const Common::Array<Common::Rect> &FlicDecoder::getMskRects() const {
+	const Track *track = getTrack(0);
+	if (track)
+		return ((FlicVideoTrack *)track)->getMskRects();
+}
+
+uint32 FlicDecoder::getTransColor(const Graphics::PixelFormat &fmt) const {
+	const Track *track = getTrack(0);
+	if (track) {
+		const FlicVideoTrack *flc = ((FlicVideoTrack *) track);
+		byte r = flc->getPalette()[0];
+		byte g = flc->getPalette()[1];
+		byte b = flc->getPalette()[2];
+		return fmt.RGBToColor(r, g, b);
+	}
+	return 0;
+}
+
+FlicDecoder::FlicVideoTrack::FlicVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height, bool skipHeader)
+	: Video::FlicDecoder::FlicVideoTrack(stream, frameCount, width, height, skipHeader) {}
+
+bool FlicDecoder::FlicVideoTrack::loadMsk(Common::SeekableReadStream &stream) {
+	_msk.resize(_frameCount);
+	for (uint i = 0; i < _frameCount; ++i) {
+		_msk[i].resize(stream.readUint32LE());
+		for (uint j = 0; j < _msk[i].size(); ++j) {
+			_msk[i][j].left = stream.readSint16LE();
+			_msk[i][j].top = stream.readSint16LE();
+			_msk[i][j].right = stream.readSint16LE();
+			_msk[i][j].bottom = stream.readSint16LE();
+		}
+	}
+	stream.skip(_frameCount * 4);
+	_bounds.left = (int16)stream.readSint32LE();
+	_bounds.top = (int16)stream.readSint32LE();
+	_bounds.right = (int16)stream.readSint32LE();
+	_bounds.bottom = (int16)stream.readSint32LE();
+
+	if (_bounds.left > _bounds.right) {
+		int16 t = _bounds.left;
+		_bounds.left = _bounds.right;
+		_bounds.right = t;
+	}
+	if (_bounds.top > _bounds.bottom) {
+		int16 t = _bounds.top;
+		_bounds.top = _bounds.bottom;
+		_bounds.bottom = t;
+	}
+	assert(stream.size() == stream.pos());
+	if (getWidth() <= _bounds.right) {
+		_bounds.right = getWidth() - 1;
+	}
+	if (getHeight() <= _bounds.bottom) {
+		_bounds.bottom = getHeight() - 1;
+	}
+	_bounds = _bounds.findIntersectingRect(Common::Rect(0, 0, _bounds.right, 479));
+	_bounds.right++;
+	_bounds.bottom++;
+}
+
+const Common::Rect &FlicDecoder::FlicVideoTrack::getBounds() const {
+	return _bounds;
+}
+
+const Graphics::Surface *FlicDecoder::FlicVideoTrack::getSurface() const {
+	return _surface;
+}
+
+const Common::Array<Common::Rect> &FlicDecoder::FlicVideoTrack::getMskRects() const {
+	assert(_curFrame >= 0);
+	return _msk[_curFrame];
+}
+
+} // End of namespace Petka
diff --git a/engines/petka/flc.h b/engines/petka/flc.h
new file mode 100644
index 0000000000..4fe3c0bdac
--- /dev/null
+++ b/engines/petka/flc.h
@@ -0,0 +1,58 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_FLC_H
+#define PETKA_FLC_H
+
+#include "video/flic_decoder.h"
+
+namespace Petka {
+
+class FlicDecoder : public Video::FlicDecoder {
+public:
+	void load(Common::SeekableReadStream *flcStream, Common::SeekableReadStream *mskStream);
+
+	const Common::Rect &getBounds() const;
+	const Common::Array<Common::Rect> &getMskRects() const;
+	const Graphics::Surface *getCurrentFrame() const;
+	uint32 getTransColor(const Graphics::PixelFormat &fmt) const;
+
+protected:
+	class FlicVideoTrack : public Video::FlicDecoder::FlicVideoTrack {
+	public:
+		FlicVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height, bool skipHeader = false);
+
+		bool loadMsk(Common::SeekableReadStream &stream);
+
+		const Common::Rect &getBounds() const;
+		const Common::Array<Common::Rect> &getMskRects() const;
+		const Graphics::Surface *getSurface() const;
+
+	private:
+		Common::Rect _bounds;
+		Common::Array<Common::Array<Common::Rect>> _msk;
+	};
+};
+
+} // End of namespace Petka
+
+#endif
diff --git a/engines/petka/obj.cpp b/engines/petka/obj.cpp
index 957e427809..4dd451a0cd 100644
--- a/engines/petka/obj.cpp
+++ b/engines/petka/obj.cpp
@@ -23,10 +23,12 @@
 #include "common/ini-file.h"
 #include "common/stream.h"
 #include "common/system.h"
+#include "common/events.h"
 
 #include "graphics/colormasks.h"
 #include "graphics/surface.h"
 
+#include "petka/flc.h"
 #include "petka/petka.h"
 #include "petka/video.h"
 #include "petka/q_system.h"
@@ -79,6 +81,18 @@ void QMessageObject::processMessage(const QMessage &msg) {
 
 	switch (msg.opcode) {
 	case kSet:
+	case kPlay:
+		if (dynamic_cast<QObjectBG *>(this)) {
+			break;
+		}
+		if (g_vm->getQSystem()->_field48) {
+			debug("SET OPCODE %d = %d", _id, msg.arg1);
+			_resourceId = msg.arg1;
+			_notLoopedSound = msg.arg2 != 5;
+		} else {
+			debug("NOT IMPL");
+		}
+
 		break;
 	case kStatus:
 		_status = (int8)msg.arg1;
@@ -93,6 +107,48 @@ void QMessageObject::processMessage(const QMessage &msg) {
 
 }
 
+bool QObject::isInPoint(int x, int y) {
+	if (_isActive)
+		return false;
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+	Common::Rect rect(_x, _y, _x + flc->getWidth(), _y + flc->getHeight());
+	if (!rect.contains(x, y))
+		return false;
+	return *(byte *)flc->getCurrentFrame()->getBasePtr(x -_x, y - _y) != 0;
+}
+
+void QObject::draw() {
+	if (!_isShown || _resourceId == -1) {
+		return;
+	}
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+	if (!flc) {
+		return;
+	}
+	Common::Rect screen(640, 480);
+	Common::Rect dest(flc->getBounds());
+	//flcRect.translate(_x, _y);
+	dest.translate(_x, _y);
+
+	Common::Rect intersect(screen.findIntersectingRect(dest));
+	if (intersect.isEmpty())
+		return;
+
+	const Graphics::Surface *frame = flc->getCurrentFrame();
+	Graphics::Surface *s = frame->convertTo(g_system->getScreenFormat(), flc->getPalette());
+	const Common::List<Common::Rect> &dirty = g_vm->videoSystem()->rects();
+	for (Common::List<Common::Rect>::const_iterator it = dirty.begin(); it != dirty.end(); ++it) {
+		Common::Rect destRect(intersect.findIntersectingRect(*it));
+		if (destRect.isEmpty())
+			continue;
+		Common::Rect srcRect(destRect);
+		srcRect.translate(-_x, -_y);
+		g_vm->videoSystem()->screen().transBlitFrom(*s, srcRect, destRect, flc->getTransColor(s->format));
+	}
+	s->free();
+	delete s;
+}
+
 void QObjectBG::processMessage(const QMessage &msg) {
 	QMessageObject::processMessage(msg);
 	switch (msg.opcode) {
@@ -125,9 +181,91 @@ void QObjectBG::draw() {
 	if (s) {
 		const Common::List<Common::Rect> &dirty = g_vm->videoSystem()->rects();
 		for (Common::List<Common::Rect>::const_iterator it = dirty.begin(); it != dirty.end(); ++it) {
-			g_vm->videoSystem()->screen().blitFrom(*s, *it, Common::Point(it->top, it->left));
+			g_vm->videoSystem()->screen().blitFrom(*s, *it, Common::Point(it->left, it->top));
 		}
 	}
 }
 
+QObjectCursor::QObjectCursor() {
+	_id = 4097;
+	_z = 1000;
+	_resourceId = 5002;
+	Common::Point pos = g_vm->getEventManager()->getMousePos();
+	_x = pos.x;
+	_y = pos.y;
+	g_vm->resMgr()->loadFlic(5002);
+}
+
+void QObjectCursor::draw() {
+	if (!_isShown) {
+		return;
+	}
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+	const Graphics::Surface *frame = flc->getCurrentFrame();
+	if (frame) {
+		Graphics::Surface *s = frame->convertTo(g_system->getScreenFormat(), flc->getPalette());
+
+		/*Common::Rect srcRect(_x, _y, _x + flc->getWidth(), _y + flc->getHeight());
+		srcRect.translate(_x, _y);
+
+		Common::Rect intersect(Common::Rect(640, 480).findIntersectingRect(srcRect));
+		srcRect = intersect;
+		srcRect.translate(-_x, -_y);
+
+		g_vm->videoSystem()->screen().transBlitFrom(*s, srcRect, intersect);*/
+
+		Common::Rect srcRect(flc->getBounds());
+		srcRect.translate(_x, _y);
+		srcRect.clip(640, 480);
+		Common::Rect destRect(srcRect);
+		srcRect.translate(-_x, -_y);
+		g_vm->videoSystem()->screen().transBlitFrom(*s, srcRect, destRect);
+		s->free();
+		delete s;
+	}
+}
+
+void QObjectCursor::update() {
+	if (!_isShown || !_animate)
+		return;
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+	while (flc && flc->needsUpdate()) {
+		flc->decodeNextFrame();
+		if (flc->endOfVideo()) {
+			flc->rewind();
+		}
+		Common::Rect dirty(flc->getBounds());
+		dirty.translate(_x, _y);
+		g_vm->videoSystem()->addDirtyRect(dirty);
+	}
+}
+
+void QObjectCursor::setCursorPos(int x, int y, bool center) {
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+	if (!_animate) {
+		flc->stop();
+		flc->rewind();
+		flc->decodeNextFrame();
+	} else if (!flc->isPlaying()) {
+		flc->rewind();
+		flc->start();
+	}
+
+	Common::Rect dirty(flc->getBounds());
+	dirty.translate(_x, _y);
+	g_vm->videoSystem()->addDirtyRect(dirty);
+
+	if (center) {
+		x = x - flc->getBounds().left - dirty.width() / 2;
+		y = y - flc->getBounds().top - dirty.height() / 2;
+	}
+
+	_x = x;
+	_y = y;
+
+	dirty = flc->getBounds();
+	dirty.translate(_x, _y);
+	g_vm->videoSystem()->addDirtyRect(dirty);
+}
+
 } // End of namespace Petka
diff --git a/engines/petka/obj.h b/engines/petka/obj.h
index 2420e93730..40085a7b95 100644
--- a/engines/petka/obj.h
+++ b/engines/petka/obj.h
@@ -27,14 +27,14 @@
 
 namespace Petka {
 
-class Screen;
-
 class QVisibleObject {
 public:
 	QVisibleObject();
 	virtual ~QVisibleObject() {};
 
 	virtual void draw() {};
+	virtual void update() {};
+	virtual bool isInPoint(int x, int y) { return false; }
 
 public:
 	int32 _resourceId;
@@ -58,8 +58,14 @@ public:
 	int32 _field28;
 	int32 _isShown;
 	int32 _animate;
-	uint16 _id;
+	int _field_34;
+	int _field_38;
+	int _isActive;
+	int _startSound;
+	int _field_44;
+	int _notLoopedSound;
 	int8 _status;
+	uint16 _id;
 	Common::String _name;
 	Common::String _nameOnScreen;
 	int32 _dialogColor;
@@ -78,7 +84,9 @@ public:
 };
 
 class QObject : public QMessageObject {
-
+public:
+	void draw() override;
+	bool isInPoint(int x, int y) override;
 };
 
 class QObjectCase : public QObject {
@@ -90,6 +98,14 @@ class QObjectStar : public QObject {
 };
 
 class QObjectCursor : public QObject {
+public:
+	QObjectCursor();
+
+	void setCursorPos(int x, int y, bool center);
+	void update() override;
+	void draw() override;
+
+private:
 
 };
 
diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
index 7d99fa45d3..09c7f1a5a9 100644
--- a/engines/petka/petka.cpp
+++ b/engines/petka/petka.cpp
@@ -39,6 +39,7 @@
 #include "petka/sound.h"
 #include "petka/petka.h"
 #include "petka/q_manager.h"
+#include "petka/q_interface.h"
 #include "petka/q_system.h"
 
 namespace Petka {
@@ -92,8 +93,10 @@ Common::Error PetkaEngine::run() {
 			case Common::EVENT_RTL:
 				return Common::kNoError;
 			case Common::EVENT_MOUSEMOVE:
+				_qsystem->_currInterface->onMouseMove(event.mouse);
 				break;
 			case Common::EVENT_LBUTTONDOWN:
+				_qsystem->_currInterface->onLeftButtonDown(event.mouse);
 				break;
 			case Common::EVENT_LBUTTONUP:
 				break;
@@ -106,7 +109,7 @@ Common::Error PetkaEngine::run() {
 			}
 		}
 		_vsys->update();
-		_system->delayMillis(15);
+		_system->delayMillis(20);
 	}
 	return Common::kNoError;
 }
@@ -153,6 +156,7 @@ Common::RandomSource &PetkaEngine::getRnd() {
 }
 
 void PetkaEngine::playVideo(Common::SeekableReadStream *stream) {
+	g_system->getMixer()->pauseAll(true);
 	Graphics::PixelFormat fmt = _system->getScreenFormat();
 
 	Video::AVIDecoder decoder;
@@ -184,8 +188,9 @@ void PetkaEngine::playVideo(Common::SeekableReadStream *stream) {
 		}
 
 		_system->updateScreen();
-		_system->delayMillis(50);
+		_system->delayMillis(15);
 	}
+	g_system->getMixer()->pauseAll(false);
 }
 
 SoundMgr *PetkaEngine::soundMgr() const {
diff --git a/engines/petka/q_interface.cpp b/engines/petka/q_interface.cpp
index 81af3a8d86..b1242b7291 100644
--- a/engines/petka/q_interface.cpp
+++ b/engines/petka/q_interface.cpp
@@ -20,14 +20,20 @@
  *
  */
 
+#include <common/system.h>
 #include "common/stream.h"
+#include "common/events.h"
 
+#include "petka/flc.h"
 #include "petka/obj.h"
 #include "petka/q_interface.h"
 #include "petka/q_system.h"
 #include "petka/q_manager.h"
 #include "petka/sound.h"
 #include "petka/petka.h"
+#include "petka/video.h"
+#include "q_interface.h"
+
 
 namespace Petka {
 
@@ -43,7 +49,7 @@ QInterfaceMain::QInterfaceMain() {
 		_bgs[i].objId = stream->readUint16LE();
 		_bgs[i].attachedObjIds.resize(stream->readUint32LE());
 		for (uint j = 0; j < _bgs[i].attachedObjIds.size(); ++j) {
-			_bgs[i].attachedObjIds[i] = stream->readUint16LE();
+			_bgs[i].attachedObjIds[j] = stream->readUint16LE();
 			QMessageObject *obj = g_vm->getQSystem()->findObject(_bgs[i].attachedObjIds[i]);
 			obj->_x = stream->readSint32LE();
 			obj->_y = stream->readSint32LE();
@@ -54,12 +60,9 @@ QInterfaceMain::QInterfaceMain() {
 	}
 }
 
-const Common::Array<BGInfo> QInterfaceMain::bgInfos() {
-	return _bgs;
-}
-
 void QInterfaceStartup::start() {
 	g_vm->getQSystem()->update();
+	g_vm->getQSystem()->_field48 = 0;
 
 	QObjectBG *bg = (QObjectBG *)g_vm->getQSystem()->findObject("STARTUP");
 	_objs.push_back(bg);
@@ -67,23 +70,84 @@ void QInterfaceStartup::start() {
 	Sound *s = g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(bg->_musicId), Audio::Mixer::SoundType::kMusicSoundType);
 	s->play(true);
 
-	const Common::Array<BGInfo> infos = g_vm->getQSystem()->_mainInterface->_bgs;
+	const Common::Array<BGInfo> &infos = g_vm->getQSystem()->_mainInterface->_bgs;
 
 	for (uint i = 0; i < infos.size(); ++i) {
 		if (infos[i].objId != bg->_id) {
 			continue;
 		}
-		QMessageObject *obj = g_vm->getQSystem()->findObject(infos[i].objId);
-		obj->_z = 1;
-		obj->_x = 0;
-		obj->_y = 0;
-		obj->_field24 = 1;
-		obj->_field20 = 1;
-		obj->_field28 = 1;
-		obj->_animate = 1;
-		obj->_isShown = 0;
-		_objs.push_back(obj);
+		for (uint j = 0; j < infos[i].attachedObjIds.size(); ++j) {
+			QMessageObject *obj = g_vm->getQSystem()->findObject(infos[i].attachedObjIds[j]);
+			obj->_z = 1;
+			obj->_x = 0;
+			obj->_y = 0;
+			obj->_field24 = 1;
+			obj->_field20 = 1;
+			obj->_field28 = 1;
+			obj->_animate = 0;
+			obj->_isShown = 0;
+			_objs.push_back(obj);
+		}
 	}
+
+
+	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
+	cursor->_resourceId = 4901;
+	cursor->_isShown = true;
+	cursor->_animate = false;
+	_objs.push_back(g_vm->getQSystem()->_cursor.get());
+	cursor->setCursorPos(cursor->_x, cursor->_y, 0);
+}
+
+void QInterfaceStartup::onLeftButtonDown(const Common::Point p) {
+	if (!_objUnderCursor)
+		return;
+	switch (_objUnderCursor->_resourceId) {
+	case 4981:
+		g_system->quit();
+		break;
+	case 4982:
+		g_vm->playVideo(g_vm->openFile("credits.avi", false));
+		break;
+	case 4983:
+		// start SaveLoad menu
+		break;
+	case 4984:
+		// new game
+		break;
+	}
+}
+
+void QInterfaceStartup::onMouseMove(const 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 != 4901 && obj->_resourceId != 4980) {
+			FlicDecoder *flc = g_vm->resMgr()->loadFlic(obj->_resourceId);
+			if (flc) {
+				bool clicked = false;
+				if (!found && obj->isInPoint(p.x, p.y)) {
+					found = true;
+					clicked = true;
+					obj->_isShown = true;
+					_objUnderCursor = obj;
+				}
+				obj->_isShown = clicked;
+				if (flc->getCurFrame() == -1) {
+					flc->decodeNextFrame();
+				}
+				Common::Rect dirty(flc->getBounds());
+				dirty.translate(obj->_x, obj->_y);
+				g_vm->videoSystem()->addDirtyRect(dirty);
+			}
+		}
+	}
+
+	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
+	cursor->_animate = _objUnderCursor != nullptr;
+	cursor->_isShown = true;
+	cursor->setCursorPos(p.x, p.y, 0);
 }
 
 } // End of namespace Petka
diff --git a/engines/petka/q_interface.h b/engines/petka/q_interface.h
index 2d5a2383e7..5e6c446b40 100644
--- a/engines/petka/q_interface.h
+++ b/engines/petka/q_interface.h
@@ -57,8 +57,6 @@ class QInterfaceMain : public QInterface {
 public:
 	QInterfaceMain();
 
-	const Common::Array<BGInfo> bgInfos();
-
 public:
 	Common::Array<BGInfo> _bgs;
 };
@@ -69,7 +67,8 @@ public:
 
 	void start() override;
 
-
+	void onLeftButtonDown(const Common::Point p) override;
+	void onMouseMove(const Common::Point p) override;
 };
 
 } // End of namespace Petka
diff --git a/engines/petka/q_manager.cpp b/engines/petka/q_manager.cpp
index f8b8120b88..c7ac90fd51 100644
--- a/engines/petka/q_manager.cpp
+++ b/engines/petka/q_manager.cpp
@@ -26,10 +26,9 @@
 
 #include "graphics/surface.h"
 
-#include "petka/petka.h"
+#include "petka/flc.h"
 #include "petka/q_manager.h"
-
-#include "video/flic_decoder.h"
+#include "petka/petka.h"
 
 namespace Petka {
 
@@ -151,7 +150,7 @@ Graphics::Surface *QManager::loadBitmap(uint32 id) {
 	return nullptr;
 }
 
-Video::FlicDecoder *QManager::loadFlic(uint32 id) {
+FlicDecoder *QManager::loadFlic(uint32 id) {
 	if (_resourceMap.contains(id)) {
 		QResource &res = _resourceMap.getVal(id);
 		if (res.type != QResource::kFlic) {
@@ -160,19 +159,21 @@ Video::FlicDecoder *QManager::loadFlic(uint32 id) {
 		return res.flcDecoder;
 	}
 
-	Common::ScopedPtr<Common::SeekableReadStream> stream(loadFileStream(id));
+	Common::String name = findResourceName(id);
+	Common::SeekableReadStream *stream = _vm.openFile(name, false);
 	if (!stream) {
 		return nullptr;
 	}
+	name.erase(name.size() - 3, 3);
+	name.toUppercase();
+	name += "MSK";
 
-	Common::ScopedPtr<Video::FlicDecoder> flc (new Video::FlicDecoder);
-	if (flc->loadStream(stream.release())) {
-		QResource &res = _resourceMap.getVal(id);
-		res.type = QResource::kFlic;
-		res.flcDecoder = flc.release();
-		return res.flcDecoder;
-	}
-	return nullptr;
+	FlicDecoder *flc = new FlicDecoder;
+	flc->load(stream, _vm.openFile(name, false));
+	QResource &res = _resourceMap.getVal(id);
+	res.type = QResource::kFlic;
+	res.flcDecoder = flc;
+	return res.flcDecoder;
 }
 
 void QManager::clear() {
diff --git a/engines/petka/q_manager.h b/engines/petka/q_manager.h
index a12e45540c..aad3658d89 100644
--- a/engines/petka/q_manager.h
+++ b/engines/petka/q_manager.h
@@ -33,18 +33,16 @@ namespace Graphics {
 	struct Surface;
 }
 
-namespace Video {
-	class FlicDecoder;
-}
-
 namespace Petka {
 
 class PetkaEngine;
 
+class FlicDecoder;
+
 struct QResource {
 	union {
 		Graphics::Surface *surface;
-		Video::FlicDecoder *flcDecoder;
+		FlicDecoder *flcDecoder;
 	};
 	enum ResType {
 		kSurface,
@@ -64,7 +62,7 @@ public:
 
 	Graphics::Surface *findOrCreateSurface(uint32 id, uint16 w, uint16 h);
 	Graphics::Surface *loadBitmap(uint32 id);
-	Video::FlicDecoder *loadFlic(uint32 id);
+	FlicDecoder *loadFlic(uint32 id);
 
 	void removeResource(uint32 id);
 	void clearUnneeded();
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index ec89de02cc..42dfe01603 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -32,8 +32,8 @@
 namespace Petka {
 
 QSystem::QSystem()
-	: _cursor(nullptr), _case(nullptr), _star(nullptr),
-	_mainInterface(nullptr), _currInterface(nullptr), _prevInterface(nullptr) {}
+	: _cursor(nullptr), _case(nullptr), _star(nullptr), _mainInterface(nullptr),
+	_currInterface(nullptr), _prevInterface(nullptr), _field48(0) {}
 
 QSystem::~QSystem() {
 
@@ -85,6 +85,7 @@ bool QSystem::init() {
 	Common::ScopedPtr<Common::SeekableReadStream> stream(g_vm->openFile("script.dat", true));
 	if (!stream)
 		return false;
+	_field48 = 1;
 	Common::ScopedPtr<Common::SeekableReadStream> namesStream(g_vm->openFile("Names.ini", false));
 	Common::ScopedPtr<Common::SeekableReadStream> castStream(g_vm->openFile("Cast.ini", false));
 	Common::ScopedPtr<Common::SeekableReadStream> bgsStream(g_vm->openFile("BGs.ini", false));
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index 0aac88347b..d2eb92c0bb 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -66,6 +66,8 @@ public:
 	Common::ScopedPtr<QInterfaceStartup> _startupInterface;
 	QInterface *_currInterface;
 	QInterface *_prevInterface;
+
+	int _field48;
 };
 
 } // End of namespace Petka
diff --git a/engines/petka/video.cpp b/engines/petka/video.cpp
index ed4b76028e..d1bca9e3e2 100644
--- a/engines/petka/video.cpp
+++ b/engines/petka/video.cpp
@@ -38,6 +38,9 @@ VideoSystem::VideoSystem() :
 void VideoSystem::update() {
 	QInterface *interface = g_vm->getQSystem()->_currInterface;
 	if (interface) {
+		for (uint i = 0; i < interface->_objs.size(); ++i) {
+			interface->_objs[i]->update();
+		}
 		for (uint i = 0; i < interface->_objs.size(); ++i) {
 			interface->_objs[i]->draw();
 		}
@@ -57,14 +60,14 @@ void VideoSystem::update() {
 			x = 3;
 		}
 
+		g_system->copyRectToScreen(_screen.getPixels(), _screen.pitch, x, 0, width, _screen.h);
+		g_system->updateScreen();
+
 		uint32 time = g_system->getMillis();
 		if (time - _shakeTime > 30) {
 			_shift = !_shift;
 			_shakeTime = time;
 		}
-
-		g_system->copyRectToScreen(_screen.getPixels(), _screen.pitch, x, 0, width, _screen.h);
-		g_system->updateScreen();
 	} else {
 		_screen.update();
 	}


Commit: cf7cbd06e2436985f0d4fde53d0bad1d6fcf22d6
    https://github.com/scummvm/scummvm/commit/cf7cbd06e2436985f0d4fde53d0bad1d6fcf22d6
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added missing object file to modulek.mk

Changed paths:
    engines/petka/module.mk


diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index 1fad7b26c6..c92a994200 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -3,6 +3,7 @@ MODULE := engines/petka
 MODULE_OBJS = \
     detection.o \
     file_mgr.o \
+    flc.o \
     obj.o \
     petka.o \
     q_interface.o \


Commit: c0bcc306123cfa37475d25cfddae182547958e48
    https://github.com/scummvm/scummvm/commit/c0bcc306123cfa37475d25cfddae182547958e48
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: moved interface classes to separate files

Changed paths:
  A engines/petka/interfaces/interface.cpp
  A engines/petka/interfaces/interface.h
  A engines/petka/interfaces/main.cpp
  A engines/petka/interfaces/main.h
  A engines/petka/interfaces/startup.cpp
  A engines/petka/interfaces/startup.h
  R engines/petka/q_interface.cpp
  R engines/petka/q_interface.h
    engines/petka/module.mk
    engines/petka/q_system.cpp
    engines/petka/q_system.h
    engines/petka/video.cpp


diff --git a/engines/petka/interfaces/interface.cpp b/engines/petka/interfaces/interface.cpp
new file mode 100644
index 0000000000..abb015c072
--- /dev/null
+++ b/engines/petka/interfaces/interface.cpp
@@ -0,0 +1,30 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "petka/interfaces/interface.h"
+
+namespace Petka {
+
+Interface::Interface()
+	: _objUnderCursor(nullptr), _startIndex(0) {}
+
+} // End of namespace Petka
diff --git a/engines/petka/q_interface.h b/engines/petka/interfaces/interface.h
similarity index 72%
rename from engines/petka/q_interface.h
rename to engines/petka/interfaces/interface.h
index 5e6c446b40..79d235bf32 100644
--- a/engines/petka/q_interface.h
+++ b/engines/petka/interfaces/interface.h
@@ -20,8 +20,8 @@
  *
  */
 
-#ifndef PETKA_Q_INTERFACE_H
-#define PETKA_Q_INTERFACE_H
+#ifndef PETKA_INTERFACE_H
+#define PETKA_INTERFACE_H
 
 #include "common/rect.h"
 #include "common/array.h"
@@ -30,10 +30,10 @@ namespace Petka {
 
 class QVisibleObject;
 
-class QInterface {
+class Interface {
 public:
-	QInterface();
-	virtual ~QInterface() {}
+	Interface();
+	virtual ~Interface() {}
 
 	virtual void start() {};
 	virtual void stop() {};
@@ -45,30 +45,7 @@ public:
 public:
 	Common::Array<QVisibleObject *> _objs;
 	QVisibleObject *_objUnderCursor;
-	uint _startIndex;
-};
-
-struct BGInfo {
-	uint16 objId;
-	Common::Array<uint16> attachedObjIds;
-};
-
-class QInterfaceMain : public QInterface {
-public:
-	QInterfaceMain();
-
-public:
-	Common::Array<BGInfo> _bgs;
-};
-
-class QInterfaceStartup : public QInterface {
-public:
-	//QInterfaceStartup();
-
-	void start() override;
-
-	void onLeftButtonDown(const Common::Point p) override;
-	void onMouseMove(const Common::Point p) override;
+	int _startIndex;
 };
 
 } // End of namespace Petka
diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
new file mode 100644
index 0000000000..b670a86958
--- /dev/null
+++ b/engines/petka/interfaces/main.cpp
@@ -0,0 +1,59 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <common/system.h>
+#include "common/stream.h"
+#include "common/events.h"
+
+#include "petka/flc.h"
+#include "petka/obj.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"
+
+namespace Petka {
+
+InterfaceMain::InterfaceMain() {
+	Common::ScopedPtr<Common::SeekableReadStream> stream(g_vm->openFile("backgrnd.bg", true));
+	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[i]);
+			obj->_x = stream->readSint32LE();
+			obj->_y = stream->readSint32LE();
+			obj->_z = stream->readSint32LE();
+			obj->_field14 = stream->readSint32LE();
+			obj->_field18 = stream->readSint32LE();
+		}
+	}
+}
+
+} // End of namespace Petka
+
diff --git a/engines/petka/interfaces/main.h b/engines/petka/interfaces/main.h
new file mode 100644
index 0000000000..8aa5f1df44
--- /dev/null
+++ b/engines/petka/interfaces/main.h
@@ -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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_MAIN_H
+#define PETKA_MAIN_H
+
+#include "petka/interfaces/interface.h"
+
+namespace Petka {
+
+struct BGInfo {
+	uint16 objId;
+	Common::Array<uint16> attachedObjIds;
+};
+
+class InterfaceMain : public Interface {
+public:
+	InterfaceMain();
+
+public:
+	Common::Array<BGInfo> _bgs;
+};
+
+} // End of namespace Petka
+
+#endif
diff --git a/engines/petka/q_interface.cpp b/engines/petka/interfaces/startup.cpp
similarity index 76%
rename from engines/petka/q_interface.cpp
rename to engines/petka/interfaces/startup.cpp
index b1242b7291..e388276dc5 100644
--- a/engines/petka/q_interface.cpp
+++ b/engines/petka/interfaces/startup.cpp
@@ -26,41 +26,17 @@
 
 #include "petka/flc.h"
 #include "petka/obj.h"
-#include "petka/q_interface.h"
+#include "petka/interfaces/main.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"
-#include "q_interface.h"
-
 
 namespace Petka {
 
-QInterface::QInterface()
-	: _objUnderCursor(nullptr) {}
-
-QInterfaceMain::QInterfaceMain() {
-	Common::ScopedPtr<Common::SeekableReadStream> stream(g_vm->openFile("backgrnd.bg", true));
-	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[i]);
-			obj->_x = stream->readSint32LE();
-			obj->_y = stream->readSint32LE();
-			obj->_z = stream->readSint32LE();
-			obj->_field14 = stream->readSint32LE();
-			obj->_field18 = stream->readSint32LE();
-		}
-	}
-}
-
-void QInterfaceStartup::start() {
+void InterfaceStartup::start() {
 	g_vm->getQSystem()->update();
 	g_vm->getQSystem()->_field48 = 0;
 
@@ -92,14 +68,14 @@ void QInterfaceStartup::start() {
 
 
 	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
-	cursor->_resourceId = 4901;
+	cursor->_resourceId = 5007;
 	cursor->_isShown = true;
 	cursor->_animate = false;
 	_objs.push_back(g_vm->getQSystem()->_cursor.get());
 	cursor->setCursorPos(cursor->_x, cursor->_y, 0);
 }
 
-void QInterfaceStartup::onLeftButtonDown(const Common::Point p) {
+void InterfaceStartup::onLeftButtonDown(const Common::Point p) {
 	if (!_objUnderCursor)
 		return;
 	switch (_objUnderCursor->_resourceId) {
@@ -110,7 +86,7 @@ void QInterfaceStartup::onLeftButtonDown(const Common::Point p) {
 		g_vm->playVideo(g_vm->openFile("credits.avi", false));
 		break;
 	case 4983:
-		// start SaveLoad menu
+
 		break;
 	case 4984:
 		// new game
@@ -118,7 +94,7 @@ void QInterfaceStartup::onLeftButtonDown(const Common::Point p) {
 	}
 }
 
-void QInterfaceStartup::onMouseMove(const Common::Point p) {
+void InterfaceStartup::onMouseMove(const Common::Point p) {
 	_objUnderCursor = nullptr;
 	bool found = false;
 	for (int i = _objs.size() - 1; i >= 0; --i) {
@@ -151,3 +127,5 @@ void QInterfaceStartup::onMouseMove(const Common::Point p) {
 }
 
 } // End of namespace Petka
+
+
diff --git a/engines/petka/interfaces/startup.h b/engines/petka/interfaces/startup.h
new file mode 100644
index 0000000000..6230e28c3a
--- /dev/null
+++ b/engines/petka/interfaces/startup.h
@@ -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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_STARTUP_H
+#define PETKA_STARTUP_H
+
+#include "petka/interfaces/interface.h"
+
+namespace Petka {
+
+class InterfaceStartup : public Interface {
+public:
+	void start() override;
+
+	void onLeftButtonDown(const Common::Point p) override;
+	void onMouseMove(const Common::Point p) override;
+};
+
+} // End of namespace Petka
+
+#endif
diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index c92a994200..52c489634f 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -6,11 +6,13 @@ MODULE_OBJS = \
     flc.o \
     obj.o \
     petka.o \
-    q_interface.o \
     q_manager.o \
     q_system.o \
     sound.o \
-    video.o
+    video.o \
+    interfaces/interface.o \
+    interfaces/main.o \
+    interfaces/startup.o
 
 # This module can be built as a plugin
 ifeq ($(ENABLE_PETKA), DYNAMIC_PLUGIN)
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 42dfe01603..4b97829ef7 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -26,7 +26,8 @@
 #include "graphics/colormasks.h"
 
 #include "petka/petka.h"
-#include "petka/q_interface.h"
+#include "petka/interfaces/startup.h"
+#include "petka/interfaces/main.cpp"
 #include "petka/q_system.h"
 
 namespace Petka {
@@ -125,8 +126,8 @@ bool QSystem::init() {
 	_allObjects.push_back(_case.get());
 	_allObjects.push_back(_star.get());
 
-	_mainInterface.reset(new QInterfaceMain());
-	_startupInterface.reset(new QInterfaceStartup());
+	_mainInterface.reset(new InterfaceMain());
+	_startupInterface.reset(new InterfaceStartup());
 	_startupInterface->start();
 	_currInterface = _startupInterface.get();
 	return true;
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index d2eb92c0bb..615474145a 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -34,9 +34,9 @@ class PetkaEngine;
 class QObjectCase;
 class QObjectCursor;
 class QObjectStar;
-class QInterfaceMain;
-class QInterfaceStartup;
-class QInterface;
+class InterfaceMain;
+class InterfaceStartup;
+class Interface;
 
 class QSystem {
 public:
@@ -62,10 +62,10 @@ public:
 	Common::ScopedPtr<QObjectCursor> _cursor;
 	Common::ScopedPtr<QObjectCase> _case;
 	Common::ScopedPtr<QObjectStar> _star;
-	Common::ScopedPtr<QInterfaceMain> _mainInterface;
-	Common::ScopedPtr<QInterfaceStartup> _startupInterface;
-	QInterface *_currInterface;
-	QInterface *_prevInterface;
+	Common::ScopedPtr<InterfaceMain> _mainInterface;
+	Common::ScopedPtr<InterfaceStartup> _startupInterface;
+	Interface *_currInterface;
+	Interface *_prevInterface;
 
 	int _field48;
 };
diff --git a/engines/petka/video.cpp b/engines/petka/video.cpp
index d1bca9e3e2..f5a3f8f71d 100644
--- a/engines/petka/video.cpp
+++ b/engines/petka/video.cpp
@@ -24,7 +24,7 @@
 
 #include "petka/petka.h"
 #include "petka/q_system.h"
-#include "petka/q_interface.h"
+#include "petka/interfaces/interface.h"
 #include "petka/obj.h"
 #include "petka/video.h"
 
@@ -36,7 +36,7 @@ VideoSystem::VideoSystem() :
 }
 
 void VideoSystem::update() {
-	QInterface *interface = g_vm->getQSystem()->_currInterface;
+	Interface *interface = g_vm->getQSystem()->_currInterface;
 	if (interface) {
 		for (uint i = 0; i < interface->_objs.size(); ++i) {
 			interface->_objs[i]->update();


Commit: dc3335308fa81700d794d39c3e394c9e42baac59
    https://github.com/scummvm/scummvm/commit/dc3335308fa81700d794d39c3e394c9e42baac59
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: removed unneeded commented code

Changed paths:
    engines/petka/obj.cpp


diff --git a/engines/petka/obj.cpp b/engines/petka/obj.cpp
index 4dd451a0cd..2698425873 100644
--- a/engines/petka/obj.cpp
+++ b/engines/petka/obj.cpp
@@ -204,16 +204,6 @@ void QObjectCursor::draw() {
 	const Graphics::Surface *frame = flc->getCurrentFrame();
 	if (frame) {
 		Graphics::Surface *s = frame->convertTo(g_system->getScreenFormat(), flc->getPalette());
-
-		/*Common::Rect srcRect(_x, _y, _x + flc->getWidth(), _y + flc->getHeight());
-		srcRect.translate(_x, _y);
-
-		Common::Rect intersect(Common::Rect(640, 480).findIntersectingRect(srcRect));
-		srcRect = intersect;
-		srcRect.translate(-_x, -_y);
-
-		g_vm->videoSystem()->screen().transBlitFrom(*s, srcRect, intersect);*/
-
 		Common::Rect srcRect(flc->getBounds());
 		srcRect.translate(_x, _y);
 		srcRect.clip(640, 480);


Commit: a2b4cdaf21997f22ddbfe78fb78d71c87ad0b752
    https://github.com/scummvm/scummvm/commit/a2b4cdaf21997f22ddbfe78fb78d71c87ad0b752
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed drawing cursor when its trans color is not black

Changed paths:
    engines/petka/obj.cpp


diff --git a/engines/petka/obj.cpp b/engines/petka/obj.cpp
index 2698425873..0481e17729 100644
--- a/engines/petka/obj.cpp
+++ b/engines/petka/obj.cpp
@@ -209,7 +209,7 @@ void QObjectCursor::draw() {
 		srcRect.clip(640, 480);
 		Common::Rect destRect(srcRect);
 		srcRect.translate(-_x, -_y);
-		g_vm->videoSystem()->screen().transBlitFrom(*s, srcRect, destRect);
+		g_vm->videoSystem()->screen().transBlitFrom(*s, srcRect, destRect, flc->getTransColor(s->format));
 		s->free();
 		delete s;
 	}


Commit: 1e11c8004001a1f725c0f46a299510304646dd2d
    https://github.com/scummvm/scummvm/commit/1e11c8004001a1f725c0f46a299510304646dd2d
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added some constants to startup class

Changed paths:
    engines/petka/interfaces/startup.cpp


diff --git a/engines/petka/interfaces/startup.cpp b/engines/petka/interfaces/startup.cpp
index e388276dc5..bfd7360649 100644
--- a/engines/petka/interfaces/startup.cpp
+++ b/engines/petka/interfaces/startup.cpp
@@ -36,6 +36,13 @@
 
 namespace Petka {
 
+enum {
+	kExit = 4981,
+	kCredits = 4982,
+	kLoad = 4983,
+	kNewGame = 4984
+};
+
 void InterfaceStartup::start() {
 	g_vm->getQSystem()->update();
 	g_vm->getQSystem()->_field48 = 0;
@@ -64,6 +71,7 @@ void InterfaceStartup::start() {
 			obj->_isShown = 0;
 			_objs.push_back(obj);
 		}
+		break;
 	}
 
 
@@ -79,17 +87,17 @@ void InterfaceStartup::onLeftButtonDown(const Common::Point p) {
 	if (!_objUnderCursor)
 		return;
 	switch (_objUnderCursor->_resourceId) {
-	case 4981:
+	case kExit:
 		g_system->quit();
 		break;
-	case 4982:
+	case kCredits:
 		g_vm->playVideo(g_vm->openFile("credits.avi", false));
 		break;
-	case 4983:
+	case kLoad:
 
 		break;
-	case 4984:
-		// new game
+	case kNewGame:
+
 		break;
 	}
 }


Commit: d24f8c52cc215881f7422a4247fa10417a76d964
    https://github.com/scummvm/scummvm/commit/d24f8c52cc215881f7422a4247fa10417a76d964
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: JANITORIAL: fixed formatting

Changed paths:
    engines/petka/interfaces/startup.cpp


diff --git a/engines/petka/interfaces/startup.cpp b/engines/petka/interfaces/startup.cpp
index bfd7360649..45f475c5bf 100644
--- a/engines/petka/interfaces/startup.cpp
+++ b/engines/petka/interfaces/startup.cpp
@@ -20,7 +20,7 @@
  *
  */
 
-#include <common/system.h>
+#include "common/system.h"
 #include "common/stream.h"
 #include "common/events.h"
 


Commit: b2432a3d0968af19ccab97dff5870b5da5c78160
    https://github.com/scummvm/scummvm/commit/b2432a3d0968af19ccab97dff5870b5da5c78160
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: made loop condition in InterfaceStartup equal to disasm

Changed paths:
    engines/petka/interfaces/startup.cpp


diff --git a/engines/petka/interfaces/startup.cpp b/engines/petka/interfaces/startup.cpp
index 45f475c5bf..20ed06a268 100644
--- a/engines/petka/interfaces/startup.cpp
+++ b/engines/petka/interfaces/startup.cpp
@@ -105,7 +105,7 @@ void InterfaceStartup::onLeftButtonDown(const Common::Point p) {
 void InterfaceStartup::onMouseMove(const Common::Point p) {
 	_objUnderCursor = nullptr;
 	bool found = false;
-	for (int i = _objs.size() - 1; i >= 0; --i) {
+	for (int i = _objs.size() - 1; i > 0; --i) {
 		QMessageObject *obj = (QMessageObject *)_objs[i];
 		if (obj->_resourceId != 4901 && obj->_resourceId != 4980) {
 			FlicDecoder *flc = g_vm->resMgr()->loadFlic(obj->_resourceId);


Commit: c05ad40ecad8c2cbac895d6328da00b35c62abe0
    https://github.com/scummvm/scummvm/commit/c05ad40ecad8c2cbac895d6328da00b35c62abe0
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed compilation

Changed paths:
    engines/petka/petka.cpp


diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
index 09c7f1a5a9..d55433c170 100644
--- a/engines/petka/petka.cpp
+++ b/engines/petka/petka.cpp
@@ -39,7 +39,7 @@
 #include "petka/sound.h"
 #include "petka/petka.h"
 #include "petka/q_manager.h"
-#include "petka/q_interface.h"
+#include "petka/interfaces/interface.h"
 #include "petka/q_system.h"
 
 namespace Petka {


Commit: 72b0685fa9b0938e9aa25eacde74d8b068aaf721
    https://github.com/scummvm/scummvm/commit/72b0685fa9b0938e9aa25eacde74d8b068aaf721
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added saveload interface

Changed paths:
  A engines/petka/interfaces/save_load.cpp
  A engines/petka/interfaces/save_load.h
    engines/petka/interfaces/startup.cpp
    engines/petka/module.mk
    engines/petka/petka.cpp
    engines/petka/q_system.cpp
    engines/petka/q_system.h


diff --git a/engines/petka/interfaces/save_load.cpp b/engines/petka/interfaces/save_load.cpp
new file mode 100644
index 0000000000..470841cffb
--- /dev/null
+++ b/engines/petka/interfaces/save_load.cpp
@@ -0,0 +1,100 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "petka/petka.h"
+#include "petka/q_system.h"
+#include "petka/q_manager.h"
+#include "petka/video.h"
+#include "petka/interfaces/save_load.h"
+
+namespace Petka {
+
+const uint kFirstSaveLoadPageId = 4990;
+const Common::Rect kSavesRects[] = {{43, 84, 151, 166}, {43, 209, 151, 291},
+									{43, 335, 151, 417}, {358, 75, 466, 157},
+									{360, 200, 468, 282}, {359, 325, 467, 407}};
+const Common::Rect kNextPageRect(596, 403, 624, 431);
+const Common::Rect kPrevPageRect(10, 414, 38, 442);
+
+void InterfaceSaveLoad::startSaveLoad(bool saveMode) {
+	_loadMode = !saveMode;
+	QObjectBG *bg = (QObjectBG *)g_vm->getQSystem()->findObject("SAVELOAD");
+	_objs.push_back(bg);
+	bg->_resourceId = kFirstSaveLoadPageId + _page + (_loadMode ? 0 : 5);
+
+	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
+	_objs.push_back(cursor);
+	_savedCursorId = cursor->_resourceId;
+	cursor->_resourceId = 4901;
+	cursor->_isShown = 1;
+	cursor->_animate = 0;
+	cursor->setCursorPos(cursor->_x, cursor->_y, 0);
+
+	g_vm->getQSystem()->_currInterface = this;
+	g_vm->videoSystem()->addDirtyRect(Common::Rect(640, 480));
+}
+
+void InterfaceSaveLoad::stop() {
+	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
+	cursor->_resourceId = _savedCursorId;
+	g_vm->getQSystem()->_currInterface = g_vm->getQSystem()->_prevInterface;
+	g_vm->getQSystem()->_currInterface->onMouseMove(Common::Point(cursor->_x, cursor->_y));
+	g_vm->videoSystem()->addDirtyRect(Common::Rect(640, 480));
+}
+
+void InterfaceSaveLoad::onLeftButtonDown(const Common::Point p) {
+	int index = findSaveLoadRectIndex(p);
+	if (index == -1) {
+		if (kPrevPageRect.contains(p) && _page > 0) {
+			_page--;
+		} else if (kNextPageRect.contains(p) && _page < 2) {
+			_page++;
+		}
+		stop();
+		startSaveLoad(_loadMode == 0);
+	} else {
+
+	}
+}
+
+void InterfaceSaveLoad::onRightButtonDown(const Common::Point p) {
+	stop();
+}
+
+void InterfaceSaveLoad::onMouseMove(const Common::Point p) {
+	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
+	cursor->_animate = findSaveLoadRectIndex(p) != -1 || kNextPageRect.contains(p) || kPrevPageRect.contains(p);
+	cursor->setCursorPos(p.x, p.y, 0);
+}
+
+int InterfaceSaveLoad::findSaveLoadRectIndex(const Common::Point p) {
+	int i = 0;
+	do {
+		if (kSavesRects[i].contains(p)) {
+			return i;
+		}
+	} while (++i < sizeof(kSavesRects) / sizeof(Common::Rect));
+	return -1;
+}
+
+} // End of namespace Petka
+
diff --git a/engines/petka/interfaces/save_load.h b/engines/petka/interfaces/save_load.h
new file mode 100644
index 0000000000..786b0b402e
--- /dev/null
+++ b/engines/petka/interfaces/save_load.h
@@ -0,0 +1,50 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_SAVE_LOAD_H
+#define PETKA_SAVE_LOAD_H
+
+#include "petka/interfaces/interface.h"
+
+namespace Petka {
+
+class InterfaceSaveLoad : public Interface {
+public:
+	void startSaveLoad(bool saveMode);
+	void stop() override;
+
+	void onLeftButtonDown(const Common::Point p) override;
+	void onRightButtonDown(const Common::Point p) override;
+	void onMouseMove(const Common::Point p) override;
+
+private:
+	int findSaveLoadRectIndex(const Common::Point p);
+
+private:
+	bool _loadMode;
+	uint _page;
+	int _savedCursorId;
+};
+
+} // End of namespace Petka
+
+#endif
diff --git a/engines/petka/interfaces/startup.cpp b/engines/petka/interfaces/startup.cpp
index 20ed06a268..ab3c0f5d8c 100644
--- a/engines/petka/interfaces/startup.cpp
+++ b/engines/petka/interfaces/startup.cpp
@@ -27,6 +27,7 @@
 #include "petka/flc.h"
 #include "petka/obj.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"
@@ -94,7 +95,7 @@ void InterfaceStartup::onLeftButtonDown(const Common::Point p) {
 		g_vm->playVideo(g_vm->openFile("credits.avi", false));
 		break;
 	case kLoad:
-
+		g_vm->getQSystem()->_saveLoadInterface->startSaveLoad(0);
 		break;
 	case kNewGame:
 
diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index 52c489634f..5877203560 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -12,6 +12,7 @@ MODULE_OBJS = \
     video.o \
     interfaces/interface.o \
     interfaces/main.o \
+    interfaces/save_load.o \
     interfaces/startup.o
 
 # This module can be built as a plugin
diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
index d55433c170..600d678ff1 100644
--- a/engines/petka/petka.cpp
+++ b/engines/petka/petka.cpp
@@ -101,6 +101,7 @@ Common::Error PetkaEngine::run() {
 			case Common::EVENT_LBUTTONUP:
 				break;
 			case Common::EVENT_RBUTTONDOWN:
+				_qsystem->_currInterface->onRightButtonDown(event.mouse);
 				break;
 			case Common::EVENT_KEYDOWN:
 				break;
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 4b97829ef7..47206a10a2 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -27,7 +27,8 @@
 
 #include "petka/petka.h"
 #include "petka/interfaces/startup.h"
-#include "petka/interfaces/main.cpp"
+#include "petka/interfaces/main.h"
+#include "petka/interfaces/save_load.h"
 #include "petka/q_system.h"
 
 namespace Petka {
@@ -128,8 +129,9 @@ bool QSystem::init() {
 
 	_mainInterface.reset(new InterfaceMain());
 	_startupInterface.reset(new InterfaceStartup());
+	_saveLoadInterface.reset(new InterfaceSaveLoad());
 	_startupInterface->start();
-	_currInterface = _startupInterface.get();
+	_prevInterface = _currInterface = _startupInterface.get();
 	return true;
 }
 
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index 615474145a..e983645ef1 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -34,6 +34,7 @@ class PetkaEngine;
 class QObjectCase;
 class QObjectCursor;
 class QObjectStar;
+class InterfaceSaveLoad;
 class InterfaceMain;
 class InterfaceStartup;
 class Interface;
@@ -63,6 +64,7 @@ public:
 	Common::ScopedPtr<QObjectCase> _case;
 	Common::ScopedPtr<QObjectStar> _star;
 	Common::ScopedPtr<InterfaceMain> _mainInterface;
+	Common::ScopedPtr<InterfaceSaveLoad> _saveLoadInterface;
 	Common::ScopedPtr<InterfaceStartup> _startupInterface;
 	Interface *_currInterface;
 	Interface *_prevInterface;


Commit: a3761ab0fb91bf81c6146eee202833ea4ba235c2
    https://github.com/scummvm/scummvm/commit/a3761ab0fb91bf81c6146eee202833ea4ba235c2
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added partial implementation of settings interface

Changed paths:
  A engines/petka/interfaces/panel.cpp
  A engines/petka/interfaces/panel.h
    engines/petka/flc.cpp
    engines/petka/flc.h
    engines/petka/module.mk
    engines/petka/q_system.cpp
    engines/petka/q_system.h
    engines/petka/video.cpp
    engines/petka/video.h


diff --git a/engines/petka/flc.cpp b/engines/petka/flc.cpp
index bd532001a2..9af7b952df 100644
--- a/engines/petka/flc.cpp
+++ b/engines/petka/flc.cpp
@@ -89,6 +89,17 @@ uint32 FlicDecoder::getTransColor(const Graphics::PixelFormat &fmt) const {
 	return 0;
 }
 
+void FlicDecoder::setFrame(int frame) {
+	FlicVideoTrack *flc = ((FlicVideoTrack *) getTrack(0));
+	if (!flc || flc->getCurFrame() + 1 == frame)
+		return;
+
+	flc->rewind();
+	do {
+		flc->decodeNextFrame();
+	} while (flc->getCurFrame() + 1 != frame);
+}
+
 FlicDecoder::FlicVideoTrack::FlicVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height, bool skipHeader)
 	: Video::FlicDecoder::FlicVideoTrack(stream, frameCount, width, height, skipHeader) {}
 
diff --git a/engines/petka/flc.h b/engines/petka/flc.h
index 4fe3c0bdac..d4853d2a96 100644
--- a/engines/petka/flc.h
+++ b/engines/petka/flc.h
@@ -31,6 +31,8 @@ class FlicDecoder : public Video::FlicDecoder {
 public:
 	void load(Common::SeekableReadStream *flcStream, Common::SeekableReadStream *mskStream);
 
+	void setFrame(int frame);
+
 	const Common::Rect &getBounds() const;
 	const Common::Array<Common::Rect> &getMskRects() const;
 	const Graphics::Surface *getCurrentFrame() const;
diff --git a/engines/petka/interfaces/panel.cpp b/engines/petka/interfaces/panel.cpp
new file mode 100644
index 0000000000..dd812888e9
--- /dev/null
+++ b/engines/petka/interfaces/panel.cpp
@@ -0,0 +1,257 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_STARTUP_H
+#define PETKA_STARTUP_H
+
+#include "common/config-manager.h"
+#include "common/system.h"
+
+#include "petka/obj.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 Petka {
+
+// ПАНЕЛЬ УПРАВЛЕНИЯ
+const char *const kPanelObjName = "\xCF\xC0\xCD\xC5\xCB\xDC\x20\xD3\xCF\xD0\xC0\xC2\xCB\xC5\xCD\xC8\xDF";
+const Common::Point kObjectsPoints[] = {{0, 2}, {5, 70}, {5, 136}, {22, 328},
+									   {87, 224}, {118, 395}, {467, 71}, {432, 144},
+									   {428, 29}, {434, 170}, {297, 214}, {470, 139},
+									   {318, 87}, {468, 172}, {262, 31}, {231, 137},
+									   {0, 0}, {0, 0}, {0, 0}, {0, 0},
+									   {0, 0}, {0, 0}, {0, 0}, {0, 0}};
+
+const uint kNewGameButtonIndex = 1;
+const uint kLoadButtonIndex = 2;
+const uint kContinueButtonIndex = 3;
+const uint kExitButtonIndex = 4;
+const uint kSaveButtonIndex = 5;
+
+const uint kSubtitleButtonIndex = 8;
+const uint kSubtitleLabelIndex = 12;
+
+const uint kSpeechVolumeSliderIndex = 15;
+const uint kDecSpeechButtonIndex = 17;
+const uint kIncSpeechButtonIndex = 18;
+
+const uint kMusicVolumeSliderIndex = 16;
+const uint kDecMusicButtonIndex = 19;
+const uint kIncMusicButtonIndex = 20;
+
+const uint kSfxVolumeSliderIndex = 9;
+const uint kDecSfxButtonIndex = 21;
+const uint kIncSfxButtonIndex = 22;
+
+const uint kSpeedSliderIndex = 10;
+const uint kDecSpeedButtonIndex = 23;
+const uint kIncSpeedButtonIndex = 24;
+
+void InterfacePanel::start() {
+	readSettings();
+
+	QObjectBG *bg = (QObjectBG *)g_vm->getQSystem()->findObject(kPanelObjName);
+	_objs.push_back(bg);
+	g_vm->getQSystem()->update();
+	const Common::Array<BGInfo> &infos = g_vm->getQSystem()->_mainInterface->_bgs;
+
+	for (uint i = 0; i < infos.size(); ++i) {
+		if (infos[i].objId != bg->_id) {
+			continue;
+		}
+		for (uint j = 0; j < infos[i].attachedObjIds.size(); ++j) {
+			QMessageObject *obj = g_vm->getQSystem()->findObject(infos[i].attachedObjIds[j]);
+			FlicDecoder *flc = g_vm->resMgr()->loadFlic(obj->_resourceId);
+			flc->decodeNextFrame();
+			obj->_z = 1;
+			obj->_x = kObjectsPoints[j].x;
+			obj->_y = kObjectsPoints[j].y;
+			obj->_field24 = 1;
+			obj->_field20 = 1;
+			obj->_field28 = 1;
+			obj->_animate = 0;
+			obj->_isShown = 1;
+			_objs.push_back(obj);
+		}
+		break;
+	}
+
+
+	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
+	_objs.push_back(cursor);
+	cursor->_resourceId = 4901;
+	cursor->_isShown = 1;
+	cursor->_animate = 1;
+	cursor->setCursorPos(cursor->_x, cursor->_y, 0);
+
+	updateSliders();
+	updateSubtitles();
+
+	g_vm->getQSystem()->_currInterface = this;
+	g_vm->videoSystem()->addDirtyRect(Common::Rect(640, 480));
+}
+
+void InterfacePanel::onLeftButtonDown(const Common::Point p) {
+	int i = 0;
+	for (i = _objs.size() - 1; i > 0; --i) {
+		if (_objs[i]->isInPoint(p.x, p.y)) {
+			break;
+		}
+	}
+	switch (i) {
+	case kNewGameButtonIndex:
+		break;
+	case kLoadButtonIndex:
+		g_vm->getQSystem()->_saveLoadInterface->startSaveLoad(0);
+		break;
+	case kContinueButtonIndex:
+		stop();
+		break;
+	case kExitButtonIndex:
+		g_system->quit();
+		break;
+	case kSaveButtonIndex:
+		g_vm->getQSystem()->_saveLoadInterface->startSaveLoad(1);
+		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(const Common::Point p) {
+	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
+	cursor->_isShown = 1;
+	cursor->setCursorPos(p.x, p.y, 0);
+}
+
+void InterfacePanel::updateSliders() {
+	applySettings();
+
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_objs[kSpeechVolumeSliderIndex]->_resourceId);
+	flc->setFrame(_speechFrame);
+	g_vm->videoSystem()->addDirtyRect(kObjectsPoints[kSpeechVolumeSliderIndex - 1], *flc);
+
+	flc = g_vm->resMgr()->loadFlic(_objs[kMusicVolumeSliderIndex]->_resourceId);
+	flc->setFrame(_musicFrame);
+	g_vm->videoSystem()->addDirtyRect(kObjectsPoints[kMusicVolumeSliderIndex - 1], *flc);
+
+	flc = g_vm->resMgr()->loadFlic(_objs[kSfxVolumeSliderIndex]->_resourceId);
+	flc->setFrame(_speechFrame);
+	g_vm->videoSystem()->addDirtyRect(kObjectsPoints[kSfxVolumeSliderIndex - 1], *flc);
+
+	flc = g_vm->resMgr()->loadFlic(_objs[kSpeedSliderIndex]->_resourceId);
+	flc->setFrame(_speedFrame);
+	g_vm->videoSystem()->addDirtyRect(kObjectsPoints[kSpeedSliderIndex - 1], *flc);
+}
+
+void InterfacePanel::updateSubtitles() {
+	applySettings();
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_objs[kSubtitleButtonIndex]->_resourceId);
+	flc->setFrame(_subtitles != 0 ? 1 : 7);
+	g_vm->videoSystem()->addDirtyRect(kObjectsPoints[kSubtitleButtonIndex - 1], *flc);
+
+	flc = g_vm->resMgr()->loadFlic(_objs[kSubtitleLabelIndex]->_resourceId);
+	flc->setFrame(_subtitles != 0 ? 1 : 2);
+	g_vm->videoSystem()->addDirtyRect(kObjectsPoints[kSubtitleLabelIndex - 1], *flc);
+}
+
+void InterfacePanel::readSettings() {
+
+}
+
+void InterfacePanel::applySettings() {
+	if (_speechFrame < 1)
+		_speechFrame = 1;
+	else if (_speechFrame > 31)
+		_speechFrame = 31;
+
+	if (_musicFrame < 1)
+		_musicFrame = 1;
+	else if (_musicFrame > 41)
+		_musicFrame = 41;
+
+	if (_sfxFrame < 1)
+		_sfxFrame = 1;
+	else if (_sfxFrame > 31)
+		_sfxFrame = 31;
+
+	if (_speedFrame < 1)
+		_speedFrame = 1;
+	else if (_speedFrame > 26)
+		_speedFrame = 26;
+
+	ConfMan.setInt("speech_volume", 255 * (_speechFrame - 1) / (31 - 1));
+	ConfMan.setInt("music_volume", 255 * (_musicFrame - 1) / (41 - 1));
+	ConfMan.setInt("sfx_volume", 255 * (_sfxFrame - 1) / (31 - 1));
+
+	// speed
+	// subtitles
+
+	g_vm->syncSoundSettings();
+}
+
+} // End of namespace Petka
+
+#endif
+
diff --git a/engines/petka/interfaces/panel.h b/engines/petka/interfaces/panel.h
new file mode 100644
index 0000000000..107d0ade2b
--- /dev/null
+++ b/engines/petka/interfaces/panel.h
@@ -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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_PANEL_H
+#define PETKA_PANEL_H
+
+#include "petka/interfaces/interface.h"
+
+namespace Petka {
+
+class InterfacePanel : public Interface {
+public:
+	void start() override;
+
+	void onLeftButtonDown(const Common::Point p) override;
+	void onMouseMove(const Common::Point p) override;
+
+private:
+	void readSettings();
+	void applySettings();
+
+	void updateSliders();
+	void updateSubtitles();
+
+private:
+	int _savedXOffset;
+	int _savedSceneWidth;
+	int _subtitles;
+	int _speechFrame;
+	int _musicFrame;
+	int _sfxFrame;
+	int _speedFrame;
+};
+
+} // End of namespace Petka
+
+#endif
diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index 5877203560..db42a26a9f 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -12,6 +12,7 @@ MODULE_OBJS = \
     video.o \
     interfaces/interface.o \
     interfaces/main.o \
+    interface/panel.o \
     interfaces/save_load.o \
     interfaces/startup.o
 
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 47206a10a2..ee9d386952 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -29,6 +29,7 @@
 #include "petka/interfaces/startup.h"
 #include "petka/interfaces/main.h"
 #include "petka/interfaces/save_load.h"
+#include "petka/interfaces/panel.h"
 #include "petka/q_system.h"
 
 namespace Petka {
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index e983645ef1..2f86ab7599 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -37,6 +37,7 @@ class QObjectStar;
 class InterfaceSaveLoad;
 class InterfaceMain;
 class InterfaceStartup;
+class InterfacePanel;
 class Interface;
 
 class QSystem {
@@ -66,6 +67,7 @@ public:
 	Common::ScopedPtr<InterfaceMain> _mainInterface;
 	Common::ScopedPtr<InterfaceSaveLoad> _saveLoadInterface;
 	Common::ScopedPtr<InterfaceStartup> _startupInterface;
+	Common::ScopedPtr<InterfacePanel> _panelInterface;
 	Interface *_currInterface;
 	Interface *_prevInterface;
 
diff --git a/engines/petka/video.cpp b/engines/petka/video.cpp
index f5a3f8f71d..0e03fbbf00 100644
--- a/engines/petka/video.cpp
+++ b/engines/petka/video.cpp
@@ -22,6 +22,7 @@
 
 #include "common/system.h"
 
+#include "petka/flc.h"
 #include "petka/petka.h"
 #include "petka/q_system.h"
 #include "petka/interfaces/interface.h"
@@ -85,4 +86,10 @@ Graphics::Screen &VideoSystem::screen() {
 	return _screen;
 }
 
+void VideoSystem::addDirtyRect(Common::Point pos, FlicDecoder &flc) {
+	Common::Rect rect = flc.getBounds();
+	rect.translate(pos.x, pos.y);
+	addDirtyRect(rect);
+}
+
 }
\ No newline at end of file
diff --git a/engines/petka/video.h b/engines/petka/video.h
index 4ea4168d83..84de1277d6 100644
--- a/engines/petka/video.h
+++ b/engines/petka/video.h
@@ -27,6 +27,8 @@
 
 namespace Petka {
 
+class FlicDecoder;
+
 class VideoSystem {
 public:
 	VideoSystem();
@@ -34,6 +36,7 @@ public:
 	void update();
 
 	void addDirtyRect(const Common::Rect &rect);
+	void addDirtyRect(Common::Point pos, FlicDecoder &flc);
 	const Common::List<Common::Rect> rects() const;
 	Graphics::Screen &screen();
 


Commit: 974fb205b30f9be80fee84b8da9a5005e9f43143
    https://github.com/scummvm/scummvm/commit/974fb205b30f9be80fee84b8da9a5005e9f43143
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented reading and applying settings in menu

Changed paths:
    engines/petka/interfaces/panel.cpp


diff --git a/engines/petka/interfaces/panel.cpp b/engines/petka/interfaces/panel.cpp
index dd812888e9..6a9be97193 100644
--- a/engines/petka/interfaces/panel.cpp
+++ b/engines/petka/interfaces/panel.cpp
@@ -217,37 +217,25 @@ void InterfacePanel::updateSubtitles() {
 }
 
 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() {
-	if (_speechFrame < 1)
-		_speechFrame = 1;
-	else if (_speechFrame > 31)
-		_speechFrame = 31;
-
-	if (_musicFrame < 1)
-		_musicFrame = 1;
-	else if (_musicFrame > 41)
-		_musicFrame = 41;
-
-	if (_sfxFrame < 1)
-		_sfxFrame = 1;
-	else if (_sfxFrame > 31)
-		_sfxFrame = 31;
-
-	if (_speedFrame < 1)
-		_speedFrame = 1;
-	else if (_speedFrame > 26)
-		_speedFrame = 26;
+	_speechFrame = MIN(MAX(1, _speechFrame), 31);
+	_musicFrame = MIN(MAX(1, _musicFrame), 41);
+	_sfxFrame = MIN(MAX(1, _sfxFrame), 31);
+	_speedFrame = MIN(MAX(1, _speedFrame), 26);
 
 	ConfMan.setInt("speech_volume", 255 * (_speechFrame - 1) / (31 - 1));
 	ConfMan.setInt("music_volume", 255 * (_musicFrame - 1) / (41 - 1));
 	ConfMan.setInt("sfx_volume", 255 * (_sfxFrame - 1) / (31 - 1));
-
-	// speed
-	// subtitles
-
+	ConfMan.setBool("subtitles", _subtitles);
+	//ConfMan.setInt("petka_speed", 4 * (_speedFrame - 1));
+	ConfMan.flushToDisk();
 	g_vm->syncSoundSettings();
 }
 


Commit: ea159a4f19e4ed9cb0cf465965569378fc6f95cb
    https://github.com/scummvm/scummvm/commit/ea159a4f19e4ed9cb0cf465965569378fc6f95cb
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed setting frame in panel interface

Changed paths:
    engines/petka/interfaces/panel.cpp


diff --git a/engines/petka/interfaces/panel.cpp b/engines/petka/interfaces/panel.cpp
index 6a9be97193..87865580eb 100644
--- a/engines/petka/interfaces/panel.cpp
+++ b/engines/petka/interfaces/panel.cpp
@@ -197,7 +197,7 @@ void InterfacePanel::updateSliders() {
 	g_vm->videoSystem()->addDirtyRect(kObjectsPoints[kMusicVolumeSliderIndex - 1], *flc);
 
 	flc = g_vm->resMgr()->loadFlic(_objs[kSfxVolumeSliderIndex]->_resourceId);
-	flc->setFrame(_speechFrame);
+	flc->setFrame(_sfxFrame);
 	g_vm->videoSystem()->addDirtyRect(kObjectsPoints[kSfxVolumeSliderIndex - 1], *flc);
 
 	flc = g_vm->resMgr()->loadFlic(_objs[kSpeedSliderIndex]->_resourceId);
@@ -208,11 +208,11 @@ void InterfacePanel::updateSliders() {
 void InterfacePanel::updateSubtitles() {
 	applySettings();
 	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_objs[kSubtitleButtonIndex]->_resourceId);
-	flc->setFrame(_subtitles != 0 ? 1 : 7);
+	flc->setFrame(_subtitles == 0 ? 1 : 7);
 	g_vm->videoSystem()->addDirtyRect(kObjectsPoints[kSubtitleButtonIndex - 1], *flc);
 
 	flc = g_vm->resMgr()->loadFlic(_objs[kSubtitleLabelIndex]->_resourceId);
-	flc->setFrame(_subtitles != 0 ? 1 : 2);
+	flc->setFrame(_subtitles == 0 ? 1 : 2);
 	g_vm->videoSystem()->addDirtyRect(kObjectsPoints[kSubtitleLabelIndex - 1], *flc);
 }
 


Commit: 56dcd053ce8c880214305c9bfb26923c2b944ae2
    https://github.com/scummvm/scummvm/commit/56dcd053ce8c880214305c9bfb26923c2b944ae2
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented mouse move event handling in settings interface

Changed paths:
    engines/petka/interfaces/panel.cpp


diff --git a/engines/petka/interfaces/panel.cpp b/engines/petka/interfaces/panel.cpp
index 87865580eb..09a3f4c146 100644
--- a/engines/petka/interfaces/panel.cpp
+++ b/engines/petka/interfaces/panel.cpp
@@ -52,23 +52,22 @@ const uint kLoadButtonIndex = 2;
 const uint kContinueButtonIndex = 3;
 const uint kExitButtonIndex = 4;
 const uint kSaveButtonIndex = 5;
-
+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 kMusicVolumeSliderIndex = 16;
 const uint kDecMusicButtonIndex = 19;
 const uint kIncMusicButtonIndex = 20;
-
-const uint kSfxVolumeSliderIndex = 9;
 const uint kDecSfxButtonIndex = 21;
 const uint kIncSfxButtonIndex = 22;
-
-const uint kSpeedSliderIndex = 10;
 const uint kDecSpeedButtonIndex = 23;
 const uint kIncSpeedButtonIndex = 24;
 
@@ -87,7 +86,7 @@ void InterfacePanel::start() {
 		for (uint j = 0; j < infos[i].attachedObjIds.size(); ++j) {
 			QMessageObject *obj = g_vm->getQSystem()->findObject(infos[i].attachedObjIds[j]);
 			FlicDecoder *flc = g_vm->resMgr()->loadFlic(obj->_resourceId);
-			flc->decodeNextFrame();
+			flc->setFrame(1);
 			obj->_z = 1;
 			obj->_x = kObjectsPoints[j].x;
 			obj->_y = kObjectsPoints[j].y;
@@ -180,6 +179,51 @@ void InterfacePanel::onLeftButtonDown(const Common::Point p) {
 }
 
 void InterfacePanel::onMouseMove(const Common::Point p) {
+	bool found = false;
+	for (uint i = _objs.size() - 1; i > 0; --i) {
+		QMessageObject *obj = (QMessageObject *)_objs[i];
+		int frame = 1;
+		if (!found && obj->isInPoint(p.x, p.y)) {
+			found = true;
+			if ((i >= kNewGameButtonIndex && i <= kSaveButtonIndex) || (i >= kDecSpeechButtonIndex && i <= kIncSpeedButtonIndex)) {
+				frame = 2;
+			}
+		}
+		if (obj->_field20 == frame)
+			continue;
+		obj->_field20 = frame;
+		obj->_field24 = frame;
+
+		int pointIndex;
+		switch (i) {
+		case kDecSpeechButtonIndex:
+		case kIncSpeechButtonIndex:
+			pointIndex = kSpeechLabelIndex - 1;
+			obj = (QMessageObject *)_objs[kSpeechLabelIndex];
+			break;
+		case kDecMusicButtonIndex:
+		case kIncMusicButtonIndex:
+			pointIndex = kMusicLabelIndex - 1;
+			obj = (QMessageObject *)_objs[kMusicLabelIndex];
+			break;
+		case kDecSfxButtonIndex:
+		case kIncSfxButtonIndex:
+			pointIndex = kSfxLabelIndex - 1;
+			obj = (QMessageObject *)_objs[kSfxLabelIndex];
+			break;
+		case kIncSpeedButtonIndex:
+		case kDecSpeedButtonIndex:
+			pointIndex = kSpeedLabelIndex - 1;
+			obj = (QMessageObject *)_objs[kSpeedLabelIndex];
+			break;
+		default:
+			pointIndex = i - 1;
+			break;
+		}
+		FlicDecoder *flc = g_vm->resMgr()->loadFlic(obj->_resourceId);
+		flc->setFrame(frame);
+		g_vm->videoSystem()->addDirtyRect(kObjectsPoints[pointIndex], *flc);
+	}
 	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
 	cursor->_isShown = 1;
 	cursor->setCursorPos(p.x, p.y, 0);


Commit: f3538539e947a5cf3a6e76543a53e114dbc50386
    https://github.com/scummvm/scummvm/commit/f3538539e947a5cf3a6e76543a53e114dbc50386
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: moved game object classes to separate files

Changed paths:
  A engines/petka/objects/object.cpp
  A engines/petka/objects/object.h
  A engines/petka/objects/object_bg.cpp
  A engines/petka/objects/object_bg.h
  A engines/petka/objects/object_case.cpp
  A engines/petka/objects/object_case.h
  A engines/petka/objects/object_cursor.cpp
  A engines/petka/objects/object_cursor.h
  A engines/petka/objects/object_star.cpp
  A engines/petka/objects/object_star.h
  R engines/petka/obj.cpp
  R engines/petka/obj.h
    engines/petka/interfaces/main.cpp
    engines/petka/interfaces/panel.cpp
    engines/petka/interfaces/save_load.cpp
    engines/petka/interfaces/startup.cpp
    engines/petka/module.mk
    engines/petka/q_system.cpp
    engines/petka/q_system.h
    engines/petka/video.cpp


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index b670a86958..0a87858ab9 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -25,7 +25,7 @@
 #include "common/events.h"
 
 #include "petka/flc.h"
-#include "petka/obj.h"
+#include "petka/objects/object.h"
 #include "petka/interfaces/main.h"
 #include "petka/q_system.h"
 #include "petka/q_manager.h"
diff --git a/engines/petka/interfaces/panel.cpp b/engines/petka/interfaces/panel.cpp
index 09a3f4c146..60f8d14a9b 100644
--- a/engines/petka/interfaces/panel.cpp
+++ b/engines/petka/interfaces/panel.cpp
@@ -26,7 +26,7 @@
 #include "common/config-manager.h"
 #include "common/system.h"
 
-#include "petka/obj.h"
+#include "petka/objects/object_cursor.h"
 #include "petka/petka.h"
 #include "petka/q_system.h"
 #include "petka/flc.h"
diff --git a/engines/petka/interfaces/save_load.cpp b/engines/petka/interfaces/save_load.cpp
index 470841cffb..59e7eb21ae 100644
--- a/engines/petka/interfaces/save_load.cpp
+++ b/engines/petka/interfaces/save_load.cpp
@@ -24,6 +24,7 @@
 #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 {
diff --git a/engines/petka/interfaces/startup.cpp b/engines/petka/interfaces/startup.cpp
index ab3c0f5d8c..b2f12e3b97 100644
--- a/engines/petka/interfaces/startup.cpp
+++ b/engines/petka/interfaces/startup.cpp
@@ -25,7 +25,7 @@
 #include "common/events.h"
 
 #include "petka/flc.h"
-#include "petka/obj.h"
+#include "petka/objects/object_cursor.h"
 #include "petka/interfaces/main.h"
 #include "petka/interfaces/save_load.h"
 #include "petka/interfaces/startup.h"
diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index db42a26a9f..44cd8b6c6b 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -4,7 +4,6 @@ MODULE_OBJS = \
     detection.o \
     file_mgr.o \
     flc.o \
-    obj.o \
     petka.o \
     q_manager.o \
     q_system.o \
@@ -12,9 +11,14 @@ MODULE_OBJS = \
     video.o \
     interfaces/interface.o \
     interfaces/main.o \
-    interface/panel.o \
+    interfaces/panel.o \
     interfaces/save_load.o \
-    interfaces/startup.o
+    interfaces/startup.o \
+    objects/object.o \
+    objects/object_bg.o \
+    objects/object_case.o \
+    objects/object_cursor.o \
+    objects/object_star.o
 
 # This module can be built as a plugin
 ifeq ($(ENABLE_PETKA), DYNAMIC_PLUGIN)
diff --git a/engines/petka/obj.cpp b/engines/petka/objects/object.cpp
similarity index 55%
rename from engines/petka/obj.cpp
rename to engines/petka/objects/object.cpp
index 0481e17729..6a743e3be6 100644
--- a/engines/petka/obj.cpp
+++ b/engines/petka/objects/object.cpp
@@ -33,7 +33,7 @@
 #include "petka/video.h"
 #include "petka/q_system.h"
 #include "petka/q_manager.h"
-#include "petka/obj.h"
+#include "petka/objects/object.h"
 
 namespace Petka {
 
@@ -47,8 +47,8 @@ void QMessageObject::processMessage(const QMessage &msg) {
 	for (uint i = 0; i < _reactions.size(); ++i) {
 		QReaction &r = _reactions[i];
 		if (r.opcode != msg.opcode ||
-		(r.status != -1 && r.status != _status) ||
-		(r.senderId != -1 && r.senderId != msg.sender->_id)) {
+			(r.status != -1 && r.status != _status) ||
+			(r.senderId != -1 && r.senderId != msg.sender->_id)) {
 			continue;
 		}
 		for (uint j = 0; j < r.messages.size(); ++j) {
@@ -57,15 +57,16 @@ void QMessageObject::processMessage(const QMessage &msg) {
 				break;
 			}
 			if (rMsg.opcode == kIf &&
-			(rMsg.arg1 == -1 || rMsg.arg1 != msg.arg1) &&
-			(rMsg.arg2 == -1 || rMsg.arg2 != msg.arg2) &&
-			(rMsg.arg3 == -1 || rMsg.arg3 != msg.arg3)) {
+				(rMsg.arg1 == -1 || rMsg.arg1 != msg.arg1) &&
+				(rMsg.arg2 == -1 || rMsg.arg2 != msg.arg2) &&
+				(rMsg.arg3 == -1 || rMsg.arg3 != msg.arg3)) {
 				break;
 			}
 			if (rMsg.opcode == kRandom && rMsg.arg2 != -1) {
-				rMsg.arg1 = (int16)g_vm->getRnd().getRandomNumber((uint)(rMsg.arg2 - 1));
+				rMsg.arg1 = (int16) g_vm->getRnd().getRandomNumber((uint) (rMsg.arg2 - 1));
 			}
-			g_vm->getQSystem()->addMessage(rMsg.objId, rMsg.opcode, rMsg.arg1, rMsg.arg2, rMsg.arg3, rMsg.unk, rMsg.sender);
+			g_vm->getQSystem()->addMessage(rMsg.objId, rMsg.opcode, rMsg.arg1, rMsg.arg2, rMsg.arg3, rMsg.unk,
+										   rMsg.sender);
 
 			switch (rMsg.opcode) {
 			case kPlay:
@@ -95,7 +96,7 @@ void QMessageObject::processMessage(const QMessage &msg) {
 
 		break;
 	case kStatus:
-		_status = (int8)msg.arg1;
+		_status = (int8) msg.arg1;
 		break;
 	case kHide:
 		break;
@@ -114,7 +115,7 @@ bool QObject::isInPoint(int x, int y) {
 	Common::Rect rect(_x, _y, _x + flc->getWidth(), _y + flc->getHeight());
 	if (!rect.contains(x, y))
 		return false;
-	return *(byte *)flc->getCurrentFrame()->getBasePtr(x -_x, y - _y) != 0;
+	return *(byte *) flc->getCurrentFrame()->getBasePtr(x - _x, y - _y) != 0;
 }
 
 void QObject::draw() {
@@ -149,113 +150,4 @@ void QObject::draw() {
 	delete s;
 }
 
-void QObjectBG::processMessage(const QMessage &msg) {
-	QMessageObject::processMessage(msg);
-	switch (msg.opcode) {
-	case kSet:
-		_resourceId = msg.arg1;
-	case kMusic:
-		_musicId = msg.arg1;
-		break;
-	case kBGsFX:
-		_fxId = msg.arg1;
-		break;
-	case kMap:
-		_showMap = msg.arg1 != 0;
-		break;
-	case kNoMap:
-		_showMap = 0;
-		break;
-	case kGoTo:
-		break;
-	case kSetSeq:
-		break;
-	case kEndSeq:
-		break;
-	}
-
-}
-
-void QObjectBG::draw() {
-	Graphics::Surface *s = g_vm->resMgr()->loadBitmap(_resourceId);
-	if (s) {
-		const Common::List<Common::Rect> &dirty = g_vm->videoSystem()->rects();
-		for (Common::List<Common::Rect>::const_iterator it = dirty.begin(); it != dirty.end(); ++it) {
-			g_vm->videoSystem()->screen().blitFrom(*s, *it, Common::Point(it->left, it->top));
-		}
-	}
-}
-
-QObjectCursor::QObjectCursor() {
-	_id = 4097;
-	_z = 1000;
-	_resourceId = 5002;
-	Common::Point pos = g_vm->getEventManager()->getMousePos();
-	_x = pos.x;
-	_y = pos.y;
-	g_vm->resMgr()->loadFlic(5002);
-}
-
-void QObjectCursor::draw() {
-	if (!_isShown) {
-		return;
-	}
-	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
-	const Graphics::Surface *frame = flc->getCurrentFrame();
-	if (frame) {
-		Graphics::Surface *s = frame->convertTo(g_system->getScreenFormat(), flc->getPalette());
-		Common::Rect srcRect(flc->getBounds());
-		srcRect.translate(_x, _y);
-		srcRect.clip(640, 480);
-		Common::Rect destRect(srcRect);
-		srcRect.translate(-_x, -_y);
-		g_vm->videoSystem()->screen().transBlitFrom(*s, srcRect, destRect, flc->getTransColor(s->format));
-		s->free();
-		delete s;
-	}
-}
-
-void QObjectCursor::update() {
-	if (!_isShown || !_animate)
-		return;
-	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
-	while (flc && flc->needsUpdate()) {
-		flc->decodeNextFrame();
-		if (flc->endOfVideo()) {
-			flc->rewind();
-		}
-		Common::Rect dirty(flc->getBounds());
-		dirty.translate(_x, _y);
-		g_vm->videoSystem()->addDirtyRect(dirty);
-	}
-}
-
-void QObjectCursor::setCursorPos(int x, int y, bool center) {
-	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
-	if (!_animate) {
-		flc->stop();
-		flc->rewind();
-		flc->decodeNextFrame();
-	} else if (!flc->isPlaying()) {
-		flc->rewind();
-		flc->start();
-	}
-
-	Common::Rect dirty(flc->getBounds());
-	dirty.translate(_x, _y);
-	g_vm->videoSystem()->addDirtyRect(dirty);
-
-	if (center) {
-		x = x - flc->getBounds().left - dirty.width() / 2;
-		y = y - flc->getBounds().top - dirty.height() / 2;
-	}
-
-	_x = x;
-	_y = y;
-
-	dirty = flc->getBounds();
-	dirty.translate(_x, _y);
-	g_vm->videoSystem()->addDirtyRect(dirty);
-}
-
-} // End of namespace Petka
+}
\ No newline at end of file
diff --git a/engines/petka/obj.h b/engines/petka/objects/object.h
similarity index 77%
rename from engines/petka/obj.h
rename to engines/petka/objects/object.h
index 40085a7b95..34d7de8446 100644
--- a/engines/petka/obj.h
+++ b/engines/petka/objects/object.h
@@ -20,8 +20,8 @@
  *
  */
 
-#ifndef PETKA_Q_MESSAGE_OBJECT_H
-#define PETKA_Q_MESSAGE_OBJECT_H
+#ifndef PETKA_OBJECT_H
+#define PETKA_OBJECT_H
 
 #include "petka/base.h"
 
@@ -72,16 +72,6 @@ public:
 	Common::Array<QReaction> _reactions;
 };
 
-class QObjectBG : public QMessageObject {
-public:
-	void processMessage(const QMessage &msg) override;
-	void draw() override;
-
-public:
-	int _showMap;
-	int _fxId;
-	int _musicId;
-};
 
 class QObject : public QMessageObject {
 public:
@@ -89,26 +79,6 @@ public:
 	bool isInPoint(int x, int y) override;
 };
 
-class QObjectCase : public QObject {
-
-};
-
-class QObjectStar : public QObject {
-
-};
-
-class QObjectCursor : public QObject {
-public:
-	QObjectCursor();
-
-	void setCursorPos(int x, int y, bool center);
-	void update() override;
-	void draw() override;
-
-private:
-
-};
-
-} // End of naespace Petka
+} // End of namespace Petka
 
 #endif
diff --git a/engines/petka/objects/object_bg.cpp b/engines/petka/objects/object_bg.cpp
new file mode 100644
index 0000000000..ee31375db0
--- /dev/null
+++ b/engines/petka/objects/object_bg.cpp
@@ -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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/ini-file.h"
+#include "common/stream.h"
+#include "common/system.h"
+#include "common/events.h"
+
+#include "graphics/colormasks.h"
+#include "graphics/surface.h"
+
+#include "petka/flc.h"
+#include "petka/petka.h"
+#include "petka/video.h"
+#include "petka/q_system.h"
+#include "petka/q_manager.h"
+#include "petka/objects/object_bg.h"
+
+namespace Petka {
+
+void QObjectBG::processMessage(const QMessage &msg) {
+	QMessageObject::processMessage(msg);
+	switch (msg.opcode) {
+	case kSet:
+		_resourceId = msg.arg1;
+	case kMusic:
+		_musicId = msg.arg1;
+		break;
+	case kBGsFX:
+		_fxId = msg.arg1;
+		break;
+	case kMap:
+		_showMap = msg.arg1 != 0;
+		break;
+	case kNoMap:
+		_showMap = 0;
+		break;
+	case kGoTo:
+		break;
+	case kSetSeq:
+		break;
+	case kEndSeq:
+		break;
+	}
+
+}
+
+void QObjectBG::draw() {
+	Graphics::Surface *s = g_vm->resMgr()->loadBitmap(_resourceId);
+	if (s) {
+		const Common::List<Common::Rect> &dirty = g_vm->videoSystem()->rects();
+		for (Common::List<Common::Rect>::const_iterator it = dirty.begin(); it != dirty.end(); ++it) {
+			g_vm->videoSystem()->screen().blitFrom(*s, *it, Common::Point(it->left, it->top));
+		}
+	}
+}
+
+}
diff --git a/engines/petka/objects/object_bg.h b/engines/petka/objects/object_bg.h
new file mode 100644
index 0000000000..d7fe99612e
--- /dev/null
+++ b/engines/petka/objects/object_bg.h
@@ -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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_OBJECT_BG_H
+#define PETKA_OBJECT_BG_H
+
+#include "petka/objects/object.h"
+
+namespace Petka {
+
+class QObjectBG : public QMessageObject {
+public:
+	void processMessage(const QMessage &msg) override;
+	void draw() override;
+
+public:
+	int _showMap;
+	int _fxId;
+	int _musicId;
+};
+
+} // End of namespace Petka
+
+#endif
\ No newline at end of file
diff --git a/engines/petka/objects/object_case.cpp b/engines/petka/objects/object_case.cpp
new file mode 100644
index 0000000000..db57b3c393
--- /dev/null
+++ b/engines/petka/objects/object_case.cpp
@@ -0,0 +1,28 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "petka/objects/object_case.h"
+
+namespace Petka {
+
+
+}
diff --git a/engines/petka/objects/object_case.h b/engines/petka/objects/object_case.h
new file mode 100644
index 0000000000..062942cf38
--- /dev/null
+++ b/engines/petka/objects/object_case.h
@@ -0,0 +1,36 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_OBJECT_CASE_H
+#define PETKA_OBJECT_CASE_H
+
+#include "petka/objects/object.h"
+
+namespace Petka {
+
+class QObjectCase : public QObject {
+
+};
+
+} // End of namespace Petka
+
+#endif
diff --git a/engines/petka/objects/object_cursor.cpp b/engines/petka/objects/object_cursor.cpp
new file mode 100644
index 0000000000..52ad0caf82
--- /dev/null
+++ b/engines/petka/objects/object_cursor.cpp
@@ -0,0 +1,112 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/ini-file.h"
+#include "common/stream.h"
+#include "common/system.h"
+#include "common/events.h"
+
+#include "graphics/colormasks.h"
+#include "graphics/surface.h"
+
+#include "petka/flc.h"
+#include "petka/petka.h"
+#include "petka/video.h"
+#include "petka/q_system.h"
+#include "petka/q_manager.h"
+#include "petka/objects/object_cursor.h"
+
+namespace Petka {
+
+QObjectCursor::QObjectCursor() {
+	_id = 4097;
+	_z = 1000;
+	_resourceId = 5002;
+	Common::Point pos = g_vm->getEventManager()->getMousePos();
+	_x = pos.x;
+	_y = pos.y;
+	g_vm->resMgr()->loadFlic(5002);
+}
+
+void QObjectCursor::draw() {
+	if (!_isShown) {
+		return;
+	}
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+	const Graphics::Surface *frame = flc->getCurrentFrame();
+	if (frame) {
+		Graphics::Surface *s = frame->convertTo(g_system->getScreenFormat(), flc->getPalette());
+		Common::Rect srcRect(flc->getBounds());
+		srcRect.translate(_x, _y);
+		srcRect.clip(640, 480);
+		Common::Rect destRect(srcRect);
+		srcRect.translate(-_x, -_y);
+		g_vm->videoSystem()->screen().transBlitFrom(*s, srcRect, destRect, flc->getTransColor(s->format));
+		s->free();
+		delete s;
+	}
+}
+
+void QObjectCursor::update() {
+	if (!_isShown || !_animate)
+		return;
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+	while (flc && flc->needsUpdate()) {
+		flc->decodeNextFrame();
+		if (flc->endOfVideo()) {
+			flc->rewind();
+		}
+		Common::Rect dirty(flc->getBounds());
+		dirty.translate(_x, _y);
+		g_vm->videoSystem()->addDirtyRect(dirty);
+	}
+}
+
+void QObjectCursor::setCursorPos(int x, int y, bool center) {
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+	if (!_animate) {
+		flc->stop();
+		flc->rewind();
+		flc->decodeNextFrame();
+	} else if (!flc->isPlaying()) {
+		flc->rewind();
+		flc->start();
+	}
+
+	Common::Rect dirty(flc->getBounds());
+	dirty.translate(_x, _y);
+	g_vm->videoSystem()->addDirtyRect(dirty);
+
+	if (center) {
+		x = x - flc->getBounds().left - dirty.width() / 2;
+		y = y - flc->getBounds().top - dirty.height() / 2;
+	}
+
+	_x = x;
+	_y = y;
+
+	dirty = flc->getBounds();
+	dirty.translate(_x, _y);
+	g_vm->videoSystem()->addDirtyRect(dirty);
+}
+
+}
diff --git a/engines/petka/objects/object_cursor.h b/engines/petka/objects/object_cursor.h
new file mode 100644
index 0000000000..7f658388f0
--- /dev/null
+++ b/engines/petka/objects/object_cursor.h
@@ -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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_OBJECT_CURSOR_H
+#define PETKA_OBJECT_CURSOR_H
+
+#include "petka/objects/object.h"
+
+namespace Petka {
+
+class QObjectCursor : public QObject {
+public:
+	QObjectCursor();
+
+	void setCursorPos(int x, int y, bool center);
+	void update() override;
+	void draw() override;
+
+private:
+
+};
+
+} // End of naespace Petka
+
+#endif
diff --git a/engines/petka/objects/object_star.cpp b/engines/petka/objects/object_star.cpp
new file mode 100644
index 0000000000..8d228fe04e
--- /dev/null
+++ b/engines/petka/objects/object_star.cpp
@@ -0,0 +1,28 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "petka/objects/object_star.h"
+
+namespace Petka {
+
+
+}
diff --git a/engines/petka/objects/object_star.h b/engines/petka/objects/object_star.h
new file mode 100644
index 0000000000..5d30f61686
--- /dev/null
+++ b/engines/petka/objects/object_star.h
@@ -0,0 +1,36 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_OBJECT_STAR_H
+#define PETKA_OBJECT_STAR_H
+
+#include "petka/objects/object.h"
+
+namespace Petka {
+
+class QObjectStar : public QObject {
+
+};
+
+} // End of namespace Petka
+
+#endif
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index ee9d386952..d24cd0e96a 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -30,6 +30,9 @@
 #include "petka/interfaces/main.h"
 #include "petka/interfaces/save_load.h"
 #include "petka/interfaces/panel.h"
+#include "petka/objects/object_cursor.h"
+#include "petka/objects/object_case.h"
+#include "petka/objects/object_star.h"
 #include "petka/q_system.h"
 
 namespace Petka {
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index 2f86ab7599..8b053a4d56 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -26,7 +26,7 @@
 #include "common/ptr.h"
 #include "common/list.h"
 
-#include "petka/obj.h"
+#include "petka/objects/object_bg.h"
 
 namespace Petka {
 
diff --git a/engines/petka/video.cpp b/engines/petka/video.cpp
index 0e03fbbf00..8f9563ac51 100644
--- a/engines/petka/video.cpp
+++ b/engines/petka/video.cpp
@@ -26,7 +26,7 @@
 #include "petka/petka.h"
 #include "petka/q_system.h"
 #include "petka/interfaces/interface.h"
-#include "petka/obj.h"
+#include "petka/objects/object.h"
 #include "petka/video.h"
 
 namespace Petka {


Commit: 313b3b5d31a256baccf1c13d52ae13b290fddc42
    https://github.com/scummvm/scummvm/commit/313b3b5d31a256baccf1c13d52ae13b290fddc42
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented AVI opcode

Changed paths:
    engines/petka/objects/object.cpp


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index 6a743e3be6..92bef30754 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -81,6 +81,11 @@ void QMessageObject::processMessage(const QMessage &msg) {
 	}
 
 	switch (msg.opcode) {
+	case kAvi: {
+		Common::String videoName = g_vm->resMgr()->findResourceName((uint16)msg.arg1);
+		g_vm->playVideo(g_vm->openFile(videoName, false));
+		break;
+	}
 	case kSet:
 	case kPlay:
 		if (dynamic_cast<QObjectBG *>(this)) {


Commit: 47984f1471374974f3342e4190af369d02cf5f02
    https://github.com/scummvm/scummvm/commit/47984f1471374974f3342e4190af369d02cf5f02
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented starting a new game

Changed paths:
    engines/petka/interfaces/main.cpp
    engines/petka/interfaces/main.h
    engines/petka/interfaces/panel.cpp
    engines/petka/interfaces/startup.cpp
    engines/petka/petka.cpp
    engines/petka/petka.h
    engines/petka/q_system.cpp


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index 0a87858ab9..4e83d4b9d5 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -45,7 +45,7 @@ InterfaceMain::InterfaceMain() {
 		_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[i]);
+			QMessageObject *obj = g_vm->getQSystem()->findObject(_bgs[i].attachedObjIds[j]);
 			obj->_x = stream->readSint32LE();
 			obj->_y = stream->readSint32LE();
 			obj->_z = stream->readSint32LE();
@@ -55,5 +55,37 @@ InterfaceMain::InterfaceMain() {
 	}
 }
 
+void InterfaceMain::start() {
+	g_vm->getQSystem()->update();
+	g_vm->getQSystem()->_field48 = 0;
+
+	loadRoom(g_vm->getQSystem()->findObject("Seq - INTRO0")->_id, false);
+}
+
+void InterfaceMain::loadRoom(int id, bool fromSave) {
+	stop();
+	_roomId = id;
+	const BGInfo *info = findBGInfo(id);
+	QObjectBG *room = (QObjectBG *)g_vm->getQSystem()->findObject(info->objId);
+	g_vm->resMgr()->loadBitmap(room->_resourceId);
+	_objs.push_back(room);
+	for (uint i = 0; i < info->attachedObjIds.size(); ++i) {
+		QMessageObject *obj = g_vm->getQSystem()->findObject(info->attachedObjIds[i]);
+		g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(obj->_resourceId), Audio::Mixer::kSFXSoundType);
+		if (obj->_isShown || obj->_isActive)
+			g_vm->resMgr()->loadFlic(obj->_resourceId);
+	}
+	if (!fromSave)
+		g_vm->getQSystem()->addMessageForAllObjects(kInitBG, 0, 0, 0, 0, room);
+}
+
+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;
+}
+
 } // End of namespace Petka
 
diff --git a/engines/petka/interfaces/main.h b/engines/petka/interfaces/main.h
index 8aa5f1df44..3a9e25f08e 100644
--- a/engines/petka/interfaces/main.h
+++ b/engines/petka/interfaces/main.h
@@ -36,8 +36,15 @@ class InterfaceMain : public Interface {
 public:
 	InterfaceMain();
 
+	void start() override;
+
+	void loadRoom(int id, bool fromSave);
+
+	const BGInfo *findBGInfo(int id) const;
+
 public:
 	Common::Array<BGInfo> _bgs;
+	int _roomId;
 };
 
 } // End of namespace Petka
diff --git a/engines/petka/interfaces/panel.cpp b/engines/petka/interfaces/panel.cpp
index 60f8d14a9b..b085bd572a 100644
--- a/engines/petka/interfaces/panel.cpp
+++ b/engines/petka/interfaces/panel.cpp
@@ -124,6 +124,7 @@ void InterfacePanel::onLeftButtonDown(const Common::Point p) {
 	}
 	switch (i) {
 	case kNewGameButtonIndex:
+		g_vm->loadPart(1);
 		break;
 	case kLoadButtonIndex:
 		g_vm->getQSystem()->_saveLoadInterface->startSaveLoad(0);
diff --git a/engines/petka/interfaces/startup.cpp b/engines/petka/interfaces/startup.cpp
index b2f12e3b97..2f0352e047 100644
--- a/engines/petka/interfaces/startup.cpp
+++ b/engines/petka/interfaces/startup.cpp
@@ -98,7 +98,7 @@ void InterfaceStartup::onLeftButtonDown(const Common::Point p) {
 		g_vm->getQSystem()->_saveLoadInterface->startSaveLoad(0);
 		break;
 	case kNewGame:
-
+		g_vm->loadPart(1);
 		break;
 	}
 }
diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
index 600d678ff1..f9ae5a1ee3 100644
--- a/engines/petka/petka.cpp
+++ b/engines/petka/petka.cpp
@@ -75,15 +75,10 @@ Common::Error PetkaEngine::run() {
 
 	_console.reset(new Console(this));
 	_fileMgr.reset(new FileMgr());
-	_resMgr.reset(new QManager(*this));
 	_soundMgr.reset(new SoundMgr());
 	_vsys.reset(new VideoSystem());
-	_qsystem.reset(new QSystem());
 
-	loadStores();
-	if (!_resMgr->init())
-		return Common::kNoGameDataFoundError;
-	_qsystem->init();
+	loadPart(0);
 
 	while (!shouldQuit()) {
 		Common::Event event;
@@ -109,6 +104,7 @@ Common::Error PetkaEngine::run() {
 				break;
 			}
 		}
+		_qsystem->update();
 		_vsys->update();
 		_system->delayMillis(20);
 	}
@@ -206,4 +202,20 @@ VideoSystem *PetkaEngine::videoSystem() const {
 	return _vsys.get();
 }
 
+byte PetkaEngine::getPart() {
+	return _part;
+}
+
+void PetkaEngine::loadPart(byte part) {
+	_part = part;
+
+	_soundMgr->removeAll();
+	loadStores();
+
+	_resMgr.reset(new QManager(*this));
+	_resMgr->init();
+	_qsystem.reset(new QSystem());
+	_qsystem->init();
+}
+
 } // End of namespace Petka
diff --git a/engines/petka/petka.h b/engines/petka/petka.h
index c556644951..c595e24a87 100644
--- a/engines/petka/petka.h
+++ b/engines/petka/petka.h
@@ -53,19 +53,20 @@ public:
 	PetkaEngine(OSystem *syst, const ADGameDescription *desc);
 	~PetkaEngine();
 
+	void loadPart(byte part);
+	byte getPart();
+
 	virtual Common::Error run();
 
 	Common::SeekableReadStream *openFile(const Common::String &name, bool addCurrentPath);
 
 	void playVideo(Common::SeekableReadStream *stream);
-
 	QSystem *getQSystem() const;
 	SoundMgr *soundMgr() const;
 	QManager *resMgr() const;
 	VideoSystem *videoSystem() const;
 
 	Common::RandomSource &getRnd();
-
 private:
 	void loadStores();
 
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index d24cd0e96a..0367155f95 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -134,8 +134,14 @@ bool QSystem::init() {
 	_mainInterface.reset(new InterfaceMain());
 	_startupInterface.reset(new InterfaceStartup());
 	_saveLoadInterface.reset(new InterfaceSaveLoad());
-	_startupInterface->start();
-	_prevInterface = _currInterface = _startupInterface.get();
+	_panelInterface.reset(new InterfacePanel());
+	if (g_vm->getPart() == 0) {
+		_startupInterface->start();
+		_prevInterface = _currInterface = _startupInterface.get();
+	} else {
+		_mainInterface->start();
+		_prevInterface = _currInterface = _mainInterface.get();
+	}
 	return true;
 }
 


Commit: 6ed94fc08d2427493e46298d8c6ebdd28358bf4b
    https://github.com/scummvm/scummvm/commit/6ed94fc08d2427493e46298d8c6ebdd28358bf4b
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented MUSIC and BGsFX opcodes

Changed paths:
    engines/petka/interfaces/main.cpp
    engines/petka/q_system.h
    engines/petka/sound.cpp


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index 4e83d4b9d5..d2975fbfed 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -63,10 +63,11 @@ void InterfaceMain::start() {
 }
 
 void InterfaceMain::loadRoom(int id, bool fromSave) {
+	QSystem *sys = g_vm->getQSystem();
 	stop();
 	_roomId = id;
 	const BGInfo *info = findBGInfo(id);
-	QObjectBG *room = (QObjectBG *)g_vm->getQSystem()->findObject(info->objId);
+	QObjectBG *room = (QObjectBG *)sys->findObject(info->objId);
 	g_vm->resMgr()->loadBitmap(room->_resourceId);
 	_objs.push_back(room);
 	for (uint i = 0; i < info->attachedObjIds.size(); ++i) {
@@ -75,6 +76,16 @@ void InterfaceMain::loadRoom(int id, bool fromSave) {
 		if (obj->_isShown || obj->_isActive)
 			g_vm->resMgr()->loadFlic(obj->_resourceId);
 	}
+	if (sys->_musicId != room->_musicId) {
+		g_vm->soundMgr()->removeSound(g_vm->resMgr()->findSoundName(sys->_musicId));
+		g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(room->_musicId), Audio::Mixer::kMusicSoundType)->play(true);
+		sys->_musicId = room->_musicId;
+	}
+	if (sys->_fxId != room->_fxId) {
+		g_vm->soundMgr()->removeSound(g_vm->resMgr()->findSoundName(sys->_fxId));
+		g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(room->_fxId), Audio::Mixer::kSFXSoundType)->play(true);
+		sys->_fxId = room->_fxId;
+	}
 	if (!fromSave)
 		g_vm->getQSystem()->addMessageForAllObjects(kInitBG, 0, 0, 0, 0, room);
 }
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index 8b053a4d56..2e6440b8fc 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -72,6 +72,8 @@ public:
 	Interface *_prevInterface;
 
 	int _field48;
+	int _fxId;
+	int _musicId;
 };
 
 } // End of namespace Petka
diff --git a/engines/petka/sound.cpp b/engines/petka/sound.cpp
index 47b9a04606..9bffed939a 100644
--- a/engines/petka/sound.cpp
+++ b/engines/petka/sound.cpp
@@ -39,6 +39,8 @@ Sound::~Sound() {
 }
 
 void Sound::play(bool isLoop) {
+	if (!_stream)
+		return;
 	stop();
 
 	Audio::AudioStream *audioStream;


Commit: d4979f659ad398e40efd22e0a67c1542ad80a1d0
    https://github.com/scummvm/scummvm/commit/d4979f659ad398e40efd22e0a67c1542ad80a1d0
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented ON and OFF opcodes

Changed paths:
    engines/petka/objects/object.cpp
    engines/petka/objects/object.h


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index 92bef30754..ecbf49be40 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -103,6 +103,14 @@ void QMessageObject::processMessage(const QMessage &msg) {
 	case kStatus:
 		_status = (int8) msg.arg1;
 		break;
+	case kOn:
+		_isActive = true;
+		show(true);
+		break;
+	case kOff:
+		_isActive = false;
+		show(false);
+		break;
 	case kHide:
 		break;
 	case kZBuffer:
diff --git a/engines/petka/objects/object.h b/engines/petka/objects/object.h
index 34d7de8446..06dfdefb91 100644
--- a/engines/petka/objects/object.h
+++ b/engines/petka/objects/object.h
@@ -34,6 +34,7 @@ public:
 
 	virtual void draw() {};
 	virtual void update() {};
+	virtual void show(bool v) {};
 	virtual bool isInPoint(int x, int y) { return false; }
 
 public:


Commit: c2e4d284bbd2e5cf18eced9bf8724c7cd7cf2630
    https://github.com/scummvm/scummvm/commit/c2e4d284bbd2e5cf18eced9bf8724c7cd7cf2630
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added ZBUFFER opcode

Changed paths:
    engines/petka/objects/object.cpp
    engines/petka/objects/object.h


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index ecbf49be40..d223f8505e 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -114,6 +114,8 @@ void QMessageObject::processMessage(const QMessage &msg) {
 	case kHide:
 		break;
 	case kZBuffer:
+		_updateZ = msg.arg1;
+		_z = (msg.arg2 != -1) ? msg.arg2 : _z;
 		break;
 	case kPassive:
 		break;
diff --git a/engines/petka/objects/object.h b/engines/petka/objects/object.h
index 06dfdefb91..920a98268f 100644
--- a/engines/petka/objects/object.h
+++ b/engines/petka/objects/object.h
@@ -59,7 +59,7 @@ public:
 	int32 _field28;
 	int32 _isShown;
 	int32 _animate;
-	int _field_34;
+	int _updateZ;
 	int _field_38;
 	int _isActive;
 	int _startSound;


Commit: 1cf2d822760dad788acd71586fe2f305740e512b
    https://github.com/scummvm/scummvm/commit/1cf2d822760dad788acd71586fe2f305740e512b
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented STOP opcode

Changed paths:
    engines/petka/objects/object.cpp


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index d223f8505e..06dad79643 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -33,7 +33,8 @@
 #include "petka/video.h"
 #include "petka/q_system.h"
 #include "petka/q_manager.h"
-#include "petka/objects/object.h"
+#include "petka/objects/object_star.h"
+#include "petka/objects/object_cursor.h"
 
 namespace Petka {
 
@@ -111,6 +112,9 @@ void QMessageObject::processMessage(const QMessage &msg) {
 		_isActive = false;
 		show(false);
 		break;
+	case kStop:
+		g_vm->getQSystem()->_cursor.get()->show(msg.arg1);
+		g_vm->getQSystem()->_star.get()->_isActive = msg.arg1;
 	case kHide:
 		break;
 	case kZBuffer:


Commit: 81ebc4193fda44f9b62ef68bf4a586243a42423c
    https://github.com/scummvm/scummvm/commit/81ebc4193fda44f9b62ef68bf4a586243a42423c
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added basic implementation of GoTo opcode(change room)

Changed paths:
    engines/petka/objects/object_bg.cpp


diff --git a/engines/petka/objects/object_bg.cpp b/engines/petka/objects/object_bg.cpp
index ee31375db0..007c51b2b9 100644
--- a/engines/petka/objects/object_bg.cpp
+++ b/engines/petka/objects/object_bg.cpp
@@ -33,6 +33,7 @@
 #include "petka/video.h"
 #include "petka/q_system.h"
 #include "petka/q_manager.h"
+#include "petka/interfaces/main.h"
 #include "petka/objects/object_bg.h"
 
 namespace Petka {
@@ -55,6 +56,8 @@ void QObjectBG::processMessage(const QMessage &msg) {
 		_showMap = 0;
 		break;
 	case kGoTo:
+		g_vm->getQSystem()->_mainInterface->loadRoom(_id, false);
+		g_vm->videoSystem()->addDirtyRect(Common::Rect(640, 480));
 		break;
 	case kSetSeq:
 		break;


Commit: 22abfc0245da441d34efd83666eed29a37991099
    https://github.com/scummvm/scummvm/commit/22abfc0245da441d34efd83666eed29a37991099
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented handling z coordinate of objects

Changed paths:
    engines/petka/objects/object.cpp
    engines/petka/objects/object.h
    engines/petka/objects/object_bg.cpp
    engines/petka/objects/object_bg.h
    engines/petka/video.cpp


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index 06dad79643..c6be92b776 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -169,4 +169,19 @@ void QObject::draw() {
 	delete s;
 }
 
+void QObject::updateZ() {
+	if (!_animate || !_isShown || !_updateZ)
+		return;
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+	if (flc) {
+		_z = 1;
+		const Common::Array<Common::Rect> rects = flc->getMskRects();
+		for (uint i = 0; i < rects.size(); ++i) {
+			if (_y + rects[i].bottom > _z)
+				_z = _y + rects[i].bottom;
+		}
+
+	}
+}
+
 }
\ No newline at end of file
diff --git a/engines/petka/objects/object.h b/engines/petka/objects/object.h
index 920a98268f..f4abec1829 100644
--- a/engines/petka/objects/object.h
+++ b/engines/petka/objects/object.h
@@ -34,6 +34,7 @@ public:
 
 	virtual void draw() {};
 	virtual void update() {};
+	virtual void updateZ() {};
 	virtual void show(bool v) {};
 	virtual bool isInPoint(int x, int y) { return false; }
 
@@ -77,6 +78,7 @@ public:
 class QObject : public QMessageObject {
 public:
 	void draw() override;
+	void updateZ() override;
 	bool isInPoint(int x, int y) override;
 };
 
diff --git a/engines/petka/objects/object_bg.cpp b/engines/petka/objects/object_bg.cpp
index 007c51b2b9..e75079aa28 100644
--- a/engines/petka/objects/object_bg.cpp
+++ b/engines/petka/objects/object_bg.cpp
@@ -38,6 +38,10 @@
 
 namespace Petka {
 
+QObjectBG::QObjectBG() {
+	_z = 0;
+}
+
 void QObjectBG::processMessage(const QMessage &msg) {
 	QMessageObject::processMessage(msg);
 	switch (msg.opcode) {
diff --git a/engines/petka/objects/object_bg.h b/engines/petka/objects/object_bg.h
index d7fe99612e..0020eee8f4 100644
--- a/engines/petka/objects/object_bg.h
+++ b/engines/petka/objects/object_bg.h
@@ -29,6 +29,7 @@ namespace Petka {
 
 class QObjectBG : public QMessageObject {
 public:
+	QObjectBG();
 	void processMessage(const QMessage &msg) override;
 	void draw() override;
 
diff --git a/engines/petka/video.cpp b/engines/petka/video.cpp
index 8f9563ac51..689a174ff8 100644
--- a/engines/petka/video.cpp
+++ b/engines/petka/video.cpp
@@ -36,12 +36,23 @@ VideoSystem::VideoSystem() :
 	addDirtyRect({0, 0, 640, 480});
 }
 
+static bool objCmp(QVisibleObject *&l, QVisibleObject *&r) {
+	return l->_z < r->_z;
+}
+
 void VideoSystem::update() {
 	Interface *interface = g_vm->getQSystem()->_currInterface;
 	if (interface) {
 		for (uint i = 0; i < interface->_objs.size(); ++i) {
 			interface->_objs[i]->update();
 		}
+
+		for (uint i = 0; i < interface->_objs.size(); ++i) {
+			interface->_objs[i]->updateZ();
+		}
+
+		Common::sort(interface->_objs.begin(), interface->_objs.end(), objCmp);
+
 		for (uint i = 0; i < interface->_objs.size(); ++i) {
 			interface->_objs[i]->draw();
 		}


Commit: 586cbd970fdf3034243ddab2dc966de7dc8c1275
    https://github.com/scummvm/scummvm/commit/586cbd970fdf3034243ddab2dc966de7dc8c1275
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented cursor show method

Changed paths:
    engines/petka/objects/object.cpp
    engines/petka/objects/object.h
    engines/petka/objects/object_cursor.cpp
    engines/petka/objects/object_cursor.h


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index c6be92b776..b9e80731f8 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -127,6 +127,10 @@ void QMessageObject::processMessage(const QMessage &msg) {
 
 }
 
+void QMessageObject::show(bool v) {
+	_isShown = v;
+}
+
 bool QObject::isInPoint(int x, int y) {
 	if (_isActive)
 		return false;
diff --git a/engines/petka/objects/object.h b/engines/petka/objects/object.h
index f4abec1829..5eec131ac6 100644
--- a/engines/petka/objects/object.h
+++ b/engines/petka/objects/object.h
@@ -48,6 +48,7 @@ class QMessageObject : public QVisibleObject {
 public:
 	QMessageObject();
 
+	void show(bool v) override;
 	virtual void processMessage(const QMessage &msg);
 
 public:
diff --git a/engines/petka/objects/object_cursor.cpp b/engines/petka/objects/object_cursor.cpp
index 52ad0caf82..6cd0451370 100644
--- a/engines/petka/objects/object_cursor.cpp
+++ b/engines/petka/objects/object_cursor.cpp
@@ -109,4 +109,12 @@ void QObjectCursor::setCursorPos(int x, int y, bool center) {
 	g_vm->videoSystem()->addDirtyRect(dirty);
 }
 
+void QObjectCursor::show(bool v) {
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+	Common::Rect rect = flc->getBounds();
+	rect.translate(_x, _y);
+	g_vm->videoSystem()->addDirtyRect(rect);
+	QMessageObject::show(v);
+}
+
 }
diff --git a/engines/petka/objects/object_cursor.h b/engines/petka/objects/object_cursor.h
index 7f658388f0..930b6e1200 100644
--- a/engines/petka/objects/object_cursor.h
+++ b/engines/petka/objects/object_cursor.h
@@ -34,6 +34,7 @@ public:
 	void setCursorPos(int x, int y, bool center);
 	void update() override;
 	void draw() override;
+	void show(bool v) override;
 
 private:
 


Commit: 703a0efe0c5249e1c213db50d4236c07a4beda61
    https://github.com/scummvm/scummvm/commit/703a0efe0c5249e1c213db50d4236c07a4beda61
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented object show method

Changed paths:
    engines/petka/objects/object.cpp
    engines/petka/objects/object.h


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index b9e80731f8..0364151190 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -35,6 +35,7 @@
 #include "petka/q_manager.h"
 #include "petka/objects/object_star.h"
 #include "petka/objects/object_cursor.h"
+#include "petka/interfaces/main.h"
 
 namespace Petka {
 
@@ -188,4 +189,18 @@ void QObject::updateZ() {
 	}
 }
 
+void QObject::show(bool v) {
+	const Common::Array<QVisibleObject*> & objs = g_vm->getQSystem()->_mainInterface->_objs;
+	for (uint i = 0; i < objs.size(); ++i) {
+		if (objs[i]->_resourceId == _resourceId) {
+			FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+			if (flc) {
+				g_vm->videoSystem()->addDirtyRect(Common::Point(_x, _y), *flc);
+			}
+			break;
+		}
+	}
+	QMessageObject::show(v);
+}
+
 }
\ No newline at end of file
diff --git a/engines/petka/objects/object.h b/engines/petka/objects/object.h
index 5eec131ac6..473f4c27c9 100644
--- a/engines/petka/objects/object.h
+++ b/engines/petka/objects/object.h
@@ -81,6 +81,7 @@ public:
 	void draw() override;
 	void updateZ() override;
 	bool isInPoint(int x, int y) override;
+	void show(bool v) override;
 };
 
 } // End of namespace Petka


Commit: 06d99e210f4be8dbb61cc6b98987506a5aeb234e
    https://github.com/scummvm/scummvm/commit/06d99e210f4be8dbb61cc6b98987506a5aeb234e
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: reworked object updating

Changed paths:
    engines/petka/flc.cpp
    engines/petka/flc.h
    engines/petka/interfaces/startup.cpp
    engines/petka/objects/object.cpp
    engines/petka/objects/object.h
    engines/petka/objects/object_cursor.cpp
    engines/petka/objects/object_cursor.h
    engines/petka/video.cpp
    engines/petka/video.h


diff --git a/engines/petka/flc.cpp b/engines/petka/flc.cpp
index 9af7b952df..6ca25c89be 100644
--- a/engines/petka/flc.cpp
+++ b/engines/petka/flc.cpp
@@ -80,7 +80,7 @@ const Common::Array<Common::Rect> &FlicDecoder::getMskRects() const {
 uint32 FlicDecoder::getTransColor(const Graphics::PixelFormat &fmt) const {
 	const Track *track = getTrack(0);
 	if (track) {
-		const FlicVideoTrack *flc = ((FlicVideoTrack *) track);
+		const FlicVideoTrack *flc = ((FlicVideoTrack *)track);
 		byte r = flc->getPalette()[0];
 		byte g = flc->getPalette()[1];
 		byte b = flc->getPalette()[2];
@@ -90,16 +90,31 @@ uint32 FlicDecoder::getTransColor(const Graphics::PixelFormat &fmt) const {
 }
 
 void FlicDecoder::setFrame(int frame) {
-	FlicVideoTrack *flc = ((FlicVideoTrack *) getTrack(0));
+	FlicVideoTrack *flc = ((FlicVideoTrack *)getTrack(0));
 	if (!flc || flc->getCurFrame() + 1 == frame)
 		return;
 
+	if (frame == -1) {
+		if (flc->getCurFrame() + 1 == flc->getFrameCount()) {
+			flc->rewind();
+		}
+		flc->decodeNextFrame();
+		return;
+	}
+
 	flc->rewind();
 	do {
 		flc->decodeNextFrame();
 	} while (flc->getCurFrame() + 1 != frame);
 }
 
+uint FlicDecoder::getDelay() const {
+	FlicVideoTrack *flc = ((FlicVideoTrack *)getTrack(0));
+	if (flc)
+		return flc->getDelay();
+	return 0;
+}
+
 FlicDecoder::FlicVideoTrack::FlicVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height, bool skipHeader)
 	: Video::FlicDecoder::FlicVideoTrack(stream, frameCount, width, height, skipHeader) {}
 
@@ -155,4 +170,8 @@ const Common::Array<Common::Rect> &FlicDecoder::FlicVideoTrack::getMskRects() co
 	return _msk[_curFrame];
 }
 
+uint FlicDecoder::FlicVideoTrack::getDelay() const {
+	return _frameDelay;
+}
+
 } // End of namespace Petka
diff --git a/engines/petka/flc.h b/engines/petka/flc.h
index d4853d2a96..a5f6939af7 100644
--- a/engines/petka/flc.h
+++ b/engines/petka/flc.h
@@ -33,6 +33,7 @@ public:
 
 	void setFrame(int frame);
 
+	uint getDelay() const;
 	const Common::Rect &getBounds() const;
 	const Common::Array<Common::Rect> &getMskRects() const;
 	const Graphics::Surface *getCurrentFrame() const;
@@ -45,6 +46,7 @@ protected:
 
 		bool loadMsk(Common::SeekableReadStream &stream);
 
+		uint getDelay() const;
 		const Common::Rect &getBounds() const;
 		const Common::Array<Common::Rect> &getMskRects() const;
 		const Graphics::Surface *getSurface() const;
diff --git a/engines/petka/interfaces/startup.cpp b/engines/petka/interfaces/startup.cpp
index 2f0352e047..adc1d50190 100644
--- a/engines/petka/interfaces/startup.cpp
+++ b/engines/petka/interfaces/startup.cpp
@@ -77,7 +77,7 @@ void InterfaceStartup::start() {
 
 
 	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
-	cursor->_resourceId = 5007;
+	cursor->_resourceId = 4901;
 	cursor->_isShown = true;
 	cursor->_animate = false;
 	_objs.push_back(g_vm->getQSystem()->_cursor.get());
@@ -119,9 +119,7 @@ void InterfaceStartup::onMouseMove(const Common::Point p) {
 					_objUnderCursor = obj;
 				}
 				obj->_isShown = clicked;
-				if (flc->getCurFrame() == -1) {
-					flc->decodeNextFrame();
-				}
+				flc->setFrame(1);
 				Common::Rect dirty(flc->getBounds());
 				dirty.translate(obj->_x, obj->_y);
 				g_vm->videoSystem()->addDirtyRect(dirty);
diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index 0364151190..39c07f1129 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -43,7 +43,7 @@ QVisibleObject::QVisibleObject()
 	: _resourceId(-1), _z(240) {}
 
 QMessageObject::QMessageObject()
-	: _id(-1), _dialogColor(-1) {}
+	: _id(-1), _dialogColor(-1), _time(0) {}
 
 void QMessageObject::processMessage(const QMessage &msg) {
 	for (uint i = 0; i < _reactions.size(); ++i) {
diff --git a/engines/petka/objects/object.h b/engines/petka/objects/object.h
index 473f4c27c9..b21b4884af 100644
--- a/engines/petka/objects/object.h
+++ b/engines/petka/objects/object.h
@@ -33,7 +33,7 @@ public:
 	virtual ~QVisibleObject() {};
 
 	virtual void draw() {};
-	virtual void update() {};
+	virtual void update(int time) {};
 	virtual void updateZ() {};
 	virtual void show(bool v) {};
 	virtual bool isInPoint(int x, int y) { return false; }
@@ -56,6 +56,7 @@ public:
 	int32 _y;
 	int32 _field14;
 	int32 _field18;
+	int32 _time;
 	int32 _field20;
 	int32 _field24;
 	int32 _field28;
diff --git a/engines/petka/objects/object_cursor.cpp b/engines/petka/objects/object_cursor.cpp
index 6cd0451370..4ab77e2907 100644
--- a/engines/petka/objects/object_cursor.cpp
+++ b/engines/petka/objects/object_cursor.cpp
@@ -66,30 +66,24 @@ void QObjectCursor::draw() {
 	}
 }
 
-void QObjectCursor::update() {
+void QObjectCursor::update(int time) {
 	if (!_isShown || !_animate)
 		return;
 	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
-	while (flc && flc->needsUpdate()) {
-		flc->decodeNextFrame();
-		if (flc->endOfVideo()) {
-			flc->rewind();
-		}
+	_time += time;
+	while (flc && _time > flc->getDelay()) {
+		flc->setFrame(-1);
 		Common::Rect dirty(flc->getBounds());
 		dirty.translate(_x, _y);
 		g_vm->videoSystem()->addDirtyRect(dirty);
+		_time -= flc->getDelay();
 	}
 }
 
 void QObjectCursor::setCursorPos(int x, int y, bool center) {
 	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
 	if (!_animate) {
-		flc->stop();
-		flc->rewind();
-		flc->decodeNextFrame();
-	} else if (!flc->isPlaying()) {
-		flc->rewind();
-		flc->start();
+		flc->setFrame(1);
 	}
 
 	Common::Rect dirty(flc->getBounds());
diff --git a/engines/petka/objects/object_cursor.h b/engines/petka/objects/object_cursor.h
index 930b6e1200..b60db5f6f3 100644
--- a/engines/petka/objects/object_cursor.h
+++ b/engines/petka/objects/object_cursor.h
@@ -32,7 +32,7 @@ public:
 	QObjectCursor();
 
 	void setCursorPos(int x, int y, bool center);
-	void update() override;
+	void update(int time) override;
 	void draw() override;
 	void show(bool v) override;
 
diff --git a/engines/petka/video.cpp b/engines/petka/video.cpp
index 689a174ff8..6249287c7b 100644
--- a/engines/petka/video.cpp
+++ b/engines/petka/video.cpp
@@ -32,7 +32,7 @@
 namespace Petka {
 
 VideoSystem::VideoSystem() :
-	_shake(false), _shift(false), _shakeTime(0) {
+	_shake(false), _shift(false), _shakeTime(0), _time(0) {
 	addDirtyRect({0, 0, 640, 480});
 }
 
@@ -42,9 +42,10 @@ static bool objCmp(QVisibleObject *&l, QVisibleObject *&r) {
 
 void VideoSystem::update() {
 	Interface *interface = g_vm->getQSystem()->_currInterface;
+	int time = g_system->getMillis();
 	if (interface) {
 		for (uint i = 0; i < interface->_objs.size(); ++i) {
-			interface->_objs[i]->update();
+			interface->_objs[i]->update(time - _time);
 		}
 
 		for (uint i = 0; i < interface->_objs.size(); ++i) {
@@ -57,7 +58,7 @@ void VideoSystem::update() {
 			interface->_objs[i]->draw();
 		}
 	}
-
+	_time = time;
 	_rects.clear();
 
 	if (_shake) {
diff --git a/engines/petka/video.h b/engines/petka/video.h
index 84de1277d6..3c1d93bc48 100644
--- a/engines/petka/video.h
+++ b/engines/petka/video.h
@@ -44,6 +44,7 @@ private:
 	Graphics::Screen _screen;
 	Common::List<Common::Rect> _rects;
 	uint32 _shakeTime;
+	int _time;
 	bool _shake;
 	bool _shift;
 };


Commit: 48a831828558e9fe31d773e95f144d954e658c00
    https://github.com/scummvm/scummvm/commit/48a831828558e9fe31d773e95f144d954e658c00
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented update method for QObject

Changed paths:
    engines/petka/objects/object.cpp
    engines/petka/objects/object.h
    engines/petka/sound.h


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index 39c07f1129..bc11a4ecde 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -29,6 +29,7 @@
 #include "graphics/surface.h"
 
 #include "petka/flc.h"
+#include "petka/sound.h"
 #include "petka/petka.h"
 #include "petka/video.h"
 #include "petka/q_system.h"
@@ -43,7 +44,7 @@ QVisibleObject::QVisibleObject()
 	: _resourceId(-1), _z(240) {}
 
 QMessageObject::QMessageObject()
-	: _id(-1), _dialogColor(-1), _time(0) {}
+	: _id(-1), _dialogColor(-1), _time(0), _sound(nullptr) {}
 
 void QMessageObject::processMessage(const QMessage &msg) {
 	for (uint i = 0; i < _reactions.size(); ++i) {
@@ -103,7 +104,7 @@ void QMessageObject::processMessage(const QMessage &msg) {
 
 		break;
 	case kStatus:
-		_status = (int8) msg.arg1;
+		_status = (int8)msg.arg1;
 		break;
 	case kOn:
 		_isActive = true;
@@ -150,6 +151,13 @@ void QObject::draw() {
 	if (!flc) {
 		return;
 	}
+	if (_animate && _startSound) {
+		if (_sound) {
+			_sound->play(!_notLoopedSound);
+			_startSound = false;
+		}
+	}
+
 	Common::Rect screen(640, 480);
 	Common::Rect dest(flc->getBounds());
 	//flcRect.translate(_x, _y);
@@ -203,4 +211,31 @@ void QObject::show(bool v) {
 	QMessageObject::show(v);
 }
 
+void QObject::update(int time) {
+	if (!_animate || !_isShown)
+		return;
+	_time += time;
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+	if (flc) {
+		while (_time > flc->getDelay()) {
+			if (_sound && _hasSound && flc->getCurFrame() == 0) {
+				_startSound = true;
+				_hasSound = false;
+			}
+			g_vm->videoSystem()->addDirtyRect(Common::Point(_x, _y), *flc);
+			flc->setFrame(-1);
+			if (flc->getCurFrame() == flc->getFrameCount() - 1) {
+				if (_notLoopedSound) {
+					_hasSound = _sound != nullptr;
+				}
+				g_vm->getQSystem()->addMessage(_id, kEnd, _resourceId, 0, 0, 0, 0);
+			}
+			if (flc->getCurFrame() + 1 == flc->getFrameCount() / 2) {
+				g_vm->getQSystem()->addMessage(_id, kHalf, _resourceId, 0, 0, 0, 0);
+			}
+			_time -= flc->getDelay();
+		}
+	}
+}
+
 }
\ No newline at end of file
diff --git a/engines/petka/objects/object.h b/engines/petka/objects/object.h
index b21b4884af..a73ebbb0ab 100644
--- a/engines/petka/objects/object.h
+++ b/engines/petka/objects/object.h
@@ -43,6 +43,7 @@ public:
 	int32 _z;
 };
 
+class Sound;
 
 class QMessageObject : public QVisibleObject {
 public:
@@ -66,8 +67,9 @@ public:
 	int _field_38;
 	int _isActive;
 	int _startSound;
-	int _field_44;
+	int _hasSound;
 	int _notLoopedSound;
+	Sound *_sound;
 	int8 _status;
 	uint16 _id;
 	Common::String _name;
@@ -80,6 +82,7 @@ public:
 class QObject : public QMessageObject {
 public:
 	void draw() override;
+	void update(int time) override;
 	void updateZ() override;
 	bool isInPoint(int x, int y) override;
 	void show(bool v) override;
diff --git a/engines/petka/sound.h b/engines/petka/sound.h
index e76003d9f3..2906a63099 100644
--- a/engines/petka/sound.h
+++ b/engines/petka/sound.h
@@ -26,6 +26,7 @@
 #include "audio/mixer.h"
 
 #include "common/hash-str.h"
+#include "common/ptr.h"
 
 namespace Common {
 class SeekableReadStream;


Commit: 6f1161f9b1d832cde3df6643880a53fb078e78d4
    https://github.com/scummvm/scummvm/commit/6f1161f9b1d832cde3df6643880a53fb078e78d4
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added SET and PLAY opcodes implementation

Changed paths:
    engines/petka/interfaces/main.cpp
    engines/petka/interfaces/startup.cpp
    engines/petka/objects/object.cpp
    engines/petka/q_system.h


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index d2975fbfed..8108403931 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -57,7 +57,7 @@ InterfaceMain::InterfaceMain() {
 
 void InterfaceMain::start() {
 	g_vm->getQSystem()->update();
-	g_vm->getQSystem()->_field48 = 0;
+	g_vm->getQSystem()->_isIniting = 0;
 
 	loadRoom(g_vm->getQSystem()->findObject("Seq - INTRO0")->_id, false);
 }
diff --git a/engines/petka/interfaces/startup.cpp b/engines/petka/interfaces/startup.cpp
index adc1d50190..7ee5c6c155 100644
--- a/engines/petka/interfaces/startup.cpp
+++ b/engines/petka/interfaces/startup.cpp
@@ -46,7 +46,7 @@ enum {
 
 void InterfaceStartup::start() {
 	g_vm->getQSystem()->update();
-	g_vm->getQSystem()->_field48 = 0;
+	g_vm->getQSystem()->_isIniting = 0;
 
 	QObjectBG *bg = (QObjectBG *)g_vm->getQSystem()->findObject("STARTUP");
 	_objs.push_back(bg);
diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index bc11a4ecde..8d97cba2b9 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -94,14 +94,35 @@ void QMessageObject::processMessage(const QMessage &msg) {
 		if (dynamic_cast<QObjectBG *>(this)) {
 			break;
 		}
-		if (g_vm->getQSystem()->_field48) {
-			debug("SET OPCODE %d = %d", _id, msg.arg1);
+		if (g_vm->getQSystem()->_isIniting) {
 			_resourceId = msg.arg1;
 			_notLoopedSound = msg.arg2 != 5;
 		} else {
-			debug("NOT IMPL");
-		}
+			_sound = g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(_resourceId), Audio::Mixer::kSFXSoundType);
+			_hasSound = _sound != nullptr;
+			_startSound = false;
+			FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+			if (flc) {
+				g_vm->videoSystem()->addDirtyRect(Common::Point(_x, _y), *flc);
+			}
 
+			flc = g_vm->resMgr()->loadFlic(msg.arg1);
+			flc->setFrame(1);
+			_time = 0;
+			if (_notLoopedSound) {
+				g_vm->soundMgr()->removeSound(g_vm->resMgr()->findSoundName(_resourceId));
+			}
+			_resourceId = msg.arg1;
+		}
+		if (msg.arg2 == 1) {
+			FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+			flc->setFrame(1);
+			g_vm->videoSystem()->addDirtyRect(Common::Rect(0, 0, 640, 480));
+			_time = 0;
+		} else if (msg.arg2 == 2) {
+			g_vm->resMgr()->loadFlic(_resourceId);
+		}
+		_notLoopedSound = msg.arg2 != 5;
 		break;
 	case kStatus:
 		_status = (int8)msg.arg1;
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index 2e6440b8fc..6b11ce00d6 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -71,7 +71,7 @@ public:
 	Interface *_currInterface;
 	Interface *_prevInterface;
 
-	int _field48;
+	int _isIniting;
 	int _fxId;
 	int _musicId;
 };


Commit: 26b411c688292863032c69677ad9d55a0e9b9384
    https://github.com/scummvm/scummvm/commit/26b411c688292863032c69677ad9d55a0e9b9384
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implementing adding sounds to objects when room loads

Changed paths:
    engines/petka/interfaces/main.cpp


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index 8108403931..1d7c18cce8 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -72,9 +72,12 @@ void InterfaceMain::loadRoom(int id, bool fromSave) {
 	_objs.push_back(room);
 	for (uint i = 0; i < info->attachedObjIds.size(); ++i) {
 		QMessageObject *obj = g_vm->getQSystem()->findObject(info->attachedObjIds[i]);
-		g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(obj->_resourceId), Audio::Mixer::kSFXSoundType);
+		obj->_sound = g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(obj->_resourceId), Audio::Mixer::kSFXSoundType);
+		obj->_hasSound = obj->_sound != nullptr;
+		obj->_startSound = false;
 		if (obj->_isShown || obj->_isActive)
 			g_vm->resMgr()->loadFlic(obj->_resourceId);
+		_objs.push_back(obj);
 	}
 	if (sys->_musicId != room->_musicId) {
 		g_vm->soundMgr()->removeSound(g_vm->resMgr()->findSoundName(sys->_musicId));


Commit: b135735d8a1be6cae620ed5f61ec3c6856af6091
    https://github.com/scummvm/scummvm/commit/b135735d8a1be6cae620ed5f61ec3c6856af6091
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented removing old room

Changed paths:
    engines/petka/interfaces/main.cpp


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index 1d7c18cce8..85efc5ef76 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -65,9 +65,39 @@ void InterfaceMain::start() {
 void InterfaceMain::loadRoom(int id, bool fromSave) {
 	QSystem *sys = g_vm->getQSystem();
 	stop();
+	QObjectBG *room = (QObjectBG *)sys->findObject(_roomId);
+	if (room) {
+		if (!fromSave)
+			sys->addMessageForAllObjects(kLeaveBG, 0, 0, 0, 0, room);
+		g_vm->resMgr()->clearUnneeded();
+		g_vm->soundMgr()->removeSoundsWithType(Audio::Mixer::kSFXSoundType);
+		const BGInfo *info = findBGInfo(room->_id);
+		if (info) {
+			for (uint i = 0; i < _objs.size();) {
+				bool removed = false;
+				if (_roomId == ((QMessageObject *) _objs[i])->_id) {
+					_objs.remove_at(i);
+					removed = true;
+				} else {
+					for (uint j = 0; j < info->attachedObjIds.size(); ++j) {
+						if (info->attachedObjIds[j] == ((QMessageObject *) _objs[i])->_id) {
+							g_vm->soundMgr()->removeSound(g_vm->resMgr()->findSoundName(_objs[i]->_resourceId));
+							_objs.remove_at(i);
+							removed = true;
+							break;
+						}
+					}
+				}
+				if (!removed)
+					++i;
+			}
+		}
+	}
+
+
 	_roomId = id;
 	const BGInfo *info = findBGInfo(id);
-	QObjectBG *room = (QObjectBG *)sys->findObject(info->objId);
+	room = (QObjectBG *)sys->findObject(info->objId);
 	g_vm->resMgr()->loadBitmap(room->_resourceId);
 	_objs.push_back(room);
 	for (uint i = 0; i < info->attachedObjIds.size(); ++i) {


Commit: e0b52484fe8aedb081298b4c475acaa82a46a6ac
    https://github.com/scummvm/scummvm/commit/e0b52484fe8aedb081298b4c475acaa82a46a6ac
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed opening files with relative path

Changed paths:
    engines/petka/file_mgr.cpp


diff --git a/engines/petka/file_mgr.cpp b/engines/petka/file_mgr.cpp
index 731f32609e..6417c78446 100644
--- a/engines/petka/file_mgr.cpp
+++ b/engines/petka/file_mgr.cpp
@@ -80,9 +80,18 @@ void FileMgr::closeAll() {
 	_stores.clear();
 }
 
+static Common::String formPath(Common::String name) {
+	for (uint i = 0; i < name.size(); ++i) {
+		if (name[i] == '\\') {
+			name.setChar('/', i);
+		}
+	}
+	return name;
+}
+
 Common::SeekableReadStream *FileMgr::getFileStream(const Common::String &name) {
 	Common::ScopedPtr<Common::File> file(new Common::File());
-	if (file->open(name)) {
+	if (file->open(formPath(name))) {
 		return file.release();
 	}
 	for (uint i = 0; i < _stores.size(); ++i) {


Commit: 55daf01e319dc3fee8d8aaaa921e36ad6f35c9c9
    https://github.com/scummvm/scummvm/commit/55daf01e319dc3fee8d8aaaa921e36ad6f35c9c9
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed opening files with empty name

Changed paths:
    engines/petka/petka.cpp


diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
index f9ae5a1ee3..f3ae17d894 100644
--- a/engines/petka/petka.cpp
+++ b/engines/petka/petka.cpp
@@ -112,6 +112,8 @@ Common::Error PetkaEngine::run() {
 }
 
 Common::SeekableReadStream *PetkaEngine::openFile(const Common::String &name, bool addCurrentPath) {
+	if (name.empty())
+		return nullptr;
 	return _fileMgr->getFileStream(addCurrentPath ? _currentPath + name : name);
 }
 


Commit: bef655aabb3bdb51c9b266dbb01a3fb8a47cc048
    https://github.com/scummvm/scummvm/commit/bef655aabb3bdb51c9b266dbb01a3fb8a47cc048
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented loading bitmaps with bpp other than 16

Changed paths:
    engines/petka/q_manager.cpp


diff --git a/engines/petka/q_manager.cpp b/engines/petka/q_manager.cpp
index c7ac90fd51..28fa9f06e6 100644
--- a/engines/petka/q_manager.cpp
+++ b/engines/petka/q_manager.cpp
@@ -26,6 +26,8 @@
 
 #include "graphics/surface.h"
 
+#include "image/bmp.h"
+
 #include "petka/flc.h"
 #include "petka/q_manager.h"
 #include "petka/petka.h"
@@ -201,7 +203,18 @@ Graphics::Surface *QManager::loadBitmapSurface(Common::SeekableReadStream &strea
 	uint32 height = stream.readUint32LE();
 	stream.skip(2);
 	uint16 bitsPerPixel = stream.readUint16LE();
-	assert(bitsPerPixel == 16);
+	if (bitsPerPixel != 16 && bitsPerPixel != 1) {
+		stream.seek(0, SEEK_SET);
+		Image::BitmapDecoder decoder;
+		if (!decoder.loadStream(stream))
+			return nullptr;
+		return decoder.getSurface()->convertTo(g_system->getScreenFormat(), decoder.getPalette());
+	}
+	else if (bitsPerPixel == 1) {
+		Graphics::Surface *s = new Graphics::Surface;
+		s->create(width, height, Graphics::PixelFormat(2, 5, 6, 5, 0, 0, 5, 11, 0));
+		return s;
+	}
 
 	/* uint32 compression = stream.readUint32BE(); */
 	/* uint32 imageSize = stream.readUint32LE(); */


Commit: acdbda77ce7b971b5a9cd946f785375edaad63c1
    https://github.com/scummvm/scummvm/commit/acdbda77ce7b971b5a9cd946f785375edaad63c1
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed SIGSEGV when sound is being played 2nd time

Changed paths:
    engines/petka/sound.cpp
    engines/petka/sound.h


diff --git a/engines/petka/sound.cpp b/engines/petka/sound.cpp
index 9bffed939a..5c54935b8e 100644
--- a/engines/petka/sound.cpp
+++ b/engines/petka/sound.cpp
@@ -44,7 +44,7 @@ void Sound::play(bool isLoop) {
 	stop();
 
 	Audio::AudioStream *audioStream;
-	Audio::SeekableAudioStream *wavStream = Audio::makeWAVStream(_stream, DisposeAfterUse::YES);
+	Audio::SeekableAudioStream *wavStream = Audio::makeWAVStream(_stream.get(), DisposeAfterUse::NO);
 	if (isLoop)
 		audioStream = Audio::makeLoopingAudioStream(wavStream, 0, 0, 0);
 	else
diff --git a/engines/petka/sound.h b/engines/petka/sound.h
index 2906a63099..7f05d1a576 100644
--- a/engines/petka/sound.h
+++ b/engines/petka/sound.h
@@ -51,7 +51,7 @@ public:
 	void setBalance(uint16 x, uint16 width);
 
 private:
-	Common::SeekableReadStream *_stream;
+	Common::ScopedPtr<Common::SeekableReadStream> _stream;
 	Audio::Mixer::SoundType _type;
 	Audio::SoundHandle _handle;
 };


Commit: 1bc8ba189ed248cc4395c2d89139a8e07d964edf
    https://github.com/scummvm/scummvm/commit/1bc8ba189ed248cc4395c2d89139a8e07d964edf
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: rewrote update method of QSystem

Changed paths:
    engines/petka/q_system.cpp


diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 0367155f95..d8b780ff0f 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -177,15 +177,9 @@ QMessageObject *QSystem::findObject(const Common::String &name) {
 
 void QSystem::update() {
 	for (Common::List<QMessage>::iterator it = _messages.begin(); it != _messages.end();) {
-		bool removeMsg = false;
-		for (uint j = 0; j < _allObjects.size(); ++j) {
-			if (it->objId == _allObjects[j]->_id) {
-				_allObjects[j]->processMessage(*it);
-				removeMsg = true;
-				break;
-			}
-		}
-		if (removeMsg) {
+		QMessageObject *obj = findObject(it->objId);
+		if (obj) {
+			obj->processMessage(*it);
 			it = _messages.erase(it);
 		} else {
 			++it;


Commit: a022df3b5da8be83cccbcf161ae53ce9a3dff3f2
    https://github.com/scummvm/scummvm/commit/a022df3b5da8be83cccbcf161ae53ce9a3dff3f2
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: changed z coord to unsigned

Changed paths:
    engines/petka/objects/object.h


diff --git a/engines/petka/objects/object.h b/engines/petka/objects/object.h
index a73ebbb0ab..0ee4244b32 100644
--- a/engines/petka/objects/object.h
+++ b/engines/petka/objects/object.h
@@ -40,7 +40,7 @@ public:
 
 public:
 	int32 _resourceId;
-	int32 _z;
+	uint32 _z;
 };
 
 class Sound;


Commit: ae51caefc4529019f10aa151d588652631267ae3
    https://github.com/scummvm/scummvm/commit/ae51caefc4529019f10aa151d588652631267ae3
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed isInPoint method of QObject

Changed paths:
    engines/petka/objects/object.cpp


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index 8d97cba2b9..c8d3e126f8 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -155,7 +155,7 @@ void QMessageObject::show(bool v) {
 }
 
 bool QObject::isInPoint(int x, int y) {
-	if (_isActive)
+	if (!_isActive)
 		return false;
 	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
 	Common::Rect rect(_x, _y, _x + flc->getWidth(), _y + flc->getHeight());


Commit: e984d7a526ae5f895bd4320974908af25c513a25
    https://github.com/scummvm/scummvm/commit/e984d7a526ae5f895bd4320974908af25c513a25
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added makeAllDirty method to video system

Changed paths:
    engines/petka/interfaces/panel.cpp
    engines/petka/interfaces/save_load.cpp
    engines/petka/objects/object.cpp
    engines/petka/objects/object_bg.cpp
    engines/petka/video.cpp
    engines/petka/video.h


diff --git a/engines/petka/interfaces/panel.cpp b/engines/petka/interfaces/panel.cpp
index b085bd572a..9ca467e7f3 100644
--- a/engines/petka/interfaces/panel.cpp
+++ b/engines/petka/interfaces/panel.cpp
@@ -112,7 +112,7 @@ void InterfacePanel::start() {
 	updateSubtitles();
 
 	g_vm->getQSystem()->_currInterface = this;
-	g_vm->videoSystem()->addDirtyRect(Common::Rect(640, 480));
+	g_vm->videoSystem()->makeAllDirty();
 }
 
 void InterfacePanel::onLeftButtonDown(const Common::Point p) {
diff --git a/engines/petka/interfaces/save_load.cpp b/engines/petka/interfaces/save_load.cpp
index 59e7eb21ae..674c5c35e1 100644
--- a/engines/petka/interfaces/save_load.cpp
+++ b/engines/petka/interfaces/save_load.cpp
@@ -51,7 +51,7 @@ void InterfaceSaveLoad::startSaveLoad(bool saveMode) {
 	cursor->setCursorPos(cursor->_x, cursor->_y, 0);
 
 	g_vm->getQSystem()->_currInterface = this;
-	g_vm->videoSystem()->addDirtyRect(Common::Rect(640, 480));
+	g_vm->videoSystem()->makeAllDirty();
 }
 
 void InterfaceSaveLoad::stop() {
@@ -59,7 +59,7 @@ void InterfaceSaveLoad::stop() {
 	cursor->_resourceId = _savedCursorId;
 	g_vm->getQSystem()->_currInterface = g_vm->getQSystem()->_prevInterface;
 	g_vm->getQSystem()->_currInterface->onMouseMove(Common::Point(cursor->_x, cursor->_y));
-	g_vm->videoSystem()->addDirtyRect(Common::Rect(640, 480));
+	g_vm->videoSystem()->makeAllDirty();
 }
 
 void InterfaceSaveLoad::onLeftButtonDown(const Common::Point p) {
diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index c8d3e126f8..ee5f7a0901 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -117,7 +117,7 @@ void QMessageObject::processMessage(const QMessage &msg) {
 		if (msg.arg2 == 1) {
 			FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
 			flc->setFrame(1);
-			g_vm->videoSystem()->addDirtyRect(Common::Rect(0, 0, 640, 480));
+			g_vm->videoSystem()->makeAllDirty();
 			_time = 0;
 		} else if (msg.arg2 == 2) {
 			g_vm->resMgr()->loadFlic(_resourceId);
diff --git a/engines/petka/objects/object_bg.cpp b/engines/petka/objects/object_bg.cpp
index e75079aa28..c915030800 100644
--- a/engines/petka/objects/object_bg.cpp
+++ b/engines/petka/objects/object_bg.cpp
@@ -61,7 +61,7 @@ void QObjectBG::processMessage(const QMessage &msg) {
 		break;
 	case kGoTo:
 		g_vm->getQSystem()->_mainInterface->loadRoom(_id, false);
-		g_vm->videoSystem()->addDirtyRect(Common::Rect(640, 480));
+		g_vm->videoSystem()->makeAllDirty();
 		break;
 	case kSetSeq:
 		break;
diff --git a/engines/petka/video.cpp b/engines/petka/video.cpp
index 6249287c7b..85ea258467 100644
--- a/engines/petka/video.cpp
+++ b/engines/petka/video.cpp
@@ -33,7 +33,7 @@ namespace Petka {
 
 VideoSystem::VideoSystem() :
 	_shake(false), _shift(false), _shakeTime(0), _time(0) {
-	addDirtyRect({0, 0, 640, 480});
+	makeAllDirty();
 }
 
 static bool objCmp(QVisibleObject *&l, QVisibleObject *&r) {
@@ -104,4 +104,8 @@ void VideoSystem::addDirtyRect(Common::Point pos, FlicDecoder &flc) {
 	addDirtyRect(rect);
 }
 
+void VideoSystem::makeAllDirty() {
+	addDirtyRect(Common::Rect(640, 480));
+}
+
 }
\ No newline at end of file
diff --git a/engines/petka/video.h b/engines/petka/video.h
index 3c1d93bc48..43d14f0e08 100644
--- a/engines/petka/video.h
+++ b/engines/petka/video.h
@@ -34,7 +34,7 @@ public:
 	VideoSystem();
 
 	void update();
-
+	void makeAllDirty();
 	void addDirtyRect(const Common::Rect &rect);
 	void addDirtyRect(Common::Point pos, FlicDecoder &flc);
 	const Common::List<Common::Rect> rects() const;


Commit: 1e21a56c2dc9ecbd8570b76c0d324409bd0e215a
    https://github.com/scummvm/scummvm/commit/1e21a56c2dc9ecbd8570b76c0d324409bd0e215a
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added initialization of QMessageObject fields according to disasm

Changed paths:
    engines/petka/objects/object.cpp
    engines/petka/objects/object.h


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index ee5f7a0901..0a7a74c10a 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -43,8 +43,21 @@ namespace Petka {
 QVisibleObject::QVisibleObject()
 	: _resourceId(-1), _z(240) {}
 
-QMessageObject::QMessageObject()
-	: _id(-1), _dialogColor(-1), _time(0), _sound(nullptr) {}
+QMessageObject::QMessageObject() {
+	_id = -1;
+	_status = 0;
+	_time = 0;
+	_dialogColor = -1;
+	_animate = true;
+	_isShown = true;
+	_isActive = true;
+	_updateZ = 0;
+	_field_38 = 0;
+	_notLoopedSound = true;
+	_startSound = false;
+	_hasSound = false;
+	_reaction = nullptr;
+}
 
 void QMessageObject::processMessage(const QMessage &msg) {
 	for (uint i = 0; i < _reactions.size(); ++i) {
diff --git a/engines/petka/objects/object.h b/engines/petka/objects/object.h
index 0ee4244b32..725d2dd67e 100644
--- a/engines/petka/objects/object.h
+++ b/engines/petka/objects/object.h
@@ -76,6 +76,7 @@ public:
 	Common::String _nameOnScreen;
 	int32 _dialogColor;
 	Common::Array<QReaction> _reactions;
+	QReaction *_reaction;
 };
 
 


Commit: c38082e60bc54ad50f93ec485fb1a19e63ebc09a
    https://github.com/scummvm/scummvm/commit/c38082e60bc54ad50f93ec485fb1a19e63ebc09a
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added ctor for QObject

Changed paths:
    engines/petka/objects/object.cpp
    engines/petka/objects/object.h


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index 0a7a74c10a..da3c18979f 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -167,6 +167,19 @@ void QMessageObject::show(bool v) {
 	_isShown = v;
 }
 
+QObject::QObject() {
+	_animate = true;
+	_updateZ = true;
+	_field24 = true;
+	_field20 = true;
+	_sound = nullptr;
+	_x = 0;
+	_y = 0;
+	_field14 = -1;
+	_field18 = -1;
+	_field28 = 0;
+}
+
 bool QObject::isInPoint(int x, int y) {
 	if (!_isActive)
 		return false;
diff --git a/engines/petka/objects/object.h b/engines/petka/objects/object.h
index 725d2dd67e..ff92e22588 100644
--- a/engines/petka/objects/object.h
+++ b/engines/petka/objects/object.h
@@ -82,6 +82,8 @@ public:
 
 class QObject : public QMessageObject {
 public:
+	QObject();
+
 	void draw() override;
 	void update(int time) override;
 	void updateZ() override;


Commit: 71d72f6df5f2d6fcaab533f4a90877864f7a19a1
    https://github.com/scummvm/scummvm/commit/71d72f6df5f2d6fcaab533f4a90877864f7a19a1
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed compilation

Changed paths:
    engines/petka/q_system.cpp


diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index d8b780ff0f..2c802101df 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -39,7 +39,7 @@ namespace Petka {
 
 QSystem::QSystem()
 	: _cursor(nullptr), _case(nullptr), _star(nullptr), _mainInterface(nullptr),
-	_currInterface(nullptr), _prevInterface(nullptr), _field48(0) {}
+	_currInterface(nullptr), _prevInterface(nullptr), _isIniting(0) {}
 
 QSystem::~QSystem() {
 
@@ -91,7 +91,7 @@ bool QSystem::init() {
 	Common::ScopedPtr<Common::SeekableReadStream> stream(g_vm->openFile("script.dat", true));
 	if (!stream)
 		return false;
-	_field48 = 1;
+	_isIniting = 1;
 	Common::ScopedPtr<Common::SeekableReadStream> namesStream(g_vm->openFile("Names.ini", false));
 	Common::ScopedPtr<Common::SeekableReadStream> castStream(g_vm->openFile("Cast.ini", false));
 	Common::ScopedPtr<Common::SeekableReadStream> bgsStream(g_vm->openFile("BGs.ini", false));


Commit: 94a66f09ab484eb5d78c40549f8a46f48abaedd4
    https://github.com/scummvm/scummvm/commit/94a66f09ab484eb5d78c40549f8a46f48abaedd4
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: load right part when running demo

Changed paths:
    engines/petka/petka.cpp


diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
index f3ae17d894..3792950857 100644
--- a/engines/petka/petka.cpp
+++ b/engines/petka/petka.cpp
@@ -28,6 +28,7 @@
 #include "common/system.h"
 #include "common/file.h"
 
+#include "engines/advancedDetector.h"
 #include "engines/util.h"
 
 #include "graphics/surface.h"
@@ -78,7 +79,7 @@ Common::Error PetkaEngine::run() {
 	_soundMgr.reset(new SoundMgr());
 	_vsys.reset(new VideoSystem());
 
-	loadPart(0);
+	loadPart(strcmp(_desc->gameId, "petka_demo") == 0 ? 1 : 0);
 
 	while (!shouldQuit()) {
 		Common::Event event;


Commit: 050d3d5dd34a1b40fa811db1d55d1b38d907fc15
    https://github.com/scummvm/scummvm/commit/050d3d5dd34a1b40fa811db1d55d1b38d907fc15
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: detect StartRoom from ini file rather than hardcoded name

Changed paths:
    engines/petka/interfaces/main.cpp


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index 85efc5ef76..4d8d505fcb 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -23,6 +23,7 @@
 #include <common/system.h>
 #include "common/stream.h"
 #include "common/events.h"
+#include "common/ini-file.h"
 
 #include "petka/flc.h"
 #include "petka/objects/object.h"
@@ -59,7 +60,12 @@ void InterfaceMain::start() {
 	g_vm->getQSystem()->update();
 	g_vm->getQSystem()->_isIniting = 0;
 
-	loadRoom(g_vm->getQSystem()->findObject("Seq - INTRO0")->_id, false);
+	Common::ScopedPtr<Common::SeekableReadStream> bgsStream(g_vm->openFile("BGs.ini", false));
+	Common::INIFile bgsIni;
+	bgsIni.loadFromStream(*bgsStream);
+	Common::String startRoom;
+	bgsIni.getKey("StartRoom", "Settings", startRoom);
+	loadRoom(g_vm->getQSystem()->findObject(startRoom)->_id, false);
 }
 
 void InterfaceMain::loadRoom(int id, bool fromSave) {


Commit: 3201b6f485145fdfb279001f90dbd5b290eeac01
    https://github.com/scummvm/scummvm/commit/3201b6f485145fdfb279001f90dbd5b290eeac01
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented SHOW and HIDE opcodes

Changed paths:
    engines/petka/objects/object.cpp


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index da3c18979f..b85af983a6 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -151,7 +151,11 @@ void QMessageObject::processMessage(const QMessage &msg) {
 	case kStop:
 		g_vm->getQSystem()->_cursor.get()->show(msg.arg1);
 		g_vm->getQSystem()->_star.get()->_isActive = msg.arg1;
+	case kShow:
+		show(true);
+		break;
 	case kHide:
+		show(false);
 		break;
 	case kZBuffer:
 		_updateZ = msg.arg1;


Commit: 2a99a2a766e6a073bff2bef70c3fbd44e41a2dc4
    https://github.com/scummvm/scummvm/commit/2a99a2a766e6a073bff2bef70c3fbd44e41a2dc4
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added PASSIVE and ACTIVE opcodes

Changed paths:
    engines/petka/objects/object.cpp


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index b85af983a6..16eb619fe8 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -161,7 +161,11 @@ void QMessageObject::processMessage(const QMessage &msg) {
 		_updateZ = msg.arg1;
 		_z = (msg.arg2 != -1) ? msg.arg2 : _z;
 		break;
+	case kActive:
+		_isActive = msg.arg1;
+		break;
 	case kPassive:
+		_isActive = false;
 		break;
 	}
 


Commit: feca9cf9c86818769bbfd6b55ab660f7aefb204b
    https://github.com/scummvm/scummvm/commit/feca9cf9c86818769bbfd6b55ab660f7aefb204b
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed CHECK opcode

Changed paths:
    engines/petka/objects/object.cpp


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index 16eb619fe8..2fd967b7ed 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -69,7 +69,7 @@ void QMessageObject::processMessage(const QMessage &msg) {
 		}
 		for (uint j = 0; j < r.messages.size(); ++j) {
 			QMessage &rMsg = r.messages[j];
-			if (r.opcode == kCheck && g_vm->getQSystem()->findObject(rMsg.objId)->_status != rMsg.arg1) {
+			if (rMsg.opcode == kCheck && g_vm->getQSystem()->findObject(rMsg.objId)->_status != rMsg.arg1) {
 				break;
 			}
 			if (rMsg.opcode == kIf &&


Commit: a4bdc33c282f690162ce00dd73a9bc99d248154c
    https://github.com/scummvm/scummvm/commit/a4bdc33c282f690162ce00dd73a9bc99d248154c
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented proper handling of PLAY opcode in handlers

Changed paths:
    engines/petka/objects/object.cpp
    engines/petka/objects/object.h


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index 2fd967b7ed..b95cca0f41 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -59,6 +59,48 @@ QMessageObject::QMessageObject() {
 	_reaction = nullptr;
 }
 
+static void processSavedReaction(QReaction **reaction, QMessageObject *obj) {
+	QReaction *r = *reaction;
+	for (uint i = 0; i < r->messages.size(); ++i) {
+		QMessage &msg = r->messages[i];
+		if (msg.opcode == kCheck && g_vm->getQSystem()->findObject(msg.objId)->_status != msg.arg1) {
+			break;
+		}
+		g_vm->getQSystem()->addMessage(msg.objId, msg.opcode, msg.arg1, msg.arg2, msg.arg3, 0, obj);
+		bool processed = true;
+		switch (msg.opcode) {
+		case kDialog:
+			break;
+		case kPlay: {
+			QMessageObject *obj = g_vm->getQSystem()->findObject(msg.objId);
+			obj->_reaction = new QReaction();
+			obj->_reactionResId = msg.arg1;
+			for (uint j = i + 1; j < r->messages.size(); ++j) {
+				obj->_reaction->messages.push_back(r->messages[j]);
+			}
+			break;
+		}
+		case kWalk:
+		case kWalkTo:
+		case kWalkVich:
+			break;
+		default:
+			processed = false;
+			break;
+		}
+		if (processed)
+			break;
+	}
+	if (*reaction != r) {
+		delete r;
+		return;
+	}
+	if (*reaction) {
+		delete *reaction;
+		*reaction = nullptr;
+	}
+}
+
 void QMessageObject::processMessage(const QMessage &msg) {
 	for (uint i = 0; i < _reactions.size(); ++i) {
 		QReaction &r = _reactions[i];
@@ -83,16 +125,28 @@ void QMessageObject::processMessage(const QMessage &msg) {
 			}
 			g_vm->getQSystem()->addMessage(rMsg.objId, rMsg.opcode, rMsg.arg1, rMsg.arg2, rMsg.arg3, rMsg.unk,
 										   rMsg.sender);
-
+			bool processed = true;
 			switch (rMsg.opcode) {
-			case kPlay:
+			case kPlay: {
+				QMessageObject *obj = g_vm->getQSystem()->findObject(rMsg.objId);
+				delete obj->_reaction;
+				obj->_reaction = new QReaction();
+				obj->_reactionResId = rMsg.arg1;
+				for (uint z = j + 1; z < r.messages.size(); ++z) {
+					obj->_reaction->messages.push_back(r.messages[z]);
+				}
 				break;
+			}
 			case kWalk:
 			case kWalkTo:
 				break;
 			case kWalkVich:
 				break;
+			default:
+				processed = false;
 			}
+			if (processed)
+				break;
 		}
 	}
 
@@ -137,6 +191,11 @@ void QMessageObject::processMessage(const QMessage &msg) {
 		}
 		_notLoopedSound = msg.arg2 != 5;
 		break;
+	case kEnd:
+		if (_reaction && _reactionResId == msg.arg1) {
+			processSavedReaction(&_reaction, this);
+		}
+ 		break;
 	case kStatus:
 		_status = (int8)msg.arg1;
 		break;
diff --git a/engines/petka/objects/object.h b/engines/petka/objects/object.h
index ff92e22588..d5681ae3a6 100644
--- a/engines/petka/objects/object.h
+++ b/engines/petka/objects/object.h
@@ -77,6 +77,7 @@ public:
 	int32 _dialogColor;
 	Common::Array<QReaction> _reactions;
 	QReaction *_reaction;
+	int16 _reactionResId;
 };
 
 


Commit: bb10d42a336e02a1daff8a9511b6d6d48e5dc448
    https://github.com/scummvm/scummvm/commit/bb10d42a336e02a1daff8a9511b6d6d48e5dc448
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented SETPOS opcode

Changed paths:
    engines/petka/objects/object.cpp
    engines/petka/objects/object.h
    engines/petka/video.cpp
    engines/petka/video.h


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index b95cca0f41..72a803e14c 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -156,6 +156,9 @@ void QMessageObject::processMessage(const QMessage &msg) {
 		g_vm->playVideo(g_vm->openFile(videoName, false));
 		break;
 	}
+	case kSetPos:
+		setPos(msg.arg1, msg.arg2);
+		break;
 	case kSet:
 	case kPlay:
 		if (dynamic_cast<QObjectBG *>(this)) {
@@ -352,4 +355,14 @@ void QObject::update(int time) {
 	}
 }
 
+void QObject::setPos(int x, int y) {
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+	if (flc) {
+		g_vm->videoSystem()->addDirtyRectFromMsk(Common::Point(_x, _y), *flc);
+		g_vm->videoSystem()->addDirtyRectFromMsk(Common::Point(x, y), *flc);
+		_x = x;
+		_y = y;
+	}
+}
+
 }
\ No newline at end of file
diff --git a/engines/petka/objects/object.h b/engines/petka/objects/object.h
index d5681ae3a6..e7e72ec836 100644
--- a/engines/petka/objects/object.h
+++ b/engines/petka/objects/object.h
@@ -36,6 +36,7 @@ public:
 	virtual void update(int time) {};
 	virtual void updateZ() {};
 	virtual void show(bool v) {};
+	virtual void setPos(int x, int y) {};
 	virtual bool isInPoint(int x, int y) { return false; }
 
 public:
@@ -89,6 +90,7 @@ public:
 	void update(int time) override;
 	void updateZ() override;
 	bool isInPoint(int x, int y) override;
+	void setPos(int x, int y) override;
 	void show(bool v) override;
 };
 
diff --git a/engines/petka/video.cpp b/engines/petka/video.cpp
index 85ea258467..f04ebe2a55 100644
--- a/engines/petka/video.cpp
+++ b/engines/petka/video.cpp
@@ -104,6 +104,15 @@ void VideoSystem::addDirtyRect(Common::Point pos, FlicDecoder &flc) {
 	addDirtyRect(rect);
 }
 
+void VideoSystem::addDirtyRectFromMsk(Common::Point pos, FlicDecoder &flc) {
+	const Common::Array<Common::Rect> &rects = flc.getMskRects();
+	for (uint i = 0; i < rects.size(); ++i) {
+		Common::Rect r = rects[i];
+		r.translate(pos.x, pos.y);
+		_rects.push_back(r);
+	}
+}
+
 void VideoSystem::makeAllDirty() {
 	addDirtyRect(Common::Rect(640, 480));
 }
diff --git a/engines/petka/video.h b/engines/petka/video.h
index 43d14f0e08..e47566ccb9 100644
--- a/engines/petka/video.h
+++ b/engines/petka/video.h
@@ -37,6 +37,7 @@ public:
 	void makeAllDirty();
 	void addDirtyRect(const Common::Rect &rect);
 	void addDirtyRect(Common::Point pos, FlicDecoder &flc);
+	void addDirtyRectFromMsk(Common::Point pos, FlicDecoder &flc);
 	const Common::List<Common::Rect> rects() const;
 	Graphics::Screen &screen();
 


Commit: 4cebc88106380e8d2b6175546b844928542bbcf2
    https://github.com/scummvm/scummvm/commit/4cebc88106380e8d2b6175546b844928542bbcf2
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed adding sound in PLAY opcode

Changed paths:
    engines/petka/objects/object.cpp


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index 72a803e14c..95ad7e02b9 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -168,7 +168,7 @@ void QMessageObject::processMessage(const QMessage &msg) {
 			_resourceId = msg.arg1;
 			_notLoopedSound = msg.arg2 != 5;
 		} else {
-			_sound = g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(_resourceId), Audio::Mixer::kSFXSoundType);
+			_sound = g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(msg.arg1), Audio::Mixer::kSFXSoundType);
 			_hasSound = _sound != nullptr;
 			_startSound = false;
 			FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);


Commit: 46fd290d8f93f5590c6bb51ecd40593c5f8e7266
    https://github.com/scummvm/scummvm/commit/46fd290d8f93f5590c6bb51ecd40593c5f8e7266
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed removing looped sounds

Changed paths:
    engines/petka/objects/object.cpp


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index 95ad7e02b9..4b71195476 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -179,7 +179,7 @@ void QMessageObject::processMessage(const QMessage &msg) {
 			flc = g_vm->resMgr()->loadFlic(msg.arg1);
 			flc->setFrame(1);
 			_time = 0;
-			if (_notLoopedSound) {
+			if (!_notLoopedSound) {
 				g_vm->soundMgr()->removeSound(g_vm->resMgr()->findSoundName(_resourceId));
 			}
 			_resourceId = msg.arg1;


Commit: 38db7a8a8bb21fc028faa12730b0aa40af827906
    https://github.com/scummvm/scummvm/commit/38db7a8a8bb21fc028faa12730b0aa40af827906
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: split loadingRoom method

Changed paths:
    engines/petka/interfaces/main.cpp
    engines/petka/interfaces/main.h


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index 4d8d505fcb..59e4502ae7 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -69,41 +69,14 @@ void InterfaceMain::start() {
 }
 
 void InterfaceMain::loadRoom(int id, bool fromSave) {
-	QSystem *sys = g_vm->getQSystem();
 	stop();
-	QObjectBG *room = (QObjectBG *)sys->findObject(_roomId);
-	if (room) {
-		if (!fromSave)
-			sys->addMessageForAllObjects(kLeaveBG, 0, 0, 0, 0, room);
-		g_vm->resMgr()->clearUnneeded();
-		g_vm->soundMgr()->removeSoundsWithType(Audio::Mixer::kSFXSoundType);
-		const BGInfo *info = findBGInfo(room->_id);
-		if (info) {
-			for (uint i = 0; i < _objs.size();) {
-				bool removed = false;
-				if (_roomId == ((QMessageObject *) _objs[i])->_id) {
-					_objs.remove_at(i);
-					removed = true;
-				} else {
-					for (uint j = 0; j < info->attachedObjIds.size(); ++j) {
-						if (info->attachedObjIds[j] == ((QMessageObject *) _objs[i])->_id) {
-							g_vm->soundMgr()->removeSound(g_vm->resMgr()->findSoundName(_objs[i]->_resourceId));
-							_objs.remove_at(i);
-							removed = true;
-							break;
-						}
-					}
-				}
-				if (!removed)
-					++i;
-			}
-		}
-	}
-
-
+	if (_roomId == id)
+		return;
+	unloadRoom(fromSave);
 	_roomId = id;
 	const BGInfo *info = findBGInfo(id);
-	room = (QObjectBG *)sys->findObject(info->objId);
+	QSystem *sys = g_vm->getQSystem();
+	QObjectBG *room = (QObjectBG *)sys->findObject(id);
 	g_vm->resMgr()->loadBitmap(room->_resourceId);
 	_objs.push_back(room);
 	for (uint i = 0; i < info->attachedObjIds.size(); ++i) {
@@ -137,5 +110,40 @@ const BGInfo *InterfaceMain::findBGInfo(int id) const {
 	return nullptr;
 }
 
+void InterfaceMain::unloadRoom(bool fromSave) {
+	if (_roomId == -1)
+		return;
+	QSystem *sys = g_vm->getQSystem();
+	QObjectBG *room = (QObjectBG *) sys->findObject(_roomId);
+	if (room) {
+		if (!fromSave)
+			sys->addMessageForAllObjects(kLeaveBG, 0, 0, 0, 0, room);
+		g_vm->resMgr()->clearUnneeded();
+		g_vm->soundMgr()->removeSoundsWithType(Audio::Mixer::kSFXSoundType);
+		const BGInfo *info = findBGInfo(_roomId);
+		if (!info)
+			return;
+		for (uint i = 0; i < _objs.size();) {
+			bool removed = false;
+			if (_roomId == ((QMessageObject *) _objs[i])->_id) {
+				_objs.remove_at(i);
+				removed = true;
+			} else {
+				for (uint j = 0; j < info->attachedObjIds.size(); ++j) {
+					if (info->attachedObjIds[j] == ((QMessageObject *) _objs[i])->_id) {
+						QMessageObject *o = (QMessageObject *) _objs.remove_at(i);
+						g_vm->soundMgr()->removeSound(g_vm->resMgr()->findSoundName(o->_resourceId));
+						o->_sound = nullptr;
+						removed = true;
+						break;
+					}
+				}
+			}
+			if (!removed)
+				++i;
+		}
+	}
+}
+
 } // End of namespace Petka
 
diff --git a/engines/petka/interfaces/main.h b/engines/petka/interfaces/main.h
index 3a9e25f08e..5f0972c49f 100644
--- a/engines/petka/interfaces/main.h
+++ b/engines/petka/interfaces/main.h
@@ -42,6 +42,8 @@ public:
 
 	const BGInfo *findBGInfo(int id) const;
 
+	void unloadRoom(bool fromSave);
+
 public:
 	Common::Array<BGInfo> _bgs;
 	int _roomId;


Commit: 6b079e85756678406c3e28d1a405b320a159ca41
    https://github.com/scummvm/scummvm/commit/6b079e85756678406c3e28d1a405b320a159ca41
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed playing previously stopped sounds

Changed paths:
    engines/petka/sound.cpp


diff --git a/engines/petka/sound.cpp b/engines/petka/sound.cpp
index 5c54935b8e..00a06b4435 100644
--- a/engines/petka/sound.cpp
+++ b/engines/petka/sound.cpp
@@ -59,6 +59,7 @@ bool Sound::isPlaying() {
 
 void Sound::stop() {
 	g_system->getMixer()->stopHandle(_handle);
+	_stream->seek(0, SEEK_SET);
 }
 
 void Sound::setBalance(uint16 x, uint16 width) {


Commit: 76c587a700cc2b967a75b56344cee8a4763b58e0
    https://github.com/scummvm/scummvm/commit/76c587a700cc2b967a75b56344cee8a4763b58e0
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed adding sound which has null file stream

Changed paths:
    engines/petka/interfaces/main.cpp
    engines/petka/sound.cpp


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index 59e4502ae7..d47cec5a43 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -90,12 +90,18 @@ void InterfaceMain::loadRoom(int id, bool fromSave) {
 	}
 	if (sys->_musicId != room->_musicId) {
 		g_vm->soundMgr()->removeSound(g_vm->resMgr()->findSoundName(sys->_musicId));
-		g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(room->_musicId), Audio::Mixer::kMusicSoundType)->play(true);
+		Sound *sound = g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(room->_musicId), Audio::Mixer::kMusicSoundType);
+		if (sound) {
+			sound->play(true);
+		}
 		sys->_musicId = room->_musicId;
 	}
 	if (sys->_fxId != room->_fxId) {
 		g_vm->soundMgr()->removeSound(g_vm->resMgr()->findSoundName(sys->_fxId));
-		g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(room->_fxId), Audio::Mixer::kSFXSoundType)->play(true);
+		Sound *sound = g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(room->_fxId), Audio::Mixer::kMusicSoundType);
+		if (sound) {
+			sound->play(true);
+		}
 		sys->_fxId = room->_fxId;
 	}
 	if (!fromSave)
diff --git a/engines/petka/sound.cpp b/engines/petka/sound.cpp
index 00a06b4435..33b8907c63 100644
--- a/engines/petka/sound.cpp
+++ b/engines/petka/sound.cpp
@@ -79,8 +79,11 @@ Sound *SoundMgr::addSound(const Common::String &name, Audio::Mixer::SoundType ty
 	Sound *sound = findSound(name);
 	if (sound)
 		return sound;
-	sound = new Sound(g_vm->openFile(name, false), type);
-	_sounds.getVal(name).reset(sound);
+	Common::SeekableReadStream *s = g_vm->openFile(name, false);
+	if (s) {
+		sound = new Sound(g_vm->openFile(name, false), type);
+		_sounds.getVal(name).reset(sound);
+	}
 	return sound;
 }
 


Commit: cd066fa2de22f61d16c49be785877ff64b9f7f7d
    https://github.com/scummvm/scummvm/commit/cd066fa2de22f61d16c49be785877ff64b9f7f7d
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: disabled updating QObject with sprites which have 1 frame

Changed paths:
    engines/petka/objects/object.cpp


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index 4b71195476..d7a631ab86 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -333,7 +333,7 @@ void QObject::update(int time) {
 		return;
 	_time += time;
 	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
-	if (flc) {
+	if (flc && flc->getFrameCount() != 1) {
 		while (_time > flc->getDelay()) {
 			if (_sound && _hasSound && flc->getCurFrame() == 0) {
 				_startSound = true;


Commit: d78926d79d916673f46708000b0c36e43253310c
    https://github.com/scummvm/scummvm/commit/d78926d79d916673f46708000b0c36e43253310c
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed checking time when to update sprites

Changed paths:
    engines/petka/objects/object.cpp
    engines/petka/objects/object_cursor.cpp


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index d7a631ab86..d59124b496 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -334,7 +334,7 @@ void QObject::update(int time) {
 	_time += time;
 	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
 	if (flc && flc->getFrameCount() != 1) {
-		while (_time > flc->getDelay()) {
+		while (_time >= flc->getDelay()) {
 			if (_sound && _hasSound && flc->getCurFrame() == 0) {
 				_startSound = true;
 				_hasSound = false;
diff --git a/engines/petka/objects/object_cursor.cpp b/engines/petka/objects/object_cursor.cpp
index 4ab77e2907..0555dac47a 100644
--- a/engines/petka/objects/object_cursor.cpp
+++ b/engines/petka/objects/object_cursor.cpp
@@ -71,7 +71,7 @@ void QObjectCursor::update(int time) {
 		return;
 	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
 	_time += time;
-	while (flc && _time > flc->getDelay()) {
+	while (flc && _time >= flc->getDelay()) {
 		flc->setFrame(-1);
 		Common::Rect dirty(flc->getBounds());
 		dirty.translate(_x, _y);


Commit: 10a2ea1f1065aa04b5286f2a7a68aa9a8136870a
    https://github.com/scummvm/scummvm/commit/10a2ea1f1065aa04b5286f2a7a68aa9a8136870a
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed frame time of video system

Changed paths:
    engines/petka/interfaces/main.cpp
    engines/petka/video.cpp
    engines/petka/video.h


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index d47cec5a43..74d39b4231 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -106,6 +106,7 @@ void InterfaceMain::loadRoom(int id, bool fromSave) {
 	}
 	if (!fromSave)
 		g_vm->getQSystem()->addMessageForAllObjects(kInitBG, 0, 0, 0, 0, room);
+	g_vm->videoSystem()->updateTime();
 }
 
 const BGInfo *InterfaceMain::findBGInfo(int id) const {
diff --git a/engines/petka/video.cpp b/engines/petka/video.cpp
index f04ebe2a55..4c8e516502 100644
--- a/engines/petka/video.cpp
+++ b/engines/petka/video.cpp
@@ -34,6 +34,7 @@ namespace Petka {
 VideoSystem::VideoSystem() :
 	_shake(false), _shift(false), _shakeTime(0), _time(0) {
 	makeAllDirty();
+	_time = g_system->getMillis();
 }
 
 static bool objCmp(QVisibleObject *&l, QVisibleObject *&r) {
@@ -117,4 +118,8 @@ void VideoSystem::makeAllDirty() {
 	addDirtyRect(Common::Rect(640, 480));
 }
 
+void VideoSystem::updateTime() {
+	_time = g_system->getMillis();
+}
+
 }
\ No newline at end of file
diff --git a/engines/petka/video.h b/engines/petka/video.h
index e47566ccb9..8be0ad9fd6 100644
--- a/engines/petka/video.h
+++ b/engines/petka/video.h
@@ -33,6 +33,7 @@ class VideoSystem {
 public:
 	VideoSystem();
 
+	void updateTime();
 	void update();
 	void makeAllDirty();
 	void addDirtyRect(const Common::Rect &rect);


Commit: f434be2bf576f397b4131d61a9a5739a809d22b7
    https://github.com/scummvm/scummvm/commit/f434be2bf576f397b4131d61a9a5739a809d22b7
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed starting game when ini files aren't needed

Changed paths:
    engines/petka/q_system.cpp


diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 2c802101df..f59373e509 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -100,10 +100,12 @@ bool QSystem::init() {
 	Common::INIFile castIni;
 	Common::INIFile bgsIni;
 
-	// fails because ini is broken for Russian letters
-	namesIni.loadFromStream(*namesStream);
-	castIni.loadFromStream(*castStream);
-	bgsIni.loadFromStream(*bgsStream);
+	if (namesStream)
+		namesIni.loadFromStream(*namesStream); // fails because ini is broken for Russian letters
+	if (castStream)
+		castIni.loadFromStream(*castStream);
+	if (bgsStream)
+		bgsIni.loadFromStream(*bgsStream);
 
 	uint32 objsCount = stream->readUint32LE();
 	uint32 bgsCount = stream->readUint32LE();


Commit: 8d9ce6cd60b279c0113686e6bd685f5ce93ae7e5
    https://github.com/scummvm/scummvm/commit/8d9ce6cd60b279c0113686e6bd685f5ce93ae7e5
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: temporarily disabled usage of ini file with names

Changed paths:
    engines/petka/q_system.cpp


diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index f59373e509..97a90e8c54 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -76,7 +76,7 @@ static void readObject(QMessageObject &obj, Common::SeekableReadStream &stream,
 		}
 	}
 
-	namesIni.getKey(obj._name, "all", obj._nameOnScreen);
+	//namesIni.getKey(obj._name, "all", obj._nameOnScreen);
 
 	Common::String rgbString;
 	if (castIni.getKey(obj._name, "all", rgbString)) {
@@ -100,8 +100,10 @@ bool QSystem::init() {
 	Common::INIFile castIni;
 	Common::INIFile bgsIni;
 
+	/*
 	if (namesStream)
-		namesIni.loadFromStream(*namesStream); // fails because ini is broken for Russian letters
+		namesIni.loadFromStream(*namesStream); //fails because ini is broken for Russian letters
+	*/
 	if (castStream)
 		castIni.loadFromStream(*castStream);
 	if (bgsStream)


Commit: dbb71b3e805bfa849d364e8afbf4b4e92d1c5260
    https://github.com/scummvm/scummvm/commit/dbb71b3e805bfa849d364e8afbf4b4e92d1c5260
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: started dialogs implementation

Changed paths:
  A engines/petka/big_dialogue.cpp
  A engines/petka/big_dialogue.h
    engines/petka/petka.cpp
    engines/petka/petka.h


diff --git a/engines/petka/big_dialogue.cpp b/engines/petka/big_dialogue.cpp
new file mode 100644
index 0000000000..bd66aebcc9
--- /dev/null
+++ b/engines/petka/big_dialogue.cpp
@@ -0,0 +1,132 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/stream.h"
+
+#include "petka/big_dialogue.h"
+#include "petka/petka.h"
+
+namespace Petka {
+
+BigDialogue::BigDialogue() {
+	_ip = nullptr;
+	_code = nullptr;
+	_codeSize = 0;
+	_startCodeIndex = 0;
+
+	Common::ScopedPtr<Common::SeekableReadStream> file(g_vm->openFile("dialogue.fix", true));
+	if (!file)
+		return;
+
+	_objDialogs.resize(file->readUint32LE());
+	for (uint i = 0; i < _objDialogs.size(); ++i) {
+		_objDialogs[i].objId = file->readUint32LE();
+		_objDialogs[i].dialogs.resize(file->readUint32LE());
+		file->skip(4); // pointer
+	}
+	for (uint i = 0; i < _objDialogs.size(); ++i) {
+		for (uint j = 0; j < _objDialogs[i].dialogs.size(); ++j) {
+			_objDialogs[i].dialogs[j].opcode = file->readUint16LE();
+			_objDialogs[i].dialogs[j].objId = file->readUint16LE();
+			_objDialogs[i].dialogs[j].handlers.resize(file->readUint32LE());
+			_objDialogs[i].dialogs[j].startHandlerIndex = file->readUint32LE();
+			file->skip(4); // pointer
+			for (uint z = 0; z < _objDialogs[i].dialogs[j].handlers.size(); ++z) {
+				_objDialogs[i].dialogs[j].handlers[z].startOpIndex = file->readUint32LE();
+				uint opsCount = file->readUint32LE();
+				file->skip(4); // pointer
+				file->skip(opsCount * 4); // operations
+			}
+		}
+	}
+
+	_codeSize = file->readUint32LE();
+	_code = new int[_codeSize * 4];
+}
+
+void BigDialogue::loadSpeechesInfo() {
+	if (!_speeches.empty())
+		return;
+
+	Common::ScopedPtr<Common::SeekableReadStream> file(g_vm->openFile("dialogue.lod", true));
+	if (!file)
+		return;
+
+	_speeches.resize(file->readUint32LE());
+	for (uint i = 0; i < _speeches.size(); ++i) {
+		_speeches[i].speakerId = file->readUint32LE();
+		file->read(_speeches[i].soundName, sizeof(_speeches[i].soundName));
+	}
+
+	char *str = new char[file->size() - file->pos()];
+	char *curr = str;
+	file->read(str, file->size() - file->pos());
+	for (uint i = 0; i < _speeches.size(); ++i) {
+		_speeches[i].text = Common::convertToU32String(curr);
+		curr += strlen(curr) + 1;
+	}
+	delete[] str;
+}
+
+const SpeechInfo *BigDialogue::getSpeechInfo() {
+	if (!_ip)
+		return nullptr;
+	byte opcode = (byte)(*_ip >> 24);
+	switch (opcode) {
+	case 2:
+		// not implemented
+		break;
+	case 8:
+		_ip += 1;
+		for (uint i = 0; i < ((*_ip >> 16) & 0xFF); ++i) {
+			while ((*_ip >> 24) != 0x01)
+				_ip += 1;
+			_ip += 1;
+		}
+		// fall through
+	case 7:
+		return &_speeches[(uint16)*_ip];
+	default:
+		break;
+	}
+	return nullptr;
+}
+
+const Dialog *BigDialogue::findDialog(uint objId, uint opcode, bool *res) const {
+	return nullptr;
+}
+
+void BigDialogue::setDialog(uint objId, uint opcode, int index) {
+	loadSpeechesInfo();
+	const Dialog *d = findDialog(objId, opcode, nullptr);
+	if (d) {
+		if (index < 0 || index >= d->handlers.size()) {
+			_ip = &_code[d->handlers[d->startHandlerIndex].startOpIndex];
+			_startCodeIndex = d->handlers[d->startHandlerIndex].startOpIndex;
+		} else {
+			_ip = &_code[d->handlers[index].startOpIndex];
+			_startCodeIndex = d->handlers[index].startOpIndex;
+		}
+	}
+}
+
+} // End of namespace Petka
\ No newline at end of file
diff --git a/engines/petka/big_dialogue.h b/engines/petka/big_dialogue.h
new file mode 100644
index 0000000000..5c00a43dd6
--- /dev/null
+++ b/engines/petka/big_dialogue.h
@@ -0,0 +1,85 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_BIG_DIALOGUE_H
+#define PETKA_BIG_DIALOGUE_H
+
+#include "common/array.h"
+#include "common/ustr.h"
+
+namespace Petka {
+
+struct DlgOperation {
+	uint16 objId;
+	byte arg;
+	byte code;
+};
+
+struct DialogHandler {
+	uint32 startOpIndex;
+	uint32 opsCount;
+	//DlgOperation *operations;
+};
+
+struct Dialog {
+	uint16 opcode;
+	uint16 objId;
+	uint32 startHandlerIndex;
+	Common::Array<DialogHandler> handlers;
+};
+
+struct ObjectDialogs {
+	uint32 objId;
+	Common::Array<Dialog> dialogs;
+};
+
+struct SpeechInfo {
+	uint32 speakerId;
+	char soundName[16];
+	Common::U32String text;
+};
+
+class BigDialogue {
+public:
+	BigDialogue();
+
+	const Dialog *findDialog(uint objId, uint opcode, bool *res) const;
+	void setDialog(uint objId, uint opcode, int index);
+
+	const SpeechInfo *getSpeechInfo();
+
+private:
+	void loadSpeechesInfo();
+
+private:
+	int *_ip;
+	int *_code;
+	uint _codeSize;
+	uint _startCodeIndex;
+
+	Common::Array<SpeechInfo> _speeches;
+	Common::Array<ObjectDialogs> _objDialogs;
+};
+
+} // End of namespace Petka
+
+#endif
diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
index 3792950857..73cc33dddf 100644
--- a/engines/petka/petka.cpp
+++ b/engines/petka/petka.cpp
@@ -42,6 +42,7 @@
 #include "petka/q_manager.h"
 #include "petka/interfaces/interface.h"
 #include "petka/q_system.h"
+#include "petka/big_dialogue.h"
 
 namespace Petka {
 
@@ -219,6 +220,7 @@ void PetkaEngine::loadPart(byte part) {
 	_resMgr->init();
 	_qsystem.reset(new QSystem());
 	_qsystem->init();
+	_dialogMan.reset(new BigDialogue());
 }
 
 } // End of namespace Petka
diff --git a/engines/petka/petka.h b/engines/petka/petka.h
index c595e24a87..9dd004916b 100644
--- a/engines/petka/petka.h
+++ b/engines/petka/petka.h
@@ -38,6 +38,7 @@ class SeekableReadStream;
 namespace Petka {
 
 class Console;
+class BigDialogue;
 class FileMgr;
 class SoundMgr;
 class QManager;
@@ -77,6 +78,7 @@ private:
 	Common::ScopedPtr<SoundMgr> _soundMgr;
 	Common::ScopedPtr<QSystem> _qsystem;
 	Common::ScopedPtr<VideoSystem> _vsys;
+	Common::ScopedPtr<BigDialogue> _dialogMan;
 	const ADGameDescription *_desc;
 
 	Common::RandomSource _rnd;


Commit: d7cf76087b92f495f5ca0a76b71d52b41266ace9
    https://github.com/scummvm/scummvm/commit/d7cf76087b92f495f5ca0a76b71d52b41266ace9
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: partial implementation of dialogs

Changed paths:
  A engines/petka/interfaces/dialog_interface.cpp
  A engines/petka/interfaces/dialog_interface.h
    engines/petka/base.h
    engines/petka/big_dialogue.cpp
    engines/petka/big_dialogue.h
    engines/petka/interfaces/main.cpp
    engines/petka/interfaces/main.h
    engines/petka/module.mk
    engines/petka/objects/object.cpp
    engines/petka/petka.cpp
    engines/petka/petka.h


diff --git a/engines/petka/base.h b/engines/petka/base.h
index e71a655db1..92de6c076e 100644
--- a/engines/petka/base.h
+++ b/engines/petka/base.h
@@ -99,7 +99,7 @@ class QMessageObject;
 struct QMessage {
 	uint16 objId;
 	uint16 opcode;
-	int16 arg1;
+	uint16 arg1;
 	int16 arg2;
 	int16 arg3;
 	QMessageObject *sender;
diff --git a/engines/petka/big_dialogue.cpp b/engines/petka/big_dialogue.cpp
index bd66aebcc9..ec214251e9 100644
--- a/engines/petka/big_dialogue.cpp
+++ b/engines/petka/big_dialogue.cpp
@@ -22,6 +22,7 @@
 
 #include "common/stream.h"
 
+#include "petka/base.h"
 #include "petka/big_dialogue.h"
 #include "petka/petka.h"
 
@@ -50,17 +51,24 @@ BigDialogue::BigDialogue() {
 			_objDialogs[i].dialogs[j].handlers.resize(file->readUint32LE());
 			_objDialogs[i].dialogs[j].startHandlerIndex = file->readUint32LE();
 			file->skip(4); // pointer
+		}
+		for (uint j = 0; j < _objDialogs[i].dialogs.size(); ++j) {
 			for (uint z = 0; z < _objDialogs[i].dialogs[j].handlers.size(); ++z) {
 				_objDialogs[i].dialogs[j].handlers[z].startOpIndex = file->readUint32LE();
-				uint opsCount = file->readUint32LE();
+				_objDialogs[i].dialogs[j].handlers[z].opsCount = file->readUint32LE();
 				file->skip(4); // pointer
-				file->skip(opsCount * 4); // operations
+			}
+		}
+		for (uint j = 0; j < _objDialogs[i].dialogs.size(); ++j) {
+			for (uint z = 0; z < _objDialogs[i].dialogs[j].handlers.size(); ++z) {
+				file->skip(_objDialogs[i].dialogs[j].handlers[z].opsCount * 4); // operations
 			}
 		}
 	}
 
 	_codeSize = file->readUint32LE();
-	_code = new int[_codeSize * 4];
+	_code = new int[_codeSize];
+	file->read(_code, _codeSize * 4);
 }
 
 void BigDialogue::loadSpeechesInfo() {
@@ -75,13 +83,14 @@ void BigDialogue::loadSpeechesInfo() {
 	for (uint i = 0; i < _speeches.size(); ++i) {
 		_speeches[i].speakerId = file->readUint32LE();
 		file->read(_speeches[i].soundName, sizeof(_speeches[i].soundName));
+		file->skip(4);
 	}
 
 	char *str = new char[file->size() - file->pos()];
 	char *curr = str;
 	file->read(str, file->size() - file->pos());
 	for (uint i = 0; i < _speeches.size(); ++i) {
-		_speeches[i].text = Common::convertToU32String(curr);
+		_speeches[i].text = Common::convertToU32String(curr, Common::CodePage::kWindows1251);
 		curr += strlen(curr) + 1;
 	}
 	delete[] str;
@@ -112,6 +121,43 @@ const SpeechInfo *BigDialogue::getSpeechInfo() {
 }
 
 const Dialog *BigDialogue::findDialog(uint objId, uint opcode, bool *res) const {
+	if (opcode == kEnd || opcode == kHalf) {
+		return nullptr;
+	}
+	if (res) {
+		*res = 0;
+	}
+	for (uint i = 0; i < _objDialogs.size(); ++i) {
+		if (_objDialogs[i].objId == objId) {
+			for (uint j = 0; j < _objDialogs[i].dialogs.size(); ++j) {
+				if (_objDialogs[i].dialogs[j].opcode == opcode) {
+					return &_objDialogs[i].dialogs[j];
+				}
+			}
+			if (opcode != kObjectUse) {
+				continue;
+			}
+			for (uint j = 0; j < _objDialogs[i].dialogs.size(); ++j) {
+				if (_objDialogs[i].dialogs[j].opcode == 0xFFFE) {
+					if (res)
+						*res = 1;
+					return &_objDialogs[i].dialogs[j];
+				}
+
+			}
+		}
+	}
+	for (uint i = 0; i < _objDialogs.size(); ++i) {
+		if (_objDialogs[i].objId != 0xFFFE)
+			continue;
+		for (uint j = 0; j < _objDialogs[i].dialogs.size(); ++j) {
+			if (_objDialogs[i].dialogs[j].opcode == opcode) {
+				if (res)
+					*res = 1;
+				return &_objDialogs[i].dialogs[j];
+			}
+		}
+	}
 	return nullptr;
 }
 
@@ -129,4 +175,86 @@ void BigDialogue::setDialog(uint objId, uint opcode, int index) {
 	}
 }
 
+uint BigDialogue::opcode() {
+	while (_ip) {
+		byte op = (*_ip >> 24);
+		switch (op) {
+		case 2: {
+			int unk1 = 0;
+			int unk2 = 1;
+			for (uint i = 0; i < (*_ip & 0xFF); ++i) {
+				if (((*_ip >> 8) & 0xFFFF) & unk2) {
+					unk1++;
+				}
+				unk2 <<= 1;
+			}
+			if (unk1 > 1)
+				return 2;
+			sub40B670(0);
+			break;
+		}
+		case 6:
+			return 3;
+		case 7:
+		case 8:
+			return 1;
+		case 9:
+			return 4;
+		default:
+			sub40B670(-1);
+			break;
+		}
+	}
+	return 3;
+}
+
+void BigDialogue::sub40B670(int arg) {
+	if (!_ip)
+		return;
+	int unk = 1;
+	if (arg != -1 && (*_ip >> 24) != 2) {
+		arg = -1;
+	}
+	while (true) {
+		byte op = (*_ip >> 24);
+		switch (op) {
+		case 2:
+			break;
+		case 3:
+			_ip = &_code[*_ip & 0xFFFF];
+			break;
+		case 4:
+			break;
+		case 5: {
+			_code[(*_ip >> 16)] |= (((1 << *(_ip) >> 24) & 0xFFFF) << 8);
+			_ip += 1;
+			unk = 0;
+			break;
+		}
+		case 7:
+			if (!unk)
+				return;
+			_ip += 1;
+			unk = 0;
+			break;
+		case 8:
+			break;
+		case 9:
+			if (unk)
+				_ip += 1;
+			else {
+				assert(0);
+				//sendSaidMsgToTalker
+			}
+			return;
+		case 10:
+			break;
+		default:
+			_ip += 1;
+			unk = 0;
+			break;
+		}
+	}
+}
+
 } // End of namespace Petka
\ No newline at end of file
diff --git a/engines/petka/big_dialogue.h b/engines/petka/big_dialogue.h
index 5c00a43dd6..15c97bd869 100644
--- a/engines/petka/big_dialogue.h
+++ b/engines/petka/big_dialogue.h
@@ -62,6 +62,10 @@ class BigDialogue {
 public:
 	BigDialogue();
 
+	uint opcode();
+
+	void sub40B670(int arg);
+
 	const Dialog *findDialog(uint objId, uint opcode, bool *res) const;
 	void setDialog(uint objId, uint opcode, int index);
 
diff --git a/engines/petka/interfaces/dialog_interface.cpp b/engines/petka/interfaces/dialog_interface.cpp
new file mode 100644
index 0000000000..2d67c1e7bb
--- /dev/null
+++ b/engines/petka/interfaces/dialog_interface.cpp
@@ -0,0 +1,159 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "petka/interfaces/dialog_interface.h"
+#include "petka/interfaces/main.h"
+#include "petka/petka.h"
+#include "petka/objects/object_cursor.h"
+#include "petka/q_system.h"
+#include "petka/big_dialogue.h"
+#include "petka/sound.h"
+
+namespace Petka {
+
+DialogInterface::DialogInterface() {
+	_field18 = 3;
+	_field14 = -1;
+	_field24 = 0;
+	_field4 = 0;
+	_field8 = 0;
+	_talker = nullptr;
+	_sender = nullptr;
+	_fieldC = 0;
+	_field10 = 1;
+}
+
+void DialogInterface::start(uint a, QMessageObject *sender) {
+	_field14 = a;
+	_fieldC = 0;
+	_field24 = 0;
+	_field4 = 0;
+	_field8 = 0;
+	_talker = nullptr;
+	_field10 = 1;
+	_field18 = 3;
+	_sender = sender;
+	_soundName.clear();
+	saveCursorState();
+	sub_4155D0(-2);
+}
+
+void DialogInterface::saveCursorState() {
+	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
+	_savedCursorId = cursor->_resourceId;
+	_wasCursorAnim = cursor->_animate;
+	_wasCursorShown = cursor->_isShown;
+	cursor->_isShown = false;
+	cursor->_animate = true;
+	cursor->_resourceId = 5006;
+}
+
+void DialogInterface::restoreCursorState() {
+	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
+	cursor->_isShown = _wasCursorShown;
+	cursor->_animate = _wasCursorAnim;
+	cursor->_resourceId = _savedCursorId;
+}
+
+void DialogInterface::sub_4155D0(int a) {
+	if (_field14 == -1 || (a == -1 && _field18 == 2))
+		return;
+	if (_field18 == -1)
+		return;
+	int talkerId = -1;
+	if (a == -1 && !_field8) {
+		talkerId = g_vm->getBigDialogue()->getSpeechInfo()->speakerId;
+	}
+	_field8 = _field4;
+	g_vm->getQSystem()->_cursor.get()->_isShown = 0;
+	if (_field4)
+		return;
+	if (_field10)
+		_field10 = 0;
+	else
+		g_vm->getBigDialogue()->sub40B670(a);
+	switch (g_vm->getBigDialogue()->opcode()) {
+
+	case 1: {
+		const SpeechInfo *info = g_vm->getBigDialogue()->getSpeechInfo();
+		Common::String soundName = g_vm->getSpeechPath() + info->soundName;
+		Sound *s = g_vm->soundMgr()->addSound(soundName, Audio::Mixer::kSpeechSoundType);
+		g_vm->soundMgr()->removeSound(_soundName);
+		_soundName = soundName;
+		if (s) {
+			s->play(0);
+		}
+		g_trackedSound = s;
+		if (talkerId != info->speakerId && _talker) {
+			QMessage msg;
+			msg.objId = _talker->_id;
+			msg.opcode = kSaid;
+			msg.arg1 = 0;
+			msg.arg2 = 0;
+			msg.arg3 = 0;
+			msg.unk = 0;
+			msg.sender = nullptr;
+			_talker->processMessage(msg);
+		}
+		_talker = g_vm->getQSystem()->findObject(info->speakerId);
+		QMessage msg;
+		msg.objId = _talker->_id;
+		msg.opcode = kSay;
+		msg.arg1 = 0;
+		msg.arg2 = 0;
+		msg.arg3 = 0;
+		msg.unk = 0;
+		msg.sender = nullptr;
+		_talker->processMessage(msg);
+		_field18 = 1;
+		break;
+	}
+	case 3:
+		g_vm->soundMgr()->removeSound(_soundName);
+		if (_talker) {
+			QMessage msg;
+			msg.objId = _talker->_id;
+			msg.opcode = kSaid;
+			msg.arg1 = 0;
+			msg.arg2 = 0;
+			msg.arg3 = 0;
+			msg.unk = 0;
+			msg.sender = nullptr;
+		}
+		_talker = nullptr;
+		_field18 = 3;
+		_field14 = -1;
+		restoreCursorState();
+		// g_qReaction
+		_sender = nullptr;
+		break;
+	case 4:
+		g_vm->soundMgr()->removeSound(_soundName);
+		_talker = nullptr;
+		_field18 = 1;
+		break;
+	default:
+		break;
+	}
+}
+
+} // End of namespace Petka
diff --git a/engines/petka/interfaces/dialog_interface.h b/engines/petka/interfaces/dialog_interface.h
new file mode 100644
index 0000000000..db32b76a11
--- /dev/null
+++ b/engines/petka/interfaces/dialog_interface.h
@@ -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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_DIALOG_INTERFACE_H
+#define PETKA_DIALOG_INTERFACE_H
+
+#include "common/str.h"
+
+namespace Petka {
+
+class QMessageObject;
+
+class DialogInterface {
+public:
+	DialogInterface();
+
+	void start(uint a, QMessageObject *sender);
+
+	void saveCursorState();
+	void restoreCursorState();
+
+	void sub_4155D0(int a);
+
+public:
+	int _field4;
+	int _field8;
+	int _fieldC;
+	int _field10;
+	int _field14;
+	int _field18;
+	int _field24;
+	Common::String _soundName;
+	int16 _savedCursorActType;
+	int16 _savedCursorId;
+	bool _wasCursorShown;
+	bool _wasCursorAnim;
+	QMessageObject *_talker;
+	QMessageObject *_sender;
+
+};
+
+} // End of namespace Petka
+
+#endif
\ No newline at end of file
diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index 74d39b4231..2165576ec0 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -36,6 +36,8 @@
 
 namespace Petka {
 
+Sound *g_trackedSound = nullptr;
+
 InterfaceMain::InterfaceMain() {
 	Common::ScopedPtr<Common::SeekableReadStream> stream(g_vm->openFile("backgrnd.bg", true));
 	if (!stream)
diff --git a/engines/petka/interfaces/main.h b/engines/petka/interfaces/main.h
index 5f0972c49f..f12352e0c3 100644
--- a/engines/petka/interfaces/main.h
+++ b/engines/petka/interfaces/main.h
@@ -24,6 +24,7 @@
 #define PETKA_MAIN_H
 
 #include "petka/interfaces/interface.h"
+#include "petka/interfaces/dialog_interface.h"
 
 namespace Petka {
 
@@ -32,6 +33,10 @@ struct BGInfo {
 	Common::Array<uint16> attachedObjIds;
 };
 
+class Sound;
+
+extern Sound *g_trackedSound;
+
 class InterfaceMain : public Interface {
 public:
 	InterfaceMain();
@@ -45,6 +50,7 @@ public:
 	void unloadRoom(bool fromSave);
 
 public:
+	DialogInterface _dialog;
 	Common::Array<BGInfo> _bgs;
 	int _roomId;
 };
diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index 44cd8b6c6b..a832ab291b 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -1,6 +1,7 @@
 MODULE := engines/petka
 
 MODULE_OBJS = \
+    big_dialogue.o \
     detection.o \
     file_mgr.o \
     flc.o \
@@ -9,6 +10,7 @@ MODULE_OBJS = \
     q_system.o \
     sound.o \
     video.o \
+    interfaces/dialog_interface.o \
     interfaces/interface.o \
     interfaces/main.o \
     interfaces/panel.o \
diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index d59124b496..c5f5170fdb 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -28,6 +28,7 @@
 #include "graphics/colormasks.h"
 #include "graphics/surface.h"
 
+#include "petka/big_dialogue.h"
 #include "petka/flc.h"
 #include "petka/sound.h"
 #include "petka/petka.h"
@@ -102,6 +103,7 @@ static void processSavedReaction(QReaction **reaction, QMessageObject *obj) {
 }
 
 void QMessageObject::processMessage(const QMessage &msg) {
+	bool reacted = false;
 	for (uint i = 0; i < _reactions.size(); ++i) {
 		QReaction &r = _reactions[i];
 		if (r.opcode != msg.opcode ||
@@ -109,6 +111,11 @@ void QMessageObject::processMessage(const QMessage &msg) {
 			(r.senderId != -1 && r.senderId != msg.sender->_id)) {
 			continue;
 		}
+		bool res;
+		if (g_vm->getBigDialogue()->findDialog(_id, msg.opcode, &res) && res == 0) {
+			g_vm->getBigDialogue()->setDialog(_id, msg.opcode, -1);
+			g_vm->getQSystem()->_mainInterface->_dialog._sender = this;
+		}
 		for (uint j = 0; j < r.messages.size(); ++j) {
 			QMessage &rMsg = r.messages[j];
 			if (rMsg.opcode == kCheck && g_vm->getQSystem()->findObject(rMsg.objId)->_status != rMsg.arg1) {
@@ -148,87 +155,98 @@ void QMessageObject::processMessage(const QMessage &msg) {
 			if (processed)
 				break;
 		}
+		reacted = true;
 	}
 
-	switch (msg.opcode) {
-	case kAvi: {
-		Common::String videoName = g_vm->resMgr()->findResourceName((uint16)msg.arg1);
-		g_vm->playVideo(g_vm->openFile(videoName, false));
-		break;
-	}
-	case kSetPos:
-		setPos(msg.arg1, msg.arg2);
-		break;
-	case kSet:
-	case kPlay:
-		if (dynamic_cast<QObjectBG *>(this)) {
+	if (reacted || !g_vm->getBigDialogue()->findDialog(_id, msg.opcode, nullptr)) {
+		switch (msg.opcode) {
+		case kAvi: {
+			Common::String videoName = g_vm->resMgr()->findResourceName((uint16) msg.arg1);
+			g_vm->playVideo(g_vm->openFile(videoName, false));
 			break;
 		}
-		if (g_vm->getQSystem()->_isIniting) {
-			_resourceId = msg.arg1;
-			_notLoopedSound = msg.arg2 != 5;
-		} else {
-			_sound = g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(msg.arg1), Audio::Mixer::kSFXSoundType);
-			_hasSound = _sound != nullptr;
-			_startSound = false;
-			FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
-			if (flc) {
-				g_vm->videoSystem()->addDirtyRect(Common::Point(_x, _y), *flc);
+		case kDialog:
+			g_vm->getQSystem()->_mainInterface->_dialog.start(msg.arg1, this);
+			break;
+		case kSetPos:
+			setPos(msg.arg1, msg.arg2);
+			break;
+		case kSet:
+		case kPlay:
+			if (dynamic_cast<QObjectBG *>(this)) {
+				break;
 			}
+			if (g_vm->getQSystem()->_isIniting) {
+				_resourceId = msg.arg1;
+				_notLoopedSound = msg.arg2 != 5;
+			} else {
+				_sound = g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(msg.arg1),
+													Audio::Mixer::kSFXSoundType);
+				_hasSound = _sound != nullptr;
+				_startSound = false;
+				FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+				if (flc) {
+					g_vm->videoSystem()->addDirtyRect(Common::Point(_x, _y), *flc);
+				}
 
-			flc = g_vm->resMgr()->loadFlic(msg.arg1);
-			flc->setFrame(1);
-			_time = 0;
-			if (!_notLoopedSound) {
-				g_vm->soundMgr()->removeSound(g_vm->resMgr()->findSoundName(_resourceId));
+				flc = g_vm->resMgr()->loadFlic(msg.arg1);
+				flc->setFrame(1);
+				_time = 0;
+				if (!_notLoopedSound) {
+					g_vm->soundMgr()->removeSound(g_vm->resMgr()->findSoundName(_resourceId));
+				}
+				_resourceId = msg.arg1;
 			}
-			_resourceId = msg.arg1;
-		}
-		if (msg.arg2 == 1) {
-			FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
-			flc->setFrame(1);
-			g_vm->videoSystem()->makeAllDirty();
-			_time = 0;
-		} else if (msg.arg2 == 2) {
-			g_vm->resMgr()->loadFlic(_resourceId);
-		}
-		_notLoopedSound = msg.arg2 != 5;
-		break;
-	case kEnd:
-		if (_reaction && _reactionResId == msg.arg1) {
-			processSavedReaction(&_reaction, this);
+			if (msg.arg2 == 1) {
+				FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+				flc->setFrame(1);
+				g_vm->videoSystem()->makeAllDirty();
+				_time = 0;
+			} else if (msg.arg2 == 2) {
+				g_vm->resMgr()->loadFlic(_resourceId);
+			}
+			_notLoopedSound = msg.arg2 != 5;
+			break;
+		case kEnd:
+			if (_reaction && _reactionResId == msg.arg1) {
+				processSavedReaction(&_reaction, this);
+			}
+			break;
+		case kStatus:
+			_status = (int8) msg.arg1;
+			break;
+		case kOn:
+			_isActive = true;
+			show(true);
+			break;
+		case kOff:
+			_isActive = false;
+			show(false);
+			break;
+		case kStop:
+			g_vm->getQSystem()->_cursor.get()->show(msg.arg1);
+			g_vm->getQSystem()->_star.get()->_isActive = msg.arg1;
+		case kShow:
+			show(true);
+			break;
+		case kHide:
+			show(false);
+			break;
+		case kZBuffer:
+			_updateZ = msg.arg1;
+			_z = (msg.arg2 != -1) ? msg.arg2 : _z;
+			break;
+		case kActive:
+			_isActive = msg.arg1;
+			break;
+		case kPassive:
+			_isActive = false;
+			break;
 		}
- 		break;
-	case kStatus:
-		_status = (int8)msg.arg1;
-		break;
-	case kOn:
-		_isActive = true;
-		show(true);
-		break;
-	case kOff:
-		_isActive = false;
-		show(false);
-		break;
-	case kStop:
-		g_vm->getQSystem()->_cursor.get()->show(msg.arg1);
-		g_vm->getQSystem()->_star.get()->_isActive = msg.arg1;
-	case kShow:
-		show(true);
-		break;
-	case kHide:
-		show(false);
-		break;
-	case kZBuffer:
-		_updateZ = msg.arg1;
-		_z = (msg.arg2 != -1) ? msg.arg2 : _z;
-		break;
-	case kActive:
-		_isActive = msg.arg1;
-		break;
-	case kPassive:
-		_isActive = false;
-		break;
+	} else {
+		g_vm->getBigDialogue()->setDialog(_id, msg.opcode, -1);
+		g_vm->getQSystem()->_mainInterface->_dialog._sender = this;
+		g_vm->getQSystem()->_mainInterface->_dialog.start(msg.arg1, this);
 	}
 
 }
@@ -271,8 +289,8 @@ void QObject::draw() {
 	if (_animate && _startSound) {
 		if (_sound) {
 			_sound->play(!_notLoopedSound);
-			_startSound = false;
 		}
+		_startSound = false;
 	}
 
 	Common::Rect screen(640, 480);
diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
index 73cc33dddf..01915a2800 100644
--- a/engines/petka/petka.cpp
+++ b/engines/petka/petka.cpp
@@ -43,6 +43,8 @@
 #include "petka/interfaces/interface.h"
 #include "petka/q_system.h"
 #include "petka/big_dialogue.h"
+#include "petka.h"
+
 
 namespace Petka {
 
@@ -218,9 +220,17 @@ void PetkaEngine::loadPart(byte part) {
 
 	_resMgr.reset(new QManager(*this));
 	_resMgr->init();
+	_dialogMan.reset(new BigDialogue());
 	_qsystem.reset(new QSystem());
 	_qsystem->init();
-	_dialogMan.reset(new BigDialogue());
+}
+
+BigDialogue *PetkaEngine::getBigDialogue() const {
+	return _dialogMan.get();
+}
+
+const Common::String &PetkaEngine::getSpeechPath() {
+	return _speechPath;
 }
 
 } // End of namespace Petka
diff --git a/engines/petka/petka.h b/engines/petka/petka.h
index 9dd004916b..87c25784a8 100644
--- a/engines/petka/petka.h
+++ b/engines/petka/petka.h
@@ -63,11 +63,15 @@ public:
 
 	void playVideo(Common::SeekableReadStream *stream);
 	QSystem *getQSystem() const;
+	BigDialogue *getBigDialogue() const;
 	SoundMgr *soundMgr() const;
 	QManager *resMgr() const;
+
 	VideoSystem *videoSystem() const;
 
 	Common::RandomSource &getRnd();
+	const Common::String &getSpeechPath();
+
 private:
 	void loadStores();
 


Commit: 25b6c21992dad2f8fc6d5e9ca1eecd1cde4200fd
    https://github.com/scummvm/scummvm/commit/25b6c21992dad2f8fc6d5e9ca1eecd1cde4200fd
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: hack to continue dialog after phrase ends

Changed paths:
    engines/petka/video.cpp


diff --git a/engines/petka/video.cpp b/engines/petka/video.cpp
index 4c8e516502..beab2e2303 100644
--- a/engines/petka/video.cpp
+++ b/engines/petka/video.cpp
@@ -22,10 +22,12 @@
 
 #include "common/system.h"
 
+#include "petka/sound.h"
 #include "petka/flc.h"
 #include "petka/petka.h"
 #include "petka/q_system.h"
-#include "petka/interfaces/interface.h"
+#include "petka/interfaces/main.h"
+#include "petka/interfaces/dialog_interface.h"
 #include "petka/objects/object.h"
 #include "petka/video.h"
 
@@ -49,6 +51,10 @@ void VideoSystem::update() {
 			interface->_objs[i]->update(time - _time);
 		}
 
+		if ((g_trackedSound && !g_trackedSound->isPlaying()) || !g_trackedSound) {
+			g_vm->getQSystem()->_mainInterface->_dialog.sub_4155D0(-1);
+		}
+
 		for (uint i = 0; i < interface->_objs.size(); ++i) {
 			interface->_objs[i]->updateZ();
 		}


Commit: c001172f62456c03278fc4ee558a9e332cd20e35
    https://github.com/scummvm/scummvm/commit/c001172f62456c03278fc4ee558a9e332cd20e35
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added misssing opcode to dialogs

Changed paths:
    engines/petka/big_dialogue.cpp


diff --git a/engines/petka/big_dialogue.cpp b/engines/petka/big_dialogue.cpp
index ec214251e9..e805f3248a 100644
--- a/engines/petka/big_dialogue.cpp
+++ b/engines/petka/big_dialogue.cpp
@@ -231,6 +231,8 @@ void BigDialogue::sub40B670(int arg) {
 			unk = 0;
 			break;
 		}
+		case 6:
+			return;
 		case 7:
 			if (!unk)
 				return;


Commit: 9f9210b236492fdd740f23699ac7eb7bbb94d9fd
    https://github.com/scummvm/scummvm/commit/9f9210b236492fdd740f23699ac7eb7bbb94d9fd
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added implementation of dialog opcode

Changed paths:
    engines/petka/interfaces/dialog_interface.cpp
    engines/petka/objects/object.cpp
    engines/petka/objects/object.h


diff --git a/engines/petka/interfaces/dialog_interface.cpp b/engines/petka/interfaces/dialog_interface.cpp
index 2d67c1e7bb..8c12efbe2b 100644
--- a/engines/petka/interfaces/dialog_interface.cpp
+++ b/engines/petka/interfaces/dialog_interface.cpp
@@ -143,7 +143,8 @@ void DialogInterface::sub_4155D0(int a) {
 		_field18 = 3;
 		_field14 = -1;
 		restoreCursorState();
-		// g_qReaction
+		if (g_dialogReaction)
+			processSavedReaction(&g_dialogReaction, _sender);
 		_sender = nullptr;
 		break;
 	case 4:
diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index c5f5170fdb..f32a70baab 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -41,6 +41,8 @@
 
 namespace Petka {
 
+QReaction *g_dialogReaction = nullptr; // FIXME
+
 QVisibleObject::QVisibleObject()
 	: _resourceId(-1), _z(240) {}
 
@@ -60,17 +62,21 @@ QMessageObject::QMessageObject() {
 	_reaction = nullptr;
 }
 
-static void processSavedReaction(QReaction **reaction, QMessageObject *obj) {
+void processSavedReaction(QReaction **reaction, QMessageObject *sender) {
 	QReaction *r = *reaction;
 	for (uint i = 0; i < r->messages.size(); ++i) {
 		QMessage &msg = r->messages[i];
 		if (msg.opcode == kCheck && g_vm->getQSystem()->findObject(msg.objId)->_status != msg.arg1) {
 			break;
 		}
-		g_vm->getQSystem()->addMessage(msg.objId, msg.opcode, msg.arg1, msg.arg2, msg.arg3, 0, obj);
+		g_vm->getQSystem()->addMessage(msg.objId, msg.opcode, msg.arg1, msg.arg2, msg.arg3, 0, sender);
 		bool processed = true;
 		switch (msg.opcode) {
 		case kDialog:
+			g_dialogReaction = new QReaction();
+			for (uint j = i + 1; j < r->messages.size(); ++j) {
+				g_dialogReaction->messages.push_back(r->messages[j]);
+			}
 			break;
 		case kPlay: {
 			QMessageObject *obj = g_vm->getQSystem()->findObject(msg.objId);
@@ -94,9 +100,7 @@ static void processSavedReaction(QReaction **reaction, QMessageObject *obj) {
 	}
 	if (*reaction != r) {
 		delete r;
-		return;
-	}
-	if (*reaction) {
+	} else if (*reaction) {
 		delete *reaction;
 		*reaction = nullptr;
 	}
@@ -134,6 +138,13 @@ void QMessageObject::processMessage(const QMessage &msg) {
 										   rMsg.sender);
 			bool processed = true;
 			switch (rMsg.opcode) {
+			case kDialog:
+				delete g_dialogReaction;
+				g_dialogReaction = new QReaction();
+				for (uint z = j + 1; z < r.messages.size(); ++z) {
+					g_dialogReaction->messages.push_back(r.messages[z]);
+				}
+				break;
 			case kPlay: {
 				QMessageObject *obj = g_vm->getQSystem()->findObject(rMsg.objId);
 				delete obj->_reaction;
@@ -246,6 +257,20 @@ void QMessageObject::processMessage(const QMessage &msg) {
 	} else {
 		g_vm->getBigDialogue()->setDialog(_id, msg.opcode, -1);
 		g_vm->getQSystem()->_mainInterface->_dialog._sender = this;
+		for (uint i = 0; i < _reactions.size(); ++i) {
+			QReaction &r = _reactions[i];
+			if (r.opcode != msg.opcode ||
+				(r.status != -1 && r.status != _status) ||
+				(r.senderId != -1 && r.senderId != msg.sender->_id)) {
+				continue;
+			}
+			delete g_dialogReaction;
+			g_dialogReaction = new QReaction();
+			for (uint j = 0; j < r.messages.size(); ++j) {
+				g_dialogReaction->messages.push_back(r.messages[j]);
+			}
+			break;
+		}
 		g_vm->getQSystem()->_mainInterface->_dialog.start(msg.arg1, this);
 	}
 
diff --git a/engines/petka/objects/object.h b/engines/petka/objects/object.h
index e7e72ec836..6c4abd2790 100644
--- a/engines/petka/objects/object.h
+++ b/engines/petka/objects/object.h
@@ -27,6 +27,8 @@
 
 namespace Petka {
 
+extern void processSavedReaction(QReaction **reaction, QMessageObject *sender);
+
 class QVisibleObject {
 public:
 	QVisibleObject();
@@ -94,6 +96,8 @@ public:
 	void show(bool v) override;
 };
 
+extern QReaction *g_dialogReaction;
+
 } // End of namespace Petka
 
 #endif


Commit: b89b0930f5d6397dd28f442ad0fe188ab5f72330
    https://github.com/scummvm/scummvm/commit/b89b0930f5d6397dd28f442ad0fe188ab5f72330
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: send SAID opcode after dialog ends

Changed paths:
    engines/petka/interfaces/dialog_interface.cpp


diff --git a/engines/petka/interfaces/dialog_interface.cpp b/engines/petka/interfaces/dialog_interface.cpp
index 8c12efbe2b..970e532219 100644
--- a/engines/petka/interfaces/dialog_interface.cpp
+++ b/engines/petka/interfaces/dialog_interface.cpp
@@ -138,8 +138,9 @@ void DialogInterface::sub_4155D0(int a) {
 			msg.arg3 = 0;
 			msg.unk = 0;
 			msg.sender = nullptr;
+			_talker->processMessage(msg);
+			_talker = nullptr;
 		}
-		_talker = nullptr;
 		_field18 = 3;
 		_field14 = -1;
 		restoreCursorState();


Commit: 38f267926646e19a46ea851ae611b5d4622856fe
    https://github.com/scummvm/scummvm/commit/38f267926646e19a46ea851ae611b5d4622856fe
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: some refactoring of dialog interface

Changed paths:
    engines/petka/interfaces/dialog_interface.cpp
    engines/petka/interfaces/dialog_interface.h


diff --git a/engines/petka/interfaces/dialog_interface.cpp b/engines/petka/interfaces/dialog_interface.cpp
index 970e532219..5dbdaded26 100644
--- a/engines/petka/interfaces/dialog_interface.cpp
+++ b/engines/petka/interfaces/dialog_interface.cpp
@@ -92,61 +92,27 @@ void DialogInterface::sub_4155D0(int a) {
 	else
 		g_vm->getBigDialogue()->sub40B670(a);
 	switch (g_vm->getBigDialogue()->opcode()) {
-
 	case 1: {
 		const SpeechInfo *info = g_vm->getBigDialogue()->getSpeechInfo();
-		Common::String soundName = g_vm->getSpeechPath() + info->soundName;
-		Sound *s = g_vm->soundMgr()->addSound(soundName, Audio::Mixer::kSpeechSoundType);
 		g_vm->soundMgr()->removeSound(_soundName);
-		_soundName = soundName;
+		if (talkerId != info->speakerId) {
+			sendMsg(kSaid);
+		}
+		_soundName = g_vm->getSpeechPath() + info->soundName;
+		Sound *s = g_vm->soundMgr()->addSound(_soundName, Audio::Mixer::kSpeechSoundType);
 		if (s) {
 			s->play(0);
 		}
 		g_trackedSound = s;
-		if (talkerId != info->speakerId && _talker) {
-			QMessage msg;
-			msg.objId = _talker->_id;
-			msg.opcode = kSaid;
-			msg.arg1 = 0;
-			msg.arg2 = 0;
-			msg.arg3 = 0;
-			msg.unk = 0;
-			msg.sender = nullptr;
-			_talker->processMessage(msg);
-		}
 		_talker = g_vm->getQSystem()->findObject(info->speakerId);
-		QMessage msg;
-		msg.objId = _talker->_id;
-		msg.opcode = kSay;
-		msg.arg1 = 0;
-		msg.arg2 = 0;
-		msg.arg3 = 0;
-		msg.unk = 0;
-		msg.sender = nullptr;
-		_talker->processMessage(msg);
+		if (talkerId != info->speakerId) {
+			sendMsg(kSay);
+		}
 		_field18 = 1;
 		break;
 	}
 	case 3:
-		g_vm->soundMgr()->removeSound(_soundName);
-		if (_talker) {
-			QMessage msg;
-			msg.objId = _talker->_id;
-			msg.opcode = kSaid;
-			msg.arg1 = 0;
-			msg.arg2 = 0;
-			msg.arg3 = 0;
-			msg.unk = 0;
-			msg.sender = nullptr;
-			_talker->processMessage(msg);
-			_talker = nullptr;
-		}
-		_field18 = 3;
-		_field14 = -1;
-		restoreCursorState();
-		if (g_dialogReaction)
-			processSavedReaction(&g_dialogReaction, _sender);
-		_sender = nullptr;
+		end();
 		break;
 	case 4:
 		g_vm->soundMgr()->removeSound(_soundName);
@@ -158,4 +124,30 @@ void DialogInterface::sub_4155D0(int a) {
 	}
 }
 
+void DialogInterface::sendMsg(uint16 opcode) {
+	if (_talker) {
+		QMessage msg;
+		msg.objId = _talker->_id;
+		msg.opcode = opcode;
+		msg.arg1 = 0;
+		msg.arg2 = 0;
+		msg.arg3 = 0;
+		msg.unk = 0;
+		msg.sender = nullptr;
+		_talker->processMessage(msg);
+	}
+}
+
+void DialogInterface::end() {
+	g_vm->soundMgr()->removeSound(_soundName);
+	sendMsg(kSaid);
+	_talker = nullptr;
+	_field18 = 3;
+	_field14 = -1;
+	restoreCursorState();
+	if (g_dialogReaction)
+		processSavedReaction(&g_dialogReaction, _sender);
+	_sender = nullptr;
+}
+
 } // End of namespace Petka
diff --git a/engines/petka/interfaces/dialog_interface.h b/engines/petka/interfaces/dialog_interface.h
index db32b76a11..ded80b92fa 100644
--- a/engines/petka/interfaces/dialog_interface.h
+++ b/engines/petka/interfaces/dialog_interface.h
@@ -40,6 +40,9 @@ public:
 
 	void sub_4155D0(int a);
 
+	void sendMsg(uint16 opcode);
+	void end();
+
 public:
 	int _field4;
 	int _field8;


Commit: f94ba47d840f3581ce442b0e03329a99395a541f
    https://github.com/scummvm/scummvm/commit/f94ba47d840f3581ce442b0e03329a99395a541f
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: disabled walk opcodes because of no implementation

Changed paths:
    engines/petka/objects/object.cpp


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index f32a70baab..910d153f4a 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -87,10 +87,12 @@ void processSavedReaction(QReaction **reaction, QMessageObject *sender) {
 			}
 			break;
 		}
+		/*
 		case kWalk:
 		case kWalkTo:
 		case kWalkVich:
 			break;
+		 */
 		default:
 			processed = false;
 			break;
@@ -155,11 +157,12 @@ void QMessageObject::processMessage(const QMessage &msg) {
 				}
 				break;
 			}
+			/*
 			case kWalk:
 			case kWalkTo:
-				break;
 			case kWalkVich:
 				break;
+			 */
 			default:
 				processed = false;
 			}


Commit: 5e34a2a507328eb31ee00ee3e31fb95c249e5836
    https://github.com/scummvm/scummvm/commit/5e34a2a507328eb31ee00ee3e31fb95c249e5836
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added hero classes

Changed paths:
  A engines/petka/objects/heroes.cpp
  A engines/petka/objects/heroes.h
    engines/petka/q_system.cpp
    engines/petka/q_system.h


diff --git a/engines/petka/objects/heroes.cpp b/engines/petka/objects/heroes.cpp
new file mode 100644
index 0000000000..df723dcb9f
--- /dev/null
+++ b/engines/petka/objects/heroes.cpp
@@ -0,0 +1,35 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "petka/objects/heroes.h"
+
+namespace Petka {
+
+QObjectChapayev::QObjectChapayev() {
+
+}
+
+QObjectPetka::QObjectPetka() {
+
+}
+
+}
diff --git a/engines/petka/objects/heroes.h b/engines/petka/objects/heroes.h
new file mode 100644
index 0000000000..94d7a3b5c9
--- /dev/null
+++ b/engines/petka/objects/heroes.h
@@ -0,0 +1,48 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_HEROES_H
+#define PETKA_HEROES_H
+
+#include "petka/objects/object.h"
+
+namespace Petka {
+
+class QObjectPetka : public QObject {
+public:
+	QObjectPetka();
+
+private:
+
+};
+
+class QObjectChapayev : public QObjectPetka {
+public:
+	QObjectChapayev();
+
+private:
+
+};
+
+} // End of namespace Petka
+
+#endif
\ No newline at end of file
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 97a90e8c54..3d733d12d6 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -33,13 +33,14 @@
 #include "petka/objects/object_cursor.h"
 #include "petka/objects/object_case.h"
 #include "petka/objects/object_star.h"
+#include "petka/objects/heroes.h"
 #include "petka/q_system.h"
 
 namespace Petka {
 
 QSystem::QSystem()
-	: _cursor(nullptr), _case(nullptr), _star(nullptr), _mainInterface(nullptr),
-	_currInterface(nullptr), _prevInterface(nullptr), _isIniting(0) {}
+	: _cursor(nullptr), _case(nullptr), _star(nullptr), _petka(nullptr), _chapayev(nullptr),
+	_mainInterface(nullptr), _currInterface(nullptr), _prevInterface(nullptr), _isIniting(0) {}
 
 QSystem::~QSystem() {
 
@@ -109,12 +110,20 @@ bool QSystem::init() {
 	if (bgsStream)
 		bgsIni.loadFromStream(*bgsStream);
 
-	uint32 objsCount = stream->readUint32LE();
+	uint32 objsCount = stream->readUint32LE() - 2;
 	uint32 bgsCount = stream->readUint32LE();
 
 	_objs.resize(objsCount);
 	_bgs.resize(bgsCount);
 
+	_petka.reset(new QObjectPetka());
+	readObject(*_petka, *stream, namesIni, castIni);
+	_allObjects.push_back(_petka.get());
+
+	_chapayev.reset(new QObjectChapayev());
+	readObject(*_chapayev, *stream, namesIni, castIni);
+	_allObjects.push_back(_chapayev.get());
+
 	Common::String name;
 	for (uint i = 0; i < objsCount; ++i) {
 		readObject(_objs[i], *stream, namesIni, castIni);
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index 6b11ce00d6..9603f3f408 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -34,6 +34,8 @@ class PetkaEngine;
 class QObjectCase;
 class QObjectCursor;
 class QObjectStar;
+class QObjectPetka;
+class QObjectChapayev;
 class InterfaceSaveLoad;
 class InterfaceMain;
 class InterfaceStartup;
@@ -61,6 +63,8 @@ public:
 	Common::Array<QObjectBG> _bgs;
 	Common::Array<QMessageObject *> _allObjects;
 	Common::List<QMessage> _messages;
+	Common::ScopedPtr<QObjectPetka> _petka;
+	Common::ScopedPtr<QObjectChapayev> _chapayev;
 	Common::ScopedPtr<QObjectCursor> _cursor;
 	Common::ScopedPtr<QObjectCase> _case;
 	Common::ScopedPtr<QObjectStar> _star;


Commit: 2f4c7107970cd5f5bd1c3f78153203d38a0cff9d
    https://github.com/scummvm/scummvm/commit/2f4c7107970cd5f5bd1c3f78153203d38a0cff9d
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented dialog opcode 0x09

Changed paths:
    engines/petka/big_dialogue.cpp


diff --git a/engines/petka/big_dialogue.cpp b/engines/petka/big_dialogue.cpp
index e805f3248a..b38bbfbed2 100644
--- a/engines/petka/big_dialogue.cpp
+++ b/engines/petka/big_dialogue.cpp
@@ -24,6 +24,10 @@
 
 #include "petka/base.h"
 #include "petka/big_dialogue.h"
+#include "petka/interfaces/main.h"
+#include "petka/interfaces/dialog_interface.h"
+#include "petka/objects/heroes.h"
+#include "petka/q_system.h"
 #include "petka/petka.h"
 
 namespace Petka {
@@ -245,8 +249,10 @@ void BigDialogue::sub40B670(int arg) {
 			if (unk)
 				_ip += 1;
 			else {
-				assert(0);
-				//sendSaidMsgToTalker
+				g_vm->getQSystem()->_mainInterface->_dialog.sendMsg(kSaid);
+				g_vm->getQSystem()->_mainInterface->_dialog._field4 = 1;
+				g_vm->getQSystem()->_mainInterface->_dialog.restoreCursorState();
+				g_vm->getQSystem()->addMessage(g_vm->getQSystem()->_chapayev->_id, kUserMsg, *_ip);
 			}
 			return;
 		case 10:


Commit: 0148ee59edb0b7de8e6a3418b1e7abb4a0bdeb1a
    https://github.com/scummvm/scummvm/commit/0148ee59edb0b7de8e6a3418b1e7abb4a0bdeb1a
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added missing object file to module.mk

Changed paths:
    engines/petka/module.mk


diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index a832ab291b..b1d39eaebf 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -20,7 +20,8 @@ MODULE_OBJS = \
     objects/object_bg.o \
     objects/object_case.o \
     objects/object_cursor.o \
-    objects/object_star.o
+    objects/object_star.o \
+    objects/heroes.o
 
 # This module can be built as a plugin
 ifeq ($(ENABLE_PETKA), DYNAMIC_PLUGIN)


Commit: c1815c18e586b0d6c859ddcd44b11eeb0679e851
    https://github.com/scummvm/scummvm/commit/c1815c18e586b0d6c859ddcd44b11eeb0679e851
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added Text class

Changed paths:
  A engines/petka/objects/text.cpp
  A engines/petka/objects/text.h
    engines/petka/interfaces/dialog_interface.cpp
    engines/petka/interfaces/interface.cpp
    engines/petka/interfaces/interface.h
    engines/petka/module.mk


diff --git a/engines/petka/interfaces/dialog_interface.cpp b/engines/petka/interfaces/dialog_interface.cpp
index 5dbdaded26..a64319a4ba 100644
--- a/engines/petka/interfaces/dialog_interface.cpp
+++ b/engines/petka/interfaces/dialog_interface.cpp
@@ -108,6 +108,7 @@ void DialogInterface::sub_4155D0(int a) {
 		if (talkerId != info->speakerId) {
 			sendMsg(kSay);
 		}
+		g_vm->getQSystem()->_mainInterface->setText(info->text, _talker->_dialogColor);
 		_field18 = 1;
 		break;
 	}
diff --git a/engines/petka/interfaces/interface.cpp b/engines/petka/interfaces/interface.cpp
index abb015c072..85a45dd5bf 100644
--- a/engines/petka/interfaces/interface.cpp
+++ b/engines/petka/interfaces/interface.cpp
@@ -20,6 +20,7 @@
  *
  */
 
+#include "petka/objects/text.h"
 #include "petka/interfaces/interface.h"
 
 namespace Petka {
@@ -27,4 +28,8 @@ namespace Petka {
 Interface::Interface()
 	: _objUnderCursor(nullptr), _startIndex(0) {}
 
+void Interface::setText(const Common::U32String &text, uint32 rgb) {
+	_objs.push_back(new QText(text, rgb));
+}
+
 } // End of namespace Petka
diff --git a/engines/petka/interfaces/interface.h b/engines/petka/interfaces/interface.h
index 79d235bf32..3db864d032 100644
--- a/engines/petka/interfaces/interface.h
+++ b/engines/petka/interfaces/interface.h
@@ -23,12 +23,14 @@
 #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:
@@ -42,6 +44,8 @@ public:
 	virtual void onRightButtonDown(const Common::Point p) {};
 	virtual void onMouseMove(const Common::Point p) {};
 
+	void setText(const Common::U32String &text, uint32 rgb);
+
 public:
 	Common::Array<QVisibleObject *> _objs;
 	QVisibleObject *_objUnderCursor;
diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index b1d39eaebf..1bc89754b9 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -21,7 +21,8 @@ MODULE_OBJS = \
     objects/object_case.o \
     objects/object_cursor.o \
     objects/object_star.o \
-    objects/heroes.o
+    objects/heroes.o \
+    objects/text.o
 
 # This module can be built as a plugin
 ifeq ($(ENABLE_PETKA), DYNAMIC_PLUGIN)
diff --git a/engines/petka/objects/text.cpp b/engines/petka/objects/text.cpp
new file mode 100644
index 0000000000..a9aabcce17
--- /dev/null
+++ b/engines/petka/objects/text.cpp
@@ -0,0 +1,49 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "graphics/fontman.h"
+#include "graphics/font.h"
+
+#include "petka/q_manager.h"
+#include "petka/petka.h"
+#include "petka/video.h"
+#include "petka/objects/text.h"
+
+namespace Petka {
+
+QText::QText(const Common::U32String &text, uint32 rgb) {
+	_resourceId = -2;
+	_z = 3000;
+	const Graphics::Font *font = FontMan.getFontByUsage(Graphics::FontManager::kLocalizedFont);
+	_rect = font->getBoundingBox("TEST FONT", 0, 0, 0);
+
+	Graphics::Surface *s = g_vm->resMgr()->findOrCreateSurface(-2, _rect.width(), _rect.height());
+	font->drawString(s, "TEST FONT", 0, 0, _rect.width(), rgb);
+}
+
+void QText::draw() {
+	const Graphics::Font *font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont);
+	const Graphics::Surface *s = g_vm->resMgr()->loadBitmap(_resourceId);
+	g_vm->videoSystem()->screen().transBlitFrom(*s, Common::Point((640 - _rect.width()) / 2, 480 - _rect.height()));
+}
+
+} // End of namespace Petka
diff --git a/engines/petka/objects/text.h b/engines/petka/objects/text.h
new file mode 100644
index 0000000000..3771e401ca
--- /dev/null
+++ b/engines/petka/objects/text.h
@@ -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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_TEXT_H
+#define PETKA_TEXT_H
+
+#include "common/rect.h"
+#include "common/ustr.h"
+
+#include "petka/objects/object.h"
+
+namespace Petka {
+
+class QText : public QVisibleObject {
+public:
+	QText(const Common::U32String &text, uint32 rgb);
+
+	void draw();
+
+private:
+	Common::Rect _rect;
+};
+
+} // End of namespace Petka
+
+#endif


Commit: 42a90418f355865a4120e040a488ddb60168287c
    https://github.com/scummvm/scummvm/commit/42a90418f355865a4120e040a488ddb60168287c
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: removed unnecessary variable

Changed paths:
    engines/petka/q_system.cpp


diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 3d733d12d6..32e1d7d300 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -124,7 +124,6 @@ bool QSystem::init() {
 	readObject(*_chapayev, *stream, namesIni, castIni);
 	_allObjects.push_back(_chapayev.get());
 
-	Common::String name;
 	for (uint i = 0; i < objsCount; ++i) {
 		readObject(_objs[i], *stream, namesIni, castIni);
 		_allObjects.push_back(&_objs[i]);


Commit: f3a2cd951af265a9b4e059a5615906cfefe09765
    https://github.com/scummvm/scummvm/commit/f3a2cd951af265a9b4e059a5615906cfefe09765
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented dialog opcode 0x10

Changed paths:
    engines/petka/big_dialogue.cpp


diff --git a/engines/petka/big_dialogue.cpp b/engines/petka/big_dialogue.cpp
index b38bbfbed2..040d0bb05b 100644
--- a/engines/petka/big_dialogue.cpp
+++ b/engines/petka/big_dialogue.cpp
@@ -216,6 +216,7 @@ void BigDialogue::sub40B670(int arg) {
 	if (!_ip)
 		return;
 	int unk = 1;
+label:
 	if (arg != -1 && (*_ip >> 24) != 2) {
 		arg = -1;
 	}
@@ -256,7 +257,15 @@ void BigDialogue::sub40B670(int arg) {
 			}
 			return;
 		case 10:
-			break;
+			do {
+				if (op == 8) {
+					break;
+				}
+				--_ip;
+				op = (*_ip >> 24);
+			} while (op != 2);
+			unk = 1;
+			goto label;
 		default:
 			_ip += 1;
 			unk = 0;


Commit: 75bb3c85c94b78e46aceb829142e634532ba131c
    https://github.com/scummvm/scummvm/commit/75bb3c85c94b78e46aceb829142e634532ba131c
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented dialog opcode 0x08

Changed paths:
    engines/petka/big_dialogue.cpp


diff --git a/engines/petka/big_dialogue.cpp b/engines/petka/big_dialogue.cpp
index 040d0bb05b..09cb3a8911 100644
--- a/engines/petka/big_dialogue.cpp
+++ b/engines/petka/big_dialogue.cpp
@@ -244,8 +244,19 @@ label:
 			_ip += 1;
 			unk = 0;
 			break;
-		case 8:
+		case 8: {
+			if (!unk)
+				return;
+			*_ip = (*_ip & 0xFF00FFFF) | ((byte)(((byte)(*_ip >> 16) + 1) % (int16)*_ip) << 16);
+			int n = *_ip & 0xFF;
+			for (int i = 0; i < n; ++i) {
+				while ((*_ip >> 24) != 10)
+					_ip += 1;
+				_ip += 1;
+			}
+			unk = 0;
 			break;
+		}
 		case 9:
 			if (unk)
 				_ip += 1;


Commit: a366e65aad691a36d8f5580fa59e6dceaaac3c85
    https://github.com/scummvm/scummvm/commit/a366e65aad691a36d8f5580fa59e6dceaaac3c85
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented dialog opcode 0x02

Changed paths:
    engines/petka/big_dialogue.cpp


diff --git a/engines/petka/big_dialogue.cpp b/engines/petka/big_dialogue.cpp
index 09cb3a8911..373b22e84b 100644
--- a/engines/petka/big_dialogue.cpp
+++ b/engines/petka/big_dialogue.cpp
@@ -216,15 +216,43 @@ void BigDialogue::sub40B670(int arg) {
 	if (!_ip)
 		return;
 	int unk = 1;
+	int unk2;
 label:
+	unk2 = arg;
 	if (arg != -1 && (*_ip >> 24) != 2) {
 		arg = -1;
 	}
 	while (true) {
 		byte op = (*_ip >> 24);
 		switch (op) {
-		case 2:
+		case 2: {
+			if (!unk)
+				return;
+			if (unk2 < 0) {
+				arg = 0;
+				unk2 = 0;
+			}
+			int n = (byte)*_ip;
+			if (n <= unk2)
+				arg = (byte) *_ip - 1;
+			int a1 = 0;
+			int a2 = 1;
+			int a3 = (*_ip >> 8) & 0xFFFF;
+			for (int i = 0; i < n;) {
+				if ((*_ip >> 24) == 10) {
+					++i;
+					if ((a3 & a2) && a1 <= arg)
+						arg++;
+					a2 *= 2;
+					a1++;
+				}
+				_ip += 1;
+			}
+			_ip += arg;
+			unk2 = arg;
+			unk = 0;
 			break;
+		}
 		case 3:
 			_ip = &_code[*_ip & 0xFFFF];
 			break;


Commit: 464718e8960f38cc95645815630d28c41b1ac468
    https://github.com/scummvm/scummvm/commit/464718e8960f38cc95645815630d28c41b1ac468
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented handling dialog opcode 0x2 when engine needs speech info

Changed paths:
    engines/petka/big_dialogue.cpp
    engines/petka/big_dialogue.h
    engines/petka/interfaces/dialog_interface.cpp


diff --git a/engines/petka/big_dialogue.cpp b/engines/petka/big_dialogue.cpp
index 373b22e84b..ec7980f98f 100644
--- a/engines/petka/big_dialogue.cpp
+++ b/engines/petka/big_dialogue.cpp
@@ -100,14 +100,39 @@ void BigDialogue::loadSpeechesInfo() {
 	delete[] str;
 }
 
-const SpeechInfo *BigDialogue::getSpeechInfo() {
+const SpeechInfo *BigDialogue::getSpeechInfo(int unk) {
 	if (!_ip)
 		return nullptr;
+	int *oldIp = _ip;
+	int op = *_ip;
 	byte opcode = (byte)(*_ip >> 24);
 	switch (opcode) {
-	case 2:
-		// not implemented
-		break;
+	case 2: {
+		int unk1 = 1;
+		byte arg = (byte)*_ip;
+		if (arg <= unk || unk >= 0) {
+			break;
+		}
+		while (true) {
+			_ip += 1;
+			if (unk == 0 && (unk1 & ((op >> 8) & 0xFFFF)))
+				break;
+			if ((*_ip >> 24) == 0x1) {
+				if (unk1 & ((op >> 8) & 0xFFFF))
+					unk--;
+				unk1 *= 2;
+			}
+		}
+		if ((*_ip >> 24) != 0x7)
+			sub40B670(-1);
+		if ((*_ip >> 24) != 0x7) {
+			_ip = oldIp;
+			break;
+		}
+		uint index = (uint16)*_ip;
+		_ip = oldIp;
+		return &_speeches[index];
+	}
 	case 8:
 		_ip += 1;
 		for (uint i = 0; i < ((*_ip >> 16) & 0xFF); ++i) {
diff --git a/engines/petka/big_dialogue.h b/engines/petka/big_dialogue.h
index 15c97bd869..74aa1c35a3 100644
--- a/engines/petka/big_dialogue.h
+++ b/engines/petka/big_dialogue.h
@@ -69,7 +69,7 @@ public:
 	const Dialog *findDialog(uint objId, uint opcode, bool *res) const;
 	void setDialog(uint objId, uint opcode, int index);
 
-	const SpeechInfo *getSpeechInfo();
+	const SpeechInfo *getSpeechInfo(int unk);
 
 private:
 	void loadSpeechesInfo();
diff --git a/engines/petka/interfaces/dialog_interface.cpp b/engines/petka/interfaces/dialog_interface.cpp
index a64319a4ba..87dfab0530 100644
--- a/engines/petka/interfaces/dialog_interface.cpp
+++ b/engines/petka/interfaces/dialog_interface.cpp
@@ -81,7 +81,7 @@ void DialogInterface::sub_4155D0(int a) {
 		return;
 	int talkerId = -1;
 	if (a == -1 && !_field8) {
-		talkerId = g_vm->getBigDialogue()->getSpeechInfo()->speakerId;
+		talkerId = g_vm->getBigDialogue()->getSpeechInfo(-1)->speakerId;
 	}
 	_field8 = _field4;
 	g_vm->getQSystem()->_cursor.get()->_isShown = 0;
@@ -93,7 +93,7 @@ void DialogInterface::sub_4155D0(int a) {
 		g_vm->getBigDialogue()->sub40B670(a);
 	switch (g_vm->getBigDialogue()->opcode()) {
 	case 1: {
-		const SpeechInfo *info = g_vm->getBigDialogue()->getSpeechInfo();
+		const SpeechInfo *info = g_vm->getBigDialogue()->getSpeechInfo(-1);
 		g_vm->soundMgr()->removeSound(_soundName);
 		if (talkerId != info->speakerId) {
 			sendMsg(kSaid);


Commit: 0559732e0573de3a5c030712367a475145da089d
    https://github.com/scummvm/scummvm/commit/0559732e0573de3a5c030712367a475145da089d
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added engine description

Changed paths:
    engines/petka/petka.h


diff --git a/engines/petka/petka.h b/engines/petka/petka.h
index 87c25784a8..d40fd274af 100644
--- a/engines/petka/petka.h
+++ b/engines/petka/petka.h
@@ -29,6 +29,17 @@
 
 #include "gui/debugger.h"
 
+/*
+ *  This is the namespace of the Petka engine.
+ *
+ *  Status of this engine: In Development
+ *
+ *  Games using this engine:
+ *  - Red Comrades Demo
+ *  - Red Comrades Save the Galaxy
+ *  - Red Comrades 2: For the Great Justice
+ */
+
 struct ADGameDescription;
 
 namespace Common {


Commit: d8aa13402590210f48ae722430aa5a5c52c89b52
    https://github.com/scummvm/scummvm/commit/d8aa13402590210f48ae722430aa5a5c52c89b52
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added debug log to Engine class

Changed paths:
    engines/petka/petka.cpp
    engines/petka/petka.h


diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
index 01915a2800..9f1ab06469 100644
--- a/engines/petka/petka.cpp
+++ b/engines/petka/petka.cpp
@@ -43,8 +43,6 @@
 #include "petka/interfaces/interface.h"
 #include "petka/q_system.h"
 #include "petka/big_dialogue.h"
-#include "petka.h"
-
 
 namespace Petka {
 
@@ -53,17 +51,26 @@ PetkaEngine *g_vm;
 PetkaEngine::PetkaEngine(OSystem *system, const ADGameDescription *desc)
 	: Engine(system), _console(nullptr), _fileMgr(nullptr), _resMgr(nullptr),
 	_qsystem(nullptr), _vsys(nullptr), _desc(desc), _rnd("petka") {
+
 	DebugMan.addDebugChannel(kPetkaDebugGeneral, "general", "General issues");
+	DebugMan.addDebugChannel(kPetkaDebugMessagingSystem, "resources", "Resources");
+	DebugMan.addDebugChannel(kPetkaDebugMessagingSystem, "message_system", "Engine message system");
+	DebugMan.addDebugChannel(kPetkaDebugDialogs, "dialogs", "Dialogs");
+
 	_part = 0;
 	_chapter = 0;
 	g_vm = this;
+
+	debug("PetkaEngine::ctor");
 }
 
 PetkaEngine::~PetkaEngine() {
+	debug("PetkaEngine::dtor");
 	DebugMan.clearAllDebugChannels();
 }
 
 Common::Error PetkaEngine::run() {
+	debug("PetkaEngine::run");
 	const Graphics::PixelFormat format(2, 5, 6, 5, 0, 11, 5, 0, 0);
 	initGraphics(640, 480, &format);
 
@@ -73,6 +80,7 @@ Common::Error PetkaEngine::run() {
 		if (file->open(videos[i])) {
 			playVideo(file);
 		} else {
+			debugC(kPetkaDebugResources, "Video file %s can't be opened", videos[i]);
 			delete file;
 		}
 	}
@@ -116,12 +124,15 @@ Common::Error PetkaEngine::run() {
 }
 
 Common::SeekableReadStream *PetkaEngine::openFile(const Common::String &name, bool addCurrentPath) {
-	if (name.empty())
+	if (name.empty()) {
+		debug("PetkaEngine::openFile: attempt to open file with empty name");
 		return nullptr;
+	}
 	return _fileMgr->getFileStream(addCurrentPath ? _currentPath + name : name);
 }
 
 void PetkaEngine::loadStores() {
+	debug("PetkaEngine::loadStores");
 	_fileMgr->closeAll();
 
 	_fileMgr->openStore("patch.str");
@@ -131,6 +142,7 @@ void PetkaEngine::loadStores() {
 	Common::ScopedPtr<Common::SeekableReadStream> stream(_fileMgr->getFileStream("PARTS.INI"));
 
 	if (!stream || !parts.loadFromStream(*stream)) {
+		debugC(kPetkaDebugResources, "PARTS.INI opening failed");
 		return;
 	}
 
@@ -213,6 +225,7 @@ byte PetkaEngine::getPart() {
 }
 
 void PetkaEngine::loadPart(byte part) {
+	debug("PetkaEngine::loadPart %d", part);
 	_part = part;
 
 	_soundMgr->removeAll();
diff --git a/engines/petka/petka.h b/engines/petka/petka.h
index d40fd274af..3b06ba69c0 100644
--- a/engines/petka/petka.h
+++ b/engines/petka/petka.h
@@ -58,6 +58,9 @@ class VideoSystem;
 
 enum {
 	kPetkaDebugGeneral = 1 << 0,
+	kPetkaDebugResources = 1 << 1,
+	kPetkaDebugMessagingSystem = 1 << 2,
+	kPetkaDebugDialogs = 1 << 3,
 };
 
 class PetkaEngine : public Engine {


Commit: 26d6f04fbeef49847170f4e32b5cfae3323036c2
    https://github.com/scummvm/scummvm/commit/26d6f04fbeef49847170f4e32b5cfae3323036c2
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added debug log to FileMgr

Changed paths:
    engines/petka/file_mgr.cpp


diff --git a/engines/petka/file_mgr.cpp b/engines/petka/file_mgr.cpp
index 6417c78446..eae20715d7 100644
--- a/engines/petka/file_mgr.cpp
+++ b/engines/petka/file_mgr.cpp
@@ -24,11 +24,13 @@
 #include "common/file.h"
 #include "common/substream.h"
 
+#include "petka/petka.h"
 #include "petka/file_mgr.h"
 
 namespace Petka {
 
 FileMgr::~FileMgr() {
+	debug("FileMgr::dtor");
 	closeAll();
 }
 
@@ -60,6 +62,9 @@ bool FileMgr::openStore(const Common::String &name) {
 		}
 	}
 	store.file = file.release();
+
+	debug("FileMgr: opened store %s (files count: %d)", name.c_str(), store.descriptions.size());
+
 	return true;
 }
 
@@ -71,9 +76,11 @@ void FileMgr::closeStore(const Common::String &name) {
 			return;
 		}
 	}
+
 }
 
 void FileMgr::closeAll() {
+	debug("FileMgr::closeAll");
 	for (uint i = 0; i < _stores.size(); ++i) {
 		delete _stores[i].file;
 	}
@@ -92,6 +99,7 @@ static Common::String formPath(Common::String name) {
 Common::SeekableReadStream *FileMgr::getFileStream(const Common::String &name) {
 	Common::ScopedPtr<Common::File> file(new Common::File());
 	if (file->open(formPath(name))) {
+		debugC(kPetkaDebugResources, "FileMgr: %s is opened from game directory", name.c_str());
 		return file.release();
 	}
 	for (uint i = 0; i < _stores.size(); ++i) {
@@ -103,6 +111,7 @@ Common::SeekableReadStream *FileMgr::getFileStream(const Common::String &name) {
 
 		}
 	}
+	debugC(kPetkaDebugResources, "FileMgr: %s not found", name.c_str());
 	return nullptr;
 }
 


Commit: c485b77229958e4d9df1a4179d5fd9c5f81126ad
    https://github.com/scummvm/scummvm/commit/c485b77229958e4d9df1a4179d5fd9c5f81126ad
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added debug log to SoundMgr

Changed paths:
    engines/petka/sound.cpp


diff --git a/engines/petka/sound.cpp b/engines/petka/sound.cpp
index 33b8907c63..251013d9f7 100644
--- a/engines/petka/sound.cpp
+++ b/engines/petka/sound.cpp
@@ -25,6 +25,7 @@
 
 #include "common/substream.h"
 #include "common/system.h"
+#include "common/debug.h"
 
 #include "petka/petka.h"
 #include "petka/sound.h"
@@ -81,6 +82,7 @@ Sound *SoundMgr::addSound(const Common::String &name, Audio::Mixer::SoundType ty
 		return sound;
 	Common::SeekableReadStream *s = g_vm->openFile(name, false);
 	if (s) {
+		debug("SoundMgr: added sound %s", name.c_str());
 		sound = new Sound(g_vm->openFile(name, false), type);
 		_sounds.getVal(name).reset(sound);
 	}
@@ -93,10 +95,12 @@ Sound *SoundMgr::findSound(const Common::String &name) const {
 }
 
 void SoundMgr::removeSound(const Common::String &name) {
-	_sounds.erase(name);
+	debug("SoundMgr::removeSound %s", name.c_str());
+ 	_sounds.erase(name);
 }
 
 void SoundMgr::removeAll() {
+	debug("SoundMgr::removeAll");
 	_sounds.clear(0);
 }
 


Commit: e4c51ddf1d8fba4fab544e41d5ea1d7f6be5daea
    https://github.com/scummvm/scummvm/commit/e4c51ddf1d8fba4fab544e41d5ea1d7f6be5daea
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: enabled saving speed variable in settings

Changed paths:
    engines/petka/interfaces/panel.cpp


diff --git a/engines/petka/interfaces/panel.cpp b/engines/petka/interfaces/panel.cpp
index 9ca467e7f3..3c98111654 100644
--- a/engines/petka/interfaces/panel.cpp
+++ b/engines/petka/interfaces/panel.cpp
@@ -266,7 +266,7 @@ void InterfacePanel::readSettings() {
 	_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;
+	_speedFrame = 1 + ConfMan.getInt("petka_speed") / 4;
 }
 
 void InterfacePanel::applySettings() {
@@ -279,7 +279,7 @@ void InterfacePanel::applySettings() {
 	ConfMan.setInt("music_volume", 255 * (_musicFrame - 1) / (41 - 1));
 	ConfMan.setInt("sfx_volume", 255 * (_sfxFrame - 1) / (31 - 1));
 	ConfMan.setBool("subtitles", _subtitles);
-	//ConfMan.setInt("petka_speed", 4 * (_speedFrame - 1));
+	ConfMan.setInt("petka_speed", 4 * (_speedFrame - 1));
 	ConfMan.flushToDisk();
 	g_vm->syncSoundSettings();
 }


Commit: 8bb12711cb34fb14763ab238e02628a077b93fc6
    https://github.com/scummvm/scummvm/commit/8bb12711cb34fb14763ab238e02628a077b93fc6
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented QObjectStar

Changed paths:
    engines/petka/interfaces/main.cpp
    engines/petka/objects/object.h
    engines/petka/objects/object_star.cpp
    engines/petka/objects/object_star.h


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index 2165576ec0..591c51b469 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -26,7 +26,7 @@
 #include "common/ini-file.h"
 
 #include "petka/flc.h"
-#include "petka/objects/object.h"
+#include "petka/objects/object_star.h"
 #include "petka/interfaces/main.h"
 #include "petka/q_system.h"
 #include "petka/q_manager.h"
@@ -56,6 +56,8 @@ InterfaceMain::InterfaceMain() {
 			obj->_field18 = stream->readSint32LE();
 		}
 	}
+
+	_objs.push_back(g_vm->getQSystem()->_star.get());
 }
 
 void InterfaceMain::start() {
diff --git a/engines/petka/objects/object.h b/engines/petka/objects/object.h
index 6c4abd2790..b6d6223b71 100644
--- a/engines/petka/objects/object.h
+++ b/engines/petka/objects/object.h
@@ -40,6 +40,8 @@ public:
 	virtual void show(bool v) {};
 	virtual void setPos(int x, int y) {};
 	virtual bool isInPoint(int x, int y) { return false; }
+	virtual void onMouseMove(int x, int y) {}
+	virtual void onClick(int x, int y) {}
 
 public:
 	int32 _resourceId;
diff --git a/engines/petka/objects/object_star.cpp b/engines/petka/objects/object_star.cpp
index 8d228fe04e..30abe53730 100644
--- a/engines/petka/objects/object_star.cpp
+++ b/engines/petka/objects/object_star.cpp
@@ -20,9 +20,74 @@
  *
  */
 
+#include "common/rect.h"
+
+#include "petka/objects/object_case.h"
+#include "petka/objects/object_cursor.h"
 #include "petka/objects/object_star.h"
+#include "petka/q_system.h"
+#include "petka/flc.h"
+#include "petka/q_manager.h"
+#include "petka/video.h"
+#include "petka/petka.h"
 
 namespace Petka {
 
+const uint kFirstCursorId = 5001;
+const uint kCaseButtonIndex = 0;
+const Common::Rect kButtonsRects[] = {{70, 74, 112, 112},
+									  {68, 0, 114, 41},
+									  {151, 51, 180, 97},
+									  {138, 125, 179, 166},
+									  {55, 145, 96, 175},
+									  {11, 79, 40, 118}};
+
+static uint findButtonIndex(int16 x, int16 y) {
+	uint i = 0;
+	for (i = 0; i < sizeof(kButtonsRects) / sizeof(Common::Rect); ++i) {
+		if (kButtonsRects[i].contains(x, y))
+			return i;
+	}
+	return i;
+}
+
+QObjectStar::QObjectStar() {
+	_isShown = false;
+	_id = 4098;
+	_resourceId = 5000;
+	_z = 999;
+	_updateZ = false;
+	_isActive = true;
+}
+
+bool QObjectStar::isInPoint(int x, int y) {
+	return _isShown;
+}
+
+void QObjectStar::onMouseMove(int x, int y) {
+	uint frame = findButtonIndex(x - _x, y - _y) % 7 + 1;
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+	if (flc && flc->getCurFrame() + 1 != frame) {
+		g_vm->videoSystem()->addDirtyRect(Common::Point(_x, _y), *flc);
+		flc->setFrame(frame);
+	}
+}
+
+void QObjectStar::onClick(int x, int y) {
+	uint button = findButtonIndex(x - _x, y - _y);
+	if (button >= sizeof(kButtonsRects) / sizeof(Common::Rect)) {
+		show(0);
+		return;
+	}
+	if (button == kCaseButtonIndex) {
+		g_vm->getQSystem()->_case->show(1);
+	} else {
+		QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
+		cursor->show(0);
+		cursor->_resourceId = button + kFirstCursorId;
+		cursor->show(1);
+	}
+	show(0);
+}
 
 }
diff --git a/engines/petka/objects/object_star.h b/engines/petka/objects/object_star.h
index 5d30f61686..7f2b33b99c 100644
--- a/engines/petka/objects/object_star.h
+++ b/engines/petka/objects/object_star.h
@@ -28,7 +28,12 @@
 namespace Petka {
 
 class QObjectStar : public QObject {
-
+public:
+	QObjectStar();
+	void update(int time) override {}
+	bool isInPoint(int x, int y) override;
+	void onMouseMove(int x, int y) override;
+	void onClick(int x, int y) override;
 };
 
 } // End of namespace Petka


Commit: 7b7268acfb2ee22c5cd81590af9fd418dcc0b0ab
    https://github.com/scummvm/scummvm/commit/7b7268acfb2ee22c5cd81590af9fd418dcc0b0ab
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented QObjectCase

Changed paths:
    engines/petka/interfaces/main.cpp
    engines/petka/objects/object_case.cpp
    engines/petka/objects/object_case.h
    engines/petka/q_system.h


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index 591c51b469..df65799bf4 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -81,10 +81,12 @@ void InterfaceMain::loadRoom(int id, bool fromSave) {
 	const BGInfo *info = findBGInfo(id);
 	QSystem *sys = g_vm->getQSystem();
 	QObjectBG *room = (QObjectBG *)sys->findObject(id);
+	g_vm->getQSystem()->_room = room;
 	g_vm->resMgr()->loadBitmap(room->_resourceId);
 	_objs.push_back(room);
 	for (uint i = 0; i < info->attachedObjIds.size(); ++i) {
 		QMessageObject *obj = g_vm->getQSystem()->findObject(info->attachedObjIds[i]);
+		debug("Added sound id %d", obj->_resourceId);
 		obj->_sound = g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(obj->_resourceId), Audio::Mixer::kSFXSoundType);
 		obj->_hasSound = obj->_sound != nullptr;
 		obj->_startSound = false;
@@ -157,4 +159,3 @@ void InterfaceMain::unloadRoom(bool fromSave) {
 }
 
 } // End of namespace Petka
-
diff --git a/engines/petka/objects/object_case.cpp b/engines/petka/objects/object_case.cpp
index db57b3c393..9e174841a2 100644
--- a/engines/petka/objects/object_case.cpp
+++ b/engines/petka/objects/object_case.cpp
@@ -20,9 +20,170 @@
  *
  */
 
+#include "petka/interfaces/main.h"
 #include "petka/objects/object_case.h"
+#include "petka/flc.h"
+#include "petka/petka.h"
+#include "petka/q_manager.h"
+#include "petka/video.h"
+#include "petka/objects/heroes.h"
+#include "petka/q_system.h"
 
 namespace Petka {
 
+// Полоска в чемодане
+const char *const kPoloska = "\xCF\xEE\xEB\xEE\xF1\xEA\xE0\x20\xE2\x20\xF7\xE5\xEC\xEE\xE4\xE0\xED\xE5";
+
+const Common::Point itemsLocation[] = {{120, 145}, {240, 145}, {360, 145},
+									   {100, 220}, {240, 220}, {380, 220}};
+
+QObjectCase::QObjectCase() {
+	_itemIndex = 0;
+	_isShown = false;
+	_updateZ = false;
+	_id = 4099;
+	_resourceId = 6000;
+	_z = 980;
+	_clickedObjIndex = -1;
+}
+
+void QObjectCase::update(int time) {
+	if (!_isShown || _clickedObjIndex >= 6)
+		return;
+	_time += time;
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(6001 + _clickedObjIndex);
+	if (flc) {
+		while (_time >= flc->getDelay()) {
+			flc->setFrame(-1);
+			_time -= flc->getDelay();
+			g_vm->videoSystem()->addDirtyRectFromMsk(Common::Point(0, 0), *flc);
+		}
+	}
+}
+
+void QObjectCase::show(bool v) {
+	_x = 0; // sys->xOffset
+	QObject::show(v);
+	if (v) {
+		fillWithItems();
+		QMessageObject *obj = g_vm->getQSystem()->findObject(kPoloska);
+		obj->_z = _z + 2;
+		obj->_x = 0; // sys->xOffset
+		g_vm->getQSystem()->_mainInterface->_objs.push_back(obj);
+	} else {
+		Common::Array<QVisibleObject *> &objs = g_vm->getQSystem()->_mainInterface->_objs;
+		for (int i = 0; i < objs.size();) {
+			if (objs[i]->_z == _z + 1 || objs[i]->_z == _z + 2) {
+				objs.remove_at(i);
+			} else {
+				++i;
+			}
+		}
+		g_vm->getQSystem()->_currInterface->_startIndex = 0;
+	}
+}
+
+bool QObjectCase::isInPoint(int x, int y) {
+	return _isShown;
+}
+
+void QObjectCase::onMouseMove(int x, int y) {
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(6009);
+	if (*(byte *)flc->getCurrentFrame()->getBasePtr(x - _x, y - _y) != 0) {
+		if (_clickedObjIndex != 3 && _clickedObjIndex < 6 && _clickedObjIndex >= 0) {
+			FlicDecoder *flc = g_vm->resMgr()->loadFlic(6001 + _clickedObjIndex);
+			flc->setFrame(1);
+			g_vm->videoSystem()->addDirtyRectFromMsk(Common::Point(0, 0), *flc);
+		}
+		_clickedObjIndex = 3;
+	} else {
+		int i;
+		for (i = 0; i < 6; ++i) {
+			FlicDecoder *flc = g_vm->resMgr()->loadFlic(6001 + i);
+			if (flc->getMskRects()[i].contains(Common::Point(x - _x, y))) {
+				break;
+			}
+		}
+
+		if (_clickedObjIndex != i && _clickedObjIndex < 6 && _clickedObjIndex >= 0) {
+			FlicDecoder *flc = g_vm->resMgr()->loadFlic(6001 + _clickedObjIndex);
+			flc->setFrame(1);
+			g_vm->videoSystem()->addDirtyRectFromMsk(Common::Point(0, 0), *flc);
+		}
+
+		if (i == 6) {
+			if (_clickedObjIndex < 6 && _clickedObjIndex >= 0) {
+				_clickedObjIndex = -1;
+			}
+		} else if (i != _clickedObjIndex) {
+			if ((i || g_vm->getQSystem()->_chapayev->_isShown) && (i != 2 || g_vm->getQSystem()->_room->_showMap)) {
+				FlicDecoder *flc = g_vm->resMgr()->loadFlic(6001 + i);
+				g_vm->videoSystem()->addDirtyRectFromMsk(Common::Point(0, 0), *flc);
+				_clickedObjIndex = i;
+			} else {
+				_clickedObjIndex = -1;
+			}
+		}
+	}
+}
+
+void QObjectCase::onClick(int x, int y) {
+	switch (_clickedObjIndex) {
+		case 0:
+			// setChapayev()
+			break;
+		case 1:
+			// loadPanel()
+			break;
+		case 2:
+			// loadMap()
+			break;
+		case 3:
+			show(0);
+			break;
+		case 4:
+			if (_items.size() > _itemIndex + 6) {
+				_itemIndex += 6;
+				fillWithItems();
+				g_vm->videoSystem()->makeAllDirty();
+			}
+			break;
+		case 5:
+			if (_itemIndex > 0) {
+				_itemIndex = (_itemIndex - 6 <= 0) ? 0 : _itemIndex - 6;
+				fillWithItems();
+				g_vm->videoSystem()->makeAllDirty();
+			}
+			break;
+		default:
+			break;
+	}
+}
+
+void QObjectCase::fillWithItems() {
+	Common::Array<QVisibleObject *> &objs = g_vm->getQSystem()->_mainInterface->_objs;
+	for (int i = 0; i < objs.size();) {
+		if (objs[i]->_z == _z + 1) {
+			objs.remove_at(i);
+		} else {
+			++i;
+		}
+	}
+
+	for (int i = 0; i < objs.size();) {
+		if (objs[i]->_resourceId == 6000) {
+			g_vm->getQSystem()->_currInterface->_startIndex = i;
+		}
+	}
+
+	for (int i = _itemIndex; i < _itemIndex + 6 >= _items.size() ? _items.size() : _itemIndex + 6; ++i) {
+		QMessageObject *obj = g_vm->getQSystem()->findObject(_items[i]);
+		obj->_z = _z + 1;
+		objs.push_back(obj);
+		g_vm->resMgr()->loadFlic(obj->_resourceId);
+		_x = itemsLocation[i - _itemIndex].x;
+		_y = itemsLocation[i - _itemIndex].y;
+	}
+}
 
 }
diff --git a/engines/petka/objects/object_case.h b/engines/petka/objects/object_case.h
index 062942cf38..5e0ee4e1d5 100644
--- a/engines/petka/objects/object_case.h
+++ b/engines/petka/objects/object_case.h
@@ -28,7 +28,19 @@
 namespace Petka {
 
 class QObjectCase : public QObject {
+public:
+	QObjectCase();
+	void update(int time) override;
+	void show(bool v) override;
+	bool isInPoint(int x, int y) override;
+	void onMouseMove(int x, int y) override;
+	void onClick(int x, int y) override;
+	void fillWithItems();
 
+private:
+	Common::Array<int> _items;
+	uint _clickedObjIndex;
+	int _itemIndex;
 };
 
 } // End of namespace Petka
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index 9603f3f408..6117eac928 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -78,6 +78,8 @@ public:
 	int _isIniting;
 	int _fxId;
 	int _musicId;
+
+	QObjectBG *_room;
 };
 
 } // End of namespace Petka


Commit: 196fb7884d7594a50fb8a81f27ca6ac59efd86ae
    https://github.com/scummvm/scummvm/commit/196fb7884d7594a50fb8a81f27ca6ac59efd86ae
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented events handling in InterfaceMain

Changed paths:
    engines/petka/interfaces/main.cpp
    engines/petka/interfaces/main.h
    engines/petka/objects/object_cursor.h


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index df65799bf4..176e990a79 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -26,6 +26,8 @@
 #include "common/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"
@@ -158,4 +160,53 @@ void InterfaceMain::unloadRoom(bool fromSave) {
 	}
 }
 
+void InterfaceMain::onLeftButtonDown(const Common::Point p) {
+	if (!g_vm->getQSystem()->_cursor->_isShown) {
+		_dialog.sub_4155D0(-1);
+		return;
+	}
+	for (int i = _objs.size() - 1; i >= 0; --i) {
+		if (_objs[i]->isInPoint(p.x, p.y)) {
+			_objs[i]->onClick(p.x, p.y);
+		}
+	}
+}
+
+void InterfaceMain::onRightButtonDown(const Common::Point p) {
+	QObjectStar *star = g_vm->getQSystem()->_star.get();
+	QObjectCase *objCase = g_vm->getQSystem()->_case.get();
+	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
+	if (!star->_isActive)
+		return;
+	if (g_vm->getQSystem()->_case.get()->_isShown && cursor->_actionType == 6) {
+		cursor->show(0);
+		cursor->_resourceId = 5005;
+		cursor->_actionType = 3;
+		cursor->_invObj = nullptr;
+		cursor->setCursorPos(p.x, p.y, 1);
+	} else {
+		if (!star->_isShown) {
+			FlicDecoder *flc = g_vm->resMgr()->loadFlic(star->_resourceId);
+			int x = MAX(p.x - flc->getWidth() / 2, 0);
+			int y = MAX(p.y - flc->getHeight() / 2, 0);
+
+			star->_x = MIN(x, 639 - flc->getWidth());
+			star->_y = MIN(y, 479 - flc->getHeight());
+		}
+		star->show(star->_isShown == 0);
+	}
+}
+
+void InterfaceMain::onMouseMove(const Common::Point p) {
+	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
+	_objUnderCursor = nullptr;
+	for (int i = _objs.size() - 1; i >= 0; --i) {
+		if (_objs[i]->isInPoint(p.x, p.y)) {
+			_objs[i]->onMouseMove(p.x, p.y);
+		}
+	}
+	cursor->_animate = _objUnderCursor != nullptr;
+	cursor->setCursorPos(p.x, p.y, true);
+}
+
 } // End of namespace Petka
diff --git a/engines/petka/interfaces/main.h b/engines/petka/interfaces/main.h
index f12352e0c3..26fd426b5d 100644
--- a/engines/petka/interfaces/main.h
+++ b/engines/petka/interfaces/main.h
@@ -49,6 +49,10 @@ public:
 
 	void unloadRoom(bool fromSave);
 
+	void onLeftButtonDown(const Common::Point p) override;
+	void onRightButtonDown(const Common::Point p) override;
+	void onMouseMove(const Common::Point p) override;
+
 public:
 	DialogInterface _dialog;
 	Common::Array<BGInfo> _bgs;
diff --git a/engines/petka/objects/object_cursor.h b/engines/petka/objects/object_cursor.h
index b60db5f6f3..a267377af6 100644
--- a/engines/petka/objects/object_cursor.h
+++ b/engines/petka/objects/object_cursor.h
@@ -36,8 +36,9 @@ public:
 	void draw() override;
 	void show(bool v) override;
 
-private:
-
+public:
+	int _actionType;
+	QMessageObject *_invObj;
 };
 
 } // End of naespace Petka


Commit: 6ba552e0a92437304d50d89b15d5c2680cbe2583
    https://github.com/scummvm/scummvm/commit/6ba552e0a92437304d50d89b15d5c2680cbe2583
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed onMouseMove method of ObjectStar

Changed paths:
    engines/petka/objects/object_star.cpp


diff --git a/engines/petka/objects/object_star.cpp b/engines/petka/objects/object_star.cpp
index 30abe53730..68533dc369 100644
--- a/engines/petka/objects/object_star.cpp
+++ b/engines/petka/objects/object_star.cpp
@@ -65,7 +65,7 @@ bool QObjectStar::isInPoint(int x, int y) {
 }
 
 void QObjectStar::onMouseMove(int x, int y) {
-	uint frame = findButtonIndex(x - _x, y - _y) % 7 + 1;
+	uint frame = (findButtonIndex(x - _x, y - _y) + 1) % 7 + 1;
 	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
 	if (flc && flc->getCurFrame() + 1 != frame) {
 		g_vm->videoSystem()->addDirtyRect(Common::Point(_x, _y), *flc);


Commit: bbfa139d9b06240cad6c0c183bc857c27ed9cb7a
    https://github.com/scummvm/scummvm/commit/bbfa139d9b06240cad6c0c183bc857c27ed9cb7a
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed crash and endless lopp in ObjectCase

Changed paths:
    engines/petka/objects/object_case.cpp


diff --git a/engines/petka/objects/object_case.cpp b/engines/petka/objects/object_case.cpp
index 9e174841a2..26b312d734 100644
--- a/engines/petka/objects/object_case.cpp
+++ b/engines/petka/objects/object_case.cpp
@@ -100,7 +100,7 @@ void QObjectCase::onMouseMove(int x, int y) {
 		int i;
 		for (i = 0; i < 6; ++i) {
 			FlicDecoder *flc = g_vm->resMgr()->loadFlic(6001 + i);
-			if (flc->getMskRects()[i].contains(Common::Point(x - _x, y))) {
+			if (flc->getMskRects()[0].contains(Common::Point(x - _x, y))) {
 				break;
 			}
 		}
@@ -170,7 +170,7 @@ void QObjectCase::fillWithItems() {
 		}
 	}
 
-	for (int i = 0; i < objs.size();) {
+	for (int i = 0; i < objs.size(); ++i) {
 		if (objs[i]->_resourceId == 6000) {
 			g_vm->getQSystem()->_currInterface->_startIndex = i;
 		}


Commit: ea4f10f4fa04cb6170453c28a732dec6aa8036ac
    https://github.com/scummvm/scummvm/commit/ea4f10f4fa04cb6170453c28a732dec6aa8036ac
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented CONTINUE opcode

Changed paths:
    engines/petka/objects/object.cpp


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index 910d153f4a..5784df4c2d 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -179,6 +179,10 @@ void QMessageObject::processMessage(const QMessage &msg) {
 			g_vm->playVideo(g_vm->openFile(videoName, false));
 			break;
 		}
+		case kContinue:
+			g_vm->getQSystem()->_mainInterface->_dialog._field4 = 0;
+			g_vm->getQSystem()->_mainInterface->_dialog.sub_4155D0(-1);
+			break;
 		case kDialog:
 			g_vm->getQSystem()->_mainInterface->_dialog.start(msg.arg1, this);
 			break;


Commit: f2b9a451a6f2403f490db0d8485c0ebdf7477807
    https://github.com/scummvm/scummvm/commit/f2b9a451a6f2403f490db0d8485c0ebdf7477807
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed crash when dialog is in process

Changed paths:
    engines/petka/big_dialogue.cpp
    engines/petka/big_dialogue.h
    engines/petka/interfaces/dialog_interface.cpp


diff --git a/engines/petka/big_dialogue.cpp b/engines/petka/big_dialogue.cpp
index ec7980f98f..22c72e63b7 100644
--- a/engines/petka/big_dialogue.cpp
+++ b/engines/petka/big_dialogue.cpp
@@ -100,7 +100,7 @@ void BigDialogue::loadSpeechesInfo() {
 	delete[] str;
 }
 
-const SpeechInfo *BigDialogue::getSpeechInfo(int unk) {
+const Common::U32String *BigDialogue::getSpeechInfo(int *talkerId, const char **soundName, int unk) {
 	if (!_ip)
 		return nullptr;
 	int *oldIp = _ip;
@@ -131,7 +131,9 @@ const SpeechInfo *BigDialogue::getSpeechInfo(int unk) {
 		}
 		uint index = (uint16)*_ip;
 		_ip = oldIp;
-		return &_speeches[index];
+		*soundName = _speeches[index].soundName;
+		*talkerId = _speeches[index].speakerId;
+		return &_speeches[index].text;
 	}
 	case 8:
 		_ip += 1;
@@ -142,7 +144,9 @@ const SpeechInfo *BigDialogue::getSpeechInfo(int unk) {
 		}
 		// fall through
 	case 7:
-		return &_speeches[(uint16)*_ip];
+		*soundName = _speeches[(uint16)*_ip].soundName;
+		*talkerId = _speeches[(uint16)*_ip].speakerId;
+		return &_speeches[(uint16)*_ip].text;
 	default:
 		break;
 	}
diff --git a/engines/petka/big_dialogue.h b/engines/petka/big_dialogue.h
index 74aa1c35a3..d49c7c04f9 100644
--- a/engines/petka/big_dialogue.h
+++ b/engines/petka/big_dialogue.h
@@ -69,7 +69,7 @@ public:
 	const Dialog *findDialog(uint objId, uint opcode, bool *res) const;
 	void setDialog(uint objId, uint opcode, int index);
 
-	const SpeechInfo *getSpeechInfo(int unk);
+	const Common::U32String *getSpeechInfo(int *talkerId, const char **soundName, int unk);
 
 private:
 	void loadSpeechesInfo();
diff --git a/engines/petka/interfaces/dialog_interface.cpp b/engines/petka/interfaces/dialog_interface.cpp
index 87dfab0530..d53992c0c6 100644
--- a/engines/petka/interfaces/dialog_interface.cpp
+++ b/engines/petka/interfaces/dialog_interface.cpp
@@ -75,13 +75,14 @@ void DialogInterface::restoreCursorState() {
 }
 
 void DialogInterface::sub_4155D0(int a) {
+	const char *soundName = nullptr;
 	if (_field14 == -1 || (a == -1 && _field18 == 2))
 		return;
 	if (_field18 == -1)
 		return;
 	int talkerId = -1;
 	if (a == -1 && !_field8) {
-		talkerId = g_vm->getBigDialogue()->getSpeechInfo(-1)->speakerId;
+		g_vm->getBigDialogue()->getSpeechInfo(&talkerId, &soundName, -1);
 	}
 	_field8 = _field4;
 	g_vm->getQSystem()->_cursor.get()->_isShown = 0;
@@ -93,19 +94,20 @@ void DialogInterface::sub_4155D0(int a) {
 		g_vm->getBigDialogue()->sub40B670(a);
 	switch (g_vm->getBigDialogue()->opcode()) {
 	case 1: {
-		const SpeechInfo *info = g_vm->getBigDialogue()->getSpeechInfo(-1);
+		int talkerId2;
+		const Common::U32String *text = g_vm->getBigDialogue()->getSpeechInfo(&talkerId2, &soundName, -1);
 		g_vm->soundMgr()->removeSound(_soundName);
-		if (talkerId != info->speakerId) {
+		if (talkerId != talkerId2) {
 			sendMsg(kSaid);
 		}
-		_soundName = g_vm->getSpeechPath() + info->soundName;
+		_soundName = g_vm->getSpeechPath() + soundName;
 		Sound *s = g_vm->soundMgr()->addSound(_soundName, Audio::Mixer::kSpeechSoundType);
 		if (s) {
 			s->play(0);
 		}
 		g_trackedSound = s;
-		_talker = g_vm->getQSystem()->findObject(info->speakerId);
-		if (talkerId != info->speakerId) {
+		_talker = g_vm->getQSystem()->findObject(talkerId2);
+		if (talkerId != talkerId2) {
 			sendMsg(kSay);
 		}
 		g_vm->getQSystem()->_mainInterface->setText(info->text, _talker->_dialogColor);


Commit: 1a61fd4c59ee8870e516d8c9d56ad31ebb2ea285
    https://github.com/scummvm/scummvm/commit/1a61fd4c59ee8870e516d8c9d56ad31ebb2ea285
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: add heroes before starting InterfaceMain

Changed paths:
    engines/petka/interfaces/main.cpp


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index 176e990a79..3c53768a3a 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -35,6 +35,7 @@
 #include "petka/sound.h"
 #include "petka/petka.h"
 #include "petka/video.h"
+#include "petka/objects/heroes.h"
 
 namespace Petka {
 
@@ -66,6 +67,9 @@ void InterfaceMain::start() {
 	g_vm->getQSystem()->update();
 	g_vm->getQSystem()->_isIniting = 0;
 
+	_objs.push_back(g_vm->getQSystem()->_petka.get());
+	_objs.push_back(g_vm->getQSystem()->_chapayev.get());
+
 	Common::ScopedPtr<Common::SeekableReadStream> bgsStream(g_vm->openFile("BGs.ini", false));
 	Common::INIFile bgsIni;
 	bgsIni.loadFromStream(*bgsStream);


Commit: 541368979ede6e25707d16f17e5db84cf7b197ef
    https://github.com/scummvm/scummvm/commit/541368979ede6e25707d16f17e5db84cf7b197ef
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: overrode cursor's isInPoint method

Changed paths:
    engines/petka/objects/object_cursor.h


diff --git a/engines/petka/objects/object_cursor.h b/engines/petka/objects/object_cursor.h
index a267377af6..4edc8e75c1 100644
--- a/engines/petka/objects/object_cursor.h
+++ b/engines/petka/objects/object_cursor.h
@@ -35,6 +35,7 @@ public:
 	void update(int time) override;
 	void draw() override;
 	void show(bool v) override;
+	bool isInPoint(int x, int y) override { return 0; }
 
 public:
 	int _actionType;


Commit: c50093da2e878bbedfc09026d5749e537bb0d49a
    https://github.com/scummvm/scummvm/commit/c50093da2e878bbedfc09026d5749e537bb0d49a
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed handling left button click

Changed paths:
    engines/petka/interfaces/main.cpp


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index 3c53768a3a..5ef3c20d68 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -172,6 +172,7 @@ void InterfaceMain::onLeftButtonDown(const Common::Point p) {
 	for (int i = _objs.size() - 1; i >= 0; --i) {
 		if (_objs[i]->isInPoint(p.x, p.y)) {
 			_objs[i]->onClick(p.x, p.y);
+			break;
 		}
 	}
 }


Commit: e1bcf2711b38705c97e983be508e87eb89c343d0
    https://github.com/scummvm/scummvm/commit/e1bcf2711b38705c97e983be508e87eb89c343d0
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: enabled case and cursor in main interface

Changed paths:
    engines/petka/interfaces/main.cpp


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index 5ef3c20d68..b988b39ea2 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -35,6 +35,7 @@
 #include "petka/sound.h"
 #include "petka/petka.h"
 #include "petka/video.h"
+#include "petka/objects/object_case.h"
 #include "petka/objects/heroes.h"
 
 namespace Petka {
@@ -60,6 +61,8 @@ InterfaceMain::InterfaceMain() {
 		}
 	}
 
+	_objs.push_back(g_vm->getQSystem()->_cursor.get());
+	_objs.push_back(g_vm->getQSystem()->_case.get());
 	_objs.push_back(g_vm->getQSystem()->_star.get());
 }
 


Commit: 8f08804aed6e61fdba7d7dd67b4ccd3c31a923f4
    https://github.com/scummvm/scummvm/commit/8f08804aed6e61fdba7d7dd67b4ccd3c31a923f4
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed choosing action type in star object

Changed paths:
    engines/petka/objects/object_star.cpp


diff --git a/engines/petka/objects/object_star.cpp b/engines/petka/objects/object_star.cpp
index 68533dc369..c6e0f19b03 100644
--- a/engines/petka/objects/object_star.cpp
+++ b/engines/petka/objects/object_star.cpp
@@ -85,6 +85,7 @@ void QObjectStar::onClick(int x, int y) {
 		QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
 		cursor->show(0);
 		cursor->_resourceId = button + kFirstCursorId;
+		cursor->_actionType = button - 1;
 		cursor->show(1);
 	}
 	show(0);


Commit: 2763c22a9fdfc1addb7f4ce67d53bd6abf3532e3
    https://github.com/scummvm/scummvm/commit/2763c22a9fdfc1addb7f4ce67d53bd6abf3532e3
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented clicking on objects depending on action type

Changed paths:
    engines/petka/objects/object.cpp
    engines/petka/objects/object.h
    engines/petka/objects/object_cursor.cpp
    engines/petka/objects/object_cursor.h


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index 5784df4c2d..2e0e9b4d00 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -38,6 +38,7 @@
 #include "petka/objects/object_star.h"
 #include "petka/objects/object_cursor.h"
 #include "petka/interfaces/main.h"
+#include "petka/objects/heroes.h"
 
 namespace Petka {
 
@@ -415,4 +416,33 @@ void QObject::setPos(int x, int y) {
 	}
 }
 
+void QObject::onClick(int x, int y) {
+	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
+	switch (cursor->_actionType) {
+	case kActionLook:
+		g_vm->getQSystem()->addMessage(_id, kLook, 0, 0, 0, 0, this);
+		break;
+	case kActionWalk:
+		g_vm->getQSystem()->addMessage(_id, kWalk, x, y, 0, 0, this);
+		break;
+	case kActionUse:
+		g_vm->getQSystem()->addMessage(_id, kUse, 0, 0, 0, 0, this);
+		break;
+	case kActionTake:
+		g_vm->getQSystem()->addMessage(_id, kTake, 0, 0, 0, 0, this);
+		break;
+	case kActionTalk:
+		g_vm->getQSystem()->addMessage(_id, kTalk, 0, 0, 0, 0, this);
+		break;
+	case kActionObjUse:
+		g_vm->getQSystem()->addMessage(_id, kObjectUse, x, y, 0, 0, g_vm->getQSystem()->_chapayev.get());
+		break;
+	case kActionObjUseChapayev:
+		g_vm->getQSystem()->addMessage(_id, kObjectUse, 0, 0, 0, 0, cursor->_invObj);
+		break;
+	default:
+		break;
+	}
+}
+
 }
\ No newline at end of file
diff --git a/engines/petka/objects/object.h b/engines/petka/objects/object.h
index b6d6223b71..3644f54059 100644
--- a/engines/petka/objects/object.h
+++ b/engines/petka/objects/object.h
@@ -96,6 +96,7 @@ public:
 	bool isInPoint(int x, int y) override;
 	void setPos(int x, int y) override;
 	void show(bool v) override;
+	void onClick(int x, int y) override;
 };
 
 extern QReaction *g_dialogReaction;
diff --git a/engines/petka/objects/object_cursor.cpp b/engines/petka/objects/object_cursor.cpp
index 0555dac47a..4c48f41729 100644
--- a/engines/petka/objects/object_cursor.cpp
+++ b/engines/petka/objects/object_cursor.cpp
@@ -45,6 +45,7 @@ QObjectCursor::QObjectCursor() {
 	_x = pos.x;
 	_y = pos.y;
 	g_vm->resMgr()->loadFlic(5002);
+	_actionType = kLook;
 }
 
 void QObjectCursor::draw() {
diff --git a/engines/petka/objects/object_cursor.h b/engines/petka/objects/object_cursor.h
index 4edc8e75c1..16c8ee609a 100644
--- a/engines/petka/objects/object_cursor.h
+++ b/engines/petka/objects/object_cursor.h
@@ -27,6 +27,16 @@
 
 namespace Petka {
 
+enum ActionType {
+	kActionLook,
+	kActionWalk,
+	kActionUse,
+	kActionTake,
+	kActionTalk,
+	kActionObjUseChapayev,
+	kActionObjUse
+};
+
 class QObjectCursor : public QObject {
 public:
 	QObjectCursor();


Commit: 6b39e634d879aee938c134782537f67a0428c625
    https://github.com/scummvm/scummvm/commit/6b39e634d879aee938c134782537f67a0428c625
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented switching to panel interface from case object

Changed paths:
    engines/petka/objects/object_case.cpp
    engines/petka/q_system.cpp
    engines/petka/q_system.h


diff --git a/engines/petka/objects/object_case.cpp b/engines/petka/objects/object_case.cpp
index 26b312d734..f25510e031 100644
--- a/engines/petka/objects/object_case.cpp
+++ b/engines/petka/objects/object_case.cpp
@@ -133,7 +133,7 @@ void QObjectCase::onClick(int x, int y) {
 			// setChapayev()
 			break;
 		case 1:
-			// loadPanel()
+			g_vm->getQSystem()->togglePanelInterface();
 			break;
 		case 2:
 			// loadMap()
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 32e1d7d300..c08814e2de 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -199,4 +199,15 @@ void QSystem::update() {
 	}
 }
 
+void QSystem::togglePanelInterface() {
+	if (_currInterface != _startupInterface.get() && _star->_isActive) {
+		_case->show(0);
+		if (_currInterface == _panelInterface.get()) {
+			_currInterface->stop();
+		} else if (_currInterface == _mainInterface.get()) {
+			_panelInterface->start();
+		}
+	}
+}
+
 }
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index 6117eac928..315fb540b0 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -58,6 +58,8 @@ public:
 	QMessageObject *findObject(int16 id);
 	QMessageObject *findObject(const Common::String &name);
 
+	void togglePanelInterface();
+
 public:
 	Common::Array<QObject> _objs;
 	Common::Array<QObjectBG> _bgs;


Commit: 0dc8c459b788fd69436c0c1d9e8a1162acaeda35
    https://github.com/scummvm/scummvm/commit/0dc8c459b788fd69436c0c1d9e8a1162acaeda35
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented map

Changed paths:
  A engines/petka/interfaces/map.cpp
  A engines/petka/interfaces/map.h
    engines/petka/module.mk
    engines/petka/objects/object_case.cpp
    engines/petka/q_system.cpp
    engines/petka/q_system.h


diff --git a/engines/petka/interfaces/map.cpp b/engines/petka/interfaces/map.cpp
new file mode 100644
index 0000000000..012080f52a
--- /dev/null
+++ b/engines/petka/interfaces/map.cpp
@@ -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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#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() {
+	if (!g_vm->getQSystem()->_room->_showMap)
+		return;
+
+	QObjectBG *bg = (QObjectBG *)g_vm->getQSystem()->findObject(mapName);
+	_roomResID = bg->_resourceId;
+	_objs.push_back(bg);
+
+	const Common::Array<BGInfo> &infos = g_vm->getQSystem()->_mainInterface->_bgs;
+
+	for (uint i = 0; i < infos.size(); ++i) {
+		if (infos[i].objId != bg->_id) {
+			continue;
+		}
+		for (uint j = 0; j < infos[i].attachedObjIds.size(); ++j) {
+			QMessageObject *obj = g_vm->getQSystem()->findObject(infos[i].attachedObjIds[j]);
+			FlicDecoder *flc = g_vm->resMgr()->loadFlic(obj->_resourceId);
+			flc->setFrame(1);
+			obj->_z = 1;
+			obj->_x = 0;
+			obj->_y = 0;
+			obj->_field24 = 1;
+			obj->_field20 = 1;
+			obj->_field28 = 1;
+			obj->_animate = obj->_isShown;
+			_objs.push_back(obj);
+		}
+		break;
+	}
+
+	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
+	_savedCursorId = cursor->_resourceId;
+	_savedCursorActionType = cursor->_actionType;
+	cursor->_isShown = true;
+	cursor->_resourceId = 4901;
+	cursor->_animate = 0;
+	cursor->_actionType;
+
+	_objs.push_back(cursor);
+	cursor->setCursorPos(cursor->_x, cursor->_y, false);
+
+	_savedXOffset = 0; // g_vm->getQSystem()->xOffset;
+	_savedSceneWidth = 640; // g_vm->getQSystem()->savedSceneWidth
+
+	g_vm->getQSystem()->addMessageForAllObjects(kInitBG, 0, 0, 0, 0, bg);
+
+	g_vm->getQSystem()->_currInterface = this;
+	g_vm->videoSystem()->updateTime();
+	g_vm->videoSystem()->makeAllDirty();
+}
+
+void InterfaceMap::stop() {
+	if (_objUnderCursor)
+		((QMessageObject *)_objUnderCursor)->_isShown = false;
+	//setText("", 0xFFFFC0, 0xA0A0A);
+
+	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
+	cursor->_resourceId = _savedCursorId;
+	cursor->_actionType = _savedCursorActionType;
+
+	g_vm->getQSystem()->_currInterface = g_vm->getQSystem()->_prevInterface;
+	g_vm->getQSystem()->_currInterface->onMouseMove(Common::Point(cursor->_x, cursor->_y));
+}
+
+void InterfaceMap::onLeftButtonDown(const Common::Point p) {
+	for (int i = _objs.size() - 1; i >= 0; --i) {
+		if (_objs[i]->isInPoint(p.x, p.y)) {
+			_objs[i]->onClick(p.x, p.y);
+			break;
+		}
+	}
+}
+
+void InterfaceMap::onMouseMove(const 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 != 4901 && obj->_resourceId != _roomResID) {
+			FlicDecoder *flc = g_vm->resMgr()->loadFlic(obj->_resourceId);
+			if (flc) {
+				int frame = 1;
+				if (!found && obj->isInPoint(p.x, p.y)) {
+					found = true;
+					frame = 2;
+					_objUnderCursor = obj;
+				}
+				if (obj->_field20 != frame) {
+					obj->_isShown = frame == 2;
+					flc->setFrame(1);
+					g_vm->videoSystem()->addDirtyRect(Common::Point(obj->_x, obj->_y), *flc);
+					obj->_field20 = frame;
+					obj->_field24 = frame;
+				}
+			}
+		}
+	}
+
+	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
+	cursor->_animate = _objUnderCursor != nullptr;
+	cursor->_isShown = true;
+	cursor->setCursorPos(p.x, p.y, 0);
+}
+
+} // End of namespace Petka
diff --git a/engines/petka/interfaces/map.h b/engines/petka/interfaces/map.h
new file mode 100644
index 0000000000..eaecb81988
--- /dev/null
+++ b/engines/petka/interfaces/map.h
@@ -0,0 +1,49 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PETKA_MAP_H
+#define PETKA_MAP_H
+
+#include "petka/interfaces/interface.h"
+
+namespace Petka {
+
+class InterfaceMap: public Interface {
+public:
+	void start() override;
+	void stop() override;
+
+	void onLeftButtonDown(const Common::Point p) override;
+	void onMouseMove(const Common::Point p) override;
+
+private:
+	int _savedXOffset;
+	int _savedSceneWidth;
+	int _savedCursorId;
+	int _savedCursorActionType;
+	int _roomResID;
+};
+
+} // End of namespace Petka
+
+#endif
+
diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index 1bc89754b9..e7b042933e 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -13,6 +13,7 @@ MODULE_OBJS = \
     interfaces/dialog_interface.o \
     interfaces/interface.o \
     interfaces/main.o \
+    interfaces/map.o \
     interfaces/panel.o \
     interfaces/save_load.o \
     interfaces/startup.o \
diff --git a/engines/petka/objects/object_case.cpp b/engines/petka/objects/object_case.cpp
index f25510e031..e63e296d7b 100644
--- a/engines/petka/objects/object_case.cpp
+++ b/engines/petka/objects/object_case.cpp
@@ -136,7 +136,7 @@ void QObjectCase::onClick(int x, int y) {
 			g_vm->getQSystem()->togglePanelInterface();
 			break;
 		case 2:
-			// loadMap()
+			g_vm->getQSystem()->toggleMapInterface();
 			break;
 		case 3:
 			show(0);
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index c08814e2de..641e32ae8a 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -30,6 +30,7 @@
 #include "petka/interfaces/main.h"
 #include "petka/interfaces/save_load.h"
 #include "petka/interfaces/panel.h"
+#include "petka/interfaces/map.h"
 #include "petka/objects/object_cursor.h"
 #include "petka/objects/object_case.h"
 #include "petka/objects/object_star.h"
@@ -147,6 +148,7 @@ bool QSystem::init() {
 	_startupInterface.reset(new InterfaceStartup());
 	_saveLoadInterface.reset(new InterfaceSaveLoad());
 	_panelInterface.reset(new InterfacePanel());
+	_mapInterface.reset(new InterfaceMap());
 	if (g_vm->getPart() == 0) {
 		_startupInterface->start();
 		_prevInterface = _currInterface = _startupInterface.get();
@@ -210,4 +212,16 @@ void QSystem::togglePanelInterface() {
 	}
 }
 
+void QSystem::toggleMapInterface() {
+	if (_currInterface != _startupInterface.get() && _star->_isActive && _room->_showMap) {
+		_case->show(0);
+		if (_currInterface == _mapInterface.get()) {
+			_currInterface->stop();
+		} else if (_currInterface == _mainInterface.get()) {
+			// setText
+			_mapInterface->start();
+		}
+	}
+}
+
 }
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index 315fb540b0..bea159feca 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -40,6 +40,7 @@ class InterfaceSaveLoad;
 class InterfaceMain;
 class InterfaceStartup;
 class InterfacePanel;
+class InterfaceMap;
 class Interface;
 
 class QSystem {
@@ -59,6 +60,7 @@ public:
 	QMessageObject *findObject(const Common::String &name);
 
 	void togglePanelInterface();
+	void toggleMapInterface();
 
 public:
 	Common::Array<QObject> _objs;
@@ -74,6 +76,7 @@ public:
 	Common::ScopedPtr<InterfaceSaveLoad> _saveLoadInterface;
 	Common::ScopedPtr<InterfaceStartup> _startupInterface;
 	Common::ScopedPtr<InterfacePanel> _panelInterface;
+	Common::ScopedPtr<InterfaceMap> _mapInterface;
 	Interface *_currInterface;
 	Interface *_prevInterface;
 


Commit: 9e7beac5d18a8e8396e5180b3410823c49eb31c0
    https://github.com/scummvm/scummvm/commit/9e7beac5d18a8e8396e5180b3410823c49eb31c0
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented inventory opcodes

Changed paths:
    engines/petka/objects/object.cpp
    engines/petka/objects/object_case.cpp
    engines/petka/objects/object_case.h


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index 2e0e9b4d00..dd9724b870 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -39,6 +39,7 @@
 #include "petka/objects/object_cursor.h"
 #include "petka/interfaces/main.h"
 #include "petka/objects/heroes.h"
+#include "petka/objects/object_case.h"
 
 namespace Petka {
 
@@ -175,6 +176,14 @@ void QMessageObject::processMessage(const QMessage &msg) {
 
 	if (reacted || !g_vm->getBigDialogue()->findDialog(_id, msg.opcode, nullptr)) {
 		switch (msg.opcode) {
+		case kAddInv:
+			g_vm->getQSystem()->_case->addItem(msg.objId);
+			break;
+		case kDelInv:
+			g_vm->getQSystem()->_case->removeItem(msg.objId);
+			break;
+		case kSetInv:
+			g_vm->getQSystem()->_case->setInv(msg.sender->_id, msg.objId);
 		case kAvi: {
 			Common::String videoName = g_vm->resMgr()->findResourceName((uint16) msg.arg1);
 			g_vm->playVideo(g_vm->openFile(videoName, false));
diff --git a/engines/petka/objects/object_case.cpp b/engines/petka/objects/object_case.cpp
index e63e296d7b..51ed1ed337 100644
--- a/engines/petka/objects/object_case.cpp
+++ b/engines/petka/objects/object_case.cpp
@@ -176,7 +176,7 @@ void QObjectCase::fillWithItems() {
 		}
 	}
 
-	for (int i = _itemIndex; i < _itemIndex + 6 >= _items.size() ? _items.size() : _itemIndex + 6; ++i) {
+	for (int i = _itemIndex; i < ((_itemIndex + 6 >= _items.size()) ? _items.size() : _itemIndex + 6); ++i) {
 		QMessageObject *obj = g_vm->getQSystem()->findObject(_items[i]);
 		obj->_z = _z + 1;
 		objs.push_back(obj);
@@ -186,4 +186,40 @@ void QObjectCase::fillWithItems() {
 	}
 }
 
+void QObjectCase::addItem(int id) {
+	_items.push_back(id);
+	if (_isShown) {
+		show(0);
+		show(1);
+	}
+}
+
+void QObjectCase::removeItem(int id) {
+	for (uint i = 0; i < _items.size(); ++i) {
+		if (_items[i] == id) {
+			_items.remove_at(i);
+		}
+	}
+
+	_itemIndex = _items.size() - 6 < 0 ? 0 : _items.size() - 6;
+
+	if (_isShown) {
+		show(0);
+		show(1);
+	}
+}
+
+void QObjectCase::setInv(int id1, int id2) {
+	for (uint i = 0; i < _items.size(); ++i) {
+		if (_items[i] == id1) {
+			_items[i] = id2;
+		}
+	}
+
+	if (_isShown) {
+		show(0);
+		show(1);
+	}
+}
+
 }
diff --git a/engines/petka/objects/object_case.h b/engines/petka/objects/object_case.h
index 5e0ee4e1d5..2ef8a5997c 100644
--- a/engines/petka/objects/object_case.h
+++ b/engines/petka/objects/object_case.h
@@ -37,6 +37,10 @@ public:
 	void onClick(int x, int y) override;
 	void fillWithItems();
 
+	void addItem(int id);
+	void removeItem(int id);
+	void setInv(int id1, int id2);
+
 private:
 	Common::Array<int> _items;
 	uint _clickedObjIndex;


Commit: 50e65957dc82b0c798bad9ee71ba1fd257824280
    https://github.com/scummvm/scummvm/commit/50e65957dc82b0c798bad9ee71ba1fd257824280
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented jump opcodes

Changed paths:
    engines/petka/objects/object.cpp


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index dd9724b870..cdb31151f2 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -270,6 +270,12 @@ void QMessageObject::processMessage(const QMessage &msg) {
 		case kPassive:
 			_isActive = false;
 			break;
+		case kJump:
+			g_vm->getQSystem()->_petka->setPos((msg.arg1 == -1 ? _field14 : msg.arg1), (msg.arg2 == -1 ? _field18 : msg.arg2));
+			break;
+		case kJumpVich:
+			g_vm->getQSystem()->_petka->setPos((msg.arg1 == -1 ? _field14 : msg.arg1), (msg.arg2 == -1 ? _field18 : msg.arg2));
+			break;
 		}
 	} else {
 		g_vm->getBigDialogue()->setDialog(_id, msg.opcode, -1);


Commit: 66261efac37d49a10f6ae72a6cd25d577b398080
    https://github.com/scummvm/scummvm/commit/66261efac37d49a10f6ae72a6cd25d577b398080
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: renamed unknown fields

Changed paths:
    engines/petka/interfaces/main.cpp
    engines/petka/objects/object.cpp
    engines/petka/objects/object.h


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index b988b39ea2..18075ea6ad 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -56,8 +56,8 @@ InterfaceMain::InterfaceMain() {
 			obj->_x = stream->readSint32LE();
 			obj->_y = stream->readSint32LE();
 			obj->_z = stream->readSint32LE();
-			obj->_field14 = stream->readSint32LE();
-			obj->_field18 = stream->readSint32LE();
+			obj->_walkX = stream->readSint32LE();
+			obj->_walkY = stream->readSint32LE();
 		}
 	}
 
diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index cdb31151f2..5fd9ba0228 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -271,10 +271,10 @@ void QMessageObject::processMessage(const QMessage &msg) {
 			_isActive = false;
 			break;
 		case kJump:
-			g_vm->getQSystem()->_petka->setPos((msg.arg1 == -1 ? _field14 : msg.arg1), (msg.arg2 == -1 ? _field18 : msg.arg2));
+			g_vm->getQSystem()->_petka->setPos((msg.arg1 == -1 ? _walkX : msg.arg1), (msg.arg2 == -1 ? _walkY : msg.arg2));
 			break;
 		case kJumpVich:
-			g_vm->getQSystem()->_petka->setPos((msg.arg1 == -1 ? _field14 : msg.arg1), (msg.arg2 == -1 ? _field18 : msg.arg2));
+			g_vm->getQSystem()->_petka->setPos((msg.arg1 == -1 ? _walkX : msg.arg1), (msg.arg2 == -1 ? _walkY : msg.arg2));
 			break;
 		}
 	} else {
@@ -311,8 +311,8 @@ QObject::QObject() {
 	_sound = nullptr;
 	_x = 0;
 	_y = 0;
-	_field14 = -1;
-	_field18 = -1;
+	_walkX = -1;
+	_walkY = -1;
 	_field28 = 0;
 }
 
diff --git a/engines/petka/objects/object.h b/engines/petka/objects/object.h
index 3644f54059..c3e6593683 100644
--- a/engines/petka/objects/object.h
+++ b/engines/petka/objects/object.h
@@ -60,8 +60,8 @@ public:
 public:
 	int32 _x;
 	int32 _y;
-	int32 _field14;
-	int32 _field18;
+	int32 _walkX;
+	int32 _walkY;
 	int32 _time;
 	int32 _field20;
 	int32 _field24;


Commit: 527488d228d80afc34ffdbce4077a3d1c80010bc
    https://github.com/scummvm/scummvm/commit/527488d228d80afc34ffdbce4077a3d1c80010bc
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added CURSOR opcode

Changed paths:
    engines/petka/objects/object.cpp
    engines/petka/objects/object_cursor.cpp
    engines/petka/objects/object_cursor.h


diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index 5fd9ba0228..1f38fa0484 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -193,6 +193,21 @@ void QMessageObject::processMessage(const QMessage &msg) {
 			g_vm->getQSystem()->_mainInterface->_dialog._field4 = 0;
 			g_vm->getQSystem()->_mainInterface->_dialog.sub_4155D0(-1);
 			break;
+		case kCursor:
+			if (msg.arg1 == -1) {
+				g_vm->getQSystem()->_cursor->returnInvItem();
+				g_vm->getQSystem()->_cursor->_resourceId = 5002;
+				g_vm->getQSystem()->_cursor->_actionType = 0;
+				g_vm->getQSystem()->_cursor->_invObj = nullptr;
+			} else {
+				g_vm->getQSystem()->_cursor->returnInvItem();
+				g_vm->getQSystem()->_cursor->_resourceId = msg.arg1;
+				g_vm->getQSystem()->_cursor->_actionType = kActionObjUse;
+				g_vm->getQSystem()->_cursor->_invObj = this;
+				_isShown = 0;
+				_isActive = 0;
+			}
+			g_vm->videoSystem()->makeAllDirty();
 		case kDialog:
 			g_vm->getQSystem()->_mainInterface->_dialog.start(msg.arg1, this);
 			break;
diff --git a/engines/petka/objects/object_cursor.cpp b/engines/petka/objects/object_cursor.cpp
index 4c48f41729..70580b925e 100644
--- a/engines/petka/objects/object_cursor.cpp
+++ b/engines/petka/objects/object_cursor.cpp
@@ -112,4 +112,11 @@ void QObjectCursor::show(bool v) {
 	QMessageObject::show(v);
 }
 
+void QObjectCursor::returnInvItem() {
+	if (_actionType == kActionObjUse) {
+		_invObj->show(1);
+		_invObj->_isActive = true;
+	}
+}
+
 }
diff --git a/engines/petka/objects/object_cursor.h b/engines/petka/objects/object_cursor.h
index 16c8ee609a..b908d5674f 100644
--- a/engines/petka/objects/object_cursor.h
+++ b/engines/petka/objects/object_cursor.h
@@ -46,6 +46,7 @@ public:
 	void draw() override;
 	void show(bool v) override;
 	bool isInPoint(int x, int y) override { return 0; }
+	void returnInvItem();
 
 public:
 	int _actionType;


Commit: 4a88f993ff209b8c1eee5e03974b376ac396781d
    https://github.com/scummvm/scummvm/commit/4a88f993ff209b8c1eee5e03974b376ac396781d
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented changing hero to chapayev

Changed paths:
    engines/petka/objects/object_case.cpp
    engines/petka/q_system.cpp
    engines/petka/q_system.h


diff --git a/engines/petka/objects/object_case.cpp b/engines/petka/objects/object_case.cpp
index 51ed1ed337..8d3638f082 100644
--- a/engines/petka/objects/object_case.cpp
+++ b/engines/petka/objects/object_case.cpp
@@ -130,7 +130,7 @@ void QObjectCase::onMouseMove(int x, int y) {
 void QObjectCase::onClick(int x, int y) {
 	switch (_clickedObjIndex) {
 		case 0:
-			// setChapayev()
+			g_vm->getQSystem()->setChapayev();
 			break;
 		case 1:
 			g_vm->getQSystem()->togglePanelInterface();
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 641e32ae8a..c0ef9e68ed 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -224,4 +224,14 @@ void QSystem::toggleMapInterface() {
 	}
 }
 
+void QSystem::setChapayev() {
+	if (_star->_isActive && _currInterface == _mainInterface.get() && _chapayev->_isShown) {
+		_cursor->show(false);
+		_cursor->_resourceId = 5007;
+		_cursor->returnInvItem();
+		_cursor->_actionType = kActionObjUseChapayev;
+		_cursor->show(true);
+	}
+}
+
 }
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index bea159feca..1dabd4a4a5 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -62,6 +62,8 @@ public:
 	void togglePanelInterface();
 	void toggleMapInterface();
 
+	void setChapayev();
+
 public:
 	Common::Array<QObject> _objs;
 	Common::Array<QObjectBG> _bgs;


Commit: 49fd19e96934f0a47993fb509c7f5672d4ef8e06
    https://github.com/scummvm/scummvm/commit/49fd19e96934f0a47993fb509c7f5672d4ef8e06
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed handling rbutton click

Changed paths:
    engines/petka/interfaces/main.cpp


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index 18075ea6ad..83f1d031b5 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -189,9 +189,11 @@ void InterfaceMain::onRightButtonDown(const Common::Point p) {
 	if (g_vm->getQSystem()->_case.get()->_isShown && cursor->_actionType == 6) {
 		cursor->show(0);
 		cursor->_resourceId = 5005;
+		cursor->returnInvItem();
 		cursor->_actionType = 3;
 		cursor->_invObj = nullptr;
 		cursor->setCursorPos(p.x, p.y, 1);
+		cursor->show(1);
 	} else {
 		if (!star->_isShown) {
 			FlicDecoder *flc = g_vm->resMgr()->loadFlic(star->_resourceId);


Commit: db52ecd907fbe489a8ce54095134d00b4c2fa697
    https://github.com/scummvm/scummvm/commit/db52ecd907fbe489a8ce54095134d00b4c2fa697
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented saving/loading system

Changed paths:
  A engines/petka/saveload.cpp
    engines/petka/big_dialogue.cpp
    engines/petka/big_dialogue.h
    engines/petka/detection.cpp
    engines/petka/module.mk
    engines/petka/objects/object_case.h
    engines/petka/petka.h
    engines/petka/q_system.cpp
    engines/petka/q_system.h


diff --git a/engines/petka/big_dialogue.cpp b/engines/petka/big_dialogue.cpp
index 22c72e63b7..fc5dcee3da 100644
--- a/engines/petka/big_dialogue.cpp
+++ b/engines/petka/big_dialogue.cpp
@@ -20,6 +20,7 @@
  *
  */
 
+#include "common/debug.h"
 #include "common/stream.h"
 
 #include "petka/base.h"
@@ -342,4 +343,15 @@ label:
 	}
 }
 
+void BigDialogue::load(Common::ReadStream *s) {
+	_codeSize = s->readUint32LE();
+	s->read(_code, 4 * _codeSize);
+
+}
+
+void BigDialogue::save(Common::WriteStream *s) {
+	s->writeUint32LE(_codeSize);
+	s->write(_code, 4 * _codeSize);
+}
+
 } // End of namespace Petka
\ No newline at end of file
diff --git a/engines/petka/big_dialogue.h b/engines/petka/big_dialogue.h
index d49c7c04f9..29322146a8 100644
--- a/engines/petka/big_dialogue.h
+++ b/engines/petka/big_dialogue.h
@@ -71,6 +71,9 @@ public:
 
 	const Common::U32String *getSpeechInfo(int *talkerId, const char **soundName, int unk);
 
+	void load(Common::ReadStream *s);
+	void save(Common::WriteStream *s);
+
 private:
 	void loadSpeechesInfo();
 
diff --git a/engines/petka/detection.cpp b/engines/petka/detection.cpp
index 97f4f9d210..9b9b651144 100644
--- a/engines/petka/detection.cpp
+++ b/engines/petka/detection.cpp
@@ -20,6 +20,9 @@
  *
  */
 
+#include "common/system.h"
+#include "common/savefile.h"
+
 #include "engines/advancedDetector.h"
 
 #include "petka/petka.h"
@@ -48,9 +51,67 @@ public:
 		return "Red Comrades (C) S.K.I.F";
 	}
 
+	virtual bool hasFeature(MetaEngineFeature f) const;
+	virtual int getMaximumSaveSlot() const { return 18; }
+	virtual SaveStateList listSaves(const char *target) const;
+	virtual void removeSaveState(const char *target, int slot) const;
+	virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
 	virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
 };
 
+bool PetkaMetaEngine::hasFeature(MetaEngineFeature f) const {
+	return
+		(f == kSupportsListSaves) ||
+		(f == kSupportsDeleteSave) ||
+		(f == kSavesSupportMetaInfo) ||
+		(f == kSavesSupportThumbnail) ||
+		(f == kSavesSupportCreationDate) ||
+		(f == kSavesSupportPlayTime);
+}
+
+SaveStateList PetkaMetaEngine::listSaves(const char *target) const {
+	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+	Common::String pattern = Common::String::format("%s.s##", target);
+	Common::StringArray filenames = saveFileMan->listSavefiles(pattern);
+
+	SaveStateList saveList;
+	for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+		// Obtain the last 2 digits of the filename, since they correspond to the save slot
+		int slotNum = atoi(file->c_str() + file->size() - 2);
+		if (slotNum >= 0 && slotNum <= getMaximumSaveSlot()) {
+			Common::ScopedPtr<Common::InSaveFile> in(saveFileMan->openForLoading(*file));
+			if (in) {
+				SaveStateDescriptor desc;
+				desc.setSaveSlot(slotNum);
+				if (Petka::readSaveHeader(*in.get(), desc))
+					saveList.push_back(desc);
+			}
+		}
+	}
+
+	// Sort saves based on slot number.
+	Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
+	return saveList;
+}
+
+void PetkaMetaEngine::removeSaveState(const char *target, int slot) const {
+	g_system->getSavefileManager()->removeSavefile(Petka::generateSaveName(slot, target));
+}
+
+SaveStateDescriptor PetkaMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+	Common::ScopedPtr<Common::InSaveFile> f(g_system->getSavefileManager()->openForLoading(Petka::generateSaveName(slot, target)));
+
+	if (f) {
+		SaveStateDescriptor desc;
+		if (!Petka::readSaveHeader(*f.get(), desc, false))
+			return SaveStateDescriptor();
+
+		return desc;
+	}
+
+	return SaveStateDescriptor();
+}
+
 bool PetkaMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
 	if (desc)
 		*engine = new Petka::PetkaEngine(syst, desc);
diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index e7b042933e..19f4f78f6f 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -6,6 +6,7 @@ MODULE_OBJS = \
     file_mgr.o \
     flc.o \
     petka.o \
+    saveload.o \
     q_manager.o \
     q_system.o \
     sound.o \
diff --git a/engines/petka/objects/object_case.h b/engines/petka/objects/object_case.h
index 2ef8a5997c..bffeadb0f1 100644
--- a/engines/petka/objects/object_case.h
+++ b/engines/petka/objects/object_case.h
@@ -41,7 +41,7 @@ public:
 	void removeItem(int id);
 	void setInv(int id1, int id2);
 
-private:
+public:
 	Common::Array<int> _items;
 	uint _clickedObjIndex;
 	int _itemIndex;
diff --git a/engines/petka/petka.h b/engines/petka/petka.h
index 3b06ba69c0..ce075852fe 100644
--- a/engines/petka/petka.h
+++ b/engines/petka/petka.h
@@ -24,8 +24,11 @@
 #define PETKA_PETKA_H
 
 #include "common/random.h"
+#include "common/stream.h"
+#include "common/savefile.h"
 
 #include "engines/engine.h"
+#include "engines/savestate.h"
 
 #include "gui/debugger.h"
 
@@ -86,6 +89,12 @@ public:
 	Common::RandomSource &getRnd();
 	const Common::String &getSpeechPath();
 
+	virtual Common::Error loadGameState(int slot) override;
+	bool canLoadGameStateCurrently() override;
+
+	Common::Error saveGameState(int slot, const Common::String &desc) override;
+	bool canSaveGameStateCurrently() override;
+
 private:
 	void loadStores();
 
@@ -107,7 +116,10 @@ private:
 	Common::String _chapterStoreName;
 
 	uint8 _part;
+	uint8 _nextPart;
 	uint8 _chapter;
+	bool _shouldChangePart;
+	Common::String _saveName;
 };
 
 class Console : public GUI::Debugger {
@@ -118,6 +130,9 @@ public:
 
 extern PetkaEngine *g_vm;
 
+WARN_UNUSED_RESULT bool readSaveHeader(Common::InSaveFile &in, SaveStateDescriptor &desc, bool skipThumbnail = true);
+Common::String generateSaveName(int slot, const char *gameId);
+
 } // End of namespace Petka
 
 #endif
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index c0ef9e68ed..885bda95b7 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -35,7 +35,9 @@
 #include "petka/objects/object_case.h"
 #include "petka/objects/object_star.h"
 #include "petka/objects/heroes.h"
+#include "petka/big_dialogue.h"
 #include "petka/q_system.h"
+#include "petka/video.h"
 
 namespace Petka {
 
@@ -234,4 +236,94 @@ void QSystem::setChapayev() {
 	}
 }
 
+static Common::String readString(Common::ReadStream *s) {
+	Common::String string;
+	uint32 len = s->readUint32LE();
+	char *buffer = (char *)malloc(len);
+	s->read(buffer, len);
+	string = Common::String(buffer, len);
+	free(buffer);
+	return string;
+}
+
+static void writeString(Common::WriteStream *s, const Common::String &string) {
+	s->writeUint32LE(string.size());
+	s->write(string.c_str(), string.size());
+}
+
+void QSystem::load(Common::ReadStream *s) {
+	uint count = s->readUint32LE();
+	for (uint i = 0; i < count; ++i) {
+		QMessageObject *obj = findObject(readString(s));
+		obj->_field_38 = s->readUint32LE();
+		obj->_status = s->readUint32LE();
+		obj->_resourceId = s->readUint32LE();
+		obj->_z = s->readUint32LE();
+		obj->_x = s->readUint32LE();
+		obj->_y = s->readUint32LE();
+		obj->_isShown = s->readUint32LE();
+		obj->_isActive = s->readUint32LE();
+		obj->_animate = s->readUint32LE();
+	}
+
+	uint itemSize = s->readUint32LE();
+	_case->_items.clear();
+	for (uint i = 0; i < itemSize; ++i) {
+		_case->_items.push_back(s->readSint32LE());
+	}
+
+	_room = (QObjectBG *)findObject(readString(s));
+	if (_room) {
+		_mainInterface->loadRoom(_room->_id, true);
+	}
+
+	g_vm->getBigDialogue()->load(s);
+
+	_cursor->_resourceId = s->readUint32LE();
+	_cursor->_actionType = s->readUint32LE();
+	int invObjId = s->readSint32LE();
+	if (invObjId != -1) {
+		_cursor->_invObj = findObject(invObjId);
+	} else {
+		_cursor->_invObj = nullptr;
+	}
+
+	g_vm->videoSystem()->makeAllDirty();
+}
+
+void QSystem::save(Common::WriteStream *s) {
+	s->writeUint32LE(_allObjects.size());
+	for (uint i = 0; i < _allObjects.size(); ++i) {
+		writeString(s, _allObjects[i]->_name);
+		s->writeUint32LE(_allObjects[i]->_field_38);
+		s->writeUint32LE(_allObjects[i]->_status);
+		s->writeUint32LE(_allObjects[i]->_resourceId);
+		s->writeUint32LE(_allObjects[i]->_z);
+		s->writeUint32LE(_allObjects[i]->_x);
+		s->writeUint32LE(_allObjects[i]->_y);
+		s->writeUint32LE(_allObjects[i]->_isShown);
+		s->writeUint32LE(_allObjects[i]->_isActive);
+		s->writeUint32LE(_allObjects[i]->_animate);
+	}
+
+	s->writeUint32LE(_case->_items.size());
+	for (uint i = 0; i < _case->_items.size(); ++i) {
+		s->writeSint32LE(_case->_items[i]);
+	}
+
+	writeString(s, _room->_name);
+
+	// heroes (no impl)
+
+	g_vm->getBigDialogue()->save(s);
+
+	s->writeUint32LE(_cursor->_resourceId);
+	s->writeUint32LE(_cursor->_actionType);
+	if (_cursor->_invObj) {
+		s->writeSint32LE(_cursor->_invObj->_resourceId);
+	} else {
+		s->writeSint32LE(-1);
+	}
+}
+
 }
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index 1dabd4a4a5..9d3e42eef7 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -24,6 +24,7 @@
 #define PETKA_Q_SYSTEM_H
 
 #include "common/ptr.h"
+#include "common/stream.h"
 #include "common/list.h"
 
 #include "petka/objects/object_bg.h"
@@ -49,6 +50,8 @@ public:
 	~QSystem();
 
 	bool init();
+	void load(Common::ReadStream *s);
+	void save(Common::WriteStream *s);
 
 	void update();
 
diff --git a/engines/petka/saveload.cpp b/engines/petka/saveload.cpp
new file mode 100644
index 0000000000..def3ada37e
--- /dev/null
+++ b/engines/petka/saveload.cpp
@@ -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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/system.h"
+#include "common/savefile.h"
+
+#include "engines/savestate.h"
+
+#include "graphics/thumbnail.h"
+
+#include "petka/petka.h"
+#include "petka/q_system.h"
+
+namespace Petka {
+
+Common::Error PetkaEngine::loadGameState(int slot) {
+	Common::SeekableReadStream *in = _saveFileMan->openForLoading(generateSaveName(slot, _targetName.c_str()));
+	if (!in)
+		return Common::kNoGameDataFoundError;
+
+	SaveStateDescriptor desc;
+	if (!readSaveHeader(*in, desc))
+		return Common::kUnknownError;
+
+	setTotalPlayTime(desc.getPlayTimeMSecs());
+
+	_nextPart = in->readUint32LE();
+	_chapter = in->readUint32LE();
+	if (_nextPart == _part) {
+		_qsystem->load(in);
+	} else {
+		_shouldChangePart = true;
+		_saveName = generateSaveName(slot, _targetName.c_str());
+	}
+
+	delete in;
+	return Common::kNoError;
+}
+
+Common::Error PetkaEngine::saveGameState(int slot, const Common::String &desc) {
+	Common::OutSaveFile *out = _saveFileMan->openForSaving(generateSaveName(slot, _targetName.c_str()));
+	if (!out)
+		return Common::kUnknownError;
+
+	out->writeUint32BE(MKTAG('p', 'e', 't', 'k'));
+
+	TimeDate curTime;
+	_system->getTimeAndDate(curTime);
+
+	out->writeUint32LE(((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF));
+	out->writeUint16LE(((curTime.tm_hour & 0xFF) << 8) | ((curTime.tm_min) & 0xFF));
+
+	out->writeUint32LE(getTotalPlayTime() / 1000);
+
+	if (!Graphics::saveThumbnail(*out))
+		return Common::kUnknownError;
+
+	out->writeUint32LE(_part);
+	out->writeUint32LE(_chapter);
+	_qsystem->save(out);
+
+	delete out;
+	return Common::kNoError;
+}
+
+bool PetkaEngine::canSaveGameStateCurrently() {
+	return true;
+}
+
+bool PetkaEngine::canLoadGameStateCurrently() {
+	return true;
+}
+
+bool readSaveHeader(Common::InSaveFile &in, SaveStateDescriptor &desc, bool skipThumbnail) {
+	if (in.readUint32BE() != MKTAG('p', 'e', 't', 'k'))
+		return false;
+
+	const Common::String description = in.readPascalString();
+	uint32 date = in.readUint32LE();
+	uint16 time = in.readUint16LE();
+	uint32 playTime = in.readUint32LE();
+
+	Graphics::Surface *thumbnail = nullptr;
+	if (!Graphics::loadThumbnail(in, thumbnail, skipThumbnail))
+		return false;
+
+	int day = (date >> 24) & 0xFF;
+	int month = (date >> 16) & 0xFF;
+	int year = date & 0xFFFF;
+
+	int hour = (time >> 8) & 0xFF;
+	int minutes = time & 0xFF;
+
+	desc.setSaveDate(year, month, day);
+	desc.setSaveTime(hour, minutes);
+	desc.setPlayTime(playTime * 1000);
+	desc.setDescription(description);
+	desc.setThumbnail(thumbnail);
+
+	return true;
+}
+
+Common::String generateSaveName(int slot, const char *gameId) {
+	return Common::String::format("%s.s%02d", gameId, slot);
+}
+
+}
+


Commit: 5e2e4596d571d600219a53348c1fadc0e75404d7
    https://github.com/scummvm/scummvm/commit/5e2e4596d571d600219a53348c1fadc0e75404d7
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: reimplemented show method of QObject

Changed paths:
    engines/petka/interfaces/interface.cpp
    engines/petka/interfaces/interface.h
    engines/petka/objects/object.cpp


diff --git a/engines/petka/interfaces/interface.cpp b/engines/petka/interfaces/interface.cpp
index 85a45dd5bf..8141a646f8 100644
--- a/engines/petka/interfaces/interface.cpp
+++ b/engines/petka/interfaces/interface.cpp
@@ -32,4 +32,13 @@ void Interface::setText(const Common::U32String &text, uint32 rgb) {
 	_objs.push_back(new QText(text, rgb));
 }
 
+QVisibleObject *Interface::findObject(int resourceId) {
+	for (uint i = 0; i < _objs.size(); ++i) {
+		if (_objs[i]->_resourceId == resourceId) {
+			return _objs[i];
+		}
+	}
+	return nullptr;
+}
+
 } // End of namespace Petka
diff --git a/engines/petka/interfaces/interface.h b/engines/petka/interfaces/interface.h
index 3db864d032..da1fa0d033 100644
--- a/engines/petka/interfaces/interface.h
+++ b/engines/petka/interfaces/interface.h
@@ -46,6 +46,8 @@ public:
 
 	void setText(const Common::U32String &text, uint32 rgb);
 
+	QVisibleObject *findObject(int resourceId);
+
 public:
 	Common::Array<QVisibleObject *> _objs;
 	QVisibleObject *_objUnderCursor;
diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index 1f38fa0484..f9b00044b6 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -396,14 +396,10 @@ void QObject::updateZ() {
 }
 
 void QObject::show(bool v) {
-	const Common::Array<QVisibleObject*> & objs = g_vm->getQSystem()->_mainInterface->_objs;
-	for (uint i = 0; i < objs.size(); ++i) {
-		if (objs[i]->_resourceId == _resourceId) {
-			FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
-			if (flc) {
-				g_vm->videoSystem()->addDirtyRect(Common::Point(_x, _y), *flc);
-			}
-			break;
+	if (g_vm->getQSystem()->_mainInterface->findObject(_resourceId)) {
+		FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+		if (flc) {
+			g_vm->videoSystem()->addDirtyRect(Common::Point(_x, _y), *flc);
 		}
 	}
 	QMessageObject::show(v);


Commit: 7c14d49398d8e3901fdad46363e2650ca7a2ae0a
    https://github.com/scummvm/scummvm/commit/7c14d49398d8e3901fdad46363e2650ca7a2ae0a
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added constants to startup interface

Changed paths:
    engines/petka/interfaces/startup.cpp


diff --git a/engines/petka/interfaces/startup.cpp b/engines/petka/interfaces/startup.cpp
index 7ee5c6c155..976e196891 100644
--- a/engines/petka/interfaces/startup.cpp
+++ b/engines/petka/interfaces/startup.cpp
@@ -37,18 +37,23 @@
 
 namespace Petka {
 
+const char *const kStartupObjName = "STARTUP";
+const char *const kCreditsVideoName = "credits.avi";
+
 enum {
 	kExit = 4981,
 	kCredits = 4982,
 	kLoad = 4983,
-	kNewGame = 4984
+	kNewGame = 4984,
+	kStartupCursorId = 4901,
+	kBackgroundId = 4980
 };
 
 void InterfaceStartup::start() {
 	g_vm->getQSystem()->update();
 	g_vm->getQSystem()->_isIniting = 0;
 
-	QObjectBG *bg = (QObjectBG *)g_vm->getQSystem()->findObject("STARTUP");
+	QObjectBG *bg = (QObjectBG *)g_vm->getQSystem()->findObject(kStartupObjName);
 	_objs.push_back(bg);
 
 	Sound *s = g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(bg->_musicId), Audio::Mixer::SoundType::kMusicSoundType);
@@ -77,7 +82,7 @@ void InterfaceStartup::start() {
 
 
 	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
-	cursor->_resourceId = 4901;
+	cursor->_resourceId = kStartupCursorId;
 	cursor->_isShown = true;
 	cursor->_animate = false;
 	_objs.push_back(g_vm->getQSystem()->_cursor.get());
@@ -92,7 +97,7 @@ void InterfaceStartup::onLeftButtonDown(const Common::Point p) {
 		g_system->quit();
 		break;
 	case kCredits:
-		g_vm->playVideo(g_vm->openFile("credits.avi", false));
+		g_vm->playVideo(g_vm->openFile(kCreditsVideoName, false));
 		break;
 	case kLoad:
 		g_vm->getQSystem()->_saveLoadInterface->startSaveLoad(0);
@@ -108,7 +113,7 @@ void InterfaceStartup::onMouseMove(const Common::Point p) {
 	bool found = false;
 	for (int i = _objs.size() - 1; i > 0; --i) {
 		QMessageObject *obj = (QMessageObject *)_objs[i];
-		if (obj->_resourceId != 4901 && obj->_resourceId != 4980) {
+		if (obj->_resourceId != kStartupCursorId && obj->_resourceId != kBackgroundId) {
 			FlicDecoder *flc = g_vm->resMgr()->loadFlic(obj->_resourceId);
 			if (flc) {
 				bool clicked = false;


Commit: b973ec372f973c11d1b58dc0a0c5201bf74e8415
    https://github.com/scummvm/scummvm/commit/b973ec372f973c11d1b58dc0a0c5201bf74e8415
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added initCursor function to interface class

Changed paths:
    engines/petka/interfaces/interface.cpp
    engines/petka/interfaces/interface.h
    engines/petka/interfaces/map.cpp
    engines/petka/interfaces/panel.cpp
    engines/petka/interfaces/startup.cpp


diff --git a/engines/petka/interfaces/interface.cpp b/engines/petka/interfaces/interface.cpp
index 8141a646f8..cffb560848 100644
--- a/engines/petka/interfaces/interface.cpp
+++ b/engines/petka/interfaces/interface.cpp
@@ -22,6 +22,9 @@
 
 #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"
 
 namespace Petka {
 
@@ -41,4 +44,14 @@ QVisibleObject *Interface::findObject(int resourceId) {
 	return nullptr;
 }
 
+void Interface::initCursor(int id, bool show, bool animate) {
+	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
+	_objs.push_back(cursor);
+	cursor->_resourceId = id;
+	cursor->_isShown = show;
+	cursor->_animate = animate;
+	cursor->_actionType = kActionLook;
+	cursor->setCursorPos(cursor->_x, cursor->_y, 0);
+}
+
 } // End of namespace Petka
diff --git a/engines/petka/interfaces/interface.h b/engines/petka/interfaces/interface.h
index da1fa0d033..f06d462388 100644
--- a/engines/petka/interfaces/interface.h
+++ b/engines/petka/interfaces/interface.h
@@ -48,6 +48,8 @@ public:
 
 	QVisibleObject *findObject(int resourceId);
 
+	void initCursor(int id, bool show, bool animate);
+
 public:
 	Common::Array<QVisibleObject *> _objs;
 	QVisibleObject *_objUnderCursor;
diff --git a/engines/petka/interfaces/map.cpp b/engines/petka/interfaces/map.cpp
index 012080f52a..c30d79db2e 100644
--- a/engines/petka/interfaces/map.cpp
+++ b/engines/petka/interfaces/map.cpp
@@ -66,13 +66,8 @@ void InterfaceMap::start() {
 	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
 	_savedCursorId = cursor->_resourceId;
 	_savedCursorActionType = cursor->_actionType;
-	cursor->_isShown = true;
-	cursor->_resourceId = 4901;
-	cursor->_animate = 0;
-	cursor->_actionType;
 
-	_objs.push_back(cursor);
-	cursor->setCursorPos(cursor->_x, cursor->_y, false);
+	initCursor(4901, 1, 0);
 
 	_savedXOffset = 0; // g_vm->getQSystem()->xOffset;
 	_savedSceneWidth = 640; // g_vm->getQSystem()->savedSceneWidth
diff --git a/engines/petka/interfaces/panel.cpp b/engines/petka/interfaces/panel.cpp
index 3c98111654..ba5a7e9bce 100644
--- a/engines/petka/interfaces/panel.cpp
+++ b/engines/petka/interfaces/panel.cpp
@@ -100,13 +100,7 @@ void InterfacePanel::start() {
 		break;
 	}
 
-
-	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
-	_objs.push_back(cursor);
-	cursor->_resourceId = 4901;
-	cursor->_isShown = 1;
-	cursor->_animate = 1;
-	cursor->setCursorPos(cursor->_x, cursor->_y, 0);
+	initCursor(4901, 1, 1);
 
 	updateSliders();
 	updateSubtitles();
diff --git a/engines/petka/interfaces/startup.cpp b/engines/petka/interfaces/startup.cpp
index 976e196891..66898972eb 100644
--- a/engines/petka/interfaces/startup.cpp
+++ b/engines/petka/interfaces/startup.cpp
@@ -80,13 +80,7 @@ void InterfaceStartup::start() {
 		break;
 	}
 
-
-	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
-	cursor->_resourceId = kStartupCursorId;
-	cursor->_isShown = true;
-	cursor->_animate = false;
-	_objs.push_back(g_vm->getQSystem()->_cursor.get());
-	cursor->setCursorPos(cursor->_x, cursor->_y, 0);
+	initCursor(kStartupCursorId, 1, 0);
 }
 
 void InterfaceStartup::onLeftButtonDown(const Common::Point p) {


Commit: eb0d3a546d6d58128fec8768335ea903ab7ed0b1
    https://github.com/scummvm/scummvm/commit/eb0d3a546d6d58128fec8768335ea903ab7ed0b1
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added fields to hero class

Changed paths:
    engines/petka/objects/heroes.cpp
    engines/petka/objects/heroes.h


diff --git a/engines/petka/objects/heroes.cpp b/engines/petka/objects/heroes.cpp
index df723dcb9f..b4c07ea7d7 100644
--- a/engines/petka/objects/heroes.cpp
+++ b/engines/petka/objects/heroes.cpp
@@ -24,12 +24,25 @@
 
 namespace Petka {
 
-QObjectChapayev::QObjectChapayev() {
-
-}
-
 QObjectPetka::QObjectPetka() {
+	_field7C = 1;
+	_reaction = nullptr;
+	_sender = nullptr;
+	_isPetka = true;
+	_isWalking = false;
+	_x = 574;
+	_y = 44;
+	_z = 200;
+	_surfId  = -5;
+	_surfH = 0;
+	_surfW = 0;
+}
 
+QObjectChapayev::QObjectChapayev() {
+	_x = 477;
+	_y = 350;
+	_surfId = -6;
+	_isPetka = false;
 }
 
 }
diff --git a/engines/petka/objects/heroes.h b/engines/petka/objects/heroes.h
index 94d7a3b5c9..1bd57b95bd 100644
--- a/engines/petka/objects/heroes.h
+++ b/engines/petka/objects/heroes.h
@@ -31,16 +31,27 @@ class QObjectPetka : public QObject {
 public:
 	QObjectPetka();
 
-private:
-
+protected:
+	int _field7C;
+	int _surfW;
+	int _surfH;
+	int _x_;
+	int _y_;
+	int _surfId;
+	int _imageId;
+	double _field98;
+	// walkObj
+	bool _isWalking;
+	bool _isPetka;
+	QReaction *_heroReaction;
+	QMessageObject *_sender;
+	int _fieldB4;
 };
 
 class QObjectChapayev : public QObjectPetka {
 public:
 	QObjectChapayev();
 
-private:
-
 };
 
 } // End of namespace Petka


Commit: afa777da2a0223b65adb334998ad8070bc09a511
    https://github.com/scummvm/scummvm/commit/afa777da2a0223b65adb334998ad8070bc09a511
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: implemented processing messages by heroes

Changed paths:
    engines/petka/objects/heroes.cpp
    engines/petka/objects/heroes.h


diff --git a/engines/petka/objects/heroes.cpp b/engines/petka/objects/heroes.cpp
index b4c07ea7d7..34663c73a4 100644
--- a/engines/petka/objects/heroes.cpp
+++ b/engines/petka/objects/heroes.cpp
@@ -20,6 +20,10 @@
  *
  */
 
+#include "petka/petka.h"
+#include "petka/q_manager.h"
+#include "petka/q_system.h"
+#include "petka/flc.h"
 #include "petka/objects/heroes.h"
 
 namespace Petka {
@@ -38,6 +42,43 @@ QObjectPetka::QObjectPetka() {
 	_surfW = 0;
 }
 
+void QObjectPetka::processMessage(const QMessage &arg) {
+	QMessage msg = arg;
+	if (msg.opcode == kImage) {
+		msg.opcode = kSet;
+		_imageId = msg.arg1;
+	}
+	if (msg.opcode == kSaid || msg.opcode == kStand) {
+		msg.opcode = kSet;
+		msg.arg1 = _imageId + 1;
+		msg.arg2 = 1;
+	}
+	if (msg.opcode == kSet || msg.opcode == kPlay) {
+		_field7C = msg.arg2 == _imageId || msg.opcode == kPlay;
+	}
+	if (msg.opcode != kWalk) {
+		if (msg.opcode == kWalked && _heroReaction) {
+			processSavedReaction(&_heroReaction, _sender);
+		}
+		QMessageObject::processMessage(msg);
+		if (msg.opcode == kSet || msg.opcode == kPlay) {
+			initSurface();
+			if (!g_vm->getQSystem()->_isIniting) {
+				setPos(_x_, _y_);
+			}
+		}
+	}
+}
+
+void QObjectPetka::initSurface() {
+	QManager *resMgr = g_vm->resMgr();
+	FlicDecoder *flc = resMgr->loadFlic(_resourceId);
+	resMgr->removeResource(_surfId);
+	resMgr->findOrCreateSurface(_surfId, flc->getWidth(), flc->getHeight());
+	_surfW = flc->getWidth() * _field98;
+	_surfH = flc->getHeight() * _field98;
+}
+
 QObjectChapayev::QObjectChapayev() {
 	_x = 477;
 	_y = 350;
diff --git a/engines/petka/objects/heroes.h b/engines/petka/objects/heroes.h
index 1bd57b95bd..d01621fe2f 100644
--- a/engines/petka/objects/heroes.h
+++ b/engines/petka/objects/heroes.h
@@ -30,6 +30,8 @@ namespace Petka {
 class QObjectPetka : public QObject {
 public:
 	QObjectPetka();
+	void processMessage(const QMessage &msg) override;
+	void initSurface();
 
 protected:
 	int _field7C;


Commit: 1599f218615b8a6425dd5057aae97fc1aeb7802a
    https://github.com/scummvm/scummvm/commit/1599f218615b8a6425dd5057aae97fc1aeb7802a
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: added heroes implementation without walking system

Changed paths:
    engines/petka/objects/heroes.cpp
    engines/petka/objects/heroes.h
    engines/petka/objects/object.cpp
    engines/petka/objects/object.h
    engines/petka/objects/object_bg.cpp
    engines/petka/q_system.cpp
    engines/petka/q_system.h


diff --git a/engines/petka/objects/heroes.cpp b/engines/petka/objects/heroes.cpp
index 34663c73a4..251f1dc97f 100644
--- a/engines/petka/objects/heroes.cpp
+++ b/engines/petka/objects/heroes.cpp
@@ -20,10 +20,14 @@
  *
  */
 
+#include "common/system.h"
+
 #include "petka/petka.h"
 #include "petka/q_manager.h"
 #include "petka/q_system.h"
 #include "petka/flc.h"
+#include "petka/video.h"
+#include "petka/sound.h"
 #include "petka/objects/heroes.h"
 
 namespace Petka {
@@ -40,6 +44,7 @@ QObjectPetka::QObjectPetka() {
 	_surfId  = -5;
 	_surfH = 0;
 	_surfW = 0;
+	_field98 = 1.0;
 }
 
 void QObjectPetka::processMessage(const QMessage &arg) {
@@ -79,6 +84,229 @@ void QObjectPetka::initSurface() {
 	_surfH = flc->getHeight() * _field98;
 }
 
+void QObjectPetka::walk(int x, int y) {
+	Common::Point walkPos(x, y);
+	if (_isShown) {
+		Common::Point currPos;
+		if (_isWalking) {
+			// currPos = _walkObj->currPos();
+		} else {
+			currPos.x = _x_;
+			currPos.y = _y_;
+		}
+
+		if (currPos.sqrDist(walkPos) >= 25 * 25) {
+			//_walkObj->init(currPos, walkPos);
+			_destX = x;
+			_destY = y;
+			_resourceId = _imageId; // + _walkObj->getResId() + 10;
+			_isWalking = true;
+			_animate = true;
+
+			initSurface();
+			FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+			flc->setFrame(1);
+
+			g_vm->videoSystem()->makeAllDirty();
+
+			_field7C = 0;
+			_time = 0;
+			_msgProcessingPaused = true;
+		}
+	} else {
+		setPos(x, y);
+	}
+}
+
+void QObjectPetka::draw() {
+	if (!_isShown || _resourceId == -1) {
+		return;
+	}
+
+	if (_animate && _startSound) {
+		if (_sound) {
+			_sound->play(!_notLoopedSound);
+		}
+		_startSound = false;
+	}
+
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+	Graphics::Surface *surf = g_vm->resMgr()->loadBitmap(_surfId);
+	if (!flc || !surf) {
+		return;
+	}
+	Graphics::Surface *conv = flc->getCurrentFrame()->convertTo(g_system->getScreenFormat(), flc->getPalette());
+	surf->copyRectToSurface(*conv, 0, 0, Common::Rect(0, 0, flc->getWidth() - 1, flc->getHeight() - 1));
+
+	Common::Rect srcRect(0, 0, _surfW, _surfH);
+	Common::Rect dstRect(srcRect);
+	dstRect.translate(_x, _y);
+
+	g_vm->videoSystem()->screen().transBlitFrom(*surf, srcRect, dstRect, flc->getTransColor(surf->format));
+	conv->free();
+	delete conv;
+}
+
+void QObjectPetka::setPos(int x, int y) {
+	y = MIN(y, 480);
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+
+	_field98 = calcSmth(y);
+
+	_surfH = flc->getHeight() * _field98;
+	_surfW = flc->getWidth() * _field98;
+
+	_x_ = x;
+	_y_ = y;
+
+	_x = x - _surfW / 2;
+	_y = y - _surfH;
+
+	g_vm->videoSystem()->makeAllDirty();
+}
+
+double QObjectPetka::calcSmth(int y) {
+	QSystem *qsys = g_vm->getQSystem();
+
+	y = MIN(y, 480);
+
+
+	if (!qsys->_unkMap.contains(qsys->_room->_name)) {
+		return 1.0;
+	}
+
+	const UnkStruct &unk = qsys->_unkMap.getVal(qsys->_room->_name);
+
+
+	double res = (y - unk.f3) * unk.f2 / (unk.f4 - unk.f3);
+	if (res < 0.0)
+		res = 0.0;
+
+	if (res + unk.f1 > unk.f5)
+		return unk.f5;
+	return res + unk.f1;
+}
+
+void QObjectPetka::updateWalk() {
+	if (_isWalking) {
+		_isWalking = false;
+		setPos(_destX, _destY);
+
+		QMessage msg {_id, kSet, (uint16)_imageId, 1, 0, nullptr, 0};
+		if (_heroReaction) {
+			uint i;
+			for (i = 0; i < _heroReaction->messages.size(); ++i) {
+				if (_heroReaction->messages[i].opcode == kGoTo || _heroReaction->messages[i].opcode == kSetSeq) {
+					_resourceId = _imageId; // + _walkObj->getResOffset() + 10;
+
+					FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+					flc->setFrame(1);
+
+					initSurface();
+
+					processMessage(QMessage {_id, kAnimate, 0, 0, 0, nullptr, 0});
+
+					_heroReaction->messages.push_back(msg);
+					_heroReaction->messages.push_back(QMessage {_id, kAnimate, 1, 0, 0, nullptr, 0});
+					break;
+				}
+			}
+			if (i == _heroReaction->messages.size())
+				processMessage(msg);
+		} else {
+			processMessage(msg);
+		}
+		_msgProcessingPaused = false;
+		g_vm->videoSystem()->makeAllDirty();
+	}
+}
+
+void QObjectPetka::setReactionAfterWalk(uint index, QReaction **reaction, QMessageObject *sender, bool deleteReaction) {
+	QReaction *r = *reaction;
+	_heroReaction = nullptr;
+
+	stopWalk();
+
+	QMessage msg {_id, kWalked, 0, 0, 0, sender, 0};
+	_heroReaction = new QReaction();
+	_sender = sender;
+
+	for (uint i = index + 1; i < r->messages.size(); ++i) {
+		_heroReaction->messages.push_back(r->messages[i]);
+	}
+
+	if (deleteReaction) {
+		if (r == *reaction) {
+			if (*reaction) {
+				delete *reaction;
+			}
+			*reaction = nullptr;
+		} else {
+			delete r;
+		}
+	}
+
+}
+
+void QObjectPetka::stopWalk() {
+	_isWalking = false;
+	_msgProcessingPaused = false;
+
+	Common::List<QMessage> &list =   g_vm->getQSystem()->_messages;
+	for (Common::List<QMessage>::iterator it = list.begin(); it != list.end();) {
+		if (it->opcode == kWalked && it->objId == _id) {
+			it->objId = -1;
+		}
+
+	}
+
+	delete _heroReaction;
+	_heroReaction = nullptr;
+
+	if (!_field7C) {
+		QMessage msg {_id, kSet, (uint16)_imageId, 1, 0, nullptr, 0};
+		processMessage(msg);
+	}
+}
+
+void QObjectPetka::update(int time) {
+	if (!_animate || !_isShown)
+		return;
+	_time += time;
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+	if (flc && flc->getFrameCount() != 1) {
+		while (_time >= flc->getDelay()) {
+			if (_sound && _hasSound && flc->getCurFrame() == 0) {
+				_startSound = true;
+				_hasSound = false;
+			}
+			flc->setFrame(-1);
+			if (flc->getCurFrame() == flc->getFrameCount() - 1) {
+				if (_notLoopedSound) {
+					_hasSound = _sound != nullptr;
+				}
+				g_vm->getQSystem()->addMessage(_id, kEnd, _resourceId, 0, 0, 0, 0);
+			}
+			if (flc->getCurFrame() + 1 == flc->getFrameCount() / 2) {
+				g_vm->getQSystem()->addMessage(_id, kHalf, _resourceId, 0, 0, 0, 0);
+			}
+
+			if (_field7C && flc->getCurFrame() == 0)
+				_time = -10000;
+
+			updateWalk();
+			flc = g_vm->resMgr()->loadFlic(_resourceId);
+
+			_surfH = flc->getHeight() * _field98;
+			_surfW = flc->getWidth() * _field98;
+
+			_time -= flc->getDelay();
+
+			g_vm->videoSystem()->addDirtyRect(Common::Rect(_x, _y, _surfW + _x, _surfH + _y));
+		}
+	}
+}
+
 QObjectChapayev::QObjectChapayev() {
 	_x = 477;
 	_y = 350;
diff --git a/engines/petka/objects/heroes.h b/engines/petka/objects/heroes.h
index d01621fe2f..11d4333242 100644
--- a/engines/petka/objects/heroes.h
+++ b/engines/petka/objects/heroes.h
@@ -33,7 +33,19 @@ public:
 	void processMessage(const QMessage &msg) override;
 	void initSurface();
 
-protected:
+	void walk(int x, int y);
+	void stopWalk();
+	void updateWalk();
+	void setReactionAfterWalk(uint index, QReaction **reaction, QMessageObject *sender, bool deleteReaction);
+
+	void draw() override;
+	void update(int time) override;
+	void setPos(int x, int y) override;
+
+	double calcSmth(int y);
+
+
+public:
 	int _field7C;
 	int _surfW;
 	int _surfH;
@@ -43,6 +55,8 @@ protected:
 	int _imageId;
 	double _field98;
 	// walkObj
+	int _destX;
+	int _destY;
 	bool _isWalking;
 	bool _isPetka;
 	QReaction *_heroReaction;
diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index f9b00044b6..1c07dc63dc 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -57,7 +57,7 @@ QMessageObject::QMessageObject() {
 	_isShown = true;
 	_isActive = true;
 	_updateZ = 0;
-	_field_38 = 0;
+	_msgProcessingPaused = 0;
 	_notLoopedSound = true;
 	_startSound = false;
 	_hasSound = false;
@@ -89,12 +89,13 @@ void processSavedReaction(QReaction **reaction, QMessageObject *sender) {
 			}
 			break;
 		}
-		/*
 		case kWalk:
 		case kWalkTo:
+			g_vm->getQSystem()->_petka->setReactionAfterWalk(i, &r, sender, 1);
+			break;
 		case kWalkVich:
+			g_vm->getQSystem()->_chapayev->setReactionAfterWalk(i, &r, sender, 1);
 			break;
-		 */
 		default:
 			processed = false;
 			break;
@@ -113,10 +114,10 @@ void processSavedReaction(QReaction **reaction, QMessageObject *sender) {
 void QMessageObject::processMessage(const QMessage &msg) {
 	bool reacted = false;
 	for (uint i = 0; i < _reactions.size(); ++i) {
-		QReaction &r = _reactions[i];
-		if (r.opcode != msg.opcode ||
-			(r.status != -1 && r.status != _status) ||
-			(r.senderId != -1 && r.senderId != msg.sender->_id)) {
+		QReaction *r = &_reactions[i];
+		if (r->opcode != msg.opcode ||
+			(r->status != -1 && r->status != _status) ||
+			(r->senderId != -1 && r->senderId != msg.sender->_id)) {
 			continue;
 		}
 		bool res;
@@ -124,8 +125,8 @@ void QMessageObject::processMessage(const QMessage &msg) {
 			g_vm->getBigDialogue()->setDialog(_id, msg.opcode, -1);
 			g_vm->getQSystem()->_mainInterface->_dialog._sender = this;
 		}
-		for (uint j = 0; j < r.messages.size(); ++j) {
-			QMessage &rMsg = r.messages[j];
+		for (uint j = 0; j < r->messages.size(); ++j) {
+			QMessage &rMsg = r->messages[j];
 			if (rMsg.opcode == kCheck && g_vm->getQSystem()->findObject(rMsg.objId)->_status != rMsg.arg1) {
 				break;
 			}
@@ -145,8 +146,8 @@ void QMessageObject::processMessage(const QMessage &msg) {
 			case kDialog:
 				delete g_dialogReaction;
 				g_dialogReaction = new QReaction();
-				for (uint z = j + 1; z < r.messages.size(); ++z) {
-					g_dialogReaction->messages.push_back(r.messages[z]);
+				for (uint z = j + 1; z < r->messages.size(); ++z) {
+					g_dialogReaction->messages.push_back(r->messages[z]);
 				}
 				break;
 			case kPlay: {
@@ -154,17 +155,19 @@ void QMessageObject::processMessage(const QMessage &msg) {
 				delete obj->_reaction;
 				obj->_reaction = new QReaction();
 				obj->_reactionResId = rMsg.arg1;
-				for (uint z = j + 1; z < r.messages.size(); ++z) {
-					obj->_reaction->messages.push_back(r.messages[z]);
+				for (uint z = j + 1; z < r->messages.size(); ++z) {
+					obj->_reaction->messages.push_back(r->messages[z]);
 				}
 				break;
 			}
-			/*
+
 			case kWalk:
 			case kWalkTo:
+				g_vm->getQSystem()->_petka->setReactionAfterWalk(j, &r, this, 0);
+				break;
 			case kWalkVich:
+				g_vm->getQSystem()->_chapayev->setReactionAfterWalk(j, &r, this, 0);
 				break;
-			 */
 			default:
 				processed = false;
 			}
@@ -291,6 +294,44 @@ void QMessageObject::processMessage(const QMessage &msg) {
 		case kJumpVich:
 			g_vm->getQSystem()->_petka->setPos((msg.arg1 == -1 ? _walkX : msg.arg1), (msg.arg2 == -1 ? _walkY : msg.arg2));
 			break;
+		case kWalk:
+			if (!reacted) {
+				if (_walkX == -1) {
+					g_vm->getQSystem()->_petka->walk(msg.arg1, msg.arg2);
+
+				} else {
+					g_vm->getQSystem()->_petka->walk(_walkX, _walkY);
+				}
+			}
+			break;
+		case kWalkTo: {
+			int destX = msg.arg1;
+			int destY = msg.arg2;
+			if (destX == -1 || destY  == -1) {
+				destX = _walkX;
+				destY = _walkY;
+			}
+			if (destX != -1) {
+				g_vm->getQSystem()->_petka->walk(destX, destY);
+				QReaction *r = g_vm->getQSystem()->_petka->_heroReaction;
+				if (r) {
+					for (uint i = 0; i < r->messages.size(); ++i) {
+						if (r->messages[i].opcode == kGoTo) {
+							g_vm->getQSystem()->_chapayev->walk(_walkX, _walkY);
+							break;
+						}
+					}
+				}
+			}
+			break;
+		}
+		case kWalkVich:
+			if (msg.arg1 == -1 || msg.arg2 == -1) {
+				g_vm->getQSystem()->_chapayev->walk(msg.arg1, msg.arg2);
+			} else if (_walkX != -1) {
+				g_vm->getQSystem()->_chapayev->walk(_walkX, _walkY);
+			}
+			break;
 		}
 	} else {
 		g_vm->getBigDialogue()->setDialog(_id, msg.opcode, -1);
@@ -335,10 +376,13 @@ bool QObject::isInPoint(int x, int y) {
 	if (!_isActive)
 		return false;
 	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
-	Common::Rect rect(_x, _y, _x + flc->getWidth(), _y + flc->getHeight());
-	if (!rect.contains(x, y))
-		return false;
-	return *(byte *) flc->getCurrentFrame()->getBasePtr(x - _x, y - _y) != 0;
+	if (flc) {
+		Common::Rect rect(_x, _y, _x + flc->getWidth(), _y + flc->getHeight());
+		if (!rect.contains(x, y))
+			return false;
+		return *(byte *) flc->getCurrentFrame()->getBasePtr(x - _x, y - _y) != 0;
+	}
+	return false;
 }
 
 void QObject::draw() {
diff --git a/engines/petka/objects/object.h b/engines/petka/objects/object.h
index c3e6593683..601da04179 100644
--- a/engines/petka/objects/object.h
+++ b/engines/petka/objects/object.h
@@ -69,7 +69,7 @@ public:
 	int32 _isShown;
 	int32 _animate;
 	int _updateZ;
-	int _field_38;
+	int _msgProcessingPaused;
 	int _isActive;
 	int _startSound;
 	int _hasSound;
diff --git a/engines/petka/objects/object_bg.cpp b/engines/petka/objects/object_bg.cpp
index c915030800..188a06cfaf 100644
--- a/engines/petka/objects/object_bg.cpp
+++ b/engines/petka/objects/object_bg.cpp
@@ -35,6 +35,7 @@
 #include "petka/q_manager.h"
 #include "petka/interfaces/main.h"
 #include "petka/objects/object_bg.h"
+#include "petka/objects/heroes.h"
 
 namespace Petka {
 
@@ -59,10 +60,14 @@ void QObjectBG::processMessage(const QMessage &msg) {
 	case kNoMap:
 		_showMap = 0;
 		break;
-	case kGoTo:
+	case kGoTo: {
 		g_vm->getQSystem()->_mainInterface->loadRoom(_id, false);
 		g_vm->videoSystem()->makeAllDirty();
+		QMessageObject *obj = g_vm->getQSystem()->findObject(_id);
+		g_vm->getQSystem()->_petka->setPos(obj->_walkX, obj->_walkY);
+		g_vm->getQSystem()->_chapayev->setPos(obj->_walkX, obj->_walkY - 2);
 		break;
+	}
 	case kSetSeq:
 		break;
 	case kEndSeq:
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 885bda95b7..5dd5c3b4ad 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -133,6 +133,21 @@ bool QSystem::init() {
 	}
 	for (uint i = 0; i < bgsCount; ++i) {
 		readObject(_bgs[i], *stream, namesIni, castIni);
+
+
+		Common::String val;
+		bgsIni.getKey(_bgs[i]._name, "Settings", val);
+
+		if (!val.empty()) {
+			UnkStruct unk;
+
+			sscanf(val.c_str(), "%lf %lf %d %d %lf", &unk.f1, &unk.f2, &unk.f3, &unk.f4, &unk.f5);
+
+			_unkMap.setVal(_bgs[i]._name, unk);
+		}
+
+
+
 		_allObjects.push_back(&_bgs[i]);
 	}
 
@@ -255,7 +270,7 @@ void QSystem::load(Common::ReadStream *s) {
 	uint count = s->readUint32LE();
 	for (uint i = 0; i < count; ++i) {
 		QMessageObject *obj = findObject(readString(s));
-		obj->_field_38 = s->readUint32LE();
+		obj->_msgProcessingPaused = s->readUint32LE();
 		obj->_status = s->readUint32LE();
 		obj->_resourceId = s->readUint32LE();
 		obj->_z = s->readUint32LE();
@@ -295,7 +310,7 @@ void QSystem::save(Common::WriteStream *s) {
 	s->writeUint32LE(_allObjects.size());
 	for (uint i = 0; i < _allObjects.size(); ++i) {
 		writeString(s, _allObjects[i]->_name);
-		s->writeUint32LE(_allObjects[i]->_field_38);
+		s->writeUint32LE(_allObjects[i]->_msgProcessingPaused);
 		s->writeUint32LE(_allObjects[i]->_status);
 		s->writeUint32LE(_allObjects[i]->_resourceId);
 		s->writeUint32LE(_allObjects[i]->_z);
diff --git a/engines/petka/q_system.h b/engines/petka/q_system.h
index 9d3e42eef7..1ad1b47e39 100644
--- a/engines/petka/q_system.h
+++ b/engines/petka/q_system.h
@@ -26,6 +26,8 @@
 #include "common/ptr.h"
 #include "common/stream.h"
 #include "common/list.h"
+#include "common/hashmap.h"
+#include "common/hash-str.h"
 
 #include "petka/objects/object_bg.h"
 
@@ -44,6 +46,14 @@ class InterfacePanel;
 class InterfaceMap;
 class Interface;
 
+struct UnkStruct {
+	double f1;
+	double f2;
+	int f3;
+	int f4;
+	double f5;
+};
+
 class QSystem {
 public:
 	explicit QSystem();
@@ -85,6 +95,8 @@ public:
 	Interface *_currInterface;
 	Interface *_prevInterface;
 
+	Common::HashMap<Common::String, UnkStruct> _unkMap;
+
 	int _isIniting;
 	int _fxId;
 	int _musicId;


Commit: 139bb33f3205c860d89309c4842a98316c4a90a0
    https://github.com/scummvm/scummvm/commit/139bb33f3205c860d89309c4842a98316c4a90a0
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed compilation

Changed paths:
    engines/petka/base.h
    engines/petka/big_dialogue.cpp
    engines/petka/flc.h
    engines/petka/interfaces/dialog_interface.cpp
    engines/petka/interfaces/panel.cpp
    engines/petka/interfaces/save_load.cpp
    engines/petka/interfaces/startup.cpp
    engines/petka/objects/heroes.cpp
    engines/petka/objects/object_case.cpp
    engines/petka/objects/object_star.cpp
    engines/petka/q_system.cpp


diff --git a/engines/petka/base.h b/engines/petka/base.h
index 92de6c076e..83fb105562 100644
--- a/engines/petka/base.h
+++ b/engines/petka/base.h
@@ -97,6 +97,17 @@ enum Opcode {
 class QMessageObject;
 
 struct QMessage {
+	QMessage() {}
+	QMessage(uint16 objId, uint16 opcode, uint16 arg1, int16 arg2, int16 arg3, QMessageObject *sender, int unk) {
+		this->objId = objId;
+		this->opcode = opcode;
+		this->arg1 = arg1;
+		this->arg2 = arg2;
+		this->arg3 = arg3;
+		this->sender = sender;
+		this->unk = unk;
+	}
+
 	uint16 objId;
 	uint16 opcode;
 	uint16 arg1;
diff --git a/engines/petka/big_dialogue.cpp b/engines/petka/big_dialogue.cpp
index fc5dcee3da..1335e491db 100644
--- a/engines/petka/big_dialogue.cpp
+++ b/engines/petka/big_dialogue.cpp
@@ -95,7 +95,7 @@ void BigDialogue::loadSpeechesInfo() {
 	char *curr = str;
 	file->read(str, file->size() - file->pos());
 	for (uint i = 0; i < _speeches.size(); ++i) {
-		_speeches[i].text = Common::convertToU32String(curr, Common::CodePage::kWindows1251);
+		_speeches[i].text = Common::convertToU32String(curr, Common::kWindows1251);
 		curr += strlen(curr) + 1;
 	}
 	delete[] str;
diff --git a/engines/petka/flc.h b/engines/petka/flc.h
index a5f6939af7..17b88c6492 100644
--- a/engines/petka/flc.h
+++ b/engines/petka/flc.h
@@ -53,7 +53,7 @@ protected:
 
 	private:
 		Common::Rect _bounds;
-		Common::Array<Common::Array<Common::Rect>> _msk;
+		Common::Array<Common::Array<Common::Rect> > _msk;
 	};
 };
 
diff --git a/engines/petka/interfaces/dialog_interface.cpp b/engines/petka/interfaces/dialog_interface.cpp
index d53992c0c6..4057b23a83 100644
--- a/engines/petka/interfaces/dialog_interface.cpp
+++ b/engines/petka/interfaces/dialog_interface.cpp
@@ -110,7 +110,7 @@ void DialogInterface::sub_4155D0(int a) {
 		if (talkerId != talkerId2) {
 			sendMsg(kSay);
 		}
-		g_vm->getQSystem()->_mainInterface->setText(info->text, _talker->_dialogColor);
+		//g_vm->getQSystem()->_mainInterface->setText(info->text, _talker->_dialogColor);
 		_field18 = 1;
 		break;
 	}
@@ -129,15 +129,7 @@ void DialogInterface::sub_4155D0(int a) {
 
 void DialogInterface::sendMsg(uint16 opcode) {
 	if (_talker) {
-		QMessage msg;
-		msg.objId = _talker->_id;
-		msg.opcode = opcode;
-		msg.arg1 = 0;
-		msg.arg2 = 0;
-		msg.arg3 = 0;
-		msg.unk = 0;
-		msg.sender = nullptr;
-		_talker->processMessage(msg);
+		_talker->processMessage(QMessage(_talker->_id, opcode, 0, 0, 0, nullptr, 0));
 	}
 }
 
diff --git a/engines/petka/interfaces/panel.cpp b/engines/petka/interfaces/panel.cpp
index ba5a7e9bce..681ed979d1 100644
--- a/engines/petka/interfaces/panel.cpp
+++ b/engines/petka/interfaces/panel.cpp
@@ -40,12 +40,12 @@ namespace Petka {
 
 // ПАНЕЛЬ УПРАВЛЕНИЯ
 const char *const kPanelObjName = "\xCF\xC0\xCD\xC5\xCB\xDC\x20\xD3\xCF\xD0\xC0\xC2\xCB\xC5\xCD\xC8\xDF";
-const Common::Point kObjectsPoints[] = {{0, 2}, {5, 70}, {5, 136}, {22, 328},
-									   {87, 224}, {118, 395}, {467, 71}, {432, 144},
-									   {428, 29}, {434, 170}, {297, 214}, {470, 139},
-									   {318, 87}, {468, 172}, {262, 31}, {231, 137},
-									   {0, 0}, {0, 0}, {0, 0}, {0, 0},
-									   {0, 0}, {0, 0}, {0, 0}, {0, 0}};
+const Common::Point kObjectsPoints[] = {Common::Point(0, 2), Common::Point(5, 70), Common::Point(5, 136), Common::Point(22, 328),
+										Common::Point(87, 224), Common::Point(118, 395), Common::Point(467, 71), Common::Point(432, 144),
+										Common::Point(428, 29), Common::Point(434, 170), Common::Point(297, 214), Common::Point(470, 139),
+										Common::Point(318, 87), Common::Point(468, 172), Common::Point(262, 31), Common::Point(231, 137),
+										Common::Point(0, 0), Common::Point(0, 0), Common::Point(0, 0), Common::Point(0, 0),
+										Common::Point(0, 0), Common::Point(0, 0), Common::Point(0, 0), Common::Point(0, 0)};
 
 const uint kNewGameButtonIndex = 1;
 const uint kLoadButtonIndex = 2;
diff --git a/engines/petka/interfaces/save_load.cpp b/engines/petka/interfaces/save_load.cpp
index 674c5c35e1..810148c79d 100644
--- a/engines/petka/interfaces/save_load.cpp
+++ b/engines/petka/interfaces/save_load.cpp
@@ -30,9 +30,9 @@
 namespace Petka {
 
 const uint kFirstSaveLoadPageId = 4990;
-const Common::Rect kSavesRects[] = {{43, 84, 151, 166}, {43, 209, 151, 291},
-									{43, 335, 151, 417}, {358, 75, 466, 157},
-									{360, 200, 468, 282}, {359, 325, 467, 407}};
+const Common::Rect kSavesRects[] = {Common::Rect(43, 84, 151, 166), Common::Rect(43, 209, 151, 291),
+									Common::Rect(43, 335, 151, 417), Common::Rect(358, 75, 466, 157),
+									Common::Rect(360, 200, 468, 282), Common::Rect(359, 325, 467, 407)};
 const Common::Rect kNextPageRect(596, 403, 624, 431);
 const Common::Rect kPrevPageRect(10, 414, 38, 442);
 
diff --git a/engines/petka/interfaces/startup.cpp b/engines/petka/interfaces/startup.cpp
index 66898972eb..d8b879929c 100644
--- a/engines/petka/interfaces/startup.cpp
+++ b/engines/petka/interfaces/startup.cpp
@@ -56,7 +56,7 @@ void InterfaceStartup::start() {
 	QObjectBG *bg = (QObjectBG *)g_vm->getQSystem()->findObject(kStartupObjName);
 	_objs.push_back(bg);
 
-	Sound *s = g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(bg->_musicId), Audio::Mixer::SoundType::kMusicSoundType);
+	Sound *s = g_vm->soundMgr()->addSound(g_vm->resMgr()->findSoundName(bg->_musicId), Audio::Mixer::kMusicSoundType);
 	s->play(true);
 
 	const Common::Array<BGInfo> &infos = g_vm->getQSystem()->_mainInterface->_bgs;
diff --git a/engines/petka/objects/heroes.cpp b/engines/petka/objects/heroes.cpp
index 251f1dc97f..5e88328c61 100644
--- a/engines/petka/objects/heroes.cpp
+++ b/engines/petka/objects/heroes.cpp
@@ -192,7 +192,7 @@ void QObjectPetka::updateWalk() {
 		_isWalking = false;
 		setPos(_destX, _destY);
 
-		QMessage msg {_id, kSet, (uint16)_imageId, 1, 0, nullptr, 0};
+		QMessage msg(_id, kSet, (uint16)_imageId, 1, 0, nullptr, 0);
 		if (_heroReaction) {
 			uint i;
 			for (i = 0; i < _heroReaction->messages.size(); ++i) {
@@ -204,10 +204,10 @@ void QObjectPetka::updateWalk() {
 
 					initSurface();
 
-					processMessage(QMessage {_id, kAnimate, 0, 0, 0, nullptr, 0});
+					processMessage(QMessage(_id, kAnimate, 0, 0, 0, nullptr, 0));
 
 					_heroReaction->messages.push_back(msg);
-					_heroReaction->messages.push_back(QMessage {_id, kAnimate, 1, 0, 0, nullptr, 0});
+					_heroReaction->messages.push_back(QMessage(_id, kAnimate, 1, 0, 0, nullptr, 0));
 					break;
 				}
 			}
@@ -227,7 +227,7 @@ void QObjectPetka::setReactionAfterWalk(uint index, QReaction **reaction, QMessa
 
 	stopWalk();
 
-	QMessage msg {_id, kWalked, 0, 0, 0, sender, 0};
+	QMessage msg(_id, kWalked, 0, 0, 0, sender, 0);
 	_heroReaction = new QReaction();
 	_sender = sender;
 
@@ -252,7 +252,7 @@ void QObjectPetka::stopWalk() {
 	_isWalking = false;
 	_msgProcessingPaused = false;
 
-	Common::List<QMessage> &list =   g_vm->getQSystem()->_messages;
+	Common::List<QMessage> &list = g_vm->getQSystem()->_messages;
 	for (Common::List<QMessage>::iterator it = list.begin(); it != list.end();) {
 		if (it->opcode == kWalked && it->objId == _id) {
 			it->objId = -1;
@@ -264,7 +264,7 @@ void QObjectPetka::stopWalk() {
 	_heroReaction = nullptr;
 
 	if (!_field7C) {
-		QMessage msg {_id, kSet, (uint16)_imageId, 1, 0, nullptr, 0};
+		QMessage msg(_id, kSet, (uint16)_imageId, 1, 0, nullptr, 0);
 		processMessage(msg);
 	}
 }
diff --git a/engines/petka/objects/object_case.cpp b/engines/petka/objects/object_case.cpp
index 8d3638f082..8741787f0a 100644
--- a/engines/petka/objects/object_case.cpp
+++ b/engines/petka/objects/object_case.cpp
@@ -34,8 +34,8 @@ namespace Petka {
 // Полоска в чемодане
 const char *const kPoloska = "\xCF\xEE\xEB\xEE\xF1\xEA\xE0\x20\xE2\x20\xF7\xE5\xEC\xEE\xE4\xE0\xED\xE5";
 
-const Common::Point itemsLocation[] = {{120, 145}, {240, 145}, {360, 145},
-									   {100, 220}, {240, 220}, {380, 220}};
+const Common::Point itemsLocation[] = {Common::Point(120, 145), Common::Point(240, 145), Common::Point(360, 145),
+									   Common::Point(100, 220), Common::Point(240, 220), Common::Point(380, 220)};
 
 QObjectCase::QObjectCase() {
 	_itemIndex = 0;
diff --git a/engines/petka/objects/object_star.cpp b/engines/petka/objects/object_star.cpp
index c6e0f19b03..16d714b87b 100644
--- a/engines/petka/objects/object_star.cpp
+++ b/engines/petka/objects/object_star.cpp
@@ -35,12 +35,12 @@ namespace Petka {
 
 const uint kFirstCursorId = 5001;
 const uint kCaseButtonIndex = 0;
-const Common::Rect kButtonsRects[] = {{70, 74, 112, 112},
-									  {68, 0, 114, 41},
-									  {151, 51, 180, 97},
-									  {138, 125, 179, 166},
-									  {55, 145, 96, 175},
-									  {11, 79, 40, 118}};
+const Common::Rect kButtonsRects[] = {Common::Rect(70, 74, 112, 112),
+									  Common::Rect(68, 0, 114, 41),
+									  Common::Rect(151, 51, 180, 97),
+									  Common::Rect(138, 125, 179, 166),
+									  Common::Rect(55, 145, 96, 175),
+									  Common::Rect(11, 79, 40, 118)};
 
 static uint findButtonIndex(int16 x, int16 y) {
 	uint i = 0;
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 5dd5c3b4ad..b7233b15ed 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -86,7 +86,7 @@ static void readObject(QMessageObject &obj, Common::SeekableReadStream &stream,
 	if (castIni.getKey(obj._name, "all", rgbString)) {
 		int r, g, b;
 		sscanf(rgbString.c_str(), "%d %d %d", &r, &g, &b);
-		obj._dialogColor = Graphics::RGBToColor<Graphics::ColorMasks<888>>((byte)r, (byte)g, (byte)b);
+		obj._dialogColor = Graphics::RGBToColor<Graphics::ColorMasks<888> >((byte)r, (byte)g, (byte)b);
 	}
 }
 
@@ -181,12 +181,12 @@ void QSystem::addMessage(const QMessage &msg) {
 }
 
 void QSystem::addMessage(uint16 objId, uint16 opcode, int16 arg1, int16 arg2, int16 arg3, int32 unk, QMessageObject *sender) {
-	_messages.push_back({objId, opcode, arg1, arg2, arg3, sender, unk});
+	_messages.push_back(QMessage(objId, opcode, arg1, arg2, arg3, sender, unk));
 }
 
 void QSystem::addMessageForAllObjects(uint16 opcode, int16 arg1, int16 arg2, int16 arg3, int32 unk, QMessageObject *sender) {
 	for (uint i = 0; i < _allObjects.size(); ++i) {
-		_messages.push_back({_allObjects[i]->_id, opcode, arg1, arg2, arg3, sender, unk});
+		_messages.push_back(QMessage(_allObjects[i]->_id, opcode, arg1, arg2, arg3, sender, unk));
 	}
 }
 


Commit: 4fcb585065350f4d036a341076c67f4e4157ec7f
    https://github.com/scummvm/scummvm/commit/4fcb585065350f4d036a341076c67f4e4157ec7f
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed compilation on newer revision of ScummVM

Changed paths:
    engines/petka/detection.cpp


diff --git a/engines/petka/detection.cpp b/engines/petka/detection.cpp
index 9b9b651144..d5e794d235 100644
--- a/engines/petka/detection.cpp
+++ b/engines/petka/detection.cpp
@@ -43,6 +43,10 @@ public:
 		_maxScanDepth = 2;
 	}
 
+	const char *getEngineId() const override {
+		return "petka";
+	}
+
 	virtual const char *getName() const {
 		return "Red Comrades";
 	}


Commit: 8e7ffaa0be234558dd05fb3b30f83008b7399037
    https://github.com/scummvm/scummvm/commit/8e7ffaa0be234558dd05fb3b30f83008b7399037
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: enabled reading of russian ini files

Changed paths:
    engines/petka/interfaces/main.cpp
    engines/petka/q_system.cpp


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index 83f1d031b5..a72d7feb5b 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -75,6 +75,7 @@ void InterfaceMain::start() {
 
 	Common::ScopedPtr<Common::SeekableReadStream> bgsStream(g_vm->openFile("BGs.ini", false));
 	Common::INIFile bgsIni;
+	bgsIni.allowNonEnglishCharacters();
 	bgsIni.loadFromStream(*bgsStream);
 	Common::String startRoom;
 	bgsIni.getKey("StartRoom", "Settings", startRoom);
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index b7233b15ed..1377cb3578 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -104,10 +104,13 @@ bool QSystem::init() {
 	Common::INIFile castIni;
 	Common::INIFile bgsIni;
 
-	/*
+	namesIni.allowNonEnglishCharacters();
+	castIni.allowNonEnglishCharacters();
+	bgsIni.allowNonEnglishCharacters();
+
+
 	if (namesStream)
 		namesIni.loadFromStream(*namesStream); //fails because ini is broken for Russian letters
-	*/
 	if (castStream)
 		castIni.loadFromStream(*castStream);
 	if (bgsStream)


Commit: 91cfe96da1d687364123994c13332990b58326e4
    https://github.com/scummvm/scummvm/commit/91cfe96da1d687364123994c13332990b58326e4
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: Add 16bit to configure.engine

Co-authored-by: Cameron Cawley <ccawley2011 at gmail.com>

Changed paths:
    engines/petka/configure.engine


diff --git a/engines/petka/configure.engine b/engines/petka/configure.engine
index d9811acc47..7a127bf14e 100644
--- a/engines/petka/configure.engine
+++ b/engines/petka/configure.engine
@@ -1,3 +1,3 @@
 # This file is included from the main "configure" script
 # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine petka "Red Comrades" no "" "" "highres"
+add_engine petka "Red Comrades" no "" "" "highres 16bit"


Commit: e0d0aa1e84114e52f8190718a9cdc8b615078da0
    https://github.com/scummvm/scummvm/commit/e0d0aa1e84114e52f8190718a9cdc8b615078da0
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: removed goto

Changed paths:
    engines/petka/big_dialogue.cpp


diff --git a/engines/petka/big_dialogue.cpp b/engines/petka/big_dialogue.cpp
index 1335e491db..ae6ab36f3f 100644
--- a/engines/petka/big_dialogue.cpp
+++ b/engines/petka/big_dialogue.cpp
@@ -247,7 +247,6 @@ void BigDialogue::sub40B670(int arg) {
 		return;
 	int unk = 1;
 	int unk2;
-label:
 	unk2 = arg;
 	if (arg != -1 && (*_ip >> 24) != 2) {
 		arg = -1;
@@ -333,8 +332,7 @@ label:
 				--_ip;
 				op = (*_ip >> 24);
 			} while (op != 2);
-			unk = 1;
-			goto label;
+			sub40B670(arg);
 		default:
 			_ip += 1;
 			unk = 0;


Commit: 6b93465bc45b979b7a3ee144e56c69bdcdf3c865
    https://github.com/scummvm/scummvm/commit/6b93465bc45b979b7a3ee144e56c69bdcdf3c865
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: reworked dialogs handling

Changed paths:
    engines/petka/big_dialogue.cpp
    engines/petka/big_dialogue.h
    engines/petka/interfaces/dialog_interface.cpp
    engines/petka/objects/object.cpp


diff --git a/engines/petka/big_dialogue.cpp b/engines/petka/big_dialogue.cpp
index ae6ab36f3f..2a4e32e580 100644
--- a/engines/petka/big_dialogue.cpp
+++ b/engines/petka/big_dialogue.cpp
@@ -34,10 +34,8 @@
 namespace Petka {
 
 BigDialogue::BigDialogue() {
-	_ip = nullptr;
-	_code = nullptr;
-	_codeSize = 0;
-	_startCodeIndex = 0;
+	_currOp = nullptr;
+	_startOpIndex = 0;
 
 	Common::ScopedPtr<Common::SeekableReadStream> file(g_vm->openFile("dialogue.fix", true));
 	if (!file)
@@ -46,34 +44,26 @@ BigDialogue::BigDialogue() {
 	_objDialogs.resize(file->readUint32LE());
 	for (uint i = 0; i < _objDialogs.size(); ++i) {
 		_objDialogs[i].objId = file->readUint32LE();
-		_objDialogs[i].dialogs.resize(file->readUint32LE());
+		_objDialogs[i].handlers.resize(file->readUint32LE());
 		file->skip(4); // pointer
 	}
 	for (uint i = 0; i < _objDialogs.size(); ++i) {
-		for (uint j = 0; j < _objDialogs[i].dialogs.size(); ++j) {
-			_objDialogs[i].dialogs[j].opcode = file->readUint16LE();
-			_objDialogs[i].dialogs[j].objId = file->readUint16LE();
-			_objDialogs[i].dialogs[j].handlers.resize(file->readUint32LE());
-			_objDialogs[i].dialogs[j].startHandlerIndex = file->readUint32LE();
+		for (uint j = 0; j < _objDialogs[i].handlers.size(); ++j) {
+			_objDialogs[i].handlers[j].opcode = file->readUint16LE();
+			_objDialogs[i].handlers[j].objId = file->readUint16LE();
+			_objDialogs[i].handlers[j].dialogs.resize(file->readUint32LE());
+			_objDialogs[i].handlers[j].startDialogIndex = file->readUint32LE();
 			file->skip(4); // pointer
 		}
-		for (uint j = 0; j < _objDialogs[i].dialogs.size(); ++j) {
-			for (uint z = 0; z < _objDialogs[i].dialogs[j].handlers.size(); ++z) {
-				_objDialogs[i].dialogs[j].handlers[z].startOpIndex = file->readUint32LE();
-				_objDialogs[i].dialogs[j].handlers[z].opsCount = file->readUint32LE();
-				file->skip(4); // pointer
-			}
-		}
-		for (uint j = 0; j < _objDialogs[i].dialogs.size(); ++j) {
-			for (uint z = 0; z < _objDialogs[i].dialogs[j].handlers.size(); ++z) {
-				file->skip(_objDialogs[i].dialogs[j].handlers[z].opsCount * 4); // operations
+		for (uint j = 0; j < _objDialogs[i].handlers.size(); ++j) {
+			for (uint z = 0; z < _objDialogs[i].handlers[j].dialogs.size(); ++z) {
+				_objDialogs[i].handlers[j].dialogs[z].startOpIndex = file->readUint32LE();
+				file->skip(4 + 4); // opsCount + pointer
 			}
 		}
 	}
 
-	_codeSize = file->readUint32LE();
-	_code = new int[_codeSize];
-	file->read(_code, _codeSize * 4);
+	load(file.get());
 }
 
 void BigDialogue::loadSpeechesInfo() {
@@ -101,81 +91,80 @@ void BigDialogue::loadSpeechesInfo() {
 	delete[] str;
 }
 
-const Common::U32String *BigDialogue::getSpeechInfo(int *talkerId, const char **soundName, int unk) {
-	if (!_ip)
+const Common::U32String *BigDialogue::getSpeechInfo(int *talkerId, const char **soundName, int choice) {
+	if (!_currOp)
 		return nullptr;
-	int *oldIp = _ip;
-	int op = *_ip;
-	byte opcode = (byte)(*_ip >> 24);
-	switch (opcode) {
-	case 2: {
-		int unk1 = 1;
-		byte arg = (byte)*_ip;
-		if (arg <= unk || unk >= 0) {
+	switch (_currOp->type) {
+	case kOperationMenu: {
+		Operation *oldOp = _currOp;
+		uint bit = 1;
+		if (_currOp->menu.bits <= choice || choice < 0) {
 			break;
 		}
 		while (true) {
-			_ip += 1;
-			if (unk == 0 && (unk1 & ((op >> 8) & 0xFFFF)))
+			_currOp += 1;
+			if (choice == 0 && (bit & _currOp->menu.bitField))
 				break;
-			if ((*_ip >> 24) == 0x1) {
-				if (unk1 & ((op >> 8) & 0xFFFF))
-					unk--;
-				unk1 *= 2;
+			if (_currOp->type == kOperationBreak) {
+				if (bit & _currOp->menu.bitField)
+					choice--;
+				bit *= 2;
 			}
 		}
-		if ((*_ip >> 24) != 0x7)
-			sub40B670(-1);
-		if ((*_ip >> 24) != 0x7) {
-			_ip = oldIp;
+		if (_currOp->type != kOperationPlay)
+			next();
+		if (_currOp->type != kOperationPlay) {
+			_currOp = oldOp;
 			break;
 		}
-		uint index = (uint16)*_ip;
-		_ip = oldIp;
+
+		uint index = _currOp->play.messageIndex;
+		_currOp = oldOp;
 		*soundName = _speeches[index].soundName;
 		*talkerId = _speeches[index].speakerId;
 		return &_speeches[index].text;
 	}
-	case 8:
-		_ip += 1;
-		for (uint i = 0; i < ((*_ip >> 16) & 0xFF); ++i) {
-			while ((*_ip >> 24) != 0x01)
-				_ip += 1;
-			_ip += 1;
+	case kOperationCircle:
+		_currOp += 1;
+		for (uint i = 0; i < _currOp->circle.count; ++i) {
+			while (_currOp->type != kOperationBreak)
+				_currOp += 1;
+			_currOp += 1;
 		}
+		assert(_currOp->type == kOperationPlay);
 		// fall through
-	case 7:
-		*soundName = _speeches[(uint16)*_ip].soundName;
-		*talkerId = _speeches[(uint16)*_ip].speakerId;
-		return &_speeches[(uint16)*_ip].text;
+	case kOperationPlay:
+		*soundName = _speeches[_currOp->play.messageIndex].soundName;
+		*talkerId = _speeches[_currOp->play.messageIndex].speakerId;
+		return &_speeches[_currOp->play.messageIndex].text;
 	default:
 		break;
 	}
 	return nullptr;
 }
 
-const Dialog *BigDialogue::findDialog(uint objId, uint opcode, bool *res) const {
+const DialogHandler *BigDialogue::findHandler(uint objId, uint opcode, bool *res) const {
 	if (opcode == kEnd || opcode == kHalf) {
 		return nullptr;
 	}
 	if (res) {
-		*res = 0;
+		*res = false;
 	}
 	for (uint i = 0; i < _objDialogs.size(); ++i) {
 		if (_objDialogs[i].objId == objId) {
-			for (uint j = 0; j < _objDialogs[i].dialogs.size(); ++j) {
-				if (_objDialogs[i].dialogs[j].opcode == opcode) {
-					return &_objDialogs[i].dialogs[j];
+			for (uint j = 0; j < _objDialogs[i].handlers.size(); ++j) {
+				if (_objDialogs[i].handlers[j].opcode == opcode) {
+					return &_objDialogs[i].handlers[j];
 				}
 			}
 			if (opcode != kObjectUse) {
 				continue;
 			}
-			for (uint j = 0; j < _objDialogs[i].dialogs.size(); ++j) {
-				if (_objDialogs[i].dialogs[j].opcode == 0xFFFE) {
+			for (uint j = 0; j < _objDialogs[i].handlers.size(); ++j) {
+				if (_objDialogs[i].handlers[j].opcode == 0xFFFE) {
 					if (res)
-						*res = 1;
-					return &_objDialogs[i].dialogs[j];
+						*res = true;
+					return &_objDialogs[i].handlers[j];
 				}
 
 			}
@@ -184,172 +173,288 @@ const Dialog *BigDialogue::findDialog(uint objId, uint opcode, bool *res) const
 	for (uint i = 0; i < _objDialogs.size(); ++i) {
 		if (_objDialogs[i].objId != 0xFFFE)
 			continue;
-		for (uint j = 0; j < _objDialogs[i].dialogs.size(); ++j) {
-			if (_objDialogs[i].dialogs[j].opcode == opcode) {
+		for (uint j = 0; j < _objDialogs[i].handlers.size(); ++j) {
+			if (_objDialogs[i].handlers[j].opcode == opcode) {
 				if (res)
-					*res = 1;
-				return &_objDialogs[i].dialogs[j];
+					*res = true;
+				return &_objDialogs[i].handlers[j];
 			}
 		}
 	}
 	return nullptr;
 }
 
-void BigDialogue::setDialog(uint objId, uint opcode, int index) {
+void BigDialogue::setHandler(uint objId, uint opcode, int index) {
 	loadSpeechesInfo();
-	const Dialog *d = findDialog(objId, opcode, nullptr);
-	if (d) {
-		if (index < 0 || index >= d->handlers.size()) {
-			_ip = &_code[d->handlers[d->startHandlerIndex].startOpIndex];
-			_startCodeIndex = d->handlers[d->startHandlerIndex].startOpIndex;
-		} else {
-			_ip = &_code[d->handlers[index].startOpIndex];
-			_startCodeIndex = d->handlers[index].startOpIndex;
-		}
+	const DialogHandler *h = findHandler(objId, opcode, nullptr);
+	if (h) {
+		_startOpIndex = h->dialogs[h->startDialogIndex].startOpIndex;
+		_currOp = &_ops[_startOpIndex];
 	}
 }
 
 uint BigDialogue::opcode() {
-	while (_ip) {
-		byte op = (*_ip >> 24);
-		switch (op) {
-		case 2: {
-			int unk1 = 0;
-			int unk2 = 1;
-			for (uint i = 0; i < (*_ip & 0xFF); ++i) {
-				if (((*_ip >> 8) & 0xFFFF) & unk2) {
-					unk1++;
-				}
-				unk2 <<= 1;
-			}
-			if (unk1 > 1)
-				return 2;
-			sub40B670(0);
+	while (_currOp) {
+		switch (_currOp->type) {
+		case kOperationMenu:
+			if (choicesCount() > 1)
+				return kOpcodeMenu;
+			next(0);
+			break;
+		case kOperationReturn:
+			return kOpcodeEnd;
+		case kOperationPlay:
+		case kOperationCircle:
+			return kOpcodePlay;
+		case kOperation9:
+			return kOpcode4;
+		default:
+			next();
 			break;
 		}
-		case 6:
-			return 3;
-		case 7:
-		case 8:
-			return 1;
-		case 9:
-			return 4;
+	}
+	return kOpcodeEnd;
+}
+
+void BigDialogue::load(Common::ReadStream *s) {
+	uint32 opsCount = s->readUint32LE();
+	_ops.resize(opsCount);
+	for (uint i = 0; i < opsCount; ++i) {
+		uint op = s->readUint32LE();
+		_ops[i].type = (byte)(op >> 24);
+		switch (_ops[i].type) {
+		case kOperationBreak:
+			break;
+		case kOperationMenu:
+			_ops[i].menu.bits = (byte)op;
+			_ops[i].menu.bitField = (uint16)(op >> 8);
+			break;
+		case kOperationMenuRet:
+			_ops[i].menuRet.opIndex = (uint16)op;
+			_ops[i].menuRet.bit = (byte)(op >> 16);
+			break;
+		case kOperation5:
+			_ops[i].op5.opIndex = (uint16)op;
+			_ops[i].op5.bit = (byte)(op >> 16);
+			break;
+		case kOperationReturn:
+			break;
+		case kOperationPlay:
+			_ops[i].play.messageIndex = (uint16)op;
+			break;
+		case kOperationCircle:
+			_ops[i].circle.count = (uint16)op;
+			_ops[i].circle.curr = (byte)(op >> 16);
+			break;
+		case kOperation9:
+			_ops[i].op9.arg = (uint16)op;
+			break;
 		default:
-			sub40B670(-1);
 			break;
 		}
 	}
-	return 3;
 }
 
-void BigDialogue::sub40B670(int arg) {
-	if (!_ip)
+void BigDialogue::save(Common::WriteStream *s) {
+	s->writeUint32LE(_ops.size());
+	for (uint i = 0; i < _ops.size(); ++i) {
+		switch (_ops[i].type) {
+		case kOperationBreak:
+			s->writeUint32LE(MKTAG(0, 0, 0, kOperationBreak));
+			break;
+		case kOperationMenu:
+			s->writeByte(_ops[i].menu.bits);
+			s->writeUint16LE(_ops[i].menu.bitField);
+			s->writeByte(kOperationMenu);
+			break;
+		case kOperationMenuRet:
+			s->writeUint16LE(_ops[i].menuRet.opIndex);
+			s->writeUint16LE(MKTAG16(_ops[i].menuRet.bit, kOperationMenuRet));
+			break;
+		case kOperation5:
+			s->writeUint16LE(_ops[i].op5.opIndex);
+			s->writeUint16LE(MKTAG16(_ops[i].op5.bit, kOperation5));
+			break;
+		case kOperationReturn:
+			s->writeUint32LE(MKTAG(0, 0, 0, kOperationReturn));
+			break;
+		case kOperationPlay:
+			s->writeUint16LE(_ops[i].play.messageIndex);
+			s->writeUint16LE(MKTAG16(0, kOperationPlay));
+			break;
+		case kOperationCircle:
+			s->writeUint16LE(_ops[i].circle.count);
+			s->writeUint16LE(MKTAG16(_ops[i].circle.curr, kOperationPlay));
+			break;
+		case kOperation9:
+			s->writeUint16LE(_ops[i].op9.arg);
+			s->writeUint16LE(MKTAG16(0, kOperation9));
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+void BigDialogue::next(int choice) {
+	bool processed = true;
+
+	if (!_currOp)
 		return;
-	int unk = 1;
-	int unk2;
-	unk2 = arg;
-	if (arg != -1 && (*_ip >> 24) != 2) {
-		arg = -1;
+	if (choice != -1 && _currOp->type != kOperationMenu) {
+		choice = -1;
 	}
+
 	while (true) {
-		byte op = (*_ip >> 24);
-		switch (op) {
-		case 2: {
-			if (!unk)
-				return;
-			if (unk2 < 0) {
-				arg = 0;
-				unk2 = 0;
+		switch (_currOp->type) {
+		case kOperationBreak:
+			while (_currOp->type != kOperationMenu && _currOp->type != kOperationCircle) {
+				_currOp--;
 			}
-			int n = (byte)*_ip;
-			if (n <= unk2)
-				arg = (byte) *_ip - 1;
-			int a1 = 0;
-			int a2 = 1;
-			int a3 = (*_ip >> 8) & 0xFFFF;
-			for (int i = 0; i < n;) {
-				if ((*_ip >> 24) == 10) {
-					++i;
-					if ((a3 & a2) && a1 <= arg)
-						arg++;
-					a2 *= 2;
-					a1++;
+			next(choice);
+			return;
+		case kOperationMenu: {
+			if (!processed)
+				return;
+			if (choice == -1)
+				choice = 0;
+			if (_currOp->menu.bits <= choice)
+				choice = _currOp->menu.bits - 1;
+			uint bits = _currOp->menu.bits;
+			uint bit = 1;
+			uint i = 0;
+			while (bits) {
+				if (_currOp->type == kOperationBreak) {
+					bits--;
+					if (!(bit & _currOp->menu.bitField) && i <= (uint)choice)
+						choice++;
+					bit *= 2;
+					i++;
 				}
-				_ip += 1;
+				_currOp += 1;
 			}
-			_ip += arg;
-			unk2 = arg;
-			unk = 0;
+			_currOp += choice;
 			break;
 		}
-		case 3:
-			_ip = &_code[*_ip & 0xFFFF];
+		case kOperationGoTo: {
+			_currOp = &_ops[_currOp->goTo.opIndex];
+			processed = false;
 			break;
-		case 4:
+		}
+		case kOperationMenuRet:
+			_ops[_currOp->menuRet.opIndex].menu.bitField &= ~(1 << _currOp->op5.bit); // disable menu item
+			checkMenu(_currOp->menuRet.opIndex);
+			_currOp += 1;
+			processed = false;
 			break;
-		case 5: {
-			_code[(*_ip >> 16)] |= (((1 << *(_ip) >> 24) & 0xFFFF) << 8);
-			_ip += 1;
-			unk = 0;
+		case kOperation5:
+			_ops[_currOp->op5.opIndex].menu.bitField |= (1 << _currOp->op5.bit); // enable menu item ???
+			_currOp += 1;
+			processed = false;
 			break;
-		}
-		case 6:
+		case kOperationReturn:
 			return;
-		case 7:
-			if (!unk)
+		case kOperationPlay:
+			if (!processed)
 				return;
-			_ip += 1;
-			unk = 0;
+			_currOp += 1;
+			processed = false;
 			break;
-		case 8: {
-			if (!unk)
+		case kOperationCircle:
+			if (!processed)
 				return;
-			*_ip = (*_ip & 0xFF00FFFF) | ((byte)(((byte)(*_ip >> 16) + 1) % (int16)*_ip) << 16);
-			int n = *_ip & 0xFF;
-			for (int i = 0; i < n; ++i) {
-				while ((*_ip >> 24) != 10)
-					_ip += 1;
-				_ip += 1;
+			_currOp->circle.curr = (byte)((_currOp->circle.curr + 1) % _currOp->circle.count);
+			for (uint i = 0; i < _currOp->circle.count; ++i) {
+				while (_currOp->type != kOperationBreak)
+					_currOp += 1;
+				_currOp += 1;
 			}
-			unk = 0;
+			processed = false;
 			break;
-		}
-		case 9:
-			if (unk)
-				_ip += 1;
+		case kOperation9:
+			if (processed)
+				_currOp += 1;
 			else {
 				g_vm->getQSystem()->_mainInterface->_dialog.sendMsg(kSaid);
 				g_vm->getQSystem()->_mainInterface->_dialog._field4 = 1;
 				g_vm->getQSystem()->_mainInterface->_dialog.restoreCursorState();
-				g_vm->getQSystem()->addMessage(g_vm->getQSystem()->_chapayev->_id, kUserMsg, *_ip);
+				g_vm->getQSystem()->addMessage(g_vm->getQSystem()->_chapayev->_id, kUserMsg, _currOp->op9.arg);
 			}
 			return;
-		case 10:
-			do {
-				if (op == 8) {
-					break;
-				}
-				--_ip;
-				op = (*_ip >> 24);
-			} while (op != 2);
-			sub40B670(arg);
 		default:
-			_ip += 1;
-			unk = 0;
+			_currOp += 1;
+			processed = false;
 			break;
 		}
 	}
+
 }
 
-void BigDialogue::load(Common::ReadStream *s) {
-	_codeSize = s->readUint32LE();
-	s->read(_code, 4 * _codeSize);
+uint BigDialogue::choicesCount() {
+	if (!_currOp || _currOp->type != kOperationMenu)
+		return 0;
+	uint count = 0;
+	uint bit = 1;
+	for (uint i = 0; i < _currOp->menu.bits; ++i) {
+		if (_currOp->menu.bitField & bit) {
+			count++;
+		}
+		bit <<= 1;
+	}
+	return count;
+}
 
+bool BigDialogue::findOperation(uint index, uint opType, uint *resIndex) {
+	while (_ops[index].type != opType) {
+		switch(_ops[index].type) {
+		case kOperationGoTo:
+			if (index >= _ops[index].goTo.opIndex)
+				return false;
+			index = _ops[index].goTo.opIndex;
+			break;
+		case kOperationReturn:
+			return false;
+		default:
+			index++;
+			break;
+		}
+	}
+	*resIndex = index;
+	return true;
 }
 
-void BigDialogue::save(Common::WriteStream *s) {
-	s->writeUint32LE(_codeSize);
-	s->write(_code, 4 * _codeSize);
+bool BigDialogue::checkMenu(uint menuIndex) {
+	if (_ops[menuIndex].type != kOperationMenu && !findOperation(menuIndex, kOperationMenu, &menuIndex)) {
+		return true;
+	}
+
+	uint count = 0;
+	uint bit = 1;
+	uint opIndex = menuIndex + 1;
+	for (uint i = 0; i < _ops[menuIndex].menu.bits; ++i) {
+		if (_ops[menuIndex].menu.bitField & bit) {
+			count++;
+		}
+		findOperation(opIndex, kOperationBreak, &opIndex);
+		opIndex++;
+		bit <<= 1;
+	}
+
+	if (!count)
+		return false;
+
+	bit = 1;
+	for (uint i = 0; i < _ops[menuIndex].menu.bits; ++i) {
+		uint subMenuIndex;
+		if ((_ops[menuIndex].menu.bitField & bit) && findOperation(_ops[opIndex + i].goTo.opIndex, kOperationMenu, &subMenuIndex) && !checkMenu(subMenuIndex)) {
+			_ops[menuIndex].menu.bitField &= ~bit;
+			count--;
+			if (count < 1)
+				return false;
+		}
+		bit <<= 1;
+	}
+	return true;
 }
 
 } // End of namespace Petka
\ No newline at end of file
diff --git a/engines/petka/big_dialogue.h b/engines/petka/big_dialogue.h
index 29322146a8..42a7d189fb 100644
--- a/engines/petka/big_dialogue.h
+++ b/engines/petka/big_dialogue.h
@@ -28,28 +28,72 @@
 
 namespace Petka {
 
-struct DlgOperation {
-	uint16 objId;
-	byte arg;
-	byte code;
+enum {
+	kOpcodePlay = 1,
+	kOpcodeMenu,
+	kOpcodeEnd,
+	kOpcode4
 };
 
-struct DialogHandler {
-	uint32 startOpIndex;
-	uint32 opsCount;
-	//DlgOperation *operations;
+enum {
+	kOperationBreak = 1,
+	kOperationMenu,
+	kOperationGoTo,
+	kOperationMenuRet,
+	kOperation5,
+	kOperationReturn,
+	kOperationPlay,
+	kOperationCircle,
+	kOperation9
+};
+
+struct Operation {
+	union {
+		struct {
+			byte bits;
+			uint16 bitField;
+		} menu;
+		struct {
+			uint16 opIndex;
+		} goTo;
+		struct {
+			uint16 opIndex;
+			byte bit;
+		} menuRet;
+		struct {
+			uint16 opIndex;
+			byte bit;
+		} op5;
+		struct {
+			uint16 messageIndex;
+		} play;
+		struct {
+			uint16 count;
+			byte curr;
+		} circle;
+		struct {
+			uint16 arg;
+		} op9;
+	};
+	byte type;
 };
 
 struct Dialog {
+	uint32 startOpIndex;
+	// uint32 opsCount;
+	// Operation *ops;
+};
+
+struct DialogHandler {
 	uint16 opcode;
 	uint16 objId;
-	uint32 startHandlerIndex;
-	Common::Array<DialogHandler> handlers;
+	uint32 startDialogIndex;
+	Common::Array<Dialog> dialogs;
 };
 
-struct ObjectDialogs {
+struct DialogGroup {
 	uint32 objId;
-	Common::Array<Dialog> dialogs;
+	Common::Array<DialogHandler> handlers;
 };
 
 struct SpeechInfo {
@@ -64,10 +108,12 @@ public:
 
 	uint opcode();
 
-	void sub40B670(int arg);
+	uint choicesCount();
+
+	void next(int choice = -1);
 
-	const Dialog *findDialog(uint objId, uint opcode, bool *res) const;
-	void setDialog(uint objId, uint opcode, int index);
+	const DialogHandler *findHandler(uint objId, uint opcode, bool *res) const;
+	void setHandler(uint objId, uint opcode, int index);
 
 	const Common::U32String *getSpeechInfo(int *talkerId, const char **soundName, int unk);
 
@@ -76,15 +122,16 @@ public:
 
 private:
 	void loadSpeechesInfo();
+	bool checkMenu(uint opIndex);
+	bool findOperation(uint startOpIndex, uint opType, uint *resIndex);
 
 private:
-	int *_ip;
-	int *_code;
-	uint _codeSize;
-	uint _startCodeIndex;
+	Operation *_currOp;
+	Common::Array<Operation> _ops;
+	uint _startOpIndex;
 
 	Common::Array<SpeechInfo> _speeches;
-	Common::Array<ObjectDialogs> _objDialogs;
+	Common::Array<DialogGroup> _objDialogs;
 };
 
 } // End of namespace Petka
diff --git a/engines/petka/interfaces/dialog_interface.cpp b/engines/petka/interfaces/dialog_interface.cpp
index 4057b23a83..218239e015 100644
--- a/engines/petka/interfaces/dialog_interface.cpp
+++ b/engines/petka/interfaces/dialog_interface.cpp
@@ -91,9 +91,9 @@ void DialogInterface::sub_4155D0(int a) {
 	if (_field10)
 		_field10 = 0;
 	else
-		g_vm->getBigDialogue()->sub40B670(a);
+		g_vm->getBigDialogue()->next(a);
 	switch (g_vm->getBigDialogue()->opcode()) {
-	case 1: {
+	case kOpcodePlay: {
 		int talkerId2;
 		const Common::U32String *text = g_vm->getBigDialogue()->getSpeechInfo(&talkerId2, &soundName, -1);
 		g_vm->soundMgr()->removeSound(_soundName);
@@ -114,10 +114,12 @@ void DialogInterface::sub_4155D0(int a) {
 		_field18 = 1;
 		break;
 	}
-	case 3:
+	case kOpcodeMenu:
+		break;
+	case kOpcodeEnd:
 		end();
 		break;
-	case 4:
+	case kOpcode4:
 		g_vm->soundMgr()->removeSound(_soundName);
 		_talker = nullptr;
 		_field18 = 1;
diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index 1c07dc63dc..6670c80056 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -121,8 +121,8 @@ void QMessageObject::processMessage(const QMessage &msg) {
 			continue;
 		}
 		bool res;
-		if (g_vm->getBigDialogue()->findDialog(_id, msg.opcode, &res) && res == 0) {
-			g_vm->getBigDialogue()->setDialog(_id, msg.opcode, -1);
+		if (g_vm->getBigDialogue()->findHandler(_id, msg.opcode, &res) && res == 0) {
+			g_vm->getBigDialogue()->setHandler(_id, msg.opcode, -1);
 			g_vm->getQSystem()->_mainInterface->_dialog._sender = this;
 		}
 		for (uint j = 0; j < r->messages.size(); ++j) {
@@ -177,7 +177,7 @@ void QMessageObject::processMessage(const QMessage &msg) {
 		reacted = true;
 	}
 
-	if (reacted || !g_vm->getBigDialogue()->findDialog(_id, msg.opcode, nullptr)) {
+	if (reacted || !g_vm->getBigDialogue()->findHandler(_id, msg.opcode, nullptr)) {
 		switch (msg.opcode) {
 		case kAddInv:
 			g_vm->getQSystem()->_case->addItem(msg.objId);
@@ -334,7 +334,7 @@ void QMessageObject::processMessage(const QMessage &msg) {
 			break;
 		}
 	} else {
-		g_vm->getBigDialogue()->setDialog(_id, msg.opcode, -1);
+		g_vm->getBigDialogue()->setHandler(_id, msg.opcode, -1);
 		g_vm->getQSystem()->_mainInterface->_dialog._sender = this;
 		for (uint i = 0; i < _reactions.size(); ++i) {
 			QReaction &r = _reactions[i];


Commit: edb68a769786bc7abf97b5c75f9ae78d6a28f675
    https://github.com/scummvm/scummvm/commit/edb68a769786bc7abf97b5c75f9ae78d6a28f675
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: removed global objects

Changed paths:
    engines/petka/interfaces/panel.cpp
    engines/petka/interfaces/panel.h
    engines/petka/interfaces/save_load.cpp
    engines/petka/interfaces/save_load.h
    engines/petka/objects/object_case.cpp
    engines/petka/objects/object_case.h
    engines/petka/objects/object_star.cpp
    engines/petka/objects/object_star.h


diff --git a/engines/petka/interfaces/panel.cpp b/engines/petka/interfaces/panel.cpp
index 681ed979d1..a7fb241e52 100644
--- a/engines/petka/interfaces/panel.cpp
+++ b/engines/petka/interfaces/panel.cpp
@@ -40,12 +40,6 @@ namespace Petka {
 
 // ПАНЕЛЬ УПРАВЛЕНИЯ
 const char *const kPanelObjName = "\xCF\xC0\xCD\xC5\xCB\xDC\x20\xD3\xCF\xD0\xC0\xC2\xCB\xC5\xCD\xC8\xDF";
-const Common::Point kObjectsPoints[] = {Common::Point(0, 2), Common::Point(5, 70), Common::Point(5, 136), Common::Point(22, 328),
-										Common::Point(87, 224), Common::Point(118, 395), Common::Point(467, 71), Common::Point(432, 144),
-										Common::Point(428, 29), Common::Point(434, 170), Common::Point(297, 214), Common::Point(470, 139),
-										Common::Point(318, 87), Common::Point(468, 172), Common::Point(262, 31), Common::Point(231, 137),
-										Common::Point(0, 0), Common::Point(0, 0), Common::Point(0, 0), Common::Point(0, 0),
-										Common::Point(0, 0), Common::Point(0, 0), Common::Point(0, 0), Common::Point(0, 0)};
 
 const uint kNewGameButtonIndex = 1;
 const uint kLoadButtonIndex = 2;
@@ -71,6 +65,34 @@ const uint kIncSfxButtonIndex = 22;
 const uint kDecSpeedButtonIndex = 23;
 const uint kIncSpeedButtonIndex = 24;
 
+InterfacePanel::InterfacePanel() {
+	_objectPoints[0] = Common::Point(0, 2);
+	_objectPoints[1] = Common::Point(5, 70);
+	_objectPoints[2] = Common::Point(5, 136);
+	_objectPoints[3] = Common::Point(22, 328);
+	_objectPoints[4] = Common::Point(87, 224);
+	_objectPoints[5] = Common::Point(118, 395);
+	_objectPoints[6] = Common::Point(467, 71);
+	_objectPoints[7] = Common::Point(432, 144);
+	_objectPoints[8] = Common::Point(428, 29);
+	_objectPoints[9] = Common::Point(434, 170);
+	_objectPoints[10] = Common::Point(297, 214);
+	_objectPoints[11] = Common::Point(470, 139);
+	_objectPoints[12] = Common::Point(318, 87);
+	_objectPoints[13] = Common::Point(468, 172);
+	_objectPoints[14] = Common::Point(262, 31);
+	_objectPoints[15] = Common::Point(231, 137);
+	_objectPoints[16] = Common::Point(0, 0);
+	_objectPoints[17] = Common::Point(0, 0);
+	_objectPoints[18] = Common::Point(0, 0);
+	_objectPoints[19] = Common::Point(0, 0);
+	_objectPoints[20] = Common::Point(0, 0);
+	_objectPoints[21] = Common::Point(0, 0);
+	_objectPoints[22] = Common::Point(0, 0);
+	_objectPoints[23] = Common::Point(0, 0);
+
+}
+
 void InterfacePanel::start() {
 	readSettings();
 
@@ -88,8 +110,8 @@ void InterfacePanel::start() {
 			FlicDecoder *flc = g_vm->resMgr()->loadFlic(obj->_resourceId);
 			flc->setFrame(1);
 			obj->_z = 1;
-			obj->_x = kObjectsPoints[j].x;
-			obj->_y = kObjectsPoints[j].y;
+			obj->_x = _objectPoints[j].x;
+			obj->_y = _objectPoints[j].y;
 			obj->_field24 = 1;
 			obj->_field20 = 1;
 			obj->_field28 = 1;
@@ -217,7 +239,7 @@ void InterfacePanel::onMouseMove(const Common::Point p) {
 		}
 		FlicDecoder *flc = g_vm->resMgr()->loadFlic(obj->_resourceId);
 		flc->setFrame(frame);
-		g_vm->videoSystem()->addDirtyRect(kObjectsPoints[pointIndex], *flc);
+		g_vm->videoSystem()->addDirtyRect(_objectPoints[pointIndex], *flc);
 	}
 	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
 	cursor->_isShown = 1;
@@ -229,30 +251,30 @@ void InterfacePanel::updateSliders() {
 
 	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_objs[kSpeechVolumeSliderIndex]->_resourceId);
 	flc->setFrame(_speechFrame);
-	g_vm->videoSystem()->addDirtyRect(kObjectsPoints[kSpeechVolumeSliderIndex - 1], *flc);
+	g_vm->videoSystem()->addDirtyRect(_objectPoints[kSpeechVolumeSliderIndex - 1], *flc);
 
 	flc = g_vm->resMgr()->loadFlic(_objs[kMusicVolumeSliderIndex]->_resourceId);
 	flc->setFrame(_musicFrame);
-	g_vm->videoSystem()->addDirtyRect(kObjectsPoints[kMusicVolumeSliderIndex - 1], *flc);
+	g_vm->videoSystem()->addDirtyRect(_objectPoints[kMusicVolumeSliderIndex - 1], *flc);
 
 	flc = g_vm->resMgr()->loadFlic(_objs[kSfxVolumeSliderIndex]->_resourceId);
 	flc->setFrame(_sfxFrame);
-	g_vm->videoSystem()->addDirtyRect(kObjectsPoints[kSfxVolumeSliderIndex - 1], *flc);
+	g_vm->videoSystem()->addDirtyRect(_objectPoints[kSfxVolumeSliderIndex - 1], *flc);
 
 	flc = g_vm->resMgr()->loadFlic(_objs[kSpeedSliderIndex]->_resourceId);
 	flc->setFrame(_speedFrame);
-	g_vm->videoSystem()->addDirtyRect(kObjectsPoints[kSpeedSliderIndex - 1], *flc);
+	g_vm->videoSystem()->addDirtyRect(_objectPoints[kSpeedSliderIndex - 1], *flc);
 }
 
 void InterfacePanel::updateSubtitles() {
 	applySettings();
 	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_objs[kSubtitleButtonIndex]->_resourceId);
 	flc->setFrame(_subtitles == 0 ? 1 : 7);
-	g_vm->videoSystem()->addDirtyRect(kObjectsPoints[kSubtitleButtonIndex - 1], *flc);
+	g_vm->videoSystem()->addDirtyRect(_objectPoints[kSubtitleButtonIndex - 1], *flc);
 
 	flc = g_vm->resMgr()->loadFlic(_objs[kSubtitleLabelIndex]->_resourceId);
 	flc->setFrame(_subtitles == 0 ? 1 : 2);
-	g_vm->videoSystem()->addDirtyRect(kObjectsPoints[kSubtitleLabelIndex - 1], *flc);
+	g_vm->videoSystem()->addDirtyRect(_objectPoints[kSubtitleLabelIndex - 1], *flc);
 }
 
 void InterfacePanel::readSettings() {
diff --git a/engines/petka/interfaces/panel.h b/engines/petka/interfaces/panel.h
index 107d0ade2b..3ff05a8728 100644
--- a/engines/petka/interfaces/panel.h
+++ b/engines/petka/interfaces/panel.h
@@ -29,6 +29,8 @@ namespace Petka {
 
 class InterfacePanel : public Interface {
 public:
+	InterfacePanel();
+
 	void start() override;
 
 	void onLeftButtonDown(const Common::Point p) override;
@@ -41,7 +43,7 @@ private:
 	void updateSliders();
 	void updateSubtitles();
 
-private:
+public:
 	int _savedXOffset;
 	int _savedSceneWidth;
 	int _subtitles;
@@ -49,6 +51,7 @@ private:
 	int _musicFrame;
 	int _sfxFrame;
 	int _speedFrame;
+	Common::Point _objectPoints[24];
 };
 
 } // End of namespace Petka
diff --git a/engines/petka/interfaces/save_load.cpp b/engines/petka/interfaces/save_load.cpp
index 810148c79d..c63269e67f 100644
--- a/engines/petka/interfaces/save_load.cpp
+++ b/engines/petka/interfaces/save_load.cpp
@@ -30,11 +30,17 @@
 namespace Petka {
 
 const uint kFirstSaveLoadPageId = 4990;
-const Common::Rect kSavesRects[] = {Common::Rect(43, 84, 151, 166), Common::Rect(43, 209, 151, 291),
-									Common::Rect(43, 335, 151, 417), Common::Rect(358, 75, 466, 157),
-									Common::Rect(360, 200, 468, 282), Common::Rect(359, 325, 467, 407)};
-const Common::Rect kNextPageRect(596, 403, 624, 431);
-const Common::Rect kPrevPageRect(10, 414, 38, 442);
+
+InterfaceSaveLoad::InterfaceSaveLoad() {
+	_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::startSaveLoad(bool saveMode) {
 	_loadMode = !saveMode;
@@ -65,9 +71,9 @@ void InterfaceSaveLoad::stop() {
 void InterfaceSaveLoad::onLeftButtonDown(const Common::Point p) {
 	int index = findSaveLoadRectIndex(p);
 	if (index == -1) {
-		if (kPrevPageRect.contains(p) && _page > 0) {
+		if (_prevPageRect.contains(p) && _page > 0) {
 			_page--;
-		} else if (kNextPageRect.contains(p) && _page < 2) {
+		} else if (_nextPageRect.contains(p) && _page < 2) {
 			_page++;
 		}
 		stop();
@@ -83,17 +89,17 @@ void InterfaceSaveLoad::onRightButtonDown(const Common::Point p) {
 
 void InterfaceSaveLoad::onMouseMove(const Common::Point p) {
 	QObjectCursor *cursor = g_vm->getQSystem()->_cursor.get();
-	cursor->_animate = findSaveLoadRectIndex(p) != -1 || kNextPageRect.contains(p) || kPrevPageRect.contains(p);
+	cursor->_animate = findSaveLoadRectIndex(p) != -1 || _nextPageRect.contains(p) || _prevPageRect.contains(p);
 	cursor->setCursorPos(p.x, p.y, 0);
 }
 
 int InterfaceSaveLoad::findSaveLoadRectIndex(const Common::Point p) {
 	int i = 0;
 	do {
-		if (kSavesRects[i].contains(p)) {
+		if (_saveRects[i].contains(p)) {
 			return i;
 		}
-	} while (++i < sizeof(kSavesRects) / sizeof(Common::Rect));
+	} while (++i < sizeof(_saveRects) / sizeof(Common::Rect));
 	return -1;
 }
 
diff --git a/engines/petka/interfaces/save_load.h b/engines/petka/interfaces/save_load.h
index 786b0b402e..91fbe0ddb0 100644
--- a/engines/petka/interfaces/save_load.h
+++ b/engines/petka/interfaces/save_load.h
@@ -29,6 +29,8 @@ namespace Petka {
 
 class InterfaceSaveLoad : public Interface {
 public:
+	InterfaceSaveLoad();
+
 	void startSaveLoad(bool saveMode);
 	void stop() override;
 
@@ -43,6 +45,10 @@ private:
 	bool _loadMode;
 	uint _page;
 	int _savedCursorId;
+
+	Common::Rect _saveRects[6];
+	Common::Rect _nextPageRect;
+	Common::Rect _prevPageRect;
 };
 
 } // End of namespace Petka
diff --git a/engines/petka/objects/object_case.cpp b/engines/petka/objects/object_case.cpp
index 8741787f0a..875452d35e 100644
--- a/engines/petka/objects/object_case.cpp
+++ b/engines/petka/objects/object_case.cpp
@@ -34,8 +34,6 @@ namespace Petka {
 // Полоска в чемодане
 const char *const kPoloska = "\xCF\xEE\xEB\xEE\xF1\xEA\xE0\x20\xE2\x20\xF7\xE5\xEC\xEE\xE4\xE0\xED\xE5";
 
-const Common::Point itemsLocation[] = {Common::Point(120, 145), Common::Point(240, 145), Common::Point(360, 145),
-									   Common::Point(100, 220), Common::Point(240, 220), Common::Point(380, 220)};
 
 QObjectCase::QObjectCase() {
 	_itemIndex = 0;
@@ -45,6 +43,13 @@ QObjectCase::QObjectCase() {
 	_resourceId = 6000;
 	_z = 980;
 	_clickedObjIndex = -1;
+
+	_itemsLocation[0] = Common::Point(120, 145);
+	_itemsLocation[1] = Common::Point(240, 145);
+	_itemsLocation[2] = Common::Point(360, 145);
+	_itemsLocation[3] = Common::Point(100, 220);
+	_itemsLocation[4] = Common::Point(240, 220);
+	_itemsLocation[5] = Common::Point(380, 220);
 }
 
 void QObjectCase::update(int time) {
@@ -181,8 +186,8 @@ void QObjectCase::fillWithItems() {
 		obj->_z = _z + 1;
 		objs.push_back(obj);
 		g_vm->resMgr()->loadFlic(obj->_resourceId);
-		_x = itemsLocation[i - _itemIndex].x;
-		_y = itemsLocation[i - _itemIndex].y;
+		_x = _itemsLocation[i - _itemIndex].x;
+		_y = _itemsLocation[i - _itemIndex].y;
 	}
 }
 
diff --git a/engines/petka/objects/object_case.h b/engines/petka/objects/object_case.h
index bffeadb0f1..bde7544b2d 100644
--- a/engines/petka/objects/object_case.h
+++ b/engines/petka/objects/object_case.h
@@ -43,6 +43,7 @@ public:
 
 public:
 	Common::Array<int> _items;
+	Common::Point _itemsLocation[6];
 	uint _clickedObjIndex;
 	int _itemIndex;
 };
diff --git a/engines/petka/objects/object_star.cpp b/engines/petka/objects/object_star.cpp
index 16d714b87b..ff1ab14b79 100644
--- a/engines/petka/objects/object_star.cpp
+++ b/engines/petka/objects/object_star.cpp
@@ -35,21 +35,6 @@ namespace Petka {
 
 const uint kFirstCursorId = 5001;
 const uint kCaseButtonIndex = 0;
-const Common::Rect kButtonsRects[] = {Common::Rect(70, 74, 112, 112),
-									  Common::Rect(68, 0, 114, 41),
-									  Common::Rect(151, 51, 180, 97),
-									  Common::Rect(138, 125, 179, 166),
-									  Common::Rect(55, 145, 96, 175),
-									  Common::Rect(11, 79, 40, 118)};
-
-static uint findButtonIndex(int16 x, int16 y) {
-	uint i = 0;
-	for (i = 0; i < sizeof(kButtonsRects) / sizeof(Common::Rect); ++i) {
-		if (kButtonsRects[i].contains(x, y))
-			return i;
-	}
-	return i;
-}
 
 QObjectStar::QObjectStar() {
 	_isShown = false;
@@ -58,6 +43,13 @@ QObjectStar::QObjectStar() {
 	_z = 999;
 	_updateZ = false;
 	_isActive = true;
+
+	_buttonRects[0] = Common::Rect(70, 74, 112, 112);
+	_buttonRects[1] = Common::Rect(68, 0, 114, 41);
+	_buttonRects[2] = Common::Rect(151, 51, 180, 97);
+	_buttonRects[3] = Common::Rect(138, 125, 179, 166);
+	_buttonRects[4] = Common::Rect(55, 145, 96, 175);
+	_buttonRects[5] = Common::Rect(11, 79, 40, 118);
 }
 
 bool QObjectStar::isInPoint(int x, int y) {
@@ -75,7 +67,7 @@ void QObjectStar::onMouseMove(int x, int y) {
 
 void QObjectStar::onClick(int x, int y) {
 	uint button = findButtonIndex(x - _x, y - _y);
-	if (button >= sizeof(kButtonsRects) / sizeof(Common::Rect)) {
+	if (button >= sizeof(_buttonRects) / sizeof(Common::Rect)) {
 		show(0);
 		return;
 	}
@@ -91,4 +83,13 @@ void QObjectStar::onClick(int x, int y) {
 	show(0);
 }
 
+uint QObjectStar::findButtonIndex(int16 x, int16 y) const {
+	uint i = 0;
+	for (i = 0; i < sizeof(_buttonRects) / sizeof(Common::Rect); ++i) {
+		if (_buttonRects[i].contains(x, y))
+			return i;
+	}
+	return i;
+}
+
 }
diff --git a/engines/petka/objects/object_star.h b/engines/petka/objects/object_star.h
index 7f2b33b99c..74726359ba 100644
--- a/engines/petka/objects/object_star.h
+++ b/engines/petka/objects/object_star.h
@@ -34,6 +34,12 @@ public:
 	bool isInPoint(int x, int y) override;
 	void onMouseMove(int x, int y) override;
 	void onClick(int x, int y) override;
+
+private:
+	uint findButtonIndex(int16 x, int16 y) const;
+
+private:
+	Common::Rect _buttonRects[6];
 };
 
 } // End of namespace Petka


Commit: c994d6bc81c8be6c0051bdf98376dedb666d4023
    https://github.com/scummvm/scummvm/commit/c994d6bc81c8be6c0051bdf98376dedb666d4023
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: JANITORIAL: fixed compiler warnings about newline

Changed paths:
    engines/petka/big_dialogue.cpp
    engines/petka/interfaces/dialog_interface.h
    engines/petka/objects/heroes.h
    engines/petka/objects/object_bg.h


diff --git a/engines/petka/big_dialogue.cpp b/engines/petka/big_dialogue.cpp
index 2a4e32e580..2ada3050a4 100644
--- a/engines/petka/big_dialogue.cpp
+++ b/engines/petka/big_dialogue.cpp
@@ -457,4 +457,4 @@ bool BigDialogue::checkMenu(uint menuIndex) {
 	return true;
 }
 
-} // End of namespace Petka
\ No newline at end of file
+} // End of namespace Petka
diff --git a/engines/petka/interfaces/dialog_interface.h b/engines/petka/interfaces/dialog_interface.h
index ded80b92fa..29b1887d3b 100644
--- a/engines/petka/interfaces/dialog_interface.h
+++ b/engines/petka/interfaces/dialog_interface.h
@@ -63,4 +63,4 @@ public:
 
 } // End of namespace Petka
 
-#endif
\ No newline at end of file
+#endif
diff --git a/engines/petka/objects/heroes.h b/engines/petka/objects/heroes.h
index 11d4333242..d7d5250b8e 100644
--- a/engines/petka/objects/heroes.h
+++ b/engines/petka/objects/heroes.h
@@ -72,4 +72,4 @@ public:
 
 } // End of namespace Petka
 
-#endif
\ No newline at end of file
+#endif
diff --git a/engines/petka/objects/object_bg.h b/engines/petka/objects/object_bg.h
index 0020eee8f4..2e654d0ed6 100644
--- a/engines/petka/objects/object_bg.h
+++ b/engines/petka/objects/object_bg.h
@@ -41,4 +41,4 @@ public:
 
 } // End of namespace Petka
 
-#endif
\ No newline at end of file
+#endif


Commit: 7a5a39fa2216e5fd5339495ec57144ff8c15511e
    https://github.com/scummvm/scummvm/commit/7a5a39fa2216e5fd5339495ec57144ff8c15511e
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: JANITORIAL: removed comma at the end of enumerator list

Changed paths:
    engines/petka/petka.h


diff --git a/engines/petka/petka.h b/engines/petka/petka.h
index ce075852fe..046e04d3a4 100644
--- a/engines/petka/petka.h
+++ b/engines/petka/petka.h
@@ -63,7 +63,7 @@ enum {
 	kPetkaDebugGeneral = 1 << 0,
 	kPetkaDebugResources = 1 << 1,
 	kPetkaDebugMessagingSystem = 1 << 2,
-	kPetkaDebugDialogs = 1 << 3,
+	kPetkaDebugDialogs = 1 << 3
 };
 
 class PetkaEngine : public Engine {


Commit: b0e6db5909ab574d6a6ade7032bd561983fc5c7e
    https://github.com/scummvm/scummvm/commit/b0e6db5909ab574d6a6ade7032bd561983fc5c7e
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: removed cast warnings

Changed paths:
    engines/petka/flc.cpp


diff --git a/engines/petka/flc.cpp b/engines/petka/flc.cpp
index 6ca25c89be..9f8b65398c 100644
--- a/engines/petka/flc.cpp
+++ b/engines/petka/flc.cpp
@@ -68,19 +68,19 @@ void FlicDecoder::load(Common::SeekableReadStream *stream, Common::SeekableReadS
 const Common::Rect &FlicDecoder::getBounds() const {
 	const Track *track = getTrack(0);
 	if (track)
-		return ((FlicVideoTrack *)track)->getBounds();
+		return ((const FlicVideoTrack *)track)->getBounds();
 }
 
 const Common::Array<Common::Rect> &FlicDecoder::getMskRects() const {
 	const Track *track = getTrack(0);
 	if (track)
-		return ((FlicVideoTrack *)track)->getMskRects();
+		return ((const FlicVideoTrack *)track)->getMskRects();
 }
 
 uint32 FlicDecoder::getTransColor(const Graphics::PixelFormat &fmt) const {
 	const Track *track = getTrack(0);
 	if (track) {
-		const FlicVideoTrack *flc = ((FlicVideoTrack *)track);
+		const FlicVideoTrack *flc = ((const FlicVideoTrack *)track);
 		byte r = flc->getPalette()[0];
 		byte g = flc->getPalette()[1];
 		byte b = flc->getPalette()[2];
@@ -109,7 +109,7 @@ void FlicDecoder::setFrame(int frame) {
 }
 
 uint FlicDecoder::getDelay() const {
-	FlicVideoTrack *flc = ((FlicVideoTrack *)getTrack(0));
+	const FlicVideoTrack *flc = ((const FlicVideoTrack *)getTrack(0));
 	if (flc)
 		return flc->getDelay();
 	return 0;


Commit: ea296c6ad7927101e0a9975e3347792b8a46574d
    https://github.com/scummvm/scummvm/commit/ea296c6ad7927101e0a9975e3347792b8a46574d
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: renamed RTL event

Changed paths:
    engines/petka/petka.cpp


diff --git a/engines/petka/petka.cpp b/engines/petka/petka.cpp
index 9f1ab06469..c0958666b3 100644
--- a/engines/petka/petka.cpp
+++ b/engines/petka/petka.cpp
@@ -97,7 +97,7 @@ Common::Error PetkaEngine::run() {
 		while (_eventMan->pollEvent(event)) {
 			switch (event.type) {
 			case Common::EVENT_QUIT:
-			case Common::EVENT_RTL:
+			case Common::EVENT_RETURN_TO_LAUNCHER:
 				return Common::kNoError;
 			case Common::EVENT_MOUSEMOVE:
 				_qsystem->_currInterface->onMouseMove(event.mouse);


Commit: ee9a09e0059f17b0597c74b48949359c9062366b
    https://github.com/scummvm/scummvm/commit/ee9a09e0059f17b0597c74b48949359c9062366b
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed setting musicId in ObjectBG

Changed paths:
    engines/petka/objects/object_bg.cpp


diff --git a/engines/petka/objects/object_bg.cpp b/engines/petka/objects/object_bg.cpp
index 188a06cfaf..d81151938f 100644
--- a/engines/petka/objects/object_bg.cpp
+++ b/engines/petka/objects/object_bg.cpp
@@ -48,6 +48,7 @@ void QObjectBG::processMessage(const QMessage &msg) {
 	switch (msg.opcode) {
 	case kSet:
 		_resourceId = msg.arg1;
+		break;
 	case kMusic:
 		_musicId = msg.arg1;
 		break;


Commit: ef65600429dab4a6a2a1d1fd3a9627321ade7cae
    https://github.com/scummvm/scummvm/commit/ef65600429dab4a6a2a1d1fd3a9627321ade7cae
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: fixed drawing save/load interface

Changed paths:
    engines/petka/interfaces/save_load.cpp


diff --git a/engines/petka/interfaces/save_load.cpp b/engines/petka/interfaces/save_load.cpp
index c63269e67f..02fd40ec49 100644
--- a/engines/petka/interfaces/save_load.cpp
+++ b/engines/petka/interfaces/save_load.cpp
@@ -32,6 +32,10 @@ namespace Petka {
 const uint kFirstSaveLoadPageId = 4990;
 
 InterfaceSaveLoad::InterfaceSaveLoad() {
+	_page = 0;
+	_loadMode = false;
+	_savedCursorId = 0;
+
 	_saveRects[0] = Common::Rect(43, 84, 151, 166);
 	_saveRects[1] = Common::Rect(43, 209, 151, 291);
 	_saveRects[2] = Common::Rect(43, 335, 151, 417);


Commit: 5a5208666f7add9fcc86dd757173940f4ed6f6c6
    https://github.com/scummvm/scummvm/commit/5a5208666f7add9fcc86dd757173940f4ed6f6c6
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: minor fixes to dialog system

Changed paths:
    engines/petka/big_dialogue.cpp


diff --git a/engines/petka/big_dialogue.cpp b/engines/petka/big_dialogue.cpp
index 2ada3050a4..8c952a9319 100644
--- a/engines/petka/big_dialogue.cpp
+++ b/engines/petka/big_dialogue.cpp
@@ -308,7 +308,7 @@ void BigDialogue::next(int choice) {
 	while (true) {
 		switch (_currOp->type) {
 		case kOperationBreak:
-			while (_currOp->type != kOperationMenu && _currOp->type != kOperationCircle) {
+			while (_currOp->type != kOperationMenu || _currOp->type != kOperationCircle) {
 				_currOp--;
 			}
 			next(choice);
@@ -342,7 +342,7 @@ void BigDialogue::next(int choice) {
 			break;
 		}
 		case kOperationMenuRet:
-			_ops[_currOp->menuRet.opIndex].menu.bitField &= ~(1 << _currOp->op5.bit); // disable menu item
+			_ops[_currOp->menuRet.opIndex].menu.bitField &= ~(1 << _currOp->menuRet.bit); // disable menu item
 			checkMenu(_currOp->menuRet.opIndex);
 			_currOp += 1;
 			processed = false;


Commit: dc3427c5055470f33a7ab840a93dfba392972f6b
    https://github.com/scummvm/scummvm/commit/dc3427c5055470f33a7ab840a93dfba392972f6b
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: rewrote search of rectangle in SaveLoad interface

Changed paths:
    engines/petka/interfaces/save_load.cpp


diff --git a/engines/petka/interfaces/save_load.cpp b/engines/petka/interfaces/save_load.cpp
index 02fd40ec49..ea15fd0c5a 100644
--- a/engines/petka/interfaces/save_load.cpp
+++ b/engines/petka/interfaces/save_load.cpp
@@ -98,12 +98,11 @@ void InterfaceSaveLoad::onMouseMove(const Common::Point p) {
 }
 
 int InterfaceSaveLoad::findSaveLoadRectIndex(const Common::Point p) {
-	int i = 0;
-	do {
+	for (uint i = 0; i < sizeof(_saveRects) / sizeof(Common::Rect); ++i) {
 		if (_saveRects[i].contains(p)) {
 			return i;
 		}
-	} while (++i < sizeof(_saveRects) / sizeof(Common::Rect));
+	}
 	return -1;
 }
 


Commit: 1b7e691f25e0a94e7abc41a741a2c609081c7472
    https://github.com/scummvm/scummvm/commit/1b7e691f25e0a94e7abc41a741a2c609081c7472
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: renamed method in DialogInterface

Changed paths:
    engines/petka/interfaces/dialog_interface.cpp
    engines/petka/interfaces/dialog_interface.h
    engines/petka/interfaces/main.cpp
    engines/petka/objects/object.cpp
    engines/petka/video.cpp


diff --git a/engines/petka/interfaces/dialog_interface.cpp b/engines/petka/interfaces/dialog_interface.cpp
index 218239e015..11c77b1cec 100644
--- a/engines/petka/interfaces/dialog_interface.cpp
+++ b/engines/petka/interfaces/dialog_interface.cpp
@@ -54,7 +54,7 @@ void DialogInterface::start(uint a, QMessageObject *sender) {
 	_sender = sender;
 	_soundName.clear();
 	saveCursorState();
-	sub_4155D0(-2);
+	next(-2);
 }
 
 void DialogInterface::saveCursorState() {
@@ -74,14 +74,14 @@ void DialogInterface::restoreCursorState() {
 	cursor->_resourceId = _savedCursorId;
 }
 
-void DialogInterface::sub_4155D0(int a) {
+void DialogInterface::next(int choice) {
 	const char *soundName = nullptr;
-	if (_field14 == -1 || (a == -1 && _field18 == 2))
+	if (_field14 == -1 || (choice == -1 && _field18 == 2))
 		return;
 	if (_field18 == -1)
 		return;
 	int talkerId = -1;
-	if (a == -1 && !_field8) {
+	if (choice == -1 && !_field8) {
 		g_vm->getBigDialogue()->getSpeechInfo(&talkerId, &soundName, -1);
 	}
 	_field8 = _field4;
@@ -91,7 +91,7 @@ void DialogInterface::sub_4155D0(int a) {
 	if (_field10)
 		_field10 = 0;
 	else
-		g_vm->getBigDialogue()->next(a);
+		g_vm->getBigDialogue()->next(choice);
 	switch (g_vm->getBigDialogue()->opcode()) {
 	case kOpcodePlay: {
 		int talkerId2;
diff --git a/engines/petka/interfaces/dialog_interface.h b/engines/petka/interfaces/dialog_interface.h
index 29b1887d3b..3c5d480d04 100644
--- a/engines/petka/interfaces/dialog_interface.h
+++ b/engines/petka/interfaces/dialog_interface.h
@@ -38,7 +38,7 @@ public:
 	void saveCursorState();
 	void restoreCursorState();
 
-	void sub_4155D0(int a);
+	void next(int choice);
 
 	void sendMsg(uint16 opcode);
 	void end();
diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index a72d7feb5b..8760d3f939 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -170,7 +170,7 @@ void InterfaceMain::unloadRoom(bool fromSave) {
 
 void InterfaceMain::onLeftButtonDown(const Common::Point p) {
 	if (!g_vm->getQSystem()->_cursor->_isShown) {
-		_dialog.sub_4155D0(-1);
+		_dialog.next(-1);
 		return;
 	}
 	for (int i = _objs.size() - 1; i >= 0; --i) {
diff --git a/engines/petka/objects/object.cpp b/engines/petka/objects/object.cpp
index 6670c80056..ba6e1628bd 100644
--- a/engines/petka/objects/object.cpp
+++ b/engines/petka/objects/object.cpp
@@ -194,7 +194,7 @@ void QMessageObject::processMessage(const QMessage &msg) {
 		}
 		case kContinue:
 			g_vm->getQSystem()->_mainInterface->_dialog._field4 = 0;
-			g_vm->getQSystem()->_mainInterface->_dialog.sub_4155D0(-1);
+			g_vm->getQSystem()->_mainInterface->_dialog.next(-1);
 			break;
 		case kCursor:
 			if (msg.arg1 == -1) {
diff --git a/engines/petka/video.cpp b/engines/petka/video.cpp
index beab2e2303..18f33dbe1c 100644
--- a/engines/petka/video.cpp
+++ b/engines/petka/video.cpp
@@ -52,7 +52,7 @@ void VideoSystem::update() {
 		}
 
 		if ((g_trackedSound && !g_trackedSound->isPlaying()) || !g_trackedSound) {
-			g_vm->getQSystem()->_mainInterface->_dialog.sub_4155D0(-1);
+			g_vm->getQSystem()->_mainInterface->_dialog.next(-1);
 		}
 
 		for (uint i = 0; i < interface->_objs.size(); ++i) {


Commit: a6cb15bd620b487cbde00db9dac51e713d7ef61d
    https://github.com/scummvm/scummvm/commit/a6cb15bd620b487cbde00db9dac51e713d7ef61d
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: new text subsystem implementation

Changed paths:
    engines/petka/interfaces/dialog_interface.cpp
    engines/petka/interfaces/dialog_interface.h
    engines/petka/interfaces/interface.cpp
    engines/petka/interfaces/interface.h
    engines/petka/interfaces/main.cpp
    engines/petka/interfaces/main.h
    engines/petka/objects/text.cpp
    engines/petka/objects/text.h
    engines/petka/q_system.cpp


diff --git a/engines/petka/interfaces/dialog_interface.cpp b/engines/petka/interfaces/dialog_interface.cpp
index 11c77b1cec..8f4445ace8 100644
--- a/engines/petka/interfaces/dialog_interface.cpp
+++ b/engines/petka/interfaces/dialog_interface.cpp
@@ -20,6 +20,8 @@
  *
  */
 
+#include "common/system.h"
+
 #include "petka/interfaces/dialog_interface.h"
 #include "petka/interfaces/main.h"
 #include "petka/petka.h"
@@ -38,13 +40,13 @@ DialogInterface::DialogInterface() {
 	_field8 = 0;
 	_talker = nullptr;
 	_sender = nullptr;
-	_fieldC = 0;
+	_hasSound = 0;
 	_field10 = 1;
 }
 
 void DialogInterface::start(uint a, QMessageObject *sender) {
 	_field14 = a;
-	_fieldC = 0;
+	_hasSound = 0;
 	_field24 = 0;
 	_field4 = 0;
 	_field8 = 0;
@@ -105,12 +107,13 @@ void DialogInterface::next(int choice) {
 		if (s) {
 			s->play(0);
 		}
+		_hasSound = s != nullptr;
 		g_trackedSound = s;
 		_talker = g_vm->getQSystem()->findObject(talkerId2);
 		if (talkerId != talkerId2) {
 			sendMsg(kSay);
 		}
-		//g_vm->getQSystem()->_mainInterface->setText(info->text, _talker->_dialogColor);
+		g_vm->getQSystem()->_mainInterface->setTextPhrase(*text, _talker->_dialogColor, g_vm->_system->getScreenFormat().RGBToColor(0x7F, 0, 0));
 		_field18 = 1;
 		break;
 	}
diff --git a/engines/petka/interfaces/dialog_interface.h b/engines/petka/interfaces/dialog_interface.h
index 3c5d480d04..c146ee754c 100644
--- a/engines/petka/interfaces/dialog_interface.h
+++ b/engines/petka/interfaces/dialog_interface.h
@@ -46,7 +46,7 @@ public:
 public:
 	int _field4;
 	int _field8;
-	int _fieldC;
+	int _hasSound;
 	int _field10;
 	int _field14;
 	int _field18;
diff --git a/engines/petka/interfaces/interface.cpp b/engines/petka/interfaces/interface.cpp
index cffb560848..fbda8cf396 100644
--- a/engines/petka/interfaces/interface.cpp
+++ b/engines/petka/interfaces/interface.cpp
@@ -25,14 +25,24 @@
 #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::setText(const Common::U32String &text, uint32 rgb) {
-	_objs.push_back(new QText(text, rgb));
+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) {
@@ -54,4 +64,17 @@ void Interface::initCursor(int id, bool show, bool animate) {
 	cursor->setCursorPos(cursor->_x, cursor->_y, 0);
 }
 
+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(-2);
+			delete _objs[i];
+			_objs.remove_at(i);
+		} else {
+			++i;
+		}
+	}
+}
+
 } // End of namespace Petka
diff --git a/engines/petka/interfaces/interface.h b/engines/petka/interfaces/interface.h
index f06d462388..8dd7523152 100644
--- a/engines/petka/interfaces/interface.h
+++ b/engines/petka/interfaces/interface.h
@@ -44,7 +44,10 @@ public:
 	virtual void onRightButtonDown(const Common::Point p) {};
 	virtual void onMouseMove(const Common::Point p) {};
 
-	void setText(const Common::U32String &text, uint32 rgb);
+	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);
 
diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index 8760d3f939..0f2ead18a5 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -20,7 +20,7 @@
  *
  */
 
-#include <common/system.h>
+#include "common/system.h"
 #include "common/stream.h"
 #include "common/events.h"
 #include "common/ini-file.h"
@@ -37,6 +37,7 @@
 #include "petka/video.h"
 #include "petka/objects/object_case.h"
 #include "petka/objects/heroes.h"
+#include "petka/objects/text.h"
 
 namespace Petka {
 
@@ -220,4 +221,26 @@ void InterfaceMain::onMouseMove(const Common::Point p) {
 	cursor->setCursorPos(p.x, p.y, true);
 }
 
+void InterfaceMain::setTextChoice(const Common::Array<Common::U32String> &choices, uint16 color, uint16 selectedColor) {
+	removeTexts();
+	_objUnderCursor = nullptr;
+	_objs.push_back(new QTextChoice(choices, color, selectedColor));
+}
+
+void InterfaceMain::setTextDescription(const Common::U32String &text, int frame) {
+	removeTexts();
+	QObjectStar *star = g_vm->getQSystem()->_star.get();
+	star->_isActive = 0;
+	_objUnderCursor = nullptr;
+	_hasTextDesc = true;
+	_objs.push_back(new QTextDescription(text, frame));
+}
+
+void InterfaceMain::removeTextDescription() {
+	_hasTextDesc = false;
+	_objUnderCursor = nullptr;
+	g_vm->getQSystem()->_star->_isActive = true;
+	removeTexts();
+}
+
 } // End of namespace Petka
diff --git a/engines/petka/interfaces/main.h b/engines/petka/interfaces/main.h
index 26fd426b5d..f6c5fb0e6f 100644
--- a/engines/petka/interfaces/main.h
+++ b/engines/petka/interfaces/main.h
@@ -53,10 +53,16 @@ public:
 	void onRightButtonDown(const Common::Point p) override;
 	void onMouseMove(const Common::Point p) override;
 
+	void setTextChoice(const Common::Array<Common::U32String> &choices, uint16 color, uint16 selectedColor);
+	void setTextDescription(const Common::U32String &text, int frame);
+
+	void removeTextDescription();
+
 public:
 	DialogInterface _dialog;
 	Common::Array<BGInfo> _bgs;
 	int _roomId;
+	bool _hasTextDesc;
 };
 
 } // End of namespace Petka
diff --git a/engines/petka/objects/text.cpp b/engines/petka/objects/text.cpp
index a9aabcce17..98cd52d520 100644
--- a/engines/petka/objects/text.cpp
+++ b/engines/petka/objects/text.cpp
@@ -20,30 +20,199 @@
  *
  */
 
+#include "graphics/fonts/ttf.h"
 #include "graphics/fontman.h"
-#include "graphics/font.h"
 
 #include "petka/q_manager.h"
 #include "petka/petka.h"
 #include "petka/video.h"
 #include "petka/objects/text.h"
+#include "petka/q_system.h"
+#include "petka/interfaces/panel.h"
+#include "petka/sound.h"
+#include "petka/interfaces/main.h"
+#include "petka/flc.h"
 
 namespace Petka {
 
-QText::QText(const Common::U32String &text, uint32 rgb) {
+QText::QText(const Common::U32String &text, uint16 textColor, uint16 outlineColor) {
 	_resourceId = -2;
 	_z = 3000;
-	const Graphics::Font *font = FontMan.getFontByUsage(Graphics::FontManager::kLocalizedFont);
-	_rect = font->getBoundingBox("TEST FONT", 0, 0, 0);
 
+	Common::ScopedPtr<Graphics::Font> font(Graphics::loadTTFFontFromArchive("FreeSans.ttf", 18));
+	Common::Rect rect = font->getBoundingBox(text, 0, 0, 0);
+	rect.right += 10;
+	rect.bottom += 4;
+
+	_rect = Common::Rect((640 - rect.width()) / 2, 479 - rect.height(), 639 - (640 - rect.width()) / 2, 479);
 	Graphics::Surface *s = g_vm->resMgr()->findOrCreateSurface(-2, _rect.width(), _rect.height());
-	font->drawString(s, "TEST FONT", 0, 0, _rect.width(), rgb);
+	font->drawString(s, text, 0, 0, s->w, textColor);
+
+	drawOutline(s, outlineColor);
 }
 
 void QText::draw() {
-	const Graphics::Font *font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont);
-	const Graphics::Surface *s = g_vm->resMgr()->loadBitmap(_resourceId);
-	g_vm->videoSystem()->screen().transBlitFrom(*s, Common::Point((640 - _rect.width()) / 2, 480 - _rect.height()));
+	const Graphics::Surface *s = g_vm->resMgr()->loadBitmap(-2);
+	g_vm->videoSystem()->screen().transBlitFrom(*s, Common::Point((640 - s->w) / 2, 479 - s->h));
+}
+
+const Common::Rect &QText::getRect() {
+	return _rect;
+}
+
+void QText::drawOutline(Graphics::Surface *s, uint16 color) {
+	for (uint y = 0; y < s->h; ++y) {
+		for (uint x = 1; x < s->w - 1; ++x) {
+			uint16 *pixel = (uint16 *)s->getBasePtr(x, y);
+			if (*pixel && *pixel != color) {
+				if (!pixel[-1])
+					pixel[-1] = (uint16)color;
+				if (!pixel[1])
+					pixel[1] = (uint16)color;
+			}
+		}
+	}
+
+	for (uint x = 0; x < s->w; ++x) {
+		for (uint y = 0; y < s->h - 1; ++y) {
+			uint16 *pixel = (uint16 *)s->getBasePtr(x, y);
+			if (*pixel && *pixel != color) {
+				pixel = (uint16 *)s->getBasePtr(x, y - 1);
+				if (*pixel == 0)
+					*pixel = color;
+				pixel = (uint16 *)s->getBasePtr(x, y + 1);
+				if (*pixel == 0)
+					*pixel = color;
+			}
+		}
+	}
+}
+
+QText::QText() {}
+
+QTextPhrase::QTextPhrase(const Common::U32String &text, uint16 textColor, uint16 outlineColor)
+	: QText(text, textColor, outlineColor), _phrase(text), _time(0) {}
+
+void QTextPhrase::draw() {
+	if (g_vm->getQSystem()->_panelInterface->_subtitles) {
+		QText::draw();
+	}
+}
+
+void QTextPhrase::update(int time) {
+	DialogInterface &dialog = g_vm->getQSystem()->_mainInterface->_dialog;
+	_time += time;
+	if (dialog._hasSound) {
+		Sound *sound = g_vm->soundMgr()->findSound(dialog._soundName);
+		if (sound && !sound->isPlaying()) {
+			_time = 0;
+			dialog.next(-1);
+		}
+	} else if (_time > _phrase.size() * 30 + 1000 || !g_vm->getQSystem()->_panelInterface->_subtitles) {
+		dialog.next(-1);
+		_time = 0;
+	}
+}
+
+void QTextPhrase::onClick(int x, int y) {
+	DialogInterface &dialog = g_vm->getQSystem()->_mainInterface->_dialog;
+	g_vm->soundMgr()->removeSound(dialog._soundName);
+	dialog._soundName.clear();
+	dialog.next(-1);
+}
+
+QTextDescription::QTextDescription(const Common::U32String &desc, uint32 frame) {
+	_z = 999;
+	_resourceId = -2;
+	_rect = Common::Rect(0, 0, 640, 480);
+
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(6008);
+	flc->setFrame(frame);
+
+	const Graphics::Surface *frameS = flc->getCurrentFrame();
+	Graphics::Surface *s = g_vm->resMgr()->findOrCreateSurface(-2, 640, 480);
+
+	Graphics::Surface *convS = frameS->convertTo(s->format);
+	s->copyRectToSurface(*convS, 0, 0, _rect);
+	convS->free();
+	delete convS;
+
+
+	Common::Rect textArea(160, 275, 598, 376);
+	Common::ScopedPtr<Graphics::Font> font(Graphics::loadTTFFontFromArchive("FreeSans.ttf", 16));
+
+	font->drawString(s, desc, textArea.left, textArea.top, textArea.width(), 0);
+}
+
+void QTextDescription::onClick(int x, int y) {
+	g_vm->getQSystem()->_mainInterface->removeTextDescription();
+}
+
+void QTextDescription::draw() {
+	Graphics::Surface *s = g_vm->resMgr()->loadBitmap(-2);
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(6008);
+	g_vm->videoSystem()->screen().transBlitFrom(*s, flc->getTransColor(s->format));
+	// todo dirty rects
+}
+
+QTextChoice::QTextChoice(const Common::Array<Common::U32String> &choices, uint16 color, uint16 selectedColor) {
+	_activeChoice = 0;
+	_choiceColor = color;
+	_selectedColor = selectedColor;
+	_choices = choices;
+
+	int w = 0;
+	int h = 0;
+	Common::ScopedPtr<Graphics::Font> font(Graphics::loadTTFFontFromArchive("FreeSans.ttf", 18));
+	for (uint i = 0; i < _choices.size(); ++i) {
+		_rects[i] = font->getBoundingBox(_choices[i]);
+		if (_rects[i].width() > w)
+			w = _rects[i].width();
+		h += _rects[i].height();
+	}
+
+	_rect = Common::Rect((640 - w) / 2, 479 - h, 639 - (640 - w) / 2, 479);
+
+	Graphics::Surface *s = g_vm->resMgr()->findOrCreateSurface(-2, w, h);
+
+	int x = _rect.left;
+	int y = _rect.top;
+	for (uint i = 0; i < _choices.size(); ++i) {
+		font->drawString(s, _choices[i], 0, y - _rect.top, s->w, color);
+		_rects[i].moveTo(x, y);
+		y += _rects[i].height();
+	}
+}
+
+void QTextChoice::onMouseMove(int x, int y) {
+	Common::Point p(x -_rect.left, y - _rect.top);
+	uint newChoice;
+	for (newChoice = 0; newChoice < _rects.size(); ++newChoice) {
+		if (_rects[newChoice].contains(p)) {
+			break;
+		}
+	}
+
+	if (newChoice != _activeChoice) {
+		Graphics::Surface *s = g_vm->resMgr()->loadBitmap(-2);
+		Common::ScopedPtr<Graphics::Font> font(Graphics::loadTTFFontFromArchive("FreeSans.ttf", 18));
+
+		if (_activeChoice < _choices.size()) {
+			font->drawString(s, _choices[_activeChoice], _rects[_activeChoice].left, _rects[_activeChoice].top, _rects[_activeChoice].width(), _choiceColor);
+		}
+
+		if (newChoice < _choices.size()) {
+			font->drawString(s, _choices[newChoice], _rects[newChoice].left, _rects[newChoice].top, _rects[newChoice].width(), _selectedColor);
+		}
+
+		_activeChoice = newChoice;
+	}
+}
+
+void QTextChoice::onClick(int x, int y) {
+	if (_activeChoice < _choices.size()) {
+		g_vm->getQSystem()->_mainInterface->_dialog.next(_activeChoice);
+	}
 }
 
 } // End of namespace Petka
diff --git a/engines/petka/objects/text.h b/engines/petka/objects/text.h
index 3771e401ca..c0030370fc 100644
--- a/engines/petka/objects/text.h
+++ b/engines/petka/objects/text.h
@@ -25,6 +25,9 @@
 
 #include "common/rect.h"
 #include "common/ustr.h"
+#include "common/str-array.h"
+
+#include "graphics/font.h"
 
 #include "petka/objects/object.h"
 
@@ -32,14 +35,56 @@ namespace Petka {
 
 class QText : public QVisibleObject {
 public:
-	QText(const Common::U32String &text, uint32 rgb);
+	QText(const Common::U32String &text, uint16 textColor, uint16 outlineColor);
 
 	void draw();
+	const Common::Rect &getRect();
 
-private:
+protected:
+	QText();
+
+	static void drawOutline(Graphics::Surface *surface, uint16 color);
+
+protected:
 	Common::Rect _rect;
 };
 
+class QTextPhrase : public QText {
+public:
+	QTextPhrase(const Common::U32String &phrase, uint16 textColor, uint16 outlineColor);
+
+	void draw() override;
+	void update(int time) override;
+	void onClick(int x, int y) override;
+
+private:
+	Common::U32String _phrase;
+	int _time;
+};
+
+class QTextDescription : public QText {
+public:
+	QTextDescription(const Common::U32String &desc, uint32 frame);
+
+	void draw() override;
+	void onClick(int x, int y) override;
+};
+
+class QTextChoice : public QText {
+public:
+	QTextChoice(const Common::Array<Common::U32String> &choices, uint16 color, uint16 selectedColor);
+
+	void onMouseMove(int x, int y) override;
+	void onClick(int x, int y) override;
+
+private:
+	Common::Array<Common::Rect> _rects;
+	Common::Array<Common::U32String> _choices;
+	uint _activeChoice;
+	uint16 _choiceColor;
+	uint16 _selectedColor;
+};
+
 } // End of namespace Petka
 
 #endif
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 1377cb3578..52ad028b72 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -22,6 +22,7 @@
 
 #include "common/ini-file.h"
 #include "common/substream.h"
+#include "common/system.h"
 
 #include "graphics/colormasks.h"
 
@@ -86,7 +87,7 @@ static void readObject(QMessageObject &obj, Common::SeekableReadStream &stream,
 	if (castIni.getKey(obj._name, "all", rgbString)) {
 		int r, g, b;
 		sscanf(rgbString.c_str(), "%d %d %d", &r, &g, &b);
-		obj._dialogColor = Graphics::RGBToColor<Graphics::ColorMasks<888> >((byte)r, (byte)g, (byte)b);
+		obj._dialogColor = g_vm->_system->getScreenFormat().RGBToColor((byte)r, (byte)g, (byte)b);
 	}
 }
 
@@ -108,7 +109,6 @@ bool QSystem::init() {
 	castIni.allowNonEnglishCharacters();
 	bgsIni.allowNonEnglishCharacters();
 
-
 	if (namesStream)
 		namesIni.loadFromStream(*namesStream); //fails because ini is broken for Russian letters
 	if (castStream)


Commit: 158a18b42b0994d5f14d46cadfac25e83f2f3410
    https://github.com/scummvm/scummvm/commit/158a18b42b0994d5f14d46cadfac25e83f2f3410
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-05-16T22:37:59+02:00

Commit Message:
PETKA: removed tracking sound by global variable

Changed paths:
    engines/petka/interfaces/dialog_interface.cpp
    engines/petka/interfaces/main.h
    engines/petka/video.cpp


diff --git a/engines/petka/interfaces/dialog_interface.cpp b/engines/petka/interfaces/dialog_interface.cpp
index 8f4445ace8..a9b612c91d 100644
--- a/engines/petka/interfaces/dialog_interface.cpp
+++ b/engines/petka/interfaces/dialog_interface.cpp
@@ -108,7 +108,6 @@ void DialogInterface::next(int choice) {
 			s->play(0);
 		}
 		_hasSound = s != nullptr;
-		g_trackedSound = s;
 		_talker = g_vm->getQSystem()->findObject(talkerId2);
 		if (talkerId != talkerId2) {
 			sendMsg(kSay);
diff --git a/engines/petka/interfaces/main.h b/engines/petka/interfaces/main.h
index f6c5fb0e6f..9fd7ad8e1c 100644
--- a/engines/petka/interfaces/main.h
+++ b/engines/petka/interfaces/main.h
@@ -35,8 +35,6 @@ struct BGInfo {
 
 class Sound;
 
-extern Sound *g_trackedSound;
-
 class InterfaceMain : public Interface {
 public:
 	InterfaceMain();
diff --git a/engines/petka/video.cpp b/engines/petka/video.cpp
index 18f33dbe1c..0980192135 100644
--- a/engines/petka/video.cpp
+++ b/engines/petka/video.cpp
@@ -51,10 +51,6 @@ void VideoSystem::update() {
 			interface->_objs[i]->update(time - _time);
 		}
 
-		if ((g_trackedSound && !g_trackedSound->isPlaying()) || !g_trackedSound) {
-			g_vm->getQSystem()->_mainInterface->_dialog.next(-1);
-		}
-
 		for (uint i = 0; i < interface->_objs.size(); ++i) {
 			interface->_objs[i]->updateZ();
 		}




More information about the Scummvm-git-logs mailing list