diff --git a/ai/heavyai/heavyAiSharedData.h b/ai/heavyai/heavyAiSharedData.h index 3117ff898..49347cff4 100644 --- a/ai/heavyai/heavyAiSharedData.h +++ b/ai/heavyai/heavyAiSharedData.h @@ -3,10 +3,15 @@ #include class Unit; +class UnitTargetedPathFindingSystem; +using spUnitTargetedPathFindingSystem = std::shared_ptr; namespace HeavyAiSharedData { +static constexpr qint32 UNIT_COUNT = 40; +static constexpr qint32 SEARCH_RANGE = 30; + enum SituationFeatures { HP, @@ -19,6 +24,7 @@ enum SituationFeatures RepairsOnPosition, CapturePoints, BuildingImportance, + Stealthed, MaxFeatures, }; @@ -27,16 +33,20 @@ enum AiCache UnitMovementPoints, MinFirerange, MaxFirerange, + TerrainDefense, CanMoveAndFire, MaxAiCache, }; - struct UnitInfo { Unit* pUnit{nullptr}; qint32 multiplier{0}; - bool reachable{false}; + std::array reachable{false}; + std::vector stealthed; + spUnitTargetedPathFindingSystem pUnitTargetedPathFindingSystem; }; +using spUnitInfo = std::shared_ptr; + } diff --git a/ai/heavyai/heavyai.cpp b/ai/heavyai/heavyai.cpp index bfc75ee35..26cd2c213 100644 --- a/ai/heavyai/heavyai.cpp +++ b/ai/heavyai/heavyai.cpp @@ -117,6 +117,7 @@ void HeavyAi::updateUnitCache(spQmlVectorUnit & pUnits) cache[HeavyAiSharedData::AiCache::UnitMovementPoints] = pUnit->getMovementpoints(pos); cache[HeavyAiSharedData::AiCache::MinFirerange] = pUnit->getMinRange(pos); cache[HeavyAiSharedData::AiCache::MaxFirerange] = pUnit->getMaxRange(pos); + cache[HeavyAiSharedData::TerrainDefense] = pUnit->getTerrainDefense(); cache[HeavyAiSharedData::AiCache::CanMoveAndFire] = static_cast(pUnit->canMoveAndFire(pos)); } } diff --git a/ai/heavyai/situationevaluator.cpp b/ai/heavyai/situationevaluator.cpp index 2ebb7f525..79b6b7fe0 100644 --- a/ai/heavyai/situationevaluator.cpp +++ b/ai/heavyai/situationevaluator.cpp @@ -1,4 +1,5 @@ #include "ai/heavyai/situationevaluator.h" +#include "ai/heavyai/unittargetedpathfindingsystem.h" #include "coreengine/globalutils.h" #include "game/gamemap.h" @@ -6,59 +7,211 @@ SituationEvaluator::SituationEvaluator(Player* pOwner) - : m_inputVector(1, UNIT_COUNT * UNIT_COUNT * HeavyAiSharedData::SituationFeatures::MaxFeatures), - m_searchRange(GlobalUtils::getSpCircle(0, SEARCH_RANGE)), + : m_inputVector(1, HeavyAiSharedData::UNIT_COUNT * HeavyAiSharedData::UNIT_COUNT * HeavyAiSharedData::SituationFeatures::MaxFeatures), + m_searchRange(GlobalUtils::getSpCircle(0, HeavyAiSharedData::SEARCH_RANGE)), m_pOwner(pOwner) { + for (qint32 i = 0; i < HeavyAiSharedData::UNIT_COUNT; ++i) + { + m_unitsInfo[i] = MemoryManagement::create(); + m_unitsInfo[i]->stealthed.resize(pOwner->getMap()->getPlayerCount()); + } } -void SituationEvaluator::updateInputVector(GameMap* pMap, const QPoint & searchPoint) +void SituationEvaluator::updateInputVector(GameMap* pMap, const QPoint & searchPoint, bool updateUnitData) { - getUnitsInRange(pMap, searchPoint); - for (qint32 i = 0; i < UNIT_COUNT; ++i) + if (updateUnitData) + { + getUnitsInRange(pMap, searchPoint); + createPathFindingSystems(pMap); + } + + for (qint32 i = 0; i < HeavyAiSharedData::UNIT_COUNT; ++i) { - Unit* pUnit = m_unitsInfo[i].pUnit; + Unit* pUnit = m_unitsInfo[i]->pUnit; if (pUnit == nullptr) { - for (qint32 feature = 0; feature < HeavyAiSharedData::SituationFeatures::MaxFeatures; ++feature) - { - qint32 basePosition = UNIT_COUNT * UNIT_COUNT * feature + i * UNIT_COUNT; - for (qint32 enemyUnit = 0; enemyUnit < UNIT_COUNT; ++enemyUnit) - { - m_inputVector(0, basePosition + enemyUnit) = 0; - } - } + clearUnitInput(i); } else { - for (qint32 feature = 0; feature < HeavyAiSharedData::SituationFeatures::MaxFeatures; ++feature) - { - qint32 basePosition = UNIT_COUNT * UNIT_COUNT * feature + i * UNIT_COUNT; + fillUnitInput(i); + } + } +} - } +void SituationEvaluator::clearUnitInput(qint32 index) +{ + for (qint32 feature = 0; feature < HeavyAiSharedData::SituationFeatures::MaxFeatures; ++feature) + { + qint32 basePosition = HeavyAiSharedData::UNIT_COUNT * HeavyAiSharedData::UNIT_COUNT * feature + index * HeavyAiSharedData::UNIT_COUNT; + for (qint32 enemyUnit = 0; enemyUnit < HeavyAiSharedData::UNIT_COUNT; ++enemyUnit) + { + m_inputVector(0, basePosition + enemyUnit) = 0; + } + } +} + +void SituationEvaluator::fillUnitInput(qint32 index) +{ + for (qint32 feature = 0; feature < HeavyAiSharedData::SituationFeatures::MaxFeatures; ++feature) + { + qint32 basePosition = HeavyAiSharedData::UNIT_COUNT * HeavyAiSharedData::UNIT_COUNT * feature + index * HeavyAiSharedData::UNIT_COUNT; + using updateFeature = void (SituationEvaluator::*)(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo); + constexpr std::array featureCb{ + &SituationEvaluator::updateHp, + &SituationEvaluator::updateHpDamage, + &SituationEvaluator::updateFundsDamage, + &SituationEvaluator::updateMovementPoints, + &SituationEvaluator::updateDistance, + &SituationEvaluator::updateHasMoved, + &SituationEvaluator::updateDefense, + &SituationEvaluator::updateRepairsOnPosition, + &SituationEvaluator::updateCapturePoints, + &SituationEvaluator::updateBuildingImportance, + &SituationEvaluator::updateStealthed, + }; + (this->*featureCb[feature])(basePosition, m_unitsInfo[index]); + } +} + +void SituationEvaluator::updateHp(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo) +{ + for (qint32 enemyUnit = 0; enemyUnit < HeavyAiSharedData::UNIT_COUNT; ++enemyUnit) + { + if (shouldFillInfo(unitInfo, enemyUnit)) + { + m_inputVector(0, basePosition + enemyUnit) = m_unitsInfo[enemyUnit]->pUnit->getHpRounded(); + } + else + { + m_inputVector(0, basePosition + enemyUnit) = 0; } } } -//void SituationEvaluator::updateHp(qint32 basePosition, const UnitInfo & unitInfo) -//{ -// for (qint32 enemyUnit = 0; enemyUnit < UNIT_COUNT; ++enemyUnit) -// { -// if (unitInfo.multiplier != m_unitsInfo[enemyUnit].multiplier) -// { -// m_inputVector(0, basePosition + enemyUnit) = m_unitsInfo[enemyUnit].pUnit->getHpRounded(); -// } -// else -// { -// m_inputVector(0, basePosition + enemyUnit) = 0; -// } -// } -//} +void SituationEvaluator::updateHpDamage(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo) +{ + +} + +void SituationEvaluator::updateFundsDamage(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo) +{ + +} + +void SituationEvaluator::updateMovementPoints(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo) +{ + for (qint32 enemyUnit = 0; enemyUnit < HeavyAiSharedData::UNIT_COUNT; ++enemyUnit) + { + if (shouldFillInfo(unitInfo, enemyUnit)) + { + m_inputVector(0, basePosition + enemyUnit) = m_unitsInfo[enemyUnit]->pUnit->getAiCache()[HeavyAiSharedData::AiCache::UnitMovementPoints]; + } + else + { + m_inputVector(0, basePosition + enemyUnit) = 0; + } + } +} + +void SituationEvaluator::updateDistance(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo) +{ + for (qint32 enemyUnit = 0; enemyUnit < HeavyAiSharedData::UNIT_COUNT; ++enemyUnit) + { + if (m_unitsInfo[enemyUnit]->pUnit != nullptr) + { + m_inputVector(0, basePosition + enemyUnit) = m_unitsInfo[enemyUnit]->multiplier * GlobalUtils::getDistance(unitInfo->pUnit->getX(), unitInfo->pUnit->getY(), + m_unitsInfo[enemyUnit]->pUnit->getX(), m_unitsInfo[enemyUnit]->pUnit->getY()); + } + else + { + m_inputVector(0, basePosition + enemyUnit) = 0; + } + } +} + +void SituationEvaluator::updateHasMoved(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo) +{ + for (qint32 enemyUnit = 0; enemyUnit < HeavyAiSharedData::UNIT_COUNT; ++enemyUnit) + { + if (unitInfo->reachable[enemyUnit]) + { + m_inputVector(0, basePosition + enemyUnit) = m_unitsInfo[enemyUnit]->pUnit->getHasMoved(); + } + else + { + m_inputVector(0, basePosition + enemyUnit) = 0; + } + } +} + +void SituationEvaluator::updateDefense(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo) +{ + for (qint32 enemyUnit = 0; enemyUnit < HeavyAiSharedData::UNIT_COUNT; ++enemyUnit) + { + if (shouldFillInfo(unitInfo, enemyUnit)) + { + m_inputVector(0, basePosition + enemyUnit) = m_unitsInfo[enemyUnit]->pUnit->getAiCache()[HeavyAiSharedData::AiCache::TerrainDefense]; + } + else + { + m_inputVector(0, basePosition + enemyUnit) = 0; + } + } +} + +void SituationEvaluator::updateRepairsOnPosition(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo) +{ + +} + +void SituationEvaluator::updateCapturePoints(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo) +{ + for (qint32 enemyUnit = 0; enemyUnit < HeavyAiSharedData::UNIT_COUNT; ++enemyUnit) + { + if (shouldFillInfo(unitInfo, enemyUnit)) + { + m_inputVector(0, basePosition + enemyUnit) = m_unitsInfo[enemyUnit]->pUnit->getCapturePoints(); + } + else + { + m_inputVector(0, basePosition + enemyUnit) = 0; + } + } +} + +void SituationEvaluator::updateBuildingImportance(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo) +{ + +} + +void SituationEvaluator::updateStealthed(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo) +{ + for (qint32 enemyUnit = 0; enemyUnit < HeavyAiSharedData::UNIT_COUNT; ++enemyUnit) + { + if (shouldFillInfo(unitInfo, enemyUnit)) + { + + m_inputVector(0, basePosition + enemyUnit) = m_unitsInfo[enemyUnit]->stealthed[unitInfo->pUnit->getOwner()->getPlayerID()]; + } + else + { + m_inputVector(0, basePosition + enemyUnit) = 0; + } + } +} + +bool SituationEvaluator::shouldFillInfo(const HeavyAiSharedData::spUnitInfo & unitInfo, qint32 enemyUnit) +{ + return unitInfo->multiplier != m_unitsInfo[enemyUnit]->multiplier && + unitInfo->reachable[enemyUnit]; +} void SituationEvaluator::getUnitsInRange(GameMap* pMap, const QPoint & searchPoint) { qint32 alliedPosition = 0; - qint32 enemyPosition = UNIT_COUNT - 1; + qint32 enemyPosition = HeavyAiSharedData::UNIT_COUNT - 1; for (const auto & point : m_searchRange->getVector()) { QPoint mapPoint = point + searchPoint; @@ -70,14 +223,16 @@ void SituationEvaluator::getUnitsInRange(GameMap* pMap, const QPoint & searchPoi { if (m_pOwner->isEnemyUnit(pUnit)) { - m_unitsInfo[enemyPosition].pUnit = pUnit; - m_unitsInfo[enemyPosition].multiplier = -1; + m_unitsInfo[enemyPosition]->pUnit = pUnit; + m_unitsInfo[enemyPosition]->multiplier = -1; + updateStealthInfo(pMap, enemyPosition); --enemyPosition; } else { - m_unitsInfo[alliedPosition].pUnit = pUnit; - m_unitsInfo[alliedPosition].multiplier = 1; + m_unitsInfo[alliedPosition]->pUnit = pUnit; + m_unitsInfo[alliedPosition]->multiplier = 1; + updateStealthInfo(pMap, alliedPosition); ++alliedPosition; } if (alliedPosition > enemyPosition) @@ -89,7 +244,27 @@ void SituationEvaluator::getUnitsInRange(GameMap* pMap, const QPoint & searchPoi } for (qint32 i = alliedPosition; i <= enemyPosition; ++i) { - m_unitsInfo[enemyPosition].pUnit = nullptr; - m_unitsInfo[enemyPosition].multiplier = 1; + m_unitsInfo[enemyPosition]->pUnit = nullptr; + m_unitsInfo[enemyPosition]->pUnitTargetedPathFindingSystem.reset(); + m_unitsInfo[enemyPosition]->multiplier = 1; + } +} + +void SituationEvaluator::updateStealthInfo(GameMap* pMap, qint32 unitPosition) +{ + for (qint32 i = 0; i < pMap->getPlayerCount(); ++i) + { + m_unitsInfo[unitPosition]->stealthed[i] = m_unitsInfo[unitPosition]->pUnit->isStealthed(pMap->getPlayer(i)); + } +} + +void SituationEvaluator::createPathFindingSystems(GameMap* pMap) +{ + for (qint32 i = 0; i < HeavyAiSharedData::UNIT_COUNT; ++i) + { + if (m_unitsInfo[i]->pUnit != nullptr) + { + m_unitsInfo[i]->pUnitTargetedPathFindingSystem = MemoryManagement::create(pMap, i, m_unitsInfo); + } } } diff --git a/ai/heavyai/situationevaluator.h b/ai/heavyai/situationevaluator.h index 1e7ab712c..ac6e84308 100644 --- a/ai/heavyai/situationevaluator.h +++ b/ai/heavyai/situationevaluator.h @@ -17,19 +17,38 @@ class SituationEvaluator : public QObject Q_OBJECT public: - static constexpr qint32 UNIT_COUNT = 40; - static constexpr qint32 SEARCH_RANGE = 30; - explicit SituationEvaluator(Player* pOwner); - - void updateInputVector(GameMap* pMap, const QPoint & searchPoint); + /** + * @brief updateInputVector + * @param pMap + * @param searchPoint position around which we want to decide if it's a winning, loosing or draw situation + * @param updateUnitData if units should be refetched and all pfs need to research + */ + void updateInputVector(GameMap* pMap, const QPoint & searchPoint, bool updateUnitData); private: void getUnitsInRange(GameMap* pMap, const QPoint & searchPoint); - + void createPathFindingSystems(GameMap* pMap); + void clearUnitInput(qint32 index); + void fillUnitInput(qint32 index); + bool shouldFillInfo(const HeavyAiSharedData::spUnitInfo & unitInfo, qint32 enemyUnit); + void updateHp(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo); + void updateHpDamage(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo); + void updateFundsDamage(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo); + void updateMovementPoints(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo); + void updateDistance(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo); + void updateHasMoved(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo); + void updateDefense(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo); + void updateRepairsOnPosition(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo); + void updateCapturePoints(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo); + void updateBuildingImportance(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo); + void updateStealthed(qint32 basePosition, const HeavyAiSharedData::spUnitInfo & unitInfo); + + void updateStealthInfo(GameMap* pMap, qint32 unitPosition); private: opennn::Tensor m_inputVector; - std::array m_unitsInfo; + + std::array m_unitsInfo; spQmlVectorPoint m_searchRange; Player* m_pOwner{nullptr}; }; diff --git a/ai/heavyai/unittargetedpathfindingsystem.cpp b/ai/heavyai/unittargetedpathfindingsystem.cpp index 53c2e83bc..4cb192b8b 100644 --- a/ai/heavyai/unittargetedpathfindingsystem.cpp +++ b/ai/heavyai/unittargetedpathfindingsystem.cpp @@ -1,34 +1,37 @@ #include "ai/heavyai/unittargetedpathfindingsystem.h" #include "coreengine/globalutils.h" -UnitTargetedPathFindingSystem::UnitTargetedPathFindingSystem(GameMap* pMap, Unit* pUnit, std::vector & pTargets) - : UnitPathFindingSystem(pMap, pUnit), - m_pTargets(pTargets) +UnitTargetedPathFindingSystem::UnitTargetedPathFindingSystem(GameMap* pMap, qint32 unitIdx, std::array & pTargets) + : UnitPathFindingSystem(pMap, pTargets[unitIdx]->pUnit), + m_pTargets(pTargets), + m_unitIdx{unitIdx} { #ifdef GRAPHICSUPPORT setObjectName("UnitTargetedPathFindingSystem"); #endif Interpreter::setCppOwnerShip(this); - m_reachableTargets.reserve(m_pTargets.size()); } qint32 UnitTargetedPathFindingSystem::getRemainingCost(qint32 x, qint32 y, qint32 currentCost) { + m_allReached = true; qint32 minCost = std::numeric_limits::max(); - for (qint32 i = 0; i < m_pTargets.size(); ++i) + for (qint32 i = m_searchIndex; i < m_pTargets.size(); ++i) { auto & target = m_pTargets[i]; - auto & cache = target.pUnit->getAiCache(); - qint32 distance = GlobalUtils::getDistance(x, y, target.pUnit->getX(), target.pUnit->getY()); + auto & cache = target->pUnit->getAiCache(); + qint32 distance = GlobalUtils::getDistance(x, y, target->pUnit->getX(), target->pUnit->getY()); qint32 maxFireRange = cache[HeavyAiSharedData::AiCache::MaxFirerange]; // in fire range? if (distance >= cache[HeavyAiSharedData::AiCache::MinFirerange] && distance <= maxFireRange) { - m_pTargets[i].reachable = true; - m_reachableTargets.push_back(m_pTargets[i]); - m_pTargets.erase(m_pTargets.cbegin() + i); + m_pTargets[m_unitIdx]->reachable[i] = true; + if (i == m_searchIndex) + { + m_searchIndex += 1; + } } else { @@ -37,6 +40,7 @@ qint32 UnitTargetedPathFindingSystem::getRemainingCost(qint32 x, qint32 y, qint3 { minCost = newCost; } + m_allReached = false; } } return minCost; @@ -44,5 +48,5 @@ qint32 UnitTargetedPathFindingSystem::getRemainingCost(qint32 x, qint32 y, qint3 bool UnitTargetedPathFindingSystem::finished(qint32 x, qint32 y, qint32 movementCosts) { - return m_pTargets.size() == 0; + return m_allReached; } diff --git a/ai/heavyai/unittargetedpathfindingsystem.h b/ai/heavyai/unittargetedpathfindingsystem.h index b567c5256..0133d630c 100644 --- a/ai/heavyai/unittargetedpathfindingsystem.h +++ b/ai/heavyai/unittargetedpathfindingsystem.h @@ -1,8 +1,11 @@ #pragma once -#include +#include "game/unitpathfindingsystem.h" #include "ai/heavyai/heavyAiSharedData.h" +class UnitTargetedPathFindingSystem; +using spUnitTargetedPathFindingSystem = std::shared_ptr; + class UnitTargetedPathFindingSystem : public UnitPathFindingSystem { Q_OBJECT @@ -12,7 +15,7 @@ class UnitTargetedPathFindingSystem : public UnitPathFindingSystem Unit* pUnit{nullptr}; }; - UnitTargetedPathFindingSystem(GameMap* pMap, Unit* pUnit, std::vector & pTargets); + UnitTargetedPathFindingSystem(GameMap* pMap, qint32 unitIdx, std::array & pTargets); /** * @brief getRemainingCost * @param x @@ -29,7 +32,9 @@ class UnitTargetedPathFindingSystem : public UnitPathFindingSystem */ virtual bool finished(qint32 x, qint32 y, qint32) override; private: - std::vector m_pTargets; - std::vector m_reachableTargets; + std::array & m_pTargets; + qint32 m_searchIndex{0}; + bool m_allReached{false}; + qint32 m_unitIdx{-1}; }; diff --git a/game/building.cpp b/game/building.cpp index bf07e3204..c1c8378dd 100644 --- a/game/building.cpp +++ b/game/building.cpp @@ -222,20 +222,6 @@ void Building::setOwner(Player* pOwner) } } -Player* Building::getOwner() -{ - return m_pOwner; -} - -qint32 Building::getOwnerID() -{ - if (m_pOwner != nullptr) - { - return m_pOwner->getPlayerID(); - } - return -1; -} - void Building::loadSprite(const QString & spriteID, bool addPlayerColor, qint32 frameTime, QPoint pos) { if (addPlayerColor) @@ -647,30 +633,6 @@ QString Building::getMinimapIcon() } } -qint32 Building::getX() const -{ - if (m_pTerrain != nullptr) - { - return m_pTerrain->Terrain::getX(); - } - else - { - return -1; - } -} - -qint32 Building::getY() const -{ - if (m_pTerrain != nullptr) - { - return m_pTerrain->Terrain::getY(); - } - else - { - return -1; - } -} - QStringList Building::getActionList() { Interpreter* pInterpreter = Interpreter::getInstance(); diff --git a/game/building.h b/game/building.h index c71508005..cdfd7ad6f 100644 --- a/game/building.h +++ b/game/building.h @@ -5,6 +5,8 @@ #include #include "game/GameEnums.h" +#include "game/player.h" +#include "game/terrain.h" #include "coreengine/fileserializable.h" #include "coreengine/scriptvariables.h" #include "coreengine/jsthis.h" @@ -12,7 +14,6 @@ #include "objects/base/tooltip.h" class QmlVectorPoint; -class Player; class Unit; class Terrain; class GameAction; @@ -257,12 +258,22 @@ class Building final : public Tooltip, public FileSerializable, public JsThis * @brief getOwnerID * @return the player owner index of this building */ - Q_INVOKABLE qint32 getOwnerID(); + Q_INVOKABLE qint32 getOwnerID() + { + if (m_pOwner != nullptr) + { + return m_pOwner->getPlayerID(); + } + return -1; + } /** * @brief getOwner * @return the pointer to the owner of this building */ - Q_INVOKABLE Player* getOwner(); + Q_INVOKABLE Player* getOwner() + { + return m_pOwner; + } /** * @brief getBuildingID * @return the string if of this building @@ -275,12 +286,32 @@ class Building final : public Tooltip, public FileSerializable, public JsThis * @brief getX * @return x coordinates of this unit */ - Q_INVOKABLE qint32 getX() const; + Q_INVOKABLE qint32 getX() const + { + if (m_pTerrain != nullptr) + { + return m_pTerrain->Terrain::getX(); + } + else + { + return -1; + } + } /** * @brief getY * @return y coordinates of this unit */ - Q_INVOKABLE qint32 getY() const; + Q_INVOKABLE qint32 getY() const + { + if (m_pTerrain != nullptr) + { + return m_pTerrain->Terrain::getY(); + } + else + { + return -1; + } + } /** * @brief getPosition * @return diff --git a/game/player.cpp b/game/player.cpp index 3739e1110..3a50b0a8e 100644 --- a/game/player.cpp +++ b/game/player.cpp @@ -547,19 +547,16 @@ oxygine::spResAnim Player::getNeutralTableAnim() return m_neutralTableAnim; } -qint32 Player::getPlayerID() const -{ - if (m_pMap != nullptr) +void Player::updatePlayerID() +{ + + for (qint32 i = 0; i < m_pMap->getPlayerCount(); i++) { - for (qint32 i = 0; i < m_pMap->getPlayerCount(); i++) + if (m_pMap->getPlayer(i) == this) { - if (m_pMap->getPlayer(i) == this) - { - return i; - } + m_playerId = i; } } - return 0; } bool Player::getFlipUnitSprites() const @@ -1163,55 +1160,85 @@ const QImage &Player::getColorTable() const void Player::updatePlayerVision(bool reduceTimer) { - // only update visual stuff if needed - if (reduceTimer || - m_pMap->getCurrentPlayer() == this || - m_pMap->getCurrentViewPlayer() == this) + qint32 width = m_pMap->getMapWidth(); + qint32 heigth = m_pMap->getMapHeight(); + if (m_FogVisionFields.size() != width || + m_FogVisionFields[width - 1].size() != heigth) { - qint32 width = m_pMap->getMapWidth(); - qint32 heigth = m_pMap->getMapHeight(); - if (m_FogVisionFields.size() != width || - m_FogVisionFields[width - 1].size() != heigth) + CONSOLE_PRINT("Loading player for player " + m_playerNameId + " vision cause it's not loaded yet", GameConsole::eWARNING); + loadVisionFields(); + } + for (qint32 x = 0; x < width; x++) + { + for (qint32 y = 0; y < heigth; y++) { - CONSOLE_PRINT("Loading player for player " + m_playerNameId + " vision cause it's not loaded yet", GameConsole::eWARNING); - loadVisionFields(); + if (reduceTimer) + { + m_FogVisionFields[x][y].m_duration -= 1; + } + qint32 duration = m_FogVisionFields[x][y].m_duration; + if (duration <= 0) + { + if (m_FogVisionFields[x][y].m_visionType == GameEnums::VisionType_Clear) + { + m_FogVisionFields[x][y].m_visionType = GameEnums::VisionType_Fogged; + } + m_FogVisionFields[x][y].m_duration = 0; + m_FogVisionFields[x][y].m_directView = false; + } } - for (qint32 x = 0; x < width; x++) + } + bool visionBlock = m_pMap->getGameRules()->getVisionBlock(); + // create vision for all units and terrain + for (qint32 x = 0; x < width; x++) + { + for (qint32 y = 0; y < heigth; y++) { - for (qint32 y = 0; y < heigth; y++) + // check terrain vision + Terrain* pTerrain = m_pMap->getTerrain(x, y); + qint32 visionRange = pTerrain->getVision(this); + if (visionRange >= 0) { - if (reduceTimer) + spQmlVectorPoint pPoints; + if (visionBlock) { - m_FogVisionFields[x][y].m_duration -= 1; + pPoints = m_pMap->getSpVisionCircle(x, y, 0, visionRange, pTerrain->getTotalVisionHigh()); } - qint32 duration = m_FogVisionFields[x][y].m_duration; - if (duration <= 0) + else { - if (m_FogVisionFields[x][y].m_visionType == GameEnums::VisionType_Clear) + pPoints = GlobalUtils::getSpCircle(0, visionRange); + } + for (auto & point : pPoints->getVector()) + { + if (m_pMap->onMap(point.x() + x, point.y() + y)) { - m_FogVisionFields[x][y].m_visionType = GameEnums::VisionType_Fogged; + Terrain* visionField = m_pMap->getTerrain(point.x() + x,point.y() + y); + Unit* pUnit = visionField->getUnit(); + bool visionHide = visionField->getVisionHide(this); + if ((!visionHide) || + ((pUnit != nullptr) && visionHide && + !pUnit->useTerrainHide() && !pUnit->isStatusStealthed())) + { + m_FogVisionFields[point.x() + x][point.y() + y].m_visionType = GameEnums::VisionType_Clear; + } } - m_FogVisionFields[x][y].m_duration = 0; - m_FogVisionFields[x][y].m_directView = false; } } - } - bool visionBlock = m_pMap->getGameRules()->getVisionBlock(); - // create vision for all units and terrain - for (qint32 x = 0; x < width; x++) - { - for (qint32 y = 0; y < heigth; y++) + // check building vision + Building* pBuilding = pTerrain->getBuilding(); + if ((pBuilding != nullptr) && + ((isAlly( pBuilding->getOwner())) || + (checkAlliance(pBuilding->getOwner()) == GameEnums::Alliance_Friend))) { - // check terrain vision - Terrain* pTerrain = m_pMap->getTerrain(x, y); - qint32 visionRange = pTerrain->getVision(this); + m_FogVisionFields[x][y].m_visionType = GameEnums::VisionType_Clear; + qint32 visionRange = pBuilding->getVision(); if (visionRange >= 0) { spQmlVectorPoint pPoints; if (visionBlock) { - pPoints = m_pMap->getSpVisionCircle(x, y, 0, visionRange, pTerrain->getTotalVisionHigh()); + pPoints = m_pMap->getSpVisionCircle(x, y, 0, visionRange, pBuilding->getTotalVisionHigh()); } else { @@ -1233,86 +1260,50 @@ void Player::updatePlayerVision(bool reduceTimer) } } } - // check building vision - Building* pBuilding = pTerrain->getBuilding(); - if ((pBuilding != nullptr) && - ((isAlly( pBuilding->getOwner())) || - (checkAlliance(pBuilding->getOwner()) == GameEnums::Alliance_Friend))) + } + // create unit vision + Unit* pUnit = pTerrain->getUnit(); + if ((pUnit != nullptr) && + (isAlly(pUnit->getOwner()))) + { + qint32 visionRange = pUnit->getVision(QPoint(x, y)); + spQmlVectorPoint pPoints; + if (visionBlock) { - m_FogVisionFields[x][y].m_visionType = GameEnums::VisionType_Clear; - qint32 visionRange = pBuilding->getVision(); - if (visionRange >= 0) + if (pBuilding != nullptr) { - spQmlVectorPoint pPoints; - if (visionBlock) - { - pPoints = m_pMap->getSpVisionCircle(x, y, 0, visionRange, pBuilding->getTotalVisionHigh()); - } - else - { - pPoints = GlobalUtils::getSpCircle(0, visionRange); - } - for (auto & point : pPoints->getVector()) - { - if (m_pMap->onMap(point.x() + x, point.y() + y)) - { - Terrain* visionField = m_pMap->getTerrain(point.x() + x,point.y() + y); - Unit* pUnit = visionField->getUnit(); - bool visionHide = visionField->getVisionHide(this); - if ((!visionHide) || - ((pUnit != nullptr) && visionHide && - !pUnit->useTerrainHide() && !pUnit->isStatusStealthed())) - { - m_FogVisionFields[point.x() + x][point.y() + y].m_visionType = GameEnums::VisionType_Clear; - } - } - } + pPoints = m_pMap->getSpVisionCircle(x, y, 0, visionRange, pUnit->getTotalVisionHigh()); + } + else + { + pPoints = m_pMap->getSpVisionCircle(x, y, 0, visionRange, pUnit->getVisionHigh() + pTerrain->getVisionHigh()); } } - // create unit vision - Unit* pUnit = pTerrain->getUnit(); - if ((pUnit != nullptr) && - (isAlly(pUnit->getOwner()))) + else { - qint32 visionRange = pUnit->getVision(QPoint(x, y)); - spQmlVectorPoint pPoints; - if (visionBlock) + pPoints = GlobalUtils::getSpCircle(0, visionRange); + } + for (auto & point : pPoints->getVector()) + { + if (m_pMap->onMap(point.x() + x, point.y() + y)) { - if (pBuilding != nullptr) + Terrain* visionField = m_pMap->getTerrain(point.x() + x,point.y() + y); + Unit* pUnit = visionField->getUnit(); + bool visionHide = visionField->getVisionHide(this); + if ((!visionHide) || + ((pUnit != nullptr) && visionHide && + !pUnit->useTerrainHide() && !pUnit->isStatusStealthed())) { - pPoints = m_pMap->getSpVisionCircle(x, y, 0, visionRange, pUnit->getTotalVisionHigh()); + m_FogVisionFields[point.x() + x][point.y() + y].m_visionType = GameEnums::VisionType_Clear; } - else + // terrain hides are visible if we're near it. + else if (((qAbs(point.x()) + qAbs(point.y())) <= 1)) { - pPoints = m_pMap->getSpVisionCircle(x, y, 0, visionRange, pUnit->getVisionHigh() + pTerrain->getVisionHigh()); + m_FogVisionFields[point.x() + x][point.y() + y].m_visionType = GameEnums::VisionType_Clear; } - } - else - { - pPoints = GlobalUtils::getSpCircle(0, visionRange); - } - for (auto & point : pPoints->getVector()) - { - if (m_pMap->onMap(point.x() + x, point.y() + y)) + else { - Terrain* visionField = m_pMap->getTerrain(point.x() + x,point.y() + y); - Unit* pUnit = visionField->getUnit(); - bool visionHide = visionField->getVisionHide(this); - if ((!visionHide) || - ((pUnit != nullptr) && visionHide && - !pUnit->useTerrainHide() && !pUnit->isStatusStealthed())) - { - m_FogVisionFields[point.x() + x][point.y() + y].m_visionType = GameEnums::VisionType_Clear; - } - // terrain hides are visible if we're near it. - else if (((qAbs(point.x()) + qAbs(point.y())) <= 1)) - { - m_FogVisionFields[point.x() + x][point.y() + y].m_visionType = GameEnums::VisionType_Clear; - } - else - { - // do nothing - } + // do nothing } } } diff --git a/game/player.h b/game/player.h index c1b2004f9..cb48dced1 100644 --- a/game/player.h +++ b/game/player.h @@ -7,7 +7,6 @@ #include #include -#include "coreengine/qmlvector.h" #include "coreengine/fileserializable.h" #include "coreengine/jsthis.h" @@ -17,6 +16,12 @@ #include "gameinput/basegameinputif.h" +class QmlVectorPoint; +using spQmlVectorPoint = std::shared_ptr; +class QmlVectorUnit; +using spQmlVectorUnit = std::shared_ptr; +class QmlVectorBuilding; +using spQmlVectorBuilding = std::shared_ptr; class SimpleProductionSystem; class GameMap; class Player; @@ -270,7 +275,14 @@ class Player : public QObject, public oxygine::Actor, public FileSerializable, p * @brief getPlayerID player id of this player from 0 to n * @return */ - Q_INVOKABLE qint32 getPlayerID() const; + Q_INVOKABLE qint32 getPlayerID() + { + if (m_pMap != nullptr && m_playerId < 0) + { + updatePlayerID(); + } + return m_playerId; + } /** * @brief getArmy the army string id of this player. * @return @@ -746,6 +758,10 @@ class Player : public QObject, public oxygine::Actor, public FileSerializable, p * @param pUnit */ qint32 calculatePlayerStrength(Unit* pUnit) const; + /** + * @brief Player::updatePlayerID + */ + void updatePlayerID(); protected: GameMap* m_pMap{nullptr}; @@ -794,6 +810,7 @@ class Player : public QObject, public oxygine::Actor, public FileSerializable, p quint64 m_socketId{0}; bool m_playerArmySelected{false}; qint32 m_averageCosts{-1}; + qint32 m_playerId{-1}; /** * @brief m_uniqueIdentifier */ diff --git a/game/terrain.cpp b/game/terrain.cpp index 4e3990b17..7a1ad861a 100644 --- a/game/terrain.cpp +++ b/game/terrain.cpp @@ -1407,11 +1407,6 @@ const QString Terrain::getTerrainID() const return m_terrainID; } -qint32 Terrain::getX() const -{ - return m_x; -} - void Terrain::setX(const qint32 value) { m_x = value; @@ -1421,11 +1416,6 @@ void Terrain::setX(const qint32 value) } } -qint32 Terrain::getY() const -{ - return m_y; -} - void Terrain::setY(const qint32 value) { m_y = value; diff --git a/game/terrain.h b/game/terrain.h index e8d6f48c4..8e9275f2d 100644 --- a/game/terrain.h +++ b/game/terrain.h @@ -8,13 +8,15 @@ #include "coreengine/JsCallback.h" #include "coreengine/scriptvariables.h" #include "coreengine/jsthis.h" - -#include "game/unit.h" -#include "game/building.h" - #include "objects/base/tooltip.h" +#include "game/GameEnums.h" +class GameAction; +class Building; +using spBuilding = std::shared_ptr; class Player; +class Unit; +using spUnit = std::shared_ptr; class TerrainFindingSystem; class GameMap; using spTerrainFindingSystem = std::shared_ptr; @@ -369,11 +371,17 @@ class Terrain final : public Tooltip, public FileSerializable, public JsThis Q_INVOKABLE const QString getTerrainID() const; Q_INVOKABLE QString getTerrainName() const; Q_INVOKABLE void setTerrainName(const QString & value, bool customName = false); - Q_INVOKABLE qint32 getX() const; + Q_INVOKABLE qint32 getX() const + { + return m_x; + } Q_INVOKABLE void setX(const qint32 value); Q_INVOKABLE qint32 getHp() const; Q_INVOKABLE void setHp(const qint32 value); - Q_INVOKABLE qint32 getY() const; + Q_INVOKABLE qint32 getY() const + { + return m_y; + } Q_INVOKABLE void setY(const qint32 value); /** * @brief Terrain::getVision diff --git a/game/unit.cpp b/game/unit.cpp index 683b70615..e2747e990 100644 --- a/game/unit.cpp +++ b/game/unit.cpp @@ -340,11 +340,6 @@ void Unit::syncAnimation(oxygine::timeMS syncTime) #endif } -Player* Unit::getOwner() -{ - return m_pOwner; -} - QString Unit::getName() { if (m_customName.isEmpty()) @@ -2587,30 +2582,6 @@ qreal Unit::getUnitDamage(const QString & weaponID) return -1.0; } -qint32 Unit::getX() const -{ - if (m_pTerrain != nullptr) - { - return m_pTerrain->Terrain::getX(); - } - else - { - return m_virtuellX; - } -} - -qint32 Unit::getY() const -{ - if (m_pTerrain != nullptr) - { - return m_pTerrain->Terrain::getY(); - } - else - { - return m_virtuellY; - } -} - void Unit::refill(bool noMaterial, qreal fuelAmount, qreal ammo1Amount, qreal ammo2Amount) { setFuel(m_fuel + m_maxFuel * fuelAmount); diff --git a/game/unit.h b/game/unit.h index c03ad4fcb..c46838559 100644 --- a/game/unit.h +++ b/game/unit.h @@ -9,6 +9,7 @@ #include "coreengine/jsthis.h" #include "game/GameEnums.h" +#include "game/terrain.h" #include "objects/base/tooltip.h" @@ -196,12 +197,32 @@ class Unit final : public Tooltip, public FileSerializable, public JsThis * @brief getX * @return x coordinates of this unit */ - Q_INVOKABLE qint32 getX() const; + Q_INVOKABLE qint32 getX() const + { + if (m_pTerrain != nullptr) + { + return m_pTerrain->Terrain::getX(); + } + else + { + return m_virtuellX; + } + } /** * @brief getY * @return y coordinates of this unit */ - Q_INVOKABLE qint32 getY() const; + Q_INVOKABLE qint32 getY() const + { + if (m_pTerrain != nullptr) + { + return m_pTerrain->Terrain::getY(); + } + else + { + return m_virtuellY; + } + } /** * @brief createUnitPathFindingSystem Note: the path finding system needs to be deleted by the caller using remove() * @return a path finding system that is explored for this unit using the given player information @@ -570,7 +591,10 @@ class Unit final : public Tooltip, public FileSerializable, public JsThis * @brief getOwner * @return the pointer to the owner of this unit */ - Q_INVOKABLE Player* getOwner(); + Q_INVOKABLE Player* getOwner() + { + return m_pOwner; + } /** * @brief getMovementType the movement type id * @return diff --git a/game/unitpathfindingsystem.cpp b/game/unitpathfindingsystem.cpp index 653955757..f1217f3b4 100644 --- a/game/unitpathfindingsystem.cpp +++ b/game/unitpathfindingsystem.cpp @@ -68,7 +68,8 @@ qint32 UnitPathFindingSystem::getCosts(qint32 index, qint32 x, qint32 y, qint32 if (!m_useBasecosts) { // check for an enemy on the field - if (pUnit != nullptr) + if (pUnit != nullptr && + pUnit->getHp() > 0.0) { // ignore unit if it's not an enemy unit or if it's stealthed if (m_pUnit->getOwner()->isEnemyUnit(pUnit) && diff --git a/objects/dialogs/editor/dialogextendmap.cpp b/objects/dialogs/editor/dialogextendmap.cpp index e5f81c2c8..084651f98 100644 --- a/objects/dialogs/editor/dialogextendmap.cpp +++ b/objects/dialogs/editor/dialogextendmap.cpp @@ -6,6 +6,7 @@ #include "objects/base/textbox.h" #include "coreengine/interpreter.h" +#include "coreengine/globalutils.h" #include "resource_management/objectmanager.h"