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/ini-file.h"
24 #include "common/substream.h"
25 #include "common/system.h"
26
27 #include "graphics/thumbnail.h"
28
29 #include "petka/petka.h"
30 #include "petka/interfaces/startup.h"
31 #include "petka/interfaces/main.h"
32 #include "petka/interfaces/save_load.h"
33 #include "petka/interfaces/sequence.h"
34 #include "petka/interfaces/panel.h"
35 #include "petka/interfaces/map.h"
36 #include "petka/objects/object_cursor.h"
37 #include "petka/objects/object_case.h"
38 #include "petka/objects/object_star.h"
39 #include "petka/objects/heroes.h"
40 #include "petka/big_dialogue.h"
41 #include "petka/q_system.h"
42 #include "petka/video.h"
43 #include "petka/q_manager.h"
44 #include "petka/flc.h"
45
46 namespace Petka {
47
QSystem(PetkaEngine & vm)48 QSystem::QSystem(PetkaEngine &vm)
49 : _vm(vm), _mainInterface(nullptr), _currInterface(nullptr), _prevInterface(nullptr),
50 _totalInit(false), _sceneWidth(640), _room(nullptr), _xOffset(0), _reqOffset(0) {}
51
~QSystem()52 QSystem::~QSystem() {
53 for (uint i = 0; i < _allObjects.size(); ++i) {
54 delete _allObjects[i];
55 }
56 }
57
init()58 bool QSystem::init() {
59 Common::ScopedPtr<Common::SeekableReadStream> stream(_vm.openFile("script.dat", true));
60 if (!stream)
61 return false;
62 Common::ScopedPtr<Common::SeekableReadStream> namesStream(_vm.openFile("Names.ini", true));
63 Common::ScopedPtr<Common::SeekableReadStream> castStream(_vm.openFile("Cast.ini", true));
64 Common::ScopedPtr<Common::SeekableReadStream> bgsStream(_vm.openFile("BGs.ini", true));
65
66 Common::INIFile namesIni;
67 Common::INIFile castIni;
68 Common::INIFile bgsIni;
69
70 namesIni.allowNonEnglishCharacters();
71 castIni.allowNonEnglishCharacters();
72 bgsIni.allowNonEnglishCharacters();
73
74 if (namesStream)
75 namesIni.loadFromStream(*namesStream);
76 if (castStream)
77 castIni.loadFromStream(*castStream);
78 if (bgsStream)
79 bgsIni.loadFromStream(*bgsStream);
80
81 uint32 objsCount = stream->readUint32LE();
82 uint32 bgsCount = stream->readUint32LE();
83 _allObjects.reserve(objsCount + bgsCount + 3);
84 for (uint i = 0; i < objsCount + bgsCount; ++i) {
85 QMessageObject *obj = nullptr;
86 if (i == 0) {
87 obj = new QObjectPetka;
88 } else if (i == 1) {
89 obj = new QObjectChapayev;
90 } else if (i < objsCount) {
91 obj = new QObject;
92 } else {
93 obj = new QObjectBG;
94 }
95 obj->readScriptData(*stream);
96 obj->readInisData(namesIni, castIni, &bgsIni);
97 _allObjects.push_back(obj);
98 }
99
100 _allObjects.push_back(new QObjectCursor);
101 _allObjects.push_back(new QObjectCase);
102 _allObjects.push_back(new QObjectStar);
103
104 _mainInterface.reset(new InterfaceMain());
105 _startupInterface.reset(new InterfaceStartup());
106 _saveLoadInterface.reset(new InterfaceSaveLoad());
107 _sequenceInterface.reset(new InterfaceSequence());
108 _panelInterface.reset(new InterfacePanel());
109 _mapInterface.reset(new InterfaceMap());
110
111 if (_vm.getPart() == 0) {
112 _prevInterface = _currInterface = _startupInterface.get();
113 } else {
114 _prevInterface = _currInterface = _mainInterface.get();
115 }
116
117 _totalInit = true;
118
119 addMessageForAllObjects(kTotalInit);
120 update();
121
122 _totalInit = false;
123
124 _currInterface->start(0);
125 return true;
126 }
127
addMessage(const QMessage & msg)128 void QSystem::addMessage(const QMessage &msg) {
129 _messages.push_back(msg);
130 }
131
addMessage(uint16 objId,uint16 opcode,int16 arg1,int16 arg2,int16 arg3,int32 unk,QMessageObject * sender)132 void QSystem::addMessage(uint16 objId, uint16 opcode, int16 arg1, int16 arg2, int16 arg3, int32 unk, QMessageObject *sender) {
133 _messages.push_back(QMessage(objId, opcode, arg1, arg2, arg3, sender, unk));
134 }
135
addMessageForAllObjects(uint16 opcode,int16 arg1,int16 arg2,int16 arg3,int32 unk,QMessageObject * sender)136 void QSystem::addMessageForAllObjects(uint16 opcode, int16 arg1, int16 arg2, int16 arg3, int32 unk, QMessageObject *sender) {
137 for (uint i = 0; i < _allObjects.size(); ++i) {
138 _messages.push_back(QMessage(_allObjects[i]->_id, opcode, arg1, arg2, arg3, sender, unk));
139 }
140 }
141
findObject(int16 id)142 QMessageObject *QSystem::findObject(int16 id) {
143 for (uint i = 0; i < _allObjects.size(); ++i) {
144 if (_allObjects[i]->_id == id)
145 return _allObjects[i];
146 }
147 return nullptr;
148 }
149
findObject(const Common::String & name)150 QMessageObject *QSystem::findObject(const Common::String &name) {
151 for (uint i = 0; i < _allObjects.size(); ++i) {
152 if (_allObjects[i]->_name == name)
153 return _allObjects[i];
154 }
155 return nullptr;
156 }
157
update()158 void QSystem::update() {
159 for (Common::List<QMessage>::iterator it = _messages.begin(); it != _messages.end();) {
160 QMessageObject *obj = findObject(it->objId);
161 if (obj && !obj->_holdMessages) {
162 obj->processMessage(*it);
163 it = _messages.erase(it);
164 } else {
165 ++it;
166 }
167 }
168 }
169
togglePanelInterface()170 void QSystem::togglePanelInterface() {
171 if (_currInterface != _startupInterface.get() && getStar()->_isActive) {
172 getCase()->show(0);
173 if (_currInterface == _panelInterface.get()) {
174 _currInterface->stop();
175 } else if (_currInterface == _mainInterface.get()) {
176 _panelInterface->start(0);
177 }
178 }
179 }
180
toggleMapInterface()181 void QSystem::toggleMapInterface() {
182 if (_currInterface != _startupInterface.get() && getStar()->_isActive && _room->_showMap) {
183 getCase()->show(false);
184 if (_currInterface == _mapInterface.get()) {
185 _currInterface->stop();
186 } else if (_currInterface == _mainInterface.get()) {
187 _currInterface->setText(Common::U32String(), 0, 0);
188 _mapInterface->start(0);
189 }
190 }
191 }
192
setCursorAction(int action)193 void QSystem::setCursorAction(int action) {
194 if (getStar()->_isActive && _currInterface == _mainInterface.get()) {
195 if (action != kActionObjUseChapayev || getChapay()->_isShown) {
196 getCursor()->setAction(action);
197
198 // original bug fix
199 _mainInterface->onMouseMove(g_system->getEventManager()->getMousePos());
200 }
201 }
202 }
203
readString(Common::ReadStream * s)204 static Common::String readString(Common::ReadStream *s) {
205 Common::String string;
206 uint32 len = s->readUint32LE();
207 char *buffer = (char *)malloc(len);
208 s->read(buffer, len);
209 string = Common::String(buffer, len);
210 free(buffer);
211 return string;
212 }
213
writeString(Common::WriteStream * s,const Common::String & string)214 static void writeString(Common::WriteStream *s, const Common::String &string) {
215 s->writeUint32LE(string.size());
216 s->write(string.c_str(), string.size());
217 }
218
load(Common::ReadStream * s)219 void QSystem::load(Common::ReadStream *s) {
220 uint count = s->readUint32LE();
221 for (uint i = 0; i < count; ++i) {
222 QMessageObject *obj = findObject(readString(s));
223 obj->_holdMessages = s->readUint32LE();
224 obj->_status = s->readUint32LE();
225 obj->_resourceId = s->readUint32LE();
226 /*obj->_z =*/ s->readUint32LE();
227 obj->_x = s->readUint32LE();
228 obj->_y = s->readUint32LE();
229 obj->_isShown = s->readUint32LE();
230 obj->_isActive = s->readUint32LE();
231 obj->_animate = s->readUint32LE();
232 }
233
234 uint itemSize = s->readUint32LE();
235 QObjectCase *objCase = getCase();
236 objCase->_items.clear();
237 for (uint i = 0; i < itemSize; ++i) {
238 objCase->_items.push_back(s->readSint32LE());
239 }
240
241 _room = (QObjectBG *)findObject(readString(s));
242 if (_room) {
243 _mainInterface->loadRoom(_room->_id, true);
244 }
245
246 QObjectPetka *petka = getPetka();
247 QObjectChapayev *chapayev = getChapay();
248
249 Common::Point pos;
250 pos.x = s->readSint32LE();
251 pos.y = s->readSint32LE();
252
253 petka->setPos(pos, false);
254
255 _xOffset = CLIP<int>(pos.x - 320, 0, _sceneWidth - 640);
256
257 pos.x = s->readSint32LE();
258 pos.y = s->readSint32LE();
259
260 chapayev->setPos(pos, false);
261
262 _vm.getBigDialogue()->load(s);
263
264 QObjectCursor *cursor = getCursor();
265 cursor->_resourceId = s->readUint32LE();
266 cursor->_actionType = s->readUint32LE();
267 int invObjId = s->readSint32LE();
268 if (invObjId != -1) {
269 cursor->_invObj = findObject(invObjId);
270 } else {
271 cursor->_invObj = nullptr;
272 }
273
274 int imageId = s->readSint32LE();
275 if (imageId != -1 && !(imageId % 100)) {
276 addMessage(petka->_id, kImage, imageId, 1);
277 }
278
279 imageId = s->readSint32LE();
280 if (imageId != -1 && !(imageId % 100)) {
281 addMessage(chapayev->_id, kImage, imageId, 1);
282 }
283
284 getStar()->_isActive = true;
285
286 _vm.videoSystem()->makeAllDirty();
287 }
288
save(Common::WriteStream * s)289 void QSystem::save(Common::WriteStream *s) {
290 s->writeUint32LE(_allObjects.size() - 3);
291 for (uint i = 0; i < _allObjects.size() - 3; ++i) {
292 writeString(s, _allObjects[i]->_name);
293 s->writeUint32LE(_allObjects[i]->_holdMessages);
294 s->writeUint32LE(_allObjects[i]->_status);
295 s->writeUint32LE(_allObjects[i]->_resourceId);
296 s->writeUint32LE(_allObjects[i]->_z);
297 s->writeUint32LE(_allObjects[i]->_x);
298 s->writeUint32LE(_allObjects[i]->_y);
299 s->writeUint32LE(_allObjects[i]->_isShown);
300 s->writeUint32LE(_allObjects[i]->_isActive);
301 s->writeUint32LE(_allObjects[i]->_animate);
302 }
303
304 QObjectCase *objCase = getCase();
305 s->writeUint32LE(objCase->_items.size());
306 for (uint i = 0; i < objCase->_items.size(); ++i) {
307 s->writeSint32LE(objCase->_items[i]);
308 }
309
310 writeString(s, _room->_name);
311
312 QObjectPetka *petka = getPetka();
313 QObjectChapayev *chapayev = getChapay();
314
315 FlicDecoder *petkaFlc = _vm.resMgr()->getFlic(petka->_resourceId);
316 FlicDecoder *chapayFlc = _vm.resMgr()->getFlic(chapayev->_resourceId);
317
318 s->writeSint32LE(petka->_x - petkaFlc->getCurrentFrame()->w * petka->_k * -0.5);
319 s->writeSint32LE(petka->_y + petkaFlc->getCurrentFrame()->h * petka->_k);
320
321 s->writeSint32LE(chapayev->_x - chapayFlc->getCurrentFrame()->w * chapayev->_k * -0.5);
322 s->writeSint32LE(chapayev->_y + chapayFlc->getCurrentFrame()->h * chapayev->_k);
323
324 _vm.getBigDialogue()->save(s);
325
326 QObjectCursor *cursor = getCursor();
327 s->writeUint32LE(cursor->_resourceId);
328 s->writeUint32LE(cursor->_actionType);
329 if (cursor->_invObj) {
330 s->writeSint32LE(cursor->_invObj->_id);
331 } else {
332 s->writeSint32LE(-1);
333 }
334
335 s->writeSint32LE(petka->_imageId);
336 s->writeSint32LE(chapayev->_imageId);
337 }
338
getPetka() const339 QObjectPetka *QSystem::getPetka() const {
340 return (QObjectPetka *)_allObjects[0];
341 }
342
getChapay() const343 QObjectChapayev *QSystem::getChapay() const {
344 return (QObjectChapayev *)_allObjects[1];
345 }
346
getCursor() const347 QObjectCursor *QSystem::getCursor() const {
348 return (QObjectCursor *)_allObjects[_allObjects.size() - 3];
349 }
350
getCase() const351 QObjectCase *QSystem::getCase() const {
352 return (QObjectCase *)_allObjects[_allObjects.size() - 2];
353 }
354
getStar() const355 QObjectStar *QSystem::getStar() const {
356 return (QObjectStar *)_allObjects.back();
357 }
358
onEvent(const Common::Event & event)359 void QSystem::onEvent(const Common::Event &event) {
360 switch (event.type) {
361 case Common::EVENT_MOUSEMOVE: {
362 Common::Point p = event.mouse;
363 p.x += _xOffset;
364 _currInterface->onMouseMove(p);
365 break;
366 }
367 case Common::EVENT_LBUTTONDOWN: {
368 Common::Point p = event.mouse;
369 p.x += _xOffset;
370 _currInterface->onLeftButtonDown(p);
371 break;
372 }
373 case Common::EVENT_RBUTTONDOWN: {
374 Common::Point p = event.mouse;
375 p.x += _xOffset;
376 _currInterface->onRightButtonDown(p);
377 break;
378 }
379 case Common::EVENT_KEYDOWN:
380 switch (event.kbd.keycode) {
381 case Common::KEYCODE_1:
382 case Common::KEYCODE_l:
383 setCursorAction(kActionLook);
384 break;
385 case Common::KEYCODE_2:
386 case Common::KEYCODE_w:
387 setCursorAction(kActionWalk);
388 break;
389 case Common::KEYCODE_3:
390 case Common::KEYCODE_g:
391 setCursorAction(kActionTake);
392 break;
393 case Common::KEYCODE_4:
394 case Common::KEYCODE_u:
395 setCursorAction(kActionUse);
396 break;
397 case Common::KEYCODE_5:
398 case Common::KEYCODE_t:
399 setCursorAction(kActionTalk);
400 break;
401 case Common::KEYCODE_6:
402 case Common::KEYCODE_c:
403 setCursorAction(kActionObjUseChapayev);
404 break;
405 case Common::KEYCODE_i:
406 toggleCase();
407 break;
408 case Common::KEYCODE_TAB:
409 case Common::KEYCODE_m:
410 toggleMapInterface();
411 break;
412 case Common::KEYCODE_o:
413 togglePanelInterface();
414 break;
415 case Common::KEYCODE_ESCAPE:
416 goPrevInterface();
417 break;
418 case Common::KEYCODE_F2: {
419 InterfaceSaveLoad::saveScreen();
420 startSaveLoad(kSaveMode);
421 break;
422 }
423 case Common::KEYCODE_F3:
424 startSaveLoad(kLoadMode);
425 break;
426 case Common::KEYCODE_r:
427 if (event.kbd.flags & Common::KBD_ALT) {
428 _mainInterface->_dialog.fixCursor(); // Buggy in original
429 }
430 break;
431 default:
432 break;
433 }
434 default:
435 break;
436 }
437 }
438
goPrevInterface()439 void QSystem::goPrevInterface() {
440 getCase()->show(false);
441 if (_currInterface != _startupInterface.get() && _currInterface != _sequenceInterface.get())
442 _currInterface->stop();
443 }
444
toggleCase()445 void QSystem::toggleCase() {
446 if (_currInterface == _mainInterface.get() && getStar()->_isActive) {
447 QObjectCase *obj = getCase();
448 obj->show(obj->_isShown == 0);
449 }
450 }
451
startSaveLoad(int id)452 void QSystem::startSaveLoad(int id) {
453 if (_currInterface == _mainInterface.get() && getStar()->_isActive) {
454 _saveLoadInterface->start(id);
455 }
456 }
457
458 }
459