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 "lastexpress/game/beetle.h"
24
25 #include "lastexpress/game/inventory.h"
26 #include "lastexpress/game/logic.h"
27 #include "lastexpress/game/scenes.h"
28 #include "lastexpress/game/state.h"
29
30 #include "lastexpress/lastexpress.h"
31 #include "lastexpress/resource.h"
32
33 namespace LastExpress {
34
Beetle(LastExpressEngine * engine)35 Beetle::Beetle(LastExpressEngine *engine) : _engine(engine), _data(NULL) {}
36
~Beetle()37 Beetle::~Beetle() {
38 SAFE_DELETE(_data);
39
40 // Free passed pointers
41 _engine = NULL;
42 }
43
load()44 void Beetle::load() {
45 // Only load in chapter 2 & 3
46 if (getProgress().chapter != kChapter2 && getProgress().chapter != kChapter3)
47 return;
48
49 // Already loaded
50 if (_data)
51 return;
52
53 // Do not load if beetle is in the wrong location
54 if (getInventory()->get(kItemBeetle)->location != kObjectLocation3)
55 return;
56
57 ///////////////////////
58 // Load Beetle data
59 _data = new BeetleData();
60
61 // Load sequences
62 _data->sequences.push_back(loadSequence("BW000.seq")); // 0
63 _data->sequences.push_back(loadSequence("BT000045.seq"));
64 _data->sequences.push_back(loadSequence("BT045000.seq"));
65 _data->sequences.push_back(loadSequence("BW045.seq"));
66 _data->sequences.push_back(loadSequence("BT045090.seq"));
67 _data->sequences.push_back(loadSequence("BT090045.seq")); // 5
68 _data->sequences.push_back(loadSequence("BW090.seq"));
69 _data->sequences.push_back(loadSequence("BT090135.seq"));
70 _data->sequences.push_back(loadSequence("BT135090.seq"));
71 _data->sequences.push_back(loadSequence("BW135.seq"));
72 _data->sequences.push_back(loadSequence("BT135180.seq")); // 10
73 _data->sequences.push_back(loadSequence("BT180135.seq"));
74 _data->sequences.push_back(loadSequence("BW180.seq"));
75 _data->sequences.push_back(loadSequence("BT180225.seq"));
76 _data->sequences.push_back(loadSequence("BT225180.seq"));
77 _data->sequences.push_back(loadSequence("BW225.seq")); // 15
78 _data->sequences.push_back(loadSequence("BT225270.seq"));
79 _data->sequences.push_back(loadSequence("BT270225.seq"));
80 _data->sequences.push_back(loadSequence("BW270.seq"));
81 _data->sequences.push_back(loadSequence("BT270315.seq"));
82 _data->sequences.push_back(loadSequence("BT315270.seq")); // 20
83 _data->sequences.push_back(loadSequence("BW315.seq"));
84 _data->sequences.push_back(loadSequence("BT315000.seq"));
85 _data->sequences.push_back(loadSequence("BT000315.seq"));
86 _data->sequences.push_back(loadSequence("BA135.seq"));
87 _data->sequences.push_back(loadSequence("BL045.seq")); // 25
88 _data->sequences.push_back(loadSequence("BL000.seq"));
89 _data->sequences.push_back(loadSequence("BL315.seq"));
90 _data->sequences.push_back(loadSequence("BL180.seq"));
91
92 // Init fields
93 _data->field_74 = 0;
94
95 // Check that all sequences are loaded properly
96 _data->isLoaded = true;
97 for (uint i = 0; i < _data->sequences.size(); i++) {
98 if (!_data->sequences[i]->isLoaded()) {
99 _data->isLoaded = false;
100 break;
101 }
102 }
103
104 _data->field_D9 = 10;
105 _data->coordOffset = 5;
106 _data->coordY = 178;
107 _data->currentSequence = 0;
108 _data->offset = 0;
109 _data->frame = NULL;
110 _data->field_D5 = 0;
111 _data->indexes[0] = 29;
112 _data->field_DD = 0;
113 }
114
unload()115 void Beetle::unload() {
116 // Remove sequences from display list
117 if (_data)
118 getScenes()->removeFromQueue(_data->frame);
119
120 // Delete all loaded sequences
121 SAFE_DELETE(_data);
122 }
123
isLoaded() const124 bool Beetle::isLoaded() const {
125 if (!_data)
126 return false;
127
128 return _data->isLoaded;
129 }
130
catchBeetle()131 bool Beetle::catchBeetle() {
132 if (!_data)
133 error("[Beetle::catchBeetle] Sequences have not been loaded");
134
135 if (getInventory()->getSelectedItem() == kItemMatchBox
136 && getInventory()->hasItem(kItemMatch)
137 && ABS((int16)(getCoords().x - _data->coordX)) < 10
138 && ABS((int16)(getCoords().y - _data->coordY)) < 10) {
139 return true;
140 }
141
142 _data->field_D5 = 0;
143 move();
144
145 return false;
146 }
147
isCatchable() const148 bool Beetle::isCatchable() const {
149 if (!_data)
150 error("[Beetle::isCatchable] Sequences have not been loaded");
151
152 return (_data->indexes[_data->offset] >= 30);
153 }
154
update()155 void Beetle::update() {
156 if (!_data)
157 error("[Beetle::update] Sequences have not been loaded");
158
159 if (!_data->isLoaded)
160 return;
161
162 move();
163
164 if (_data->field_D5)
165 _data->field_D5--;
166
167 if (_data->currentSequence && _data->indexes[_data->offset] != 29) {
168 drawUpdate();
169 return;
170 }
171
172 if (getInventory()->get(kItemBeetle)->location == kObjectLocation3) {
173 if ((!_data->field_DD && rnd(10) < 1)
174 || (_data->field_DD && rnd(30) < 1)
175 || rnd(100) < 1) {
176
177 _data->field_DD++;
178 if (_data->field_DD > 3)
179 _data->field_DD = 0;
180
181 updateData(24);
182
183 _data->coordX = (int16)(rnd(250) + 190);
184 _data->coordOffset = (int16)(rnd(5) + 5);
185
186 if (_data->field_D9 > 1)
187 _data->field_D9--;
188
189 drawUpdate();
190 }
191 }
192 }
193
drawUpdate()194 void Beetle::drawUpdate() {
195 if (!_data)
196 error("[Beetle::drawUpdate] Sequences have not been loaded");
197
198 if (_data->frame != NULL) {
199 getScenes()->setCoordinates(_data->frame);
200 getScenes()->removeFromQueue(_data->frame);
201 }
202
203 // Update current frame
204 switch (_data->indexes[_data->offset]) {
205 default:
206 _data->currentFrame += 10;
207 break;
208
209 case 3:
210 case 6:
211 case 9:
212 case 12:
213 case 15:
214 case 18:
215 case 21:
216 case 24:
217 case 25:
218 case 26:
219 case 27:
220 case 28:
221 _data->currentFrame++;
222 break;
223 }
224
225 // Update current sequence
226 if (_data->currentSequence->count() <= _data->currentFrame) {
227 switch (_data->indexes[_data->offset]) {
228 default:
229 _data->offset++;
230 _data->currentSequence = _data->sequences[_data->indexes[_data->offset]];
231 break;
232
233 case 3:
234 case 6:
235 case 9:
236 case 12:
237 case 15:
238 case 18:
239 case 21:
240 break;
241 }
242
243 _data->currentFrame = 0;
244 if (_data->indexes[_data->offset] == 29) {
245 SAFE_DELETE(_data->frame);
246 _data->currentSequence = NULL; // pointer to existing sequence
247 return;
248 }
249 }
250
251 // Update coordinates
252 switch (_data->indexes[_data->offset]) {
253 default:
254 break;
255
256 case 0:
257 _data->coordY -= _data->coordOffset;
258 break;
259
260 case 3:
261 _data->coordX += _data->coordOffset;
262 _data->coordY -= _data->coordOffset;
263 break;
264
265 case 6:
266 _data->coordX += _data->coordOffset;
267 break;
268
269 case 9:
270 _data->coordX += _data->coordOffset;
271 _data->coordY += _data->coordOffset;
272 break;
273
274 case 12:
275 _data->coordY += _data->coordOffset;
276 break;
277
278 case 15:
279 _data->coordX -= _data->coordOffset;
280 _data->coordY += _data->coordOffset;
281 break;
282
283 case 18:
284 _data->coordX -= _data->coordOffset;
285 break;
286
287 case 21:
288 _data->coordX -= _data->coordOffset;
289 _data->coordY -= _data->coordOffset;
290 break;
291 }
292
293 // Update beetle data
294 int rnd = rnd(100);
295 if (_data->coordX < 165 || _data->coordX > 465) {
296 uint index = 0;
297
298 if (rnd >= 30) {
299 if (rnd >= 70)
300 index = (_data->coordX < 165) ? 9 : 15;
301 else
302 index = (_data->coordX < 165) ? 6 : 18;
303 } else {
304 index = (_data->coordX < 165) ? 3 : 21;
305 }
306
307 updateData(index);
308 }
309
310 if (_data->coordY < 178) {
311 switch (_data->indexes[_data->offset]) {
312 default:
313 updateData(26);
314 break;
315
316 case 3:
317 updateData(25);
318 break;
319
320 case 21:
321 updateData(27);
322 break;
323 }
324 }
325
326 if (_data->coordY > 354) {
327 switch (_data->indexes[_data->offset]) {
328 default:
329 break;
330
331 case 9:
332 case 12:
333 case 15:
334 updateData(28);
335 break;
336 }
337 }
338
339 // Invert direction
340 invertDirection();
341
342 SequenceFrame *frame = new SequenceFrame(_data->currentSequence, (uint16)_data->currentFrame);
343 updateFrame(frame);
344
345 invertDirection();
346
347 getScenes()->addToQueue(frame);
348
349 SAFE_DELETE(_data->frame);
350 _data->frame = frame;
351 }
352
invertDirection()353 void Beetle::invertDirection() {
354 if (!_data)
355 error("[Beetle::invertDirection] Sequences have not been loaded");
356
357 switch (_data->indexes[_data->offset]) {
358 default:
359 break;
360
361 case 24:
362 case 25:
363 case 26:
364 case 27:
365 case 28:
366 _data->coordY = -_data->coordY;
367 break;
368 }
369 }
370
move()371 void Beetle::move() {
372 if (!_data)
373 error("[Beetle::move] Sequences have not been loaded");
374
375 if (_data->indexes[_data->offset] >= 24 && _data->indexes[_data->offset] <= 29)
376 return;
377
378 if (_data->field_D5)
379 return;
380
381 if (ABS((int)(getCoords().x - _data->coordX)) > 35)
382 return;
383
384 if (ABS((int)(getCoords().y - _data->coordY)) > 35)
385 return;
386
387 int32 deltaX = getCoords().x - _data->coordX;
388 int32 deltaY = -getCoords().y - _data->coordY;
389 uint32 index = 0;
390
391 // FIXME: check code path
392 if (deltaX >= 0) {
393 if (deltaY > 0) {
394 if (100 * deltaY - 241 * deltaX <= 0) {
395 if (100 * deltaY - 41 * deltaX <= 0)
396 index = 18;
397 else
398 index = 15;
399 } else {
400 index = 12;
401 }
402
403 goto update_data;
404 }
405 }
406
407 if (deltaX < 0) {
408
409 if (deltaY > 0) {
410 if (100 * deltaY + 241 * deltaX <= 0) {
411 if (100 * deltaY + 41 * deltaX <= 0)
412 index = 6;
413 else
414 index = 9;
415 } else {
416 index = 12;
417 }
418
419 goto update_data;
420 }
421
422 if (deltaY <= 0) {
423 if (100 * deltaY - 41 * deltaX <= 0) {
424 if (100 * deltaY - 241 * deltaX <= 0)
425 index = 0;
426 else
427 index = 3;
428 } else {
429 index = 6;
430 }
431
432 goto update_data;
433 }
434 }
435
436 update_data:
437 updateData(index);
438
439 if (_data->coordOffset >= 15) {
440 _data->field_D5 = 0;
441 return;
442 }
443
444 _data->coordOffset = _data->coordOffset + (int16)(4 * rnd(100)/100 + _data->field_D9);
445 _data->field_D5 = 0;
446 }
447
448 // Update the beetle sequence to show the correct frames in the correct place
updateFrame(SequenceFrame * frame) const449 void Beetle::updateFrame(SequenceFrame *frame) const {
450 if (!_data)
451 error("[Beetle::updateFrame] Sequences have not been loaded");
452
453 if (!frame)
454 return;
455
456 // Update coordinates
457 if (_data->coordX > 0)
458 frame->getInfo()->xPos1 = (uint16)_data->coordX;
459
460 if (_data->coordY > 0)
461 frame->getInfo()->yPos1 = (uint16)_data->coordY;
462 }
463
updateData(uint32 index)464 void Beetle::updateData(uint32 index) {
465 if (!_data)
466 error("[Beetle::updateData] Sequences have not been loaded");
467
468 if (!_data->isLoaded)
469 return;
470
471 if (index == 25 || index == 26 || index == 27 || index == 28) {
472 _data->indexes[0] = index;
473 _data->indexes[1] = 29;
474 _data->offset = 0;
475
476 _data->currentSequence = _data->sequences[index];
477 _data->currentFrame = 0;
478 _data->index = index;
479 } else {
480 if (!_data->sequences[index])
481 return;
482
483 if (_data->index == index)
484 return;
485
486 _data->offset = 0;
487
488 // Special case for sequence 24
489 if (index == 24) {
490 _data->indexes[0] = index;
491 _data->coordY = 178;
492 _data->index = _data->indexes[1];
493 _data->indexes[1] = (_data->coordX >= 265) ? 15 : 9;
494 _data->currentFrame = 0;
495 _data->currentSequence = _data->sequences[index];
496 } else {
497 if (index <= _data->index) {
498 for (uint32 i = _data->index - 1; i > index; ++_data->offset) {
499 _data->indexes[_data->offset] = i;
500 i -= 3;
501 }
502 } else {
503 for (uint32 i = _data->index + 1; i < index; ++_data->offset) {
504 _data->indexes[_data->offset] = i;
505 i += 3;
506 }
507 }
508
509 _data->index = index;
510 _data->indexes[_data->offset] = index;
511 _data->currentFrame = 0;
512 _data->offset = 0;
513 _data->currentSequence = _data->sequences[_data->indexes[0]];
514 }
515 }
516 }
517
518 } // End of namespace LastExpress
519