From bb88aaf119f2946b7c3fba01c4f7da5d40d2aa5c Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Fri, 20 May 2016 22:15:38 +0200 Subject: SCUMM HE: Added Moonbase Traveller class --- engines/scumm/he/moonbase/ai_traveller.cpp | 259 +++++++++++++++++++++++++++++ engines/scumm/he/moonbase/ai_traveller.h | 122 ++++++++++++++ engines/scumm/module.mk | 1 + 3 files changed, 382 insertions(+) create mode 100644 engines/scumm/he/moonbase/ai_traveller.cpp create mode 100644 engines/scumm/he/moonbase/ai_traveller.h diff --git a/engines/scumm/he/moonbase/ai_traveller.cpp b/engines/scumm/he/moonbase/ai_traveller.cpp new file mode 100644 index 0000000000..5437ab1547 --- /dev/null +++ b/engines/scumm/he/moonbase/ai_traveller.cpp @@ -0,0 +1,259 @@ +/* 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/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() { + _waterFlag = 0; + setValueG(0); + unsetDisabled(); +} + +Traveller::Traveller(int originX, int originY) { + _waterFlag = 0; + setValueG(0); + unsetDisabled(); + + _posX = originX; + _posY = originY; +} + +void Traveller::adjustPosX(int offsetX) { + int maxX = 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 = 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 = GetDistance(_posX, _posY, _targetPosX, _targetPosY); + // Divide by _maxDist to get minimum number of jumps to goal + retVal /= static_cast(_maxDist); + + return retVal * 2.0; +} + +int Traveller::numChildrenToGen() { + if (!_numToGen) + _numToGen = 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; + + static int dir, angle, power; + + if (completionState) { + // Calculate angle between here and target + int directAngle = 0; + + if (GetEnergyHogType()) + directAngle = GetAngle(_posX, _posY, _targetPosX, _targetPosY, 1); + else + directAngle = GetAngle(_posX, _posY, _targetPosX, _targetPosY); + + // Calculate the offset angle for this index + if (!_sizeAngleStep) + _sizeAngleStep = 52 - (GetAnimSpeed() * 7); + + dir = _sizeAngleStep * ((static_cast(index / NUM_POWER_STEPS) + 1) >> 1); + // Calculate the sign value for the offset for this index + int orientation = dir * (((static_cast(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 = GetDistance(_posX, _posY, _targetPosX, _targetPosY); + + if (directDist > _maxDist + 120) + maxPower = GetMaxPower(); + else + maxPower = (static_cast(directDist) / static_cast(_maxDist + 120)) * GetMaxPower(); + + maxPower -= 70; + power = 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 = 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 = GetCurrentPlayer(); + int maxX = GetMaxX(); + + // Check new position to see if landing is clear + if (coords > 0) { + int yCoord = coords / maxX; + int xCoord = coords - (yCoord * maxX); + + int terrain = GetTerrain(xCoord, yCoord); + assert(terrain == TERRAIN_TYPE_GOOD); + + float pwr = GetMinPower() * .3; + float cosine = cos((static_cast(angle) / 360) * (2 * M_PI)); + float sine = sin((static_cast(angle) / 360) * (2 * M_PI)); + int xParam = xCoord + (pwr * cosine); + int yParam = yCoord + (pwr * sine); + + if (xParam < 0) + xParam += GetMaxX(); + else if (xParam > GetMaxX()) + xParam -= GetMaxX(); + + if (yParam < 0) + yParam += GetMaxY(); + else if (yParam > GetMaxY()) + yParam -= GetMaxY(); + + if (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 (intVecItr i = (lastXCoord[whoseTurn]).begin(), j = (lastYCoord[whoseTurn]).begin(); i != (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 (CheckIfWaterState(xCoord, yCoord)) { + int terrainSquareSize = GetTerrainSquareSize(); + xCoord = ((xCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2)); + yCoord = ((yCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2)); + + int xDist = xCoord - _posX; + int yDist = yCoord - _posY; + retTraveller->setPosX(xCoord + (terrainSquareSize * 1.414 * (xDist / (abs(xDist) + 1)))); + retTraveller->setPosY(yCoord + (terrainSquareSize * 1.414 * (yDist / (abs(yDist) + 1)))); + + int closestHub = GetClosestUnit(retTraveller->getPosX(), retTraveller->getPosY(), GetMaxX(), GetCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 110); + + retTraveller->setWaterSourceX(GetHubX(closestHub)); + retTraveller->setWaterSourceY(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 (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 diff --git a/engines/scumm/he/moonbase/ai_traveller.h b/engines/scumm/he/moonbase/ai_traveller.h new file mode 100644 index 0000000000..7b1bad9a29 --- /dev/null +++ b/engines/scumm/he/moonbase/ai_traveller.h @@ -0,0 +1,122 @@ +/* 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. + * + */ + +#ifndef SCUMM_HE_MOONBASE_AI_TRAVELER_H +#define SCUMM_HE_MOONBASE_AI_TRAVELER_H + +#include "scumm/he/moonbase/ai_node.h" + +namespace Scumm { + +const int NUM_TO_GEN = 9; + +const int NUM_POWER_STEPS = 3; +const double SIZE_POWER_STEP = .15; +const int SIZE_ANGLE_STEP = 45; +const int VARIATION_EXTENT = 3; +const int DIRECTION_WEIGHT = 5; + +class Traveller : public IContainedObject { +private: + static int _targetPosX; + static int _targetPosY; + static int _maxDist; + + static int _numToGen; + static int _sizeAngleStep; + + int _sourceHub; + + int _posX; + int _posY; + int _angleTo; + int _powerTo; + + int _disabled; + int _waterFlag; + int _waterSourceX; + int _waterSourceY; + int _waterDestX; + int _waterDestY; + + +protected: + virtual float calcH(); + +public: + Traveller(); + Traveller(int originX, int originY); + ~Traveller() {} + + IContainedObject *duplicate() { return this; } + + static void setTargetPosX(int posX) { _targetPosX = posX; } + static void setTargetPosY(int posY) { _targetPosY = posY; } + static void setMaxDist(int maxDist) { _maxDist = maxDist; } + + void setSourceHub(int sourceHub) { _sourceHub = sourceHub; } + + void setPosX(int posX) { _posX = posX; } + void setPosY(int posY) { _posY = posY; } + void setAngleTo(int angleTo) { _angleTo = angleTo; } + void setPowerTo(int powerTo) { _powerTo = powerTo; } + + void setWaterSourceX(int waterSourceX) { _waterSourceX = waterSourceX; } + void setWaterSourceY(int waterSourceY) { _waterSourceY = waterSourceY; } + + void setWaterDestX(int waterDestX) { _waterDestX = waterDestX; } + void setWaterDestY(int waterDestY) { _waterDestY = waterDestY; } + + int getSourceHub() const { return _sourceHub; } + + int getPosX() const { return _posX; } + int getPosY() const { return _posY; } + int getAngleTo() const { return _angleTo; } + int getPowerTo() const { return _powerTo; } + + int getWaterSourceX() const { return _waterSourceX; } + int getWaterSourceY() const { return _waterSourceY; } + int getWaterDestX() const { return _waterDestX; } + int getWaterDestY() const { return _waterDestY; } + + void setDisabled() { _disabled = 1; } + void unsetDisabled() { _disabled = 0; } + int getDisabled() { return _disabled; } + + void adjustPosX(int offsetX); + void adjustPosY(int offsetY); + void adjustXY(int offsetX, int offsetY); + + void enableWaterFlag() { _waterFlag = 1; } + void disableWaterFlag() { _waterFlag = 0; } + int GetWaterFlag() const { return _waterFlag; } + + virtual int numChildrenToGen(); + virtual IContainedObject *createChildObj(int, int &); + + virtual int checkSuccess(); + virtual float calcT(); +}; + +} // End of namespace Scumm + +#endif diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk index d6199f5b01..57b687231f 100644 --- a/engines/scumm/module.mk +++ b/engines/scumm/module.mk @@ -142,6 +142,7 @@ MODULE_OBJS += \ he/moonbase/ai_defenseunit.o \ he/moonbase/ai_node.o \ he/moonbase/ai_targetacquisition.o \ + he/moonbase/ai_traveller.o \ he/moonbase/ai_types.o \ he/moonbase/ai_weapon.o \ he/moonbase/moonbase.o \ -- cgit v1.2.3