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/system.h"
24
25 #include "petka/petka.h"
26 #include "petka/q_manager.h"
27 #include "petka/q_system.h"
28 #include "petka/flc.h"
29 #include "petka/video.h"
30 #include "petka/sound.h"
31 #include "petka/objects/heroes.h"
32 #include "petka/interfaces/panel.h"
33
34 namespace Petka {
35
QObjectPetka()36 QObjectPetka::QObjectPetka()
37 : _walk(nullptr) {
38 _field7C = 1;
39 _reaction = nullptr;
40 _heroReaction = nullptr;
41 _sender = nullptr;
42 _isWalking = false;
43 _x = 574;
44 _y = 444;
45 _z = 200;
46 // _surfId = -5;
47 _surfH = 0;
48 _surfW = 0;
49 _k = 1.0;
50 }
51
processMessage(const QMessage & arg)52 void QObjectPetka::processMessage(const QMessage &arg) {
53 QMessage msg = arg;
54 if (msg.opcode == kImage) {
55 msg.opcode = kSet;
56 _imageId = msg.arg1;
57
58 _walk.reset(new Walk(_imageId + 10));
59
60 QObjectBG *room = g_vm->getQSystem()->_room;
61 if (room)
62 _walk->setBackground(g_vm->resMgr()->findResourceName(room->_resourceId));
63 }
64 if (msg.opcode == kSaid || msg.opcode == kStand) {
65 msg.opcode = kSet;
66 msg.arg1 = _imageId;
67 msg.arg2 = 1;
68 }
69 if (msg.opcode == kSay) {
70 msg.opcode = kSet;
71 msg.arg1 = _imageId + 1;
72 msg.arg2 = 1;
73 }
74 if (msg.opcode == kSet || msg.opcode == kPlay) {
75 _field7C = msg.arg1 == _imageId || msg.opcode == kPlay;
76 }
77 if (msg.opcode != kWalk) {
78 if (msg.opcode == kWalked && _heroReaction) {
79 QReaction *reaction = _heroReaction;
80 _heroReaction = nullptr;
81 _sender->processReaction(reaction);
82 }
83 QMessageObject::processMessage(msg);
84 if (msg.opcode == kSet || msg.opcode == kPlay) {
85 initSurface();
86 if (!g_vm->getQSystem()->_totalInit) {
87 setPos(Common::Point(_x_, _y_), false);
88 }
89 }
90 }
91 }
92
initSurface()93 void QObjectPetka::initSurface() {
94 QManager *resMgr = g_vm->resMgr();
95 FlicDecoder *flc = resMgr->getFlic(_resourceId);
96 _surfW = flc->getWidth() * _k;
97 _surfH = flc->getHeight() * _k;
98 }
99
walk(int x,int y)100 void QObjectPetka::walk(int x, int y) {
101 Common::Point walkPos(x, y);
102 if (!_isShown) {
103 setPos(walkPos, false);
104 return;
105 }
106
107
108 Common::Point currPos;
109 if (_isWalking) {
110 currPos = _walk->currPos();
111 } else {
112 currPos.x = _x_;
113 currPos.y = _y_;
114 }
115
116
117 if (currPos.sqrDist(walkPos) >= 25) {
118 _walk->init(currPos, walkPos);
119 _destX = x;
120 _destY = y;
121 _resourceId = _imageId + _walk->getSpriteId() + 10;
122 _isWalking = true;
123 _animate = true;
124
125 initSurface();
126 FlicDecoder *flc = g_vm->resMgr()->getFlic(_resourceId);
127 flc->setFrame(1);
128
129 sub_408940();
130
131 g_vm->videoSystem()->makeAllDirty();
132
133 _field7C = 0;
134 _time = 0;
135 _holdMessages = true;
136 }
137 }
138
draw()139 void QObjectPetka::draw() {
140 if (!_isShown || _resourceId == -1) {
141 return;
142 }
143
144 if (_animate && _startSound) {
145 if (_sound) {
146 _sound->play(_loopedSound);
147 if (_loopedSound) {
148 _sound = nullptr;
149 }
150 }
151 _startSound = false;
152 }
153
154 FlicDecoder *flc = g_vm->resMgr()->getFlic(_resourceId);
155 if (!flc) {
156 return;
157 }
158 Graphics::Surface *conv = flc->getCurrentFrame()->convertTo(g_system->getScreenFormat(), flc->getPalette());
159
160 Common::Rect srcRect(0, 0, conv->w, conv->h);
161 Common::Rect dstRect(0, 0, _surfW, _surfH);
162 dstRect.translate(_x - g_vm->getQSystem()->_xOffset, _y);
163
164 g_vm->videoSystem()->transBlitFrom(*conv, srcRect, dstRect, flc->getTransColor(conv->format));
165 conv->free();
166 delete conv;
167 }
168
setPos(Common::Point p,bool)169 void QObjectPetka::setPos(Common::Point p, bool) {
170 QSystem *sys = g_vm->getQSystem();
171
172 int xOff = sys->_xOffset;
173 Common::Rect dirty(_x - xOff, _y, _surfW + _x - xOff, _surfH + _y);
174 g_vm->videoSystem()->addDirtyRect(dirty);
175
176 p.y = MIN<int16>(p.y, 480);
177 FlicDecoder *flc = g_vm->resMgr()->getFlic(_resourceId);
178
179 _k = calcPerspective(p.y);
180
181 _surfH = flc->getHeight() * _k;
182 _surfW = flc->getWidth() * _k;
183
184 _x_ = p.x;
185 _y_ = p.y;
186
187 _x = p.x - _surfW / 2;
188 _y = p.y - _surfH;
189
190 recalcOffset();
191
192 g_vm->videoSystem()->addDirtyRect(Common::Rect(_x - xOff, _y, _surfW + _x - xOff, _surfH + _y));
193 }
194
calcPerspective(int y)195 double QObjectPetka::calcPerspective(int y) {
196 QSystem *qsys = g_vm->getQSystem();
197
198 y = MIN(y, 480);
199
200 const Perspective &pers = qsys->_room->_persp;
201 double res = (y - pers.y0) * pers.k / (pers.y1 - pers.y0);
202 if (res < 0.0)
203 res = 0.0;
204
205 if (res + pers.f0 > pers.f1)
206 return pers.f1;
207 return res + pers.f0;
208 }
209
updateWalk()210 void QObjectPetka::updateWalk() {
211 if (!_isWalking)
212 return;
213
214 int v = _walk->sub_423350();
215
216 switch (v) {
217 case 0: {
218 _isWalking = false;
219 setPos(Common::Point(_walk->destX, _walk->destY), false);
220
221 QMessage msg(_id, kSet, (uint16) _imageId, 1, 0, nullptr, 0);
222 if (_heroReaction) {
223 uint i;
224 for (i = 0; i < _heroReaction->messages.size(); ++i) {
225 if (_heroReaction->messages[i].opcode == kGoTo || _heroReaction->messages[i].opcode == kSetSeq) {
226 _resourceId = _imageId + _walk->getSpriteId() + 10;
227
228 FlicDecoder *flc = g_vm->resMgr()->getFlic(_resourceId);
229 flc->setFrame(1);
230
231 initSurface();
232
233 processMessage(QMessage(_id, kAnimate, 0, 0, 0, nullptr, 0));
234
235 _heroReaction->messages.push_back(msg);
236 _heroReaction->messages.push_back(QMessage(_id, kAnimate, 1, 0, 0, nullptr, 0));
237 break;
238 }
239 }
240 if (i == _heroReaction->messages.size())
241 processMessage(msg);
242 } else {
243 processMessage(msg);
244 }
245 _holdMessages = false;
246 g_vm->videoSystem()->makeAllDirty();
247 break;
248 }
249 case 1:
250 sub_408940();
251 break;
252 case 2: {
253 _resourceId = _walk->getSpriteId() + _imageId + 10;
254
255 FlicDecoder *flc = g_vm->resMgr()->getFlic(_resourceId);
256 flc->setFrame(1);
257
258 _time = flc->getDelay();
259
260 initSurface();
261 g_vm->videoSystem()->makeAllDirty();
262 break;
263 }
264 default:
265 break;
266 }
267 }
268
setReactionAfterWalk(uint index,QReaction * reaction,QMessageObject * sender,bool deleteReaction)269 void QObjectPetka::setReactionAfterWalk(uint index, QReaction *reaction, QMessageObject *sender, bool deleteReaction) {
270 _heroReaction = nullptr;
271
272 stopWalk();
273
274 QMessage msg(_id, kWalked, 0, 0, 0, sender, 0);
275 g_vm->getQSystem()->addMessage(msg);
276 _heroReaction = new QReaction();
277 _sender = sender;
278
279 for (uint i = index + 1; i < reaction->messages.size(); ++i) {
280 _heroReaction->messages.push_back(reaction->messages[i]);
281 }
282
283 if (deleteReaction) {
284 delete reaction;
285 }
286
287 }
288
stopWalk()289 void QObjectPetka::stopWalk() {
290 _isWalking = false;
291 _holdMessages = false;
292
293 Common::List<QMessage> &list = g_vm->getQSystem()->_messages;
294 for (Common::List<QMessage>::iterator it = list.begin(); it != list.end(); ++it) {
295 if (it->opcode == kWalked && it->objId == _id) {
296 it->objId = -1;
297 }
298
299 }
300
301 delete _heroReaction;
302 _heroReaction = nullptr;
303
304 if (!_field7C) {
305 Common::Point p = _walk->sub_4234B0();
306
307 _x = p.x;
308 _y = p.y;
309
310 QMessage msg(_id, kSet, (uint16)_imageId, 1, 0, nullptr, 0);
311 processMessage(msg);
312 }
313 }
314
update(int time)315 void QObjectPetka::update(int time) {
316 if (!_animate || !_isShown)
317 return;
318 if (_isWalking)
319 _time += time * (g_vm->getQSystem()->_panelInterface->getHeroSpeed() + 50) / 50;
320 else
321 _time += time;
322 FlicDecoder *flc = g_vm->resMgr()->getFlic(_resourceId);
323 if (flc && flc->getFrameCount() != 1) {
324 if (_sound) {
325 Common::Rect bounds = flc->getBounds();
326 _sound->setBalance(bounds.left + bounds.width() / 2 - g_vm->getQSystem()->_xOffset, 640);
327 }
328
329 while (_time >= (int)flc->getDelay()) {
330 if (_sound && flc->getCurFrame() == 0) {
331 _startSound = true;
332 }
333 flc->setFrame(-1);
334 if (flc->getCurFrame() == (int32)flc->getFrameCount() - 1) {
335 g_vm->getQSystem()->addMessage(_id, kEnd, _resourceId, 0, 0, 0, 0);
336 }
337 if (flc->getCurFrame() + 1 == (int32)flc->getFrameCount() / 2) {
338 g_vm->getQSystem()->addMessage(_id, kHalf, _resourceId, 0, 0, 0, 0);
339 }
340
341 if (_field7C && flc->getCurFrame() == 0)
342 _time = -10000;
343
344 updateWalk();
345 flc = g_vm->resMgr()->getFlic(_resourceId);
346
347 _surfH = flc->getHeight() * _k;
348 _surfW = flc->getWidth() * _k;
349
350 _time -= flc->getDelay();
351
352 g_vm->videoSystem()->addDirtyRect(Common::Rect(_x, _y, _surfW + _x, _surfH + _y));
353 }
354 }
355 }
356
isInPoint(Common::Point p)357 bool QObjectPetka::isInPoint(Common::Point p) {
358 if (!_isActive)
359 return false;
360 FlicDecoder *flc = g_vm->resMgr()->getFlic(_resourceId);
361 const Graphics::Surface *flcSurface = flc->getCurrentFrame();
362 Common::Rect bounds(_surfW, _surfH);
363 Graphics::ManagedSurface s(_surfW, _surfH, flcSurface->format);
364 s.transBlitFrom(*flcSurface, Common::Rect(0, 0, flcSurface->w, flcSurface->h), bounds);
365 p.x -= _x;
366 p.y -= _y;
367 if (!bounds.contains(p.x, p.y))
368 return false;
369 return *(uint16 *)s.getBasePtr(p.x, p.y) != 0;
370 }
371
updateZ()372 void QObjectPetka::updateZ() {
373 if (_animate && _isShown && _updateZ) {
374 FlicDecoder *flc = g_vm->resMgr()->getFlic(_resourceId);
375 if (_isWalking) {
376 _z = _walk->currPos().y;
377 } else {
378 _z = _y + flc->getHeight() * _k;
379 }
380 }
381 }
382
sub_408940()383 void QObjectPetka::sub_408940() {
384 FlicDecoder *flc = g_vm->resMgr()->getFlic(_resourceId);
385 QSystem *sys = g_vm->getQSystem();
386
387 int xOff = sys->_xOffset;
388 Common::Rect dirty(_x - xOff, _y, _surfW + _x - xOff, _surfH + _y);
389 g_vm->videoSystem()->addDirtyRect(dirty);
390
391 Common::Point currPos = _walk->currPos();
392 _k = calcPerspective(currPos.y);
393 _surfW = flc->getWidth() * _k;
394 _surfH = flc->getHeight() * _k;
395
396 Common::Point p = _walk->sub_4234B0();
397 _x = p.x;
398 _y = p.y;
399
400 _x_ = currPos.x;
401 _y_ = currPos.y;
402
403 recalcOffset();
404
405 g_vm->videoSystem()->addDirtyRect(Common::Rect(_x - xOff, _y, _surfW + _x - xOff, _surfH + _y));
406 }
407
recalcOffset()408 void QObjectPetka::recalcOffset() {
409 QSystem *sys = g_vm->getQSystem();
410 int xOff = sys->_xOffset;
411
412 if (_x_ < xOff + 160 || _x_ > xOff + 480) {
413 sys->_reqOffset = _x_ - 320;
414 }
415 sys->_reqOffset = CLIP<int>(sys->_reqOffset, 0, sys->_sceneWidth - 640);
416 }
417
QObjectChapayev()418 QObjectChapayev::QObjectChapayev() {
419 _x = 477;
420 _y = 350;
421 // _surfId = -6;
422 }
423
424 }
425