1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "common/config-manager.h"
24 #include "common/debug-channels.h"
25 #include "common/error.h"
26 #include "common/events.h"
27 #include "common/ini-file.h"
28 #include "common/stream.h"
29 #include "common/system.h"
30 #include "common/file.h"
31
32 #include "engines/advancedDetector.h"
33 #include "engines/util.h"
34
35 #include "graphics/surface.h"
36
37 #include "video/avi_decoder.h"
38
39 #include "petka/file_mgr.h"
40 #include "petka/video.h"
41 #include "petka/sound.h"
42 #include "petka/petka.h"
43 #include "petka/q_manager.h"
44 #include "petka/interfaces/interface.h"
45 #include "petka/q_system.h"
46 #include "petka/big_dialogue.h"
47
48 namespace Petka {
49
50 PetkaEngine *g_vm;
51
PetkaEngine(OSystem * system,const ADGameDescription * desc)52 PetkaEngine::PetkaEngine(OSystem *system, const ADGameDescription *desc)
53 : Engine(system), _console(nullptr), _fileMgr(nullptr), _resMgr(nullptr),
54 _qsystem(nullptr), _vsys(nullptr), _desc(desc), _videoDec(nullptr), _rnd("petka") {
55
56 _part = 0xFF;
57 _chapter = 0;
58 _shouldChangePart = false;
59 _nextPart = 0;
60 _saveSlot = -1;
61 g_vm = this;
62
63 debug("PetkaEngine::ctor");
64 }
65
~PetkaEngine()66 PetkaEngine::~PetkaEngine() {
67 debug("PetkaEngine::dtor");
68 }
69
run()70 Common::Error PetkaEngine::run() {
71 debug("PetkaEngine::run");
72 const Graphics::PixelFormat format(2, 5, 6, 5, 0, 11, 5, 0, 0);
73 initGraphics(640, 480, &format);
74
75 const char *const videos[] = {"buka.avi", "skif.avi", "adv.avi"};
76 for (uint i = 0; i < sizeof(videos) / sizeof(char *); ++i) {
77 Common::ScopedPtr<Common::File> file(new Common::File);
78 if (file->open(videos[i])) {
79 playVideo(file.release());
80 } else {
81 debugC(kPetkaDebugResources, "Video file %s can't be opened", videos[i]);
82 }
83 }
84
85 _console.reset(new Console(this));
86 _fileMgr.reset(new FileMgr());
87 _soundMgr.reset(new SoundMgr(*this));
88 _vsys.reset(new VideoSystem(*this));
89 _resMgr.reset(new QManager(*this));
90
91 loadPart(isDemo() ? 1 : 0);
92
93 if (ConfMan.hasKey("save_slot")) {
94 loadGameState(ConfMan.getInt("save_slot"));
95 }
96
97 while (!shouldQuit()) {
98 Common::Event event;
99 while (_eventMan->pollEvent(event)) {
100 switch (event.type) {
101 case Common::EVENT_QUIT:
102 case Common::EVENT_RETURN_TO_LAUNCHER:
103 return Common::kNoError;
104 default:
105 _qsystem->onEvent(event);
106 break;
107 }
108 }
109 _qsystem->update();
110
111 if (_shouldChangePart) {
112 loadPart(_nextPart);
113 if (_saveSlot != -1)
114 loadGameState(_saveSlot);
115 _saveSlot = -1;
116 _shouldChangePart = false;
117 _vsys->makeAllDirty();
118 }
119
120 _vsys->update();
121 _system->delayMillis(20);
122 }
123 return Common::kNoError;
124 }
125
openFile(const Common::String & name,bool addCurrentPath)126 Common::SeekableReadStream *PetkaEngine::openFile(const Common::String &name, bool addCurrentPath) {
127 if (name.empty()) {
128 return nullptr;
129 }
130 return _fileMgr->getFileStream(addCurrentPath ? _currentPath + name : name);
131 }
132
loadStores()133 void PetkaEngine::loadStores() {
134 debug("PetkaEngine::loadStores");
135 _fileMgr->closeAll();
136
137 _fileMgr->openStore("patch.str");
138 _fileMgr->openStore("main.str");
139
140 Common::INIFile parts;
141 Common::ScopedPtr<Common::SeekableReadStream> stream(_fileMgr->getFileStream("PARTS.INI"));
142
143 if (!stream || !parts.loadFromStream(*stream)) {
144 debugC(kPetkaDebugResources, "PARTS.INI opening failed");
145 return;
146 }
147
148 const char *const names[] = {"Background", "Flics", "Wav", "SFX", "Music", "Speech"};
149 const Common::String section = Common::String::format("Part %d", _part);
150
151 parts.getKey("CurrentPath", section, _currentPath);
152 parts.getKey("PathSpeech", section, _speechPath);
153
154 Common::String storeName;
155 for (uint i = 0; i < sizeof(names) / sizeof(char *); ++i) {
156 parts.getKey(names[i], section, storeName);
157 _fileMgr->openStore(storeName);
158 }
159
160 parts.getKey("Chapter", Common::String::format("Part %d Chapter %d", _part, _chapter), _chapterStoreName);
161 _fileMgr->openStore(_chapterStoreName);
162 }
163
getQSystem() const164 QSystem *PetkaEngine::getQSystem() const {
165 return _qsystem.get();
166 }
167
getRnd()168 Common::RandomSource &PetkaEngine::getRnd() {
169 return _rnd;
170 }
171
playVideo(Common::SeekableReadStream * stream)172 void PetkaEngine::playVideo(Common::SeekableReadStream *stream) {
173 PauseToken token = pauseEngine();
174 Graphics::PixelFormat fmt = _system->getScreenFormat();
175
176 _videoDec.reset(new Video::AVIDecoder);
177 if (!_videoDec->loadStream(stream)) {
178 _videoDec.reset();
179 return;
180 }
181
182 _videoDec->start();
183
184 while (!_videoDec->endOfVideo() && !shouldQuit()) {
185 Common::Event event;
186 while (_eventMan->pollEvent(event)) {
187 switch (event.type) {
188 case Common::EVENT_RETURN_TO_LAUNCHER:
189 case Common::EVENT_QUIT:
190 case Common::EVENT_LBUTTONDOWN:
191 case Common::EVENT_RBUTTONDOWN:
192 case Common::EVENT_KEYDOWN:
193 _videoDec.reset();
194 return;
195 default:
196 break;
197 }
198 }
199
200 if (_videoDec->needsUpdate()) {
201 const Graphics::Surface *frame = _videoDec->decodeNextFrame();
202 if (frame) {
203 Common::ScopedPtr<Graphics::Surface, Graphics::SurfaceDeleter> f(frame->convertTo(fmt));
204 _system->copyRectToScreen(f->getPixels(), f->pitch, 0, 0, f->w, f->h);
205 }
206 }
207
208 _system->updateScreen();
209 _system->delayMillis(15);
210 }
211
212 _videoDec.reset();
213 }
214
isDemo() const215 bool PetkaEngine::isDemo() const {
216 return _desc->flags & ADGF_DEMO;
217 }
218
isPetka2() const219 bool PetkaEngine::isPetka2() const {
220 return strcmp(_desc->gameId, "petka2") == 0;
221 }
222
soundMgr() const223 SoundMgr *PetkaEngine::soundMgr() const {
224 return _soundMgr.get();
225 }
226
resMgr() const227 QManager *PetkaEngine::resMgr() const {
228 return _resMgr.get();
229 }
230
videoSystem() const231 VideoSystem *PetkaEngine::videoSystem() const {
232 return _vsys.get();
233 }
234
getPart()235 byte PetkaEngine::getPart() {
236 return _part;
237 }
238
loadPart(byte part)239 void PetkaEngine::loadPart(byte part) {
240 debug("PetkaEngine::loadPart %d", part);
241 _part = part;
242
243 _soundMgr->removeAll();
244 loadStores();
245
246 _resMgr.reset(new QManager(*this));
247 _resMgr->init();
248 _dialogMan.reset(new BigDialogue(*this));
249 _qsystem.reset(new QSystem(*this));
250 _qsystem->init();
251 }
252
loadPartAtNextFrame(byte part)253 void PetkaEngine::loadPartAtNextFrame(byte part) {
254 _shouldChangePart = true;
255 _nextPart = part;
256 _chapter = 1;
257 _saveSlot = -1;
258 }
259
loadChapter(byte chapter)260 void PetkaEngine::loadChapter(byte chapter) {
261 Common::INIFile parts;
262 Common::ScopedPtr<Common::SeekableReadStream> stream(_fileMgr->getFileStream("PARTS.INI"));
263
264 if (!stream || !parts.loadFromStream(*stream)) {
265 debugC(kPetkaDebugResources, "PARTS.INI opening failed");
266 return;
267 }
268
269 _fileMgr->closeStore(_chapterStoreName);
270
271 const Common::String section = Common::String::format("Part %d Chapter %d", _part, chapter);
272 parts.getKey("Chapter", section, _chapterStoreName);
273 if (_chapterStoreName.empty())
274 return;
275
276 _fileMgr->openStore(_chapterStoreName);
277
278 Common::ScopedPtr<Common::SeekableReadStream> namesStream(openFile("Names.ini", true));
279 Common::ScopedPtr<Common::SeekableReadStream> castStream(openFile("Cast.ini", true));
280
281 Common::INIFile namesIni;
282 Common::INIFile castIni;
283
284 namesIni.allowNonEnglishCharacters();
285 castIni.allowNonEnglishCharacters();
286
287 if (namesStream)
288 namesIni.loadFromStream(*namesStream);
289 if (castStream)
290 castIni.loadFromStream(*castStream);
291
292 for (uint i = 0; i < _qsystem->_allObjects.size(); ++i) {
293 QMessageObject *obj = _qsystem->_allObjects[i];
294 obj->readInisData(namesIni, castIni, nullptr);
295 }
296 _chapter = chapter;
297 }
298
getBigDialogue() const299 BigDialogue *PetkaEngine::getBigDialogue() const {
300 return _dialogMan.get();
301 }
302
getSpeechPath()303 const Common::String &PetkaEngine::getSpeechPath() {
304 return _speechPath;
305 }
306
hasFeature(EngineFeature f) const307 bool PetkaEngine::hasFeature(EngineFeature f) const {
308 return
309 f == kSupportsReturnToLauncher ||
310 f == kSupportsLoadingDuringRuntime ||
311 f == kSupportsSavingDuringRuntime ||
312 f == kSupportsChangingOptionsDuringRuntime;
313 }
314
pauseEngineIntern(bool pause)315 void PetkaEngine::pauseEngineIntern(bool pause) {
316 if (!pause && _vsys)
317 _vsys->updateTime();
318
319 if (_videoDec)
320 _videoDec->pauseVideo(pause);
321
322 Engine::pauseEngineIntern(pause);
323 }
324
325 } // End of namespace Petka
326