scummvm/engines/lastexpress/game/beetle.cpp
2011-06-28 22:54:51 -04:00

515 lines
11 KiB
C++

/* 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 "lastexpress/game/beetle.h"
#include "lastexpress/game/inventory.h"
#include "lastexpress/game/logic.h"
#include "lastexpress/game/scenes.h"
#include "lastexpress/game/state.h"
#include "lastexpress/helpers.h"
#include "lastexpress/lastexpress.h"
#include "lastexpress/resource.h"
namespace LastExpress {
Beetle::Beetle(LastExpressEngine *engine) : _engine(engine), _data(NULL) {}
Beetle::~Beetle() {
SAFE_DELETE(_data);
// Free passed pointers
_engine = NULL;
}
void Beetle::load() {
// Only load in chapter 2 & 3
if (getProgress().chapter != kChapter2 && getProgress().chapter != kChapter3)
return;
// Already loaded
if (_data)
return;
// Do not load if beetle is in the wrong location
if (getInventory()->get(kItemBeetle)->location != kObjectLocation3)
return;
///////////////////////
// Load Beetle data
_data = new BeetleData();
// Load sequences
_data->sequences.push_back(loadSequence("BW000.seq")); // 0
_data->sequences.push_back(loadSequence("BT000045.seq"));
_data->sequences.push_back(loadSequence("BT045000.seq"));
_data->sequences.push_back(loadSequence("BW045.seq"));
_data->sequences.push_back(loadSequence("BT045090.seq"));
_data->sequences.push_back(loadSequence("BT090045.seq")); // 5
_data->sequences.push_back(loadSequence("BW090.seq"));
_data->sequences.push_back(loadSequence("BT090135.seq"));
_data->sequences.push_back(loadSequence("BT135090.seq"));
_data->sequences.push_back(loadSequence("BW135.seq"));
_data->sequences.push_back(loadSequence("BT135180.seq")); // 10
_data->sequences.push_back(loadSequence("BT180135.seq"));
_data->sequences.push_back(loadSequence("BW180.seq"));
_data->sequences.push_back(loadSequence("BT180225.seq"));
_data->sequences.push_back(loadSequence("BT225180.seq"));
_data->sequences.push_back(loadSequence("BW225.seq")); // 15
_data->sequences.push_back(loadSequence("BT225270.seq"));
_data->sequences.push_back(loadSequence("BT270225.seq"));
_data->sequences.push_back(loadSequence("BW270.seq"));
_data->sequences.push_back(loadSequence("BT270315.seq"));
_data->sequences.push_back(loadSequence("BT315270.seq")); // 20
_data->sequences.push_back(loadSequence("BW315.seq"));
_data->sequences.push_back(loadSequence("BT315000.seq"));
_data->sequences.push_back(loadSequence("BT000315.seq"));
_data->sequences.push_back(loadSequence("BA135.seq"));
_data->sequences.push_back(loadSequence("BL045.seq")); // 25
_data->sequences.push_back(loadSequence("BL000.seq"));
_data->sequences.push_back(loadSequence("BL315.seq"));
_data->sequences.push_back(loadSequence("BL180.seq"));
// Init fields
_data->field_74 = 0;
// Check that all sequences are loaded properly
_data->isLoaded = true;
for (int i = 0; i < (int)_data->sequences.size(); i++) {
if (!_data->sequences[i]->isLoaded()) {
_data->isLoaded = false;
break;
}
}
_data->field_D9 = 10;
_data->coordOffset = 5;
_data->coordY = 178;
_data->currentSequence = 0;
_data->offset = 0;
_data->frame = NULL;
_data->field_D5 = 0;
_data->indexes[0] = 29;
_data->field_DD = 0;
}
void Beetle::unload() {
// Remove sequences from display list
if (_data)
getScenes()->removeFromQueue(_data->frame);
// Delete all loaded sequences
SAFE_DELETE(_data);
}
bool Beetle::isLoaded() const {
if (!_data)
return false;
return _data->isLoaded;
}
bool Beetle::catchBeetle() {
if (!_data)
error("[Beetle::catchBeetle] Sequences have not been loaded");
if (getInventory()->getSelectedItem() == kItemMatchBox
&& getInventory()->hasItem(kItemMatch)
&& ABS((int16)(getCoords().x - _data->coordX)) < 10
&& ABS((int16)(getCoords().y - _data->coordY)) < 10) {
return true;
}
_data->field_D5 = 0;
move();
return false;
}
bool Beetle::isCatchable() const {
if (!_data)
error("[Beetle::isCatchable] Sequences have not been loaded");
return (_data->indexes[_data->offset] >= 30);
}
void Beetle::update() {
if (!_data)
error("[Beetle::update] Sequences have not been loaded");
if (!_data->isLoaded)
return;
move();
if (_data->field_D5)
_data->field_D5--;
if (_data->currentSequence && _data->indexes[_data->offset] != 29) {
drawUpdate();
return;
}
if (getInventory()->get(kItemBeetle)->location == kObjectLocation3) {
if ((!_data->field_DD && rnd(10) < 1)
|| (_data->field_DD && rnd(30) < 1)
|| rnd(100) < 1) {
_data->field_DD++;
if (_data->field_DD > 3)
_data->field_DD = 0;
updateData(24);
_data->coordX = (int16)(rnd(250) + 190);
_data->coordOffset = (int16)(rnd(5) + 5);
if (_data->field_D9 > 1)
_data->field_D9--;
drawUpdate();
}
}
}
void Beetle::drawUpdate() {
if (!_data)
error("[Beetle::drawUpdate] Sequences have not been loaded");
if (_data->frame != NULL) {
getScenes()->setCoordinates(_data->frame);
getScenes()->removeFromQueue(_data->frame);
}
// Update current frame
switch (_data->indexes[_data->offset]) {
default:
_data->currentFrame += 10;
break;
case 3:
case 6:
case 9:
case 12:
case 15:
case 18:
case 21:
case 24:
case 25:
case 26:
case 27:
case 28:
_data->currentFrame++;
break;
}
// Update current sequence
if (_data->currentSequence->count() <= _data->currentFrame) {
switch (_data->indexes[_data->offset]) {
default:
_data->offset++;
_data->currentSequence = _data->sequences[_data->indexes[_data->offset]];
break;
case 3:
case 6:
case 9:
case 12:
case 15:
case 18:
case 21:
break;
}
_data->currentFrame = 0;
if (_data->indexes[_data->offset] == 29) {
SAFE_DELETE(_data->frame);
_data->currentSequence = NULL; // pointer to existing sequence
return;
}
}
// Update coordinates
switch (_data->indexes[_data->offset]) {
default:
break;
case 0:
_data->coordY -= _data->coordOffset;
break;
case 3:
_data->coordX += _data->coordOffset;
_data->coordY -= _data->coordOffset;
break;
case 6:
_data->coordX += _data->coordOffset;
break;
case 9:
_data->coordX += _data->coordOffset;
_data->coordY += _data->coordOffset;
break;
case 12:
_data->coordY += _data->coordOffset;
break;
case 15:
_data->coordX -= _data->coordOffset;
_data->coordY += _data->coordOffset;
break;
case 18:
_data->coordX -= _data->coordOffset;
break;
case 21:
_data->coordX -= _data->coordOffset;
_data->coordY -= _data->coordOffset;
break;
}
// Update beetle data
int rnd = rnd(100);
if (_data->coordX < 165 || _data->coordX > 465) {
uint index = 0;
if (rnd >= 30) {
if (rnd >= 70)
index = (_data->coordX < 165) ? 9 : 15;
else
index = (_data->coordX < 165) ? 6 : 18;
} else {
index = (_data->coordX < 165) ? 3 : 21;
}
updateData(index);
}
if (_data->coordY < 178) {
switch (_data->indexes[_data->offset]) {
default:
updateData(26);
break;
case 3:
updateData(25);
break;
case 21:
updateData(27);
break;
}
}
if (_data->coordY > 354) {
switch (_data->indexes[_data->offset]) {
default:
break;
case 9:
case 12:
case 15:
updateData(28);
break;
}
}
#define INVERT_Y() \
switch (_data->indexes[_data->offset]) { \
default: \
break; \
case 24: \
case 25: \
case 26: \
case 27: \
case 28: \
_data->coordY = -_data->coordY; \
break; \
}
// Invert direction
INVERT_Y();
SequenceFrame *frame = new SequenceFrame(_data->currentSequence, (uint16)_data->currentFrame);
updateFrame(frame);
INVERT_Y();
getScenes()->addToQueue(frame);
SAFE_DELETE(_data->frame);
_data->frame = frame;
}
void Beetle::move() {
if (!_data)
error("[Beetle::move] Sequences have not been loaded");
if (_data->indexes[_data->offset] >= 24 && _data->indexes[_data->offset] <= 29)
return;
if (_data->field_D5)
return;
if (ABS((int)(getCoords().x - _data->coordX)) > 35)
return;
if (ABS((int)(getCoords().y - _data->coordY)) > 35)
return;
int32 deltaX = getCoords().x - _data->coordX;
int32 deltaY = -getCoords().y - _data->coordY;
uint32 index = 0;
// FIXME: check code path
if (deltaX >= 0) {
if (deltaY > 0) {
if (100 * deltaY - 241 * deltaX <= 0) {
if (100 * deltaY - 41 * deltaX <= 0)
index = 18;
else
index = 15;
} else {
index = 12;
}
goto update_data;
}
}
if (deltaX < 0) {
if (deltaY > 0) {
if (100 * deltaY + 241 * deltaX <= 0) {
if (100 * deltaY + 41 * deltaX <= 0)
index = 6;
else
index = 9;
} else {
index = 12;
}
goto update_data;
}
if (deltaY <= 0) {
if (100 * deltaY - 41 * deltaX <= 0) {
if (100 * deltaY - 241 * deltaX <= 0)
index = 0;
else
index = 3;
} else {
index = 6;
}
goto update_data;
}
}
update_data:
updateData(index);
if (_data->coordOffset >= 15) {
_data->field_D5 = 0;
return;
}
_data->coordOffset = _data->coordOffset + (int16)(4 * rnd(100)/100 + _data->field_D9);
_data->field_D5 = 0;
}
// Update the beetle sequence to show the correct frames in the correct place
void Beetle::updateFrame(SequenceFrame *frame) const {
if (!_data)
error("[Beetle::updateFrame] Sequences have not been loaded");
if (!frame)
return;
// Update coordinates
if (_data->coordX > 0)
frame->getInfo()->xPos1 = (uint16)_data->coordX;
if (_data->coordY > 0)
frame->getInfo()->yPos1 = (uint16)_data->coordY;
}
void Beetle::updateData(uint32 index) {
if (!_data)
error("[Beetle::updateData] Sequences have not been loaded");
if (!_data->isLoaded)
return;
if (index == 25 || index == 26 || index == 27 || index == 28) {
_data->indexes[0] = index;
_data->indexes[1] = 29;
_data->offset = 0;
_data->currentSequence = _data->sequences[index];
_data->currentFrame = 0;
_data->index = index;
} else {
if (!_data->sequences[index])
return;
if (_data->index == index)
return;
_data->offset = 0;
// Special case for sequence 24
if (index == 24) {
_data->indexes[0] = index;
_data->coordY = 178;
_data->index = _data->indexes[1];
_data->indexes[1] = (_data->coordX >= 265) ? 15 : 9;
_data->currentFrame = 0;
_data->currentSequence = _data->sequences[index];
} else {
if (index <= _data->index) {
for (uint32 i = _data->index - 1; i > index; ++_data->offset) {
_data->indexes[_data->offset] = i;
i -= 3;
}
} else {
for (uint32 i = _data->index + 1; i < index; ++_data->offset) {
_data->indexes[_data->offset] = i;
i += 3;
}
}
_data->index = index;
_data->indexes[_data->offset] = index;
_data->currentFrame = 0;
_data->offset = 0;
_data->currentSequence = _data->sequences[_data->indexes[0]];
}
}
}
} // End of namespace LastExpress