/* 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 3 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, see .
*
*/
#include "lastexpress/data/archive.h"
#include "lastexpress/data/gold_archive.h"
#include "lastexpress/game/beetle.h"
#include "lastexpress/game/logic.h"
#include "lastexpress/lastexpress.h"
namespace LastExpress {
CBeetle::CBeetle(LastExpressEngine *engine) {
_engine = engine;
// Walk sequences
_sequences[0] = _engine->getArchiveManager()->loadSeq("BW000.seq", 15, 0);
_sequences[3] = _engine->getArchiveManager()->loadSeq("BW045.seq", 15, 0);
_sequences[6] = _engine->getArchiveManager()->loadSeq("BW090.seq", 15, 0);
_sequences[9] = _engine->getArchiveManager()->loadSeq("BW135.seq", 15, 0);
_sequences[12] = _engine->getArchiveManager()->loadSeq("BW180.seq", 15, 0);
_sequences[15] = _engine->getArchiveManager()->loadSeq("BW225.seq", 15, 0);
_sequences[18] = _engine->getArchiveManager()->loadSeq("BW270.seq", 15, 0);
_sequences[21] = _engine->getArchiveManager()->loadSeq("BW315.seq", 15, 0);
// Angle turn sequences
_sequences[1] = _engine->getArchiveManager()->loadSeq("BT000045.seq", 15, 0);
_sequences[4] = _engine->getArchiveManager()->loadSeq("BT045090.seq", 15, 0);
_sequences[7] = _engine->getArchiveManager()->loadSeq("BT090135.seq", 15, 0);
_sequences[10] = _engine->getArchiveManager()->loadSeq("BT135180.seq", 15, 0);
_sequences[13] = _engine->getArchiveManager()->loadSeq("BT180225.seq", 15, 0);
_sequences[16] = _engine->getArchiveManager()->loadSeq("BT225270.seq", 15, 0);
_sequences[19] = _engine->getArchiveManager()->loadSeq("BT270315.seq", 15, 0);
_sequences[22] = _engine->getArchiveManager()->loadSeq("BT315000.seq", 15, 0);
// Inverse angle turn sequences
_sequences[2] = _engine->getArchiveManager()->loadSeq("BT045000.seq", 15, 0);
_sequences[5] = _engine->getArchiveManager()->loadSeq("BT090045.seq", 15, 0);
_sequences[8] = _engine->getArchiveManager()->loadSeq("BT135090.seq", 15, 0);
_sequences[11] = _engine->getArchiveManager()->loadSeq("BT180135.seq", 15, 0);
_sequences[14] = _engine->getArchiveManager()->loadSeq("BT225180.seq", 15, 0);
_sequences[17] = _engine->getArchiveManager()->loadSeq("BT270225.seq", 15, 0);
_sequences[20] = _engine->getArchiveManager()->loadSeq("BT315270.seq", 15, 0);
_sequences[23] = _engine->getArchiveManager()->loadSeq("BT000315.seq", 15, 0);
// Other sequences
_sequences[24] = _engine->getArchiveManager()->loadSeq("BA135.seq", 15, 0);
_sequences[25] = _engine->getArchiveManager()->loadSeq("BL045.seq", 15, 0);
_sequences[26] = _engine->getArchiveManager()->loadSeq("BL000.seq", 15, 0);
_sequences[27] = _engine->getArchiveManager()->loadSeq("BL315.seq", 15, 0);
_sequences[28] = _engine->getArchiveManager()->loadSeq("BL180.seq", 15, 0);
_sequences[29] = nullptr;
_loaded = true;
for (int i = 0; i < 29; i++) {
if (!_sequences[i]) {
_loaded = false;
break;
}
}
_fleeSpeed = 10;
_coordOffset = 5;
_coords.y = 178;
_currentSequence = nullptr;
_currentDirectionIndex = 0;
_frame = nullptr;
_mouseCooldown = 0;
_directions[0] = 29;
_spawnCounter = 0;
}
CBeetle::~CBeetle() {
if (_currentSequence)
_engine->getSpriteManager()->removeSprite(&_currentSequence->sprites[_currentFrame]);
for (int i = 0; i < ARRAYSIZE(_sequences); i++) {
if (_sequences[i]) {
_engine->getMemoryManager()->freeMem(_sequences[i]->rawSeqData);
delete _sequences[i];
_sequences[i] = nullptr;
}
}
_currentSequence = nullptr;
}
void CBeetle::tick() {
if (!_loaded)
return;
checkMouse();
if (_mouseCooldown)
_mouseCooldown--;
if (!_currentSequence || _directions[_currentDirectionIndex] == 29) {
if (_engine->getLogicManager()->_items[kItemBeetle].floating != 3 ||
((_spawnCounter || rnd(10)) && (_spawnCounter >= 3 || rnd(30)) && rnd(100))) {
return;
}
_spawnCounter++;
if (_spawnCounter > 3)
_spawnCounter = 0;
_engine->_beetle->setDirection(24);
_coords.x = rnd(250) + 190;
_coordOffset = rnd(5) + 5;
if (_fleeSpeed > 1)
_fleeSpeed--;
}
if (_frame) {
_engine->getSpriteManager()->queueErase(_frame);
_engine->getSpriteManager()->removeSprite(_frame);
}
int curDir = _directions[_currentDirectionIndex];
if (curDir == 0 || curDir == 3 || curDir == 6 || curDir == 9 || curDir == 12 || curDir == 15 || curDir == 18 || curDir == 21 || curDir == 24 || curDir == 27 || curDir == 26 || curDir == 25 || curDir == 28) {
_currentFrame++;
} else {
_currentFrame += 10;
}
bool terminate = false;
assert(_currentSequence);
if (_currentSequence->numFrames <= _currentFrame) {
curDir = _directions[_currentDirectionIndex];
if (curDir != 0 && curDir != 3 && curDir != 6 && curDir != 9 && curDir != 12 && curDir != 15 && curDir != 18 && curDir != 21) {
_currentDirectionIndex++;
_currentSequence = _sequences[_directions[_currentDirectionIndex]];
}
_currentFrame = 0;
if (_directions[_currentDirectionIndex] == 29) {
_frame = nullptr;
_currentSequence = nullptr;
terminate = true;
}
}
if (terminate) {
return;
}
curDir = _directions[_currentDirectionIndex];
if (!curDir || curDir == 3 || curDir == 6 || curDir == 9 || curDir == 12 || curDir == 15 || curDir == 18 || curDir == 21) {
switch (curDir) {
case 0:
_coords.y -= _coordOffset;
break;
case 3:
_coords.x += _coordOffset;
_coords.y -= _coordOffset;
break;
case 6:
_coords.x += _coordOffset;
break;
case 9:
_coords.x += _coordOffset;
_coords.y += _coordOffset;
break;
case 12:
_coords.y += _coordOffset;
break;
case 15:
_coords.x -= _coordOffset;
_coords.y += _coordOffset;
break;
case 18:
_coords.x -= _coordOffset;
break;
case 21:
_coords.x -= _coordOffset;
_coords.y -= _coordOffset;
break;
default:
break;
}
}
uint randNum = rnd(100);
if (_coords.x > 465) {
if (randNum >= 30) {
if (randNum >= 70)
setDirection(15);
else
setDirection(18);
} else {
setDirection(21);
}
}
if (_coords.x < 165) {
if (randNum >= 30) {
if (randNum >= 70)
setDirection(9);
else
setDirection(6);
} else {
setDirection(3);
}
}
if (_coords.y < 178) {
curDir = _directions[_currentDirectionIndex];
if (curDir) {
if (curDir == 3) {
setDirection(25);
} else if (curDir == 21) {
setDirection(27);
}
} else {
setDirection(26);
}
}
if (_coords.y > 354) {
curDir = _directions[_currentDirectionIndex];
if (curDir == 9 || curDir == 12 || curDir == 15)
setDirection(28);
}
curDir = _directions[_currentDirectionIndex];
if (curDir == 24 || curDir == 27 || curDir == 26 || curDir == 25 || curDir == 28)
_coords.y = -_coords.y;
_engine->positionSprite(&_currentSequence->sprites[_currentFrame], _coords);
curDir = _directions[_currentDirectionIndex];
if (curDir == 24 || curDir == 27 || curDir == 26 || curDir == 25 || curDir == 28)
_coords.y = -_coords.y;
_engine->getSpriteManager()->drawSprite(&_currentSequence->sprites[_currentFrame]);
_frame = &_currentSequence->sprites[_currentFrame];
}
void CBeetle::checkMouse() {
int16 cursorX;
int16 cursorY;
int curDir;
int scaledDiffY;
int16 diffX;
int16 diffY;
cursorX = _engine->_cursorX;
cursorY = _engine->_cursorY;
curDir = _directions[_currentDirectionIndex];
if (curDir != 29 && curDir != 27 && curDir != 26 && curDir != 25 && curDir != 28 && curDir != 24 &&
!_mouseCooldown && ABS(cursorX - _coords.x) <= 35) {
if (ABS(cursorY - _coords.y) <= 35) {
diffX = cursorX - _coords.x;
diffY = _coords.y - cursorY;
if (diffX < 0) {
if (diffY <= 0) {
scaledDiffY = 100 * diffY;
if (scaledDiffY - 41 * diffX <= 0) {
if (scaledDiffY - 241 * diffX <= 0) {
setDirection(0);
} else {
setDirection(3);
}
} else {
setDirection(6);
}
if (_coordOffset >= 15) {
_mouseCooldown = 10;
return;
}
} else {
scaledDiffY = 100 * diffY;
if (scaledDiffY + 241 * diffX <= 0) {
if (scaledDiffY + 41 * diffX <= 0) {
setDirection(6);
} else {
setDirection(9);
}
} else {
setDirection(12);
}
if (_coordOffset >= 15) {
_mouseCooldown = 10;
return;
}
}
} else if (diffY <= 0) {
scaledDiffY = 100 * diffY;
if (scaledDiffY + 41 * diffX <= 0) {
if (scaledDiffY + 241 * diffX <= 0) {
setDirection(0);
} else {
setDirection(21);
}
} else {
setDirection(18);
}
if (_coordOffset >= 15) {
_mouseCooldown = 10;
return;
}
} else {
scaledDiffY = 100 * diffY;
if (scaledDiffY - 241 * diffX <= 0) {
if (scaledDiffY - 41 * diffX <= 0) {
setDirection(18);
} else {
setDirection(15);
}
} else {
setDirection(12);
}
if (_coordOffset >= 15) {
_mouseCooldown = 10;
return;
}
}
_coordOffset = _coordOffset + 4 * (rnd(100)) / 100 + _fleeSpeed;
_mouseCooldown = 10;
}
}
}
void CBeetle::setDirection(int direction) {
if (_loaded) {
if (direction == 27 || direction == 26 || direction == 25 || direction == 28) {
_directions[0] = direction;
_directions[1] = 29;
_currentDirectionIndex = 0;
_currentSequence = _sequences[direction];
_currentFrame = 0;
_index = direction;
} else if (_sequences[direction]) {
if (direction != _index) {
_currentDirectionIndex = 0;
if (direction == 24) {
_directions[0] = 24;
_coords.y = 178;
if (_coords.x >= 265) {
_directions[1] = 15;
} else {
_directions[1] = 9;
}
_currentSequence = _sequences[24];
_currentFrame = 0;
_index = _directions[1];
} else {
if (direction <= _index) {
for (int i = _index - 1; i > direction; ++_currentDirectionIndex) {
_directions[_currentDirectionIndex] = i;
i -= 3;
}
} else {
for (int j = _index + 1; j < direction; ++_currentDirectionIndex) {
_directions[_currentDirectionIndex] = j;
j += 3;
}
}
_index = direction;
_directions[_currentDirectionIndex] = direction;
_currentFrame = 0;
_currentDirectionIndex = 0;
_currentSequence = _sequences[_directions[0]];
}
}
}
}
}
bool CBeetle::onTable() {
return _directions[_currentDirectionIndex] != 29;
}
bool CBeetle::click() {
if (_engine->getLogicManager()->_activeItem == kItemMatchBox &&
_engine->getLogicManager()->cathHasItem(12) &&
ABS(_engine->_cursorX - _coords.x) < 10 &&
ABS(_engine->_cursorY - _coords.y) < 10) {
return true;
}
_mouseCooldown = 0;
checkMouse();
return false;
}
void LastExpressEngine::doBeetle() {
int32 chapter = getLogicManager()->_globals[11];
if (chapter >= 2 && chapter <= 3 && !_beetle && getLogicManager()->_items[kItemBeetle].floating == 3) {
_beetle = new CBeetle(this);
}
}
void LastExpressEngine::endBeetle() {
if (_beetle) {
delete _beetle;
_beetle = nullptr;
}
}
void LastExpressEngine::positionSprite(Sprite *sprite, Common::Point coord) {
if (sprite) {
int spriteWidth = sprite->rect.right - sprite->rect.left + 1;
int spriteHeight = sprite->rect.bottom - sprite->rect.top + 1;
int widthFactor = sprite->rect.width + 2 * (-640 * sprite->rect.top - sprite->rect.left);
int heightFactor = 2 * (sprite->rect.right + 640 * sprite->rect.bottom) - sprite->rect.height;
if (coord.x > 0)
sprite->rect.left = coord.x;
if (coord.y > 0)
sprite->rect.top = coord.y;
sprite->rect.right = sprite->rect.left + spriteWidth - 1;
sprite->rect.bottom = sprite->rect.top + spriteHeight - 1;
sprite->rect.width = widthFactor + 2 * (sprite->rect.left + 640 * sprite->rect.top);
sprite->rect.height = 2 * (sprite->rect.right + 640 * sprite->rect.bottom) - heightFactor;
}
}
} // End of namespace LastExpress