diff options
Diffstat (limited to 'engines/scumm/he/moonbase/ai_traveller.cpp')
-rw-r--r-- | engines/scumm/he/moonbase/ai_traveller.cpp | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/engines/scumm/he/moonbase/ai_traveller.cpp b/engines/scumm/he/moonbase/ai_traveller.cpp new file mode 100644 index 0000000000..b1c9985b9d --- /dev/null +++ b/engines/scumm/he/moonbase/ai_traveller.cpp @@ -0,0 +1,277 @@ +/* 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 "scumm/he/intern_he.h" +#include "scumm/he/moonbase/moonbase.h" +#include "scumm/he/moonbase/ai_traveller.h" +#include "scumm/he/moonbase/ai_main.h" + +namespace Scumm { + +int Traveller::_targetPosX = 0; +int Traveller::_targetPosY = 0; +int Traveller::_maxDist = 0; + +int Traveller::_numToGen = 0; +int Traveller::_sizeAngleStep = 0; + +Traveller::Traveller(AI *ai) : _ai(ai) { + _waterFlag = 0; + setValueG(0); + unsetDisabled(); + + _sourceHub = 0; + _angleTo = 0; + _powerTo = 0; + _waterSourceX = 0; + _waterSourceY = 0; + _waterDestX = 0; + _waterDestY = 0; +} + +Traveller::Traveller(int originX, int originY, AI *ai) : _ai(ai) { + _waterFlag = 0; + setValueG(0); + unsetDisabled(); + + _posX = originX; + _posY = originY; + + _sourceHub = 0; + _angleTo = 0; + _powerTo = 0; + _waterSourceX = 0; + _waterSourceY = 0; + _waterDestX = 0; + _waterDestY = 0; +} + +void Traveller::adjustPosX(int offsetX) { + int maxX = _ai->getMaxX(); + int deltaX = _posX + offsetX; + + if (deltaX < 0) _posX = maxX + deltaX; + else if (deltaX > maxX) _posX = deltaX - maxX; + else _posX = deltaX; +} + +void Traveller::adjustPosY(int offsetY) { + int maxY = _ai->getMaxX(); + int deltaY = _posY + offsetY; + + if (deltaY < 0) _posY = maxY + deltaY; + else if (deltaY > maxY) _posY = deltaY - maxY; + else _posY = deltaY; +} + +void Traveller::adjustXY(int offsetX, int offsetY) { + adjustPosX(offsetX); + adjustPosY(offsetY); +} + +float Traveller::calcH() { + float retVal = 0; + // Calc dist from here to target + retVal = _ai->getDistance(_posX, _posY, _targetPosX, _targetPosY); + // Divide by _maxDist to get minimum number of jumps to goal + retVal /= static_cast<float>(_maxDist); + + return retVal * 2.0; +} + +int Traveller::numChildrenToGen() { + if (!_numToGen) + _numToGen = _ai->getAnimSpeed() + 2; + + return _numToGen; +} + +IContainedObject *Traveller::createChildObj(int index, int &completionFlag) { + static int nodeCount = 0; + static int completionState = 1; + + if (!index) nodeCount = 0; + + nodeCount++; + + Traveller *retTraveller = new Traveller(_ai); + + static int dir, angle, power; + + if (completionState) { + // Calculate angle between here and target + int directAngle = 0; + + if (_ai->getEnergyHogType()) + directAngle = _ai->calcAngle(_posX, _posY, _targetPosX, _targetPosY, 1); + else + directAngle = _ai->calcAngle(_posX, _posY, _targetPosX, _targetPosY); + + // Calculate the offset angle for this index + if (!_sizeAngleStep) + _sizeAngleStep = 52 - (_ai->getAnimSpeed() * 7); + + dir = _sizeAngleStep * ((static_cast<int>(index / NUM_POWER_STEPS) + 1) >> 1); + // Calculate the sign value for the offset for this index + int orientation = dir * (((static_cast<int>(index / NUM_POWER_STEPS) % 2) << 1) - 1); + // Add the offset angle to the direct angle to target + angle = orientation + directAngle; + + // Calculate power for this index + int maxPower = 0; + int directDist = _ai->getDistance(_posX, _posY, _targetPosX, _targetPosY); + + if (directDist > _maxDist + 120) + maxPower = _ai->getMaxPower(); + else + maxPower = (int)((static_cast<float>(directDist) / static_cast<float>(_maxDist + 120)) * _ai->getMaxPower()); + + maxPower -= 70; + power = (int)(maxPower * (1 - ((index % NUM_POWER_STEPS) * SIZE_POWER_STEP))); + } + + retTraveller->setAngleTo(angle); + retTraveller->setPowerTo(power); + + // Set this object's position to the new one determined by the power and angle from above + static int lastSuccessful = 0; + int coords = 0; + + if (!(index % NUM_POWER_STEPS) || (!lastSuccessful)) { + coords = _ai->simulateBuildingLaunch(_posX, _posY, power, angle, 10, 0); + lastSuccessful = 0; + } else { + completionState = 1; + lastSuccessful = 0; + } + + if (!coords) { + completionFlag = 0; + completionState = 0; + delete retTraveller; + return NULL; + } else { + completionFlag = 1; + completionState = 1; + } + + int whoseTurn = _ai->getCurrentPlayer(); + int maxX = _ai->getMaxX(); + + // Check new position to see if landing is clear + if (coords > 0) { + int yCoord = coords / maxX; + int xCoord = coords - (yCoord * maxX); + + int terrain = _ai->getTerrain(xCoord, yCoord); + assert(terrain == TERRAIN_TYPE_GOOD); + + float pwr = _ai->getMinPower() * .3; + float cosine = cos((static_cast<float>(angle) / 360) * (2 * M_PI)); + float sine = sin((static_cast<float>(angle) / 360) * (2 * M_PI)); + int xParam = (int)(xCoord + (pwr * cosine)); + int yParam = (int)(yCoord + (pwr * sine)); + + if (xParam < 0) + xParam += _ai->getMaxX(); + else if (xParam > _ai->getMaxX()) + xParam -= _ai->getMaxX(); + + if (yParam < 0) + yParam += _ai->getMaxY(); + else if (yParam > _ai->getMaxY()) + yParam -= _ai->getMaxY(); + + if (_ai->checkIfWaterState(xParam, yParam)) { + delete retTraveller; + return NULL; + } + + retTraveller->setPosY(yCoord); + retTraveller->setPosX(xCoord); + + // Iterate through the previous action list, making sure this one isn't on it + for (Common::Array<int>::iterator i = (_ai->_lastXCoord[whoseTurn]).begin(), j = (_ai->_lastYCoord[whoseTurn]).begin(); i != (_ai->_lastXCoord[whoseTurn]).end(); i++, j++) { + // Check if this shot is the same as the last time we tried + if ((*i == retTraveller->getPosX()) && (*j == retTraveller->getPosY())) { + retTraveller->setDisabled(); + delete retTraveller; + return NULL; + } + } + + retTraveller->setValueG(getG() + 7 + (dir * DIRECTION_WEIGHT)); + lastSuccessful = 1; + } else { + int yCoord = -coords / maxX; + int xCoord = -coords - (yCoord * maxX); + + // If landing fault is because of water, add 1 extra to g and turn on water flag. Also set coords, and adjust power to water fault location + if (_ai->checkIfWaterState(xCoord, yCoord)) { + int terrainSquareSize = _ai->getTerrainSquareSize(); + xCoord = ((xCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2)); + yCoord = ((yCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2)); + + int xDist = xCoord - _posX; + int yDist = yCoord - _posY; + retTraveller->setPosX((int)(xCoord + (terrainSquareSize * 1.414 * (xDist / (abs(xDist) + 1))))); + retTraveller->setPosY((int)(yCoord + (terrainSquareSize * 1.414 * (yDist / (abs(yDist) + 1))))); + + int closestHub = _ai->getClosestUnit(retTraveller->getPosX(), retTraveller->getPosY(), _ai->getMaxX(), _ai->getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 110); + + retTraveller->setWaterSourceX(_ai->getHubX(closestHub)); + retTraveller->setWaterSourceY(_ai->getHubY(closestHub)); + retTraveller->setWaterDestX(retTraveller->getPosX()); + retTraveller->setWaterDestY(retTraveller->getPosY()); + + retTraveller->setPowerTo(power); + retTraveller->setAngleTo(angle); + + retTraveller->setValueG(getG() + 10 + (dir * DIRECTION_WEIGHT)); + retTraveller->enableWaterFlag(); + } else { + // If not, set G to highest value + retTraveller->setDisabled(); + delete retTraveller; + return NULL; + } + } + + return retTraveller; +} + +int Traveller::checkSuccess() { + if (_ai->getDistance(_posX + 1, _posY, _targetPosX, _targetPosY) < _maxDist) + return SUCCESS; + + return 0; +} + +float Traveller::calcT() { + assert(!_disabled); + + if (_disabled) return FAILURE; + + return (checkSuccess() != SUCCESS) ? (getG() + calcH()) : SUCCESS; +} + +} // End of namespace Scumm |