StreetConnections BuildOperation::calculateStreetConnections( const MapCoords& mapCoords, const ToDrawOrToReplaceWith& toDrawOrToReplaceWith) const { // Angrenzende Straßen (auf der Karte und im BuildOperationResult) checken const Map* map = context.game->getMap(); auto isStreetThere = [&](const MapCoords& mapCoordsInLamdba) { if (map->isStreetAt(mapCoordsInLamdba)) { return true; } auto iter = result.find(mapCoordsInLamdba); if (iter != result.cend()) { std::shared_ptr<MapObjectFixed>& mapObjectToUse = (toDrawOrToReplaceWith == TO_DRAW) ? iter->second->mapObjectToDraw : iter->second->mapObjectToReplaceWith; return (std::dynamic_pointer_cast<Street>(mapObjectToUse) != nullptr); } return false; }; bool isStreetNorth = isStreetThere(MapCoords(mapCoords.x(), mapCoords.y() - 1)); bool isStreetEast = isStreetThere(MapCoords(mapCoords.x() + 1, mapCoords.y())); bool isStreetSouth = isStreetThere(MapCoords(mapCoords.x(), mapCoords.y() + 1)); bool isStreetWest = isStreetThere(MapCoords(mapCoords.x() - 1, mapCoords.y())); StreetConnections streetConnections; streetConnections.set(StreetConnections::BIT_POS_NORTH, isStreetNorth); streetConnections.set(StreetConnections::BIT_POS_EAST, isStreetEast); streetConnections.set(StreetConnections::BIT_POS_SOUTH, isStreetSouth); streetConnections.set(StreetConnections::BIT_POS_WEST, isStreetWest); return streetConnections; }
/** * @brief Testet das Ausführen einer einfachen Bauoperation. */ TEST_F(BuildOperationTest, regularBuild) { const MapObjectType* marketplace = configMgr->getMapObjectType("marketplace"); // Testaufbau player->coins = 5000; colony->getGoods(configMgr->getGood("tools")).inventory = 20; colony->getGoods(configMgr->getGood("wood")).inventory = 40; colony->getGoods(configMgr->getGood("bricks")).inventory = 30; BuildOperation buildOperation(context, *player); buildOperation.requestBuildWhenNothingInTheWay(MapCoords(45, 33), marketplace, Direction::SOUTH); buildOperation.requestBuildWhenNothingInTheWay(MapCoords(37, 33), marketplace, Direction::NORTH); buildOperation.requestBuildWhenNothingInTheWay(MapCoords(38, 37), marketplace, Direction::WEST); buildOperation.doBuild(); // Testauswertung: Resourcen korrekt abgezogen ASSERT_EQ(4400, player->coins); ASSERT_EQ(8, colony->getGoods(configMgr->getGood("tools")).inventory); ASSERT_EQ(10, colony->getGoods(configMgr->getGood("wood")).inventory); ASSERT_EQ(30, colony->getGoods(configMgr->getGood("bricks")).inventory); // Testauswertung: Gebäude in die Map übernommen assertCorrectBuild({45, 33}, marketplace, Direction::SOUTH, 4, 3); assertCorrectBuild({37, 33}, marketplace, Direction::NORTH, 4, 3); assertCorrectBuild({38, 37}, marketplace, Direction::WEST, 3, 4); }
/** * @brief Fügt einen Abreißauftrag der Queue hinzu und prüft, ob alle betroffenen Kacheln als "zu entfernen" * markiert werden */ TEST_F(BuildOperationTest, demolishMapObject) { BuildOperation buildOperation(context, *player); buildOperation.requestDemolish(*context.game->getMap()->getMapObjectFixedAt({48, 40})); BuildOperationResult result = buildOperation.getResult(); ASSERT_EQ(BuildOperationResult::OK, result.result); ASSERT_EQ(4, result.size()); ASSERT_EQ(true, result.at(MapCoords(48, 40))->deleteMapObjectThere); ASSERT_EQ(true, result.at(MapCoords(49, 40))->deleteMapObjectThere); ASSERT_EQ(true, result.at(MapCoords(48, 41))->deleteMapObjectThere); ASSERT_EQ(true, result.at(MapCoords(49, 41))->deleteMapObjectThere); }
virtual void SetUp() { GameTest::SetUp(); FourthDirection southView = Direction::SOUTH; northernForest1 = game->addHarvestable( MapCoords(30, 30), configMgr->getMapObjectType("northern-forest1"), southView); northernForest1->setAge(1.0); northernForest2 = game->addHarvestable( MapCoords(30, 31), configMgr->getMapObjectType("northern-forest2"), southView); northernForest2->setAge(1.3); }
virtual void SetUp() { GameTest::SetUp(); sheepFarm = dynamic_cast<Building*>(game->addStructure( MapCoords(28, 30), configMgr->getMapObjectType("sheep-farm"), Direction::SOUTH, game->getPlayer(0))); cattleFarm = dynamic_cast<Building*>(game->addStructure( MapCoords(38, 28), configMgr->getMapObjectType("cattle-farm"), Direction::SOUTH, game->getPlayer(0))); // Schafe/Rinder so einstellen, dass sie ewig zum Grasfressen brauchen. // Wir wollen nicht, dass während des Tests welche zurücklaufen. configMgr->getMapObjectType("sheep")->secondsToProduce = 9999; }
void WindowManager::OnMouseMotionEvent(unsigned int x, unsigned int y) { MapCoords(x, y); // hand over to root window m_spRootWindow->OnMouseMotionEvent(x, y); // check if mouse left any rectangle if (!m_listAllTrackMouseLeaveEntries.empty()) { std::list<T_TrackMouseLeaveEntry>::iterator iter = m_listAllTrackMouseLeaveEntries.begin(), stop = m_listAllTrackMouseLeaveEntries.end(); Point p(x,y); while (iter != stop) { const T_TrackMouseLeaveEntry& entry = *iter; if (!entry.first.IsInside(p)) { entry.second(); // remove entry; returns iterator to next element iter = m_listAllTrackMouseLeaveEntries.erase(iter); } else ++iter; } } }
Cube* Map::Get(size_t x, size_t y, size_t z) { ItCubeInstance res = m_data.find(MapCoords(x,y,z)); if( res == m_data.end() ) return NULL; return std::get<0>(res->second); }
/** * @brief Spezialtest "halbe Kreuzung" * * Wir bauen einen Feldweg von (46, 31) nach (46, 33). * Allerdings reicht das Geld nur für eine Kachel. * * Wir erwarten, dass beim Bau nur ein T-Stück entsteht, obwohl eine Kreuzung gezogen wurde. */ TEST_F(BuildOperationTest, partialCrossroads) { const Map* map = game->getMap(); const MapObjectType* farmRoad = configMgr->getMapObjectType("farm-road"); // Testaufbau player->coins = 5; BuildOperation buildOperation(context, *player); for (int y = 31; y <= 33; y++) { buildOperation.requestBuildWhenNothingInTheWay(MapCoords(46, y), farmRoad, Direction::SOUTH); } buildOperation.doBuild(); // Testauswertung ASSERT_EQ(0, player->coins); assertCorrectBuild({46, 31}, farmRoad, Direction::SOUTH, 1, 1); ASSERT_EQ(StreetConnections::BIT_MASK_SOUTH, dynamic_cast<const Street*>(map->getMapObjectFixedAt({46, 31}))->streetConnections); assertCorrectBuild({46, 32}, farmRoad, Direction::SOUTH, 1, 1); ASSERT_EQ(StreetConnections::BIT_MASK_NORTH | StreetConnections::BIT_MASK_EAST | StreetConnections::BIT_MASK_WEST, dynamic_cast<const Street*>(map->getMapObjectFixedAt({46, 32}))->streetConnections); ASSERT_TRUE(map->getMapObjectFixedAt({46, 33}) == nullptr); }
/** * @brief Testet das Ausführen einer Bauoperation, die Straßen überbaut bzw. anpasst * * Ziehe Straßenzug von (46, 31) nach (46, 36). * 4 Kacheln kommen neu dazu, 2 werden überbaut (wovon nur eine was kostet). */ TEST_F(BuildOperationTest, overbuildAndAdeptStreet) { const Map* map = game->getMap(); const MapObjectType* farmRoad = configMgr->getMapObjectType("farm-road"); const MapObjectType* cobbledStreet = configMgr->getMapObjectType("cobbled-street"); // Testaufbau player->coins = 1000; colony->getGoods(configMgr->getGood("tools")).inventory = 10; colony->getGoods(configMgr->getGood("wood")).inventory = 20; colony->getGoods(configMgr->getGood("bricks")).inventory = 25; BuildOperation buildOperation(context, *player); for (int y = 31; y <= 36; y++) { buildOperation.requestBuildWhenNothingInTheWay(MapCoords(46, y), cobbledStreet, Direction::SOUTH); } unsigned long mapObjectsCountBefore = game->getMap()->getMapObjects().size(); buildOperation.doBuild(); unsigned long mapObjectsCountAfter = game->getMap()->getMapObjects().size(); // Testauswertung: Sicherstellen, dass die Anzahl der Map-Objekte stimmt. // Nicht, dass es zwei Map-Objekte auf derselben Koordinate gibt ASSERT_EQ(mapObjectsCountBefore + 4, mapObjectsCountAfter); // Testauswertung: Resourcen korrekt abgezogen (nur 5 der 6 Kacheln kosten was) ASSERT_EQ(975, player->coins); ASSERT_EQ(10, colony->getGoods(configMgr->getGood("tools")).inventory); ASSERT_EQ(20, colony->getGoods(configMgr->getGood("wood")).inventory); ASSERT_EQ(20, colony->getGoods(configMgr->getGood("bricks")).inventory); // Testauswertung: Straßen in die Map übernommen bzw. angepasst assertCorrectBuild({46, 31}, cobbledStreet, Direction::SOUTH, 1, 1); ASSERT_EQ(StreetConnections::BIT_MASK_SOUTH, dynamic_cast<const Street*>(map->getMapObjectFixedAt({46, 31}))->streetConnections); assertCorrectBuild({46, 32}, cobbledStreet, Direction::SOUTH, 1, 1); ASSERT_EQ(StreetConnections::BIT_MASK_NORTH | StreetConnections::BIT_MASK_EAST | StreetConnections::BIT_MASK_SOUTH | StreetConnections::BIT_MASK_WEST, dynamic_cast<const Street*>(map->getMapObjectFixedAt({46, 32}))->streetConnections); for (int y = 33; y <= 35; y++) { assertCorrectBuild({ 46, y }, cobbledStreet, Direction::SOUTH, 1, 1); ASSERT_EQ(StreetConnections::BIT_MASK_NORTH | StreetConnections::BIT_MASK_SOUTH, dynamic_cast<const Street*>(map->getMapObjectFixedAt({ 46, y }))->streetConnections); } assertCorrectBuild({46, 36}, cobbledStreet, Direction::SOUTH, 1, 1); ASSERT_EQ(StreetConnections::BIT_MASK_NORTH | StreetConnections::BIT_MASK_EAST | StreetConnections::BIT_MASK_WEST, dynamic_cast<const Street*>(map->getMapObjectFixedAt({46, 36}))->streetConnections); assertCorrectBuild({45, 32}, farmRoad, Direction::SOUTH, 1, 1); ASSERT_EQ(StreetConnections::BIT_MASK_EAST | StreetConnections::BIT_MASK_WEST, dynamic_cast<const Street*>(map->getMapObjectFixedAt({45, 32}))->streetConnections); assertCorrectBuild({47, 32}, farmRoad, Direction::SOUTH, 1, 1); ASSERT_EQ(StreetConnections::BIT_MASK_WEST, dynamic_cast<const Street*>(map->getMapObjectFixedAt({47, 32}))->streetConnections); }
virtual void SetUp() { GameTest::SetUp(); weavingMill = dynamic_cast<Building*>(game->addStructure( MapCoords(31, 30), configMgr->getMapObjectType("weaving-mill1"), Direction::SOUTH, game->getPlayer(0))); sheepFarm1 = dynamic_cast<Building*>(game->addStructure( MapCoords(35, 35), configMgr->getMapObjectType("sheep-farm"), Direction::SOUTH, game->getPlayer(0))); sheepFarm2 = dynamic_cast<Building*>(game->addStructure( MapCoords(30, 35), configMgr->getMapObjectType("sheep-farm"), Direction::SOUTH, game->getPlayer(0))); // keine Wartezeit am Träger einstellen weavingMill->nextCarrierMinTicks = 0; ASSERT_TRUE(weavingMill->carriers.empty()); }
Cube* Map::GetByPixel(GLfloat x, GLfloat y, GLfloat z){ GLfloat cubeSize=Cube::m_size; x+=cubeSize*0.5; y+=cubeSize*0.5; z+=cubeSize*0.5; ItCubeInstance res = m_data.find(MapCoords((size_t)(x/Cube::m_size),(size_t)(y/Cube::m_size),(size_t)(z/Cube::m_size))); if( res == m_data.end() ) return NULL; return std::get<0>(res->second); }
/** * @brief Testet, ob die Webstube einen Träger zur Schaffarm mit dem volleren Lager schickt */ TEST_F(CarrierTest, checkThatCarrierIsSentToFullerInventoryFirst) { // Testaufbau sheepFarm1->productionSlots.output.inventory = 2; sheepFarm2->productionSlots.output.inventory = 3; // Testdurchführung game->update(500); ASSERT_EQ(1, weavingMill->carriers.size()); const Carrier* carrier = *weavingMill->carriers.cbegin(); ASSERT_EQ(MapCoords(30, 35), *carrier->route.crbegin()); }
bool Map::Exists(size_t x, size_t y, size_t z){ /*if( x > m_width || x < 0 || y > m_height || y < 0 || z > m_depth || z < 0 ) throw std::out_of_range("Position is out of the map in Exists");*/ if( m_data.find(MapCoords(x,y,z)) == m_data.end() ){ return false; }else{ return true; } }
bool WindowManager::OnMouseButtonEvent(bool bPressed, int iMouseButton, unsigned int x, unsigned int y) { MapCoords(x, y); // hand over to root window bool bRet = m_spRootWindow->OnMouseButtonEvent(bPressed, iMouseButton, x, y); if (!bPressed) ClearTrackMouseUpWindows(iMouseButton); return bRet; }
void Map::moveMapObject(MapObjectMoving* mapObject, const DoubleMapCoords newMapCoords) { const int mapWidth = mapObject->getMapWidth(); const int mapHeight = mapObject->getMapHeight(); // Fläche auf den MapTiles ummarkieren. // Wir markieren mehrere Kacheln, wenn sich das Objekt zwischen zwei Kacheln befindet. const DoubleMapCoords& mapCoords = mapObject->getMapCoords(); for (int my = int(std::floor(mapCoords.y())); my < int(std::ceil(mapCoords.y())) + mapHeight; my++) { for (int mx = int(std::floor(mapCoords.x())); mx < int(std::ceil(mapCoords.x())) + mapWidth; mx++) { getMapTileAt(MapCoords(mx, my))->mapObjectsMoving.remove(mapObject); } } mapObject->setMapCoords(newMapCoords); for (int my = int(std::floor(newMapCoords.y())); my < int(std::ceil(newMapCoords.y())) + mapHeight; my++) { for (int mx = int(std::floor(newMapCoords.x())); mx < int(std::ceil(newMapCoords.x())) + mapWidth; mx++) { getMapTileAt(MapCoords(mx, my))->mapObjectsMoving.push_back(mapObject); } } }
/** * @brief Überprüft, ob man die Objekte in der richtigen Reihenfolge wieder aus der Liste kriegt */ TEST_F(BuildOperationTest, orderOfInsertion) { const MapObjectType* pioneersHouse1 = configMgr->getMapObjectType("pioneers-house1"); BuildOperation buildOperation(context, *player); buildOperation.requestBuild({36, 37}, pioneersHouse1, Direction::EAST); buildOperation.requestBuild({39, 40}, pioneersHouse1, Direction::EAST); buildOperation.requestBuild({36, 39}, pioneersHouse1, Direction::EAST); buildOperation.requestBuild({39, 34}, pioneersHouse1, Direction::EAST); const std::list<MapObjectToBuild>& mapObjectsToBuild = buildOperation.getMapObjectsToBuild(); auto iter = mapObjectsToBuild.cbegin(); ASSERT_EQ(MapCoords(36, 37), iter->mapCoords); iter++; ASSERT_EQ(MapCoords(39, 40), iter->mapCoords); iter++; ASSERT_EQ(MapCoords(36, 39), iter->mapCoords); iter++; ASSERT_EQ(MapCoords(39, 34), iter->mapCoords); iter++; ASSERT_TRUE(iter == mapObjectsToBuild.cend()); }
void Map::deleteMapObject(MapObject* mapObject) { mapObjects.remove(mapObject); const int mapWidth = mapObject->getMapWidth(); const int mapHeight = mapObject->getMapHeight(); // Unterscheidung nach fixen und beweglichen Map-Objekten MapObjectFixed* mapObjectFixed = dynamic_cast<MapObjectFixed*>(mapObject); if (mapObjectFixed != nullptr) { const MapCoords& mapCoords = mapObjectFixed->getMapCoords(); // Fläche auf den MapTiles als belegt markieren for (int my = mapCoords.y(); my < mapCoords.y() + mapHeight; my++) { for (int mx = mapCoords.x(); mx < mapCoords.x() + mapWidth; mx++) { getMapTileAt(MapCoords(mx, my))->mapObjectFixed = nullptr; } } } else { MapObjectMoving* mapObjectMoving = dynamic_cast<MapObjectMoving*>(mapObject); if (mapObjectMoving != nullptr) { // Fläche auf den MapTiles ummarkieren. // Es sind u.U. mehrere Kacheln markiert, wenn sich das Objekt zwischen zwei Kacheln befindet. const DoubleMapCoords& mapCoords = mapObjectMoving->getMapCoords(); for (int my = int(std::floor(mapCoords.y())); my < int(std::ceil(mapCoords.y())) + mapHeight; my++) { for (int mx = int(std::floor(mapCoords.x())); mx < int(std::ceil(mapCoords.x())) + mapWidth; mx++) { getMapTileAt(MapCoords(mx, my))->mapObjectsMoving.remove(mapObjectMoving); } } } else { assert (false); } } delete mapObject; }
/** * @brief Testet, ob bei gleich vollem Lager der Träger zum Gebäude schickt, * was länger nicht abgeholt wurde. Webstube muss aus 2 Schaffarmen die richtige wählen. */ TEST_F(CarrierTest, checkThatCarrierIsSentByLastCollectionWhenSameInventory) { // Testaufbau sheepFarm1->productionSlots.output.inventory = 1; sheepFarm2->productionSlots.output.inventory = 1; sheepFarm1->lastGoodsCollections = 42; sheepFarm2->lastGoodsCollections = 46; // Testdurchführung game->update(500); ASSERT_EQ(1, weavingMill->carriers.size()); const Carrier* carrier = *weavingMill->carriers.cbegin(); ASSERT_EQ(MapCoords(35, 35), *carrier->route.crbegin()); }
/** * @brief Überprüft, ob Überlappungen beim Hinzufügen von Bauaufträgen korrekt erkannt werden. */ TEST_F(BuildOperationTest, overlappingRequestBuild) { const MapObjectType* marketplace = configMgr->getMapObjectType("marketplace"); { // Ersten Marktplatz setzen BuildOperation buildOperation(context, *player); buildOperation.requestBuildWhenNothingInTheWay(MapCoords(45, 33), marketplace, Direction::SOUTH); ASSERT_EQ(12, buildOperation.getResult().size()); // Weiteren Marktplatz überlappen -> es darf sich nix tun buildOperation.requestBuildWhenNothingInTheWay(MapCoords(48, 32), marketplace, Direction::WEST); ASSERT_EQ(12, buildOperation.getResult().size()); // Weiteren Marktplatz überlappen über Bauqueue und bestehendes Objekt -> es darf sich auch nix tun buildOperation.requestBuildWhenNothingInTheWay(MapCoords(43, 31), marketplace, Direction::WEST); ASSERT_EQ(12, buildOperation.getResult().size()); // Weiteren Marktplatz korrekt hinzufügen buildOperation.requestBuildWhenNothingInTheWay(MapCoords(49, 33), marketplace, Direction::EAST); ASSERT_EQ(24, buildOperation.getResult().size()); } { const MapCoords mapCoords(47, 39); // Mit requestBuildWhenNothingInTheWay darf ich auf der Karte nicht überlappen BuildOperation buildOperation(context, *player); buildOperation.requestBuildWhenNothingInTheWay(mapCoords, marketplace, Direction::SOUTH); ASSERT_EQ(0, buildOperation.getResult().size()); // Mit requestBuild schon buildOperation.requestBuild(mapCoords, marketplace, Direction::SOUTH); ASSERT_EQ(12, buildOperation.getResult().size()); } }
void PFO_CubeColorBlockGL::GetCoords(int indx, SC_CoordArray& topCoords, SC_CoordArray& bottomCoords, const double& reduceFactor) { cubeData->GetBlockCoords(indx, topCoords, bottomCoords); if (reduceFactor < 0.999) { Line3D pointLine; pointLine.stPt = cubeData->GetCoord(indx); for (int k = 0; k < topCoords.Size(); k++) { pointLine.endPt = topCoords[k]; topCoords[k] = pointLine.PointOnLine(reduceFactor); pointLine.endPt = bottomCoords[k]; bottomCoords[k] = pointLine.PointOnLine(reduceFactor); } } MapCoords(topCoords); MapCoords(bottomCoords); }
void Map::addMapObject(MapObject* mapObject) { // Objekt in die Liste einreihen mapObjects.push_front(mapObject); int mapWidth = mapObject->getMapWidth(); int mapHeight = mapObject->getMapHeight(); // Unterscheidung nach fixen und beweglichen Map-Objekten // Fläche auf den MapTiles als belegt markieren MapObjectFixed* mapObjectFixed = dynamic_cast<MapObjectFixed*>(mapObject); if (mapObjectFixed != nullptr) { const MapCoords& mapCoords = mapObjectFixed->getMapCoords(); for (int my = mapCoords.y(); my < mapCoords.y() + mapHeight; my++) { for (int mx = mapCoords.x(); mx < mapCoords.x() + mapWidth; mx++) { getMapTileAt(MapCoords(mx, my))->mapObjectFixed = mapObjectFixed; } } return; } MapObjectMoving* mapObjectMoving = dynamic_cast<MapObjectMoving*>(mapObject); if (mapObjectMoving != nullptr) { const DoubleMapCoords& mapCoords = mapObjectMoving->getMapCoords(); for (int my = int(std::floor(mapCoords.y())); my < int(std::ceil(mapCoords.y())) + mapHeight; my++) { for (int mx = int(std::floor(mapCoords.x())); mx < int(std::ceil(mapCoords.x())) + mapWidth; mx++) { getMapTileAt(MapCoords(mx, my))->mapObjectsMoving.push_back(mapObjectMoving); } } return; } assert(false); }
/** * @brief Überprüft, ob korrekt erkannt wird, wenn was im Weg is */ TEST_F(BuildOperationTest, somethingInTheWay) { const MapObjectType* tavern = configMgr->getMapObjectType("tavern"); { // Wirtshaus normal einsetzen: genug Platz BuildOperation buildOperation(context, *player); buildOperation.requestBuild(MapCoords(45, 33), tavern, Direction::SOUTH); const BuildOperationResult& result = buildOperation.getResult(); ASSERT_EQ(BuildOperationResult::OK, result.result); ASSERT_EQ(6, result.size()); ASSERT_EQ(true, result.at(MapCoords(46, 35))->buildAllowed); } { // Wirtshaus gedreht einsetzen: genug Platz BuildOperation buildOperation(context, *player); buildOperation.requestBuild(MapCoords(45, 33), tavern, Direction::WEST); const BuildOperationResult& result = buildOperation.getResult(); ASSERT_EQ(BuildOperationResult::OK, result.result); ASSERT_EQ(6, result.size()); ASSERT_EQ(true, result.at(MapCoords(47, 34))->buildAllowed); } { // Wirtshaus normal einsetzen: ein Feldweg im Weg BuildOperation buildOperation(context, *player); buildOperation.requestBuild(MapCoords(39, 34), tavern, Direction::NORTH); const BuildOperationResult& result = buildOperation.getResult(); ASSERT_EQ(BuildOperationResult::NOT_OK, result.result); ASSERT_EQ(6, result.size()); ASSERT_EQ(false, result.at(MapCoords(40, 35))->buildAllowed); } { // Wirtshaus gedreht einsetzen: ein Feldweg im Weg BuildOperation buildOperation(context, *player); buildOperation.requestBuild(MapCoords(38, 36), tavern, Direction::EAST); const BuildOperationResult& result = buildOperation.getResult(); ASSERT_EQ(BuildOperationResult::NOT_OK, result.result); ASSERT_EQ(6, result.size()); ASSERT_EQ(false, result.at(MapCoords(40, 37))->buildAllowed); } }
/** * @brief Test, der Straßenanpassung testet, wenn die Resourcen nicht mehr reichen. * Beim Bau dürfen nur Ersetzungen vorgenommen werden, die angrenzen an Straßen, wofür die Resourcen reichen. * * Wir bauen einen Feldweg von (43, 44) nach (47, 44). * Allerdings reicht das Geld nur für zwei Kacheln. */ TEST_F(BuildOperationTest, adeptStreetsOutOfResources) { const Map* map = game->getMap(); const MapObjectType* farmRoad = configMgr->getMapObjectType("farm-road"); const MapObjectType* cobbledStreet = configMgr->getMapObjectType("cobbled-street"); // Testaufbau player->coins = 10; BuildOperation buildOperation(context, *player); for (int x = 43; x <= 47; x++) { buildOperation.requestBuildWhenNothingInTheWay(MapCoords(x, 44), farmRoad, Direction::SOUTH); } buildOperation.doBuild(); // Testauswertung // Resourcen korrekt nur für 2 Kacheln abgezogen ASSERT_EQ(0, player->coins); // Bau korrekt assertCorrectBuild({43, 44}, farmRoad, Direction::SOUTH, 1, 1); ASSERT_EQ(StreetConnections::BIT_MASK_EAST | StreetConnections::BIT_MASK_SOUTH, dynamic_cast<const Street*>(map->getMapObjectFixedAt({43, 44}))->streetConnections); assertCorrectBuild({44, 44}, farmRoad, Direction::SOUTH, 1, 1); for (int x = 45; x <= 47; x++) { ASSERT_TRUE(game->getMap()->getMapObjectFixedAt({x, 44}) == nullptr); } // partielle Anpassung an (44, 44): nur West! Für die Ost-Verbindung reichen die Resourcen nicht ASSERT_EQ(StreetConnections::BIT_MASK_WEST, dynamic_cast<const Street*>(map->getMapObjectFixedAt({44, 44}))->streetConnections); // Anpassung an (43, 45) assertCorrectBuild({43, 45}, cobbledStreet, Direction::SOUTH, 1, 1); ASSERT_EQ(StreetConnections::BIT_MASK_NORTH, dynamic_cast<const Street*>(map->getMapObjectFixedAt({43, 45}))->streetConnections); // Keine Anpassungen an (45, 45), (47, 45), (47, 43), da die Resourcen nicht reichen ASSERT_EQ(0, dynamic_cast<const Street*>(map->getMapObjectFixedAt({45, 45}))->streetConnections); ASSERT_EQ(0, dynamic_cast<const Street*>(map->getMapObjectFixedAt({47, 45}))->streetConnections); ASSERT_EQ(StreetConnections::BIT_MASK_NORTH, dynamic_cast<const Street*>(map->getMapObjectFixedAt({47, 43}))->streetConnections); }
void BuildOperation::rebuildResultDemolish() { for (const MapObjectToBuild& mapObjectToBuild : mapObjectsToBuild) { const MapCoords& mapCoords = mapObjectToBuild.mapCoords; const MapObjectFixed* mapObjectFixed = context.game->getMap()->getMapObjectFixedAt(mapCoords); assert(mapObjectFixed != nullptr); std::shared_ptr<BuildOperationResultBit> resultBit(new BuildOperationResultBit()); resultBit->buildAllowed = true; resultBit->deleteMapObjectThere = true; // ResultBit den Koordinaten zuweisen for (int y = 0, my = mapObjectToBuild.mapCoords.y(); y < mapObjectFixed->getMapHeight(); y++, my++) { for (int x = 0, mx = mapObjectToBuild.mapCoords.x(); x < mapObjectFixed->getMapWidth(); x++, mx++) { result[MapCoords(mx, my)] = resultBit; } } } // TODO Straßen umbiegen, wenn wir löschen }
/* Update the visibility of the cube x,y,z. * add: true = adding a cube, false = removing */ void Map::UpdateVisibility(size_t x, size_t y, size_t z) throw(std::out_of_range) { ItCubeInstance cube, neighbour1, neighbour2, neighbour3, neighbour4, neighbour5, neighbour6, end; cube = m_data.find(MapCoords(x,y,z)); end = m_data.end(); if( cube == end ) throw std::out_of_range("Cube is not in the map in UpdateVisibility"); neighbour1 = m_data.find(MapCoords(x-1,y,z)); neighbour2 = m_data.find(MapCoords(x+1,y,z)); neighbour3 = m_data.find(MapCoords(x,y-1,z)); neighbour4 = m_data.find(MapCoords(x,y+1,z)); neighbour5 = m_data.find(MapCoords(x,y,z-1)); neighbour6 = m_data.find(MapCoords(x,y,z+1)); if( std::get<1>(cube->second) && neighbour1 != end && neighbour2 != end && neighbour3 != end && neighbour4 != end && neighbour5 != end && neighbour6 != end ) { // It can be hidden Cube* pointer = std::get<0>(cube->second); cube->second = std::make_tuple(pointer,false); } else if( !std::get<1>(cube->second) ) { Cube* pointer = std::get<0>(cube->second); cube->second = std::make_tuple(pointer,true); } }
virtual void SetUp() { GameTest::SetUp(); FourthDirection southView = Direction::SOUTH; Player* player = game->getPlayer(0); const MapObjectType* cobbledStreet = configMgr->getMapObjectType("cobbled-street"); office1 = dynamic_cast<Building*>(game->getMap()->getMapObjectFixedAt(MapCoords(28, 18))); // keine Wartezeit am Träger einstellen office1->nextCarrierMinTicks = 0; // Rinderfarm bauen und Zick-Zack-Straße zum Kontor ziehen game->addStreet(MapCoords(28, 20), cobbledStreet, southView, player, StreetConnections("0010")); game->addStreet(MapCoords(28, 21), cobbledStreet, southView, player, StreetConnections("1010")); game->addStreet(MapCoords(28, 22), cobbledStreet, southView, player, StreetConnections("1001")); game->addStreet(MapCoords(27, 22), cobbledStreet, southView, player, StreetConnections("0101")); game->addStreet(MapCoords(26, 22), cobbledStreet, southView, player, StreetConnections("0110")); game->addStreet(MapCoords(26, 23), cobbledStreet, southView, player, StreetConnections("1010")); game->addStreet(MapCoords(26, 24), cobbledStreet, southView, player, StreetConnections("1010")); game->addStreet(MapCoords(26, 25), cobbledStreet, southView, player, StreetConnections("1010")); game->addStreet(MapCoords(26, 26), cobbledStreet, southView, player, StreetConnections("1000")); cattleFarm = dynamic_cast<Building*>(game->addStructure( MapCoords(26, 27), configMgr->getMapObjectType("cattle-farm"), southView, player)); }
/** * @brief Test, ob der Marktkarren die Route korrekt abläuft. Besonders wichtig ist der Übergang zwischen 2 Kacheln * Wir machen die Rinderfarm-Lager voll, damit das Kontor abholen muss und testen damit, ob der Marktkarren * ordnungsgemäß läuft. * * Siehe `doc/carrier-walking-test.xcf` für den Testaufbau und die einzelnen Schritte */ TEST_F(CarrierWalkingTest, checkThatCarrierWalksCorrectlyOnTheStreet) { // Da es keine halbe Ticks gibt, treten Rundungsfehler zwischen den echten Koordinaten und den theoretisch // errechneten Koordinaten auf. Dies ist der maximale Fehler, den die Tests erlauben. const double allowedCoordsError = 0.01; Colony* colony = office1->getColony(); const Good* cattleGood = configMgr->getGood("cattle"); // Lager voll machen cattleFarm->productionSlots.output.increaseInventory(999); // Anfangsbedingungen: kein Marktkarren da, Gebäudelager voll und bereit zur Abholung, 5t in der Kolonie ASSERT_EQ(5, colony->getGoods(cattleGood).inventory); ASSERT_TRUE(office1->carriers.empty()); ASSERT_TRUE(cattleFarm->productionSlots.output.isInventoryFull()); ASSERT_FALSE(cattleFarm->productionSlots.output.markedForPickup); // "Start": Erstes Update nach 1ms aufrufen. Danach sollte nun ein Marktkarren mit Abholauftrag da sein. office1->setLastUpdateTicks(0); game->update(1); ASSERT_EQ(1, office1->carriers.size()); const Carrier* carrier = *office1->carriers.cbegin(); ASSERT_EQ(1, office1->getLastUpdateTicks()); ASSERT_EQ(1, carrier->getLastUpdateTicks()); ASSERT_EQ(carrier->owningBuilding, office1); ASSERT_TRUE(carrier->route.back() == MapCoords(26, 27)); ASSERT_TRUE(carrier->onOutboundTrip); ASSERT_EQ("cattle", carrier->carriedGoods.good->name); ASSERT_EQ(0, carrier->carriedGoods.inventory); ASSERT_TRUE(carrier->getMapCoords() == DoubleMapCoords(28, 19)); ASSERT_TRUE(carrier->getCurrentMovingDirection() == Direction::SOUTH); ASSERT_TRUE(cattleFarm->productionSlots.output.markedForPickup); // "Step 1": Testet Bewegung innerhalb einer Kachel // Nach einer Sekunde: Der Marktkarren muss nun eine dreiviertelte Kachel (speed = 0.75, siehe EconomicsMgr) bewegt sein. game->update(1000); // Träger sollte sich (1000 * 0,75 =) 0,75 Kacheln fortbewegt haben ASSERT_EQ(1001, office1->getLastUpdateTicks()); ASSERT_EQ(1001, carrier->getLastUpdateTicks()); ASSERT_NEAR(28, carrier->getMapCoords().x(), allowedCoordsError); ASSERT_NEAR(19.75, carrier->getMapCoords().y(), allowedCoordsError); ASSERT_TRUE(carrier->getCurrentMovingDirection() == Direction::SOUTH); // "Step 2": Test, wenn eine Kachel geradlinig übersprungen wird game->update(2500); // Träger sollte sich (2500 * 0,75 =) 1,875 Kacheln fortbewegt haben ASSERT_EQ(3501, office1->getLastUpdateTicks()); ASSERT_EQ(3501, carrier->getLastUpdateTicks()); ASSERT_NEAR(28, carrier->getMapCoords().x(), allowedCoordsError); ASSERT_NEAR(21.625, carrier->getMapCoords().y(), allowedCoordsError); ASSERT_TRUE(carrier->getCurrentMovingDirection() == Direction::SOUTH); // "Step 3": Test, wenn mehrere Kacheln, auch über Ecken hinweg, übersprungen werden game->update(8000); // Träger sollte sich (8000 * 0,75 =) 6 Kacheln fortbewegt haben ASSERT_EQ(11501, office1->getLastUpdateTicks()); ASSERT_EQ(11501, carrier->getLastUpdateTicks()); ASSERT_NEAR(26, carrier->getMapCoords().x(), allowedCoordsError); ASSERT_NEAR(25.625, carrier->getMapCoords().y(), allowedCoordsError); ASSERT_TRUE(carrier->getCurrentMovingDirection() == Direction::SOUTH); // Am Gebäude ankommen, sollte den Rücktransport triggern game->update(2000); // Träger sollte sich (2000 * 0,75 =) 1,5 Kacheln fortbewegt haben. Ziel wurde bereits nach 1,375 Kacheln erreicht. ASSERT_EQ(1, office1->carriers.size()); carrier = *office1->carriers.cbegin(); ASSERT_EQ(13501, office1->getLastUpdateTicks()); ASSERT_EQ(13501, carrier->getLastUpdateTicks()); ASSERT_TRUE(carrier->route.back() == MapCoords(28, 19)); ASSERT_FALSE(carrier->onOutboundTrip); ASSERT_EQ("cattle", carrier->carriedGoods.good->name); ASSERT_EQ(4, carrier->carriedGoods.inventory); // Rinderfarm kann nur 4 Tonnen halten ASSERT_TRUE(carrier->getMapCoords() == DoubleMapCoords(26, 27)); ASSERT_TRUE(carrier->getCurrentMovingDirection() == Direction::NORTH); ASSERT_EQ(0, cattleFarm->productionSlots.output.inventory); ASSERT_FALSE(cattleFarm->productionSlots.output.markedForPickup); // Ein großer Zeitsprung und der Rücktransport sollte längst erledigt sein. game->update(20000); ASSERT_TRUE(office1->carriers.empty()); ASSERT_EQ(9, colony->getGoods(cattleGood).inventory); }
/* Fall 1: ganz normal * * x=23 * | * □□▨□□ * □▨▨▨□ * ▨▨▣▨▨ — y=12 * □▨▨▨□ * □□▨□□ */ TEST(CatchmentAreaTest, isInsideCatchmentArea_Normal) { Building building; building.setMapWidth(1); building.setMapHeight(1); building.setMapCoords(MapCoords(23, 12)); building.setView(Direction::SOUTH); RectangleData<char>* catchmentArea = new RectangleData<char>(5, 5); memcpy(catchmentArea->data, "0010001110111110111000100", 25); MapObjectType mapObjectType; mapObjectType.catchmentArea.reset(catchmentArea); building.setMapObjectType(&mapObjectType); ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(23, 12))); // Gebäude selber ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(22, 12))); // Punkte innerhalb Einzugsbereich ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(21, 12))); ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(23, 11))); ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(23, 10))); ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(24, 13))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(21, 10))); // Punkte außerhalb Einzugsbereich ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(22, 10))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(21, 11))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(23, 9))); // Außerhalb des Rechtecks ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(23, 15))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(20, 12))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(26, 12))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(0, 0))); }
/* Fall 3: prüft, ob sich alles korrekt verhält, wenn das Gebäude gedreht ist. * * Süd Ost Nord West * ===== ===== ====== ====== * * x=88 x=88 x=88 x=88 * | | | | * □□□□□□□□□ □□□□ ▨▨▨□□□□□□ □▨▨▨ * □▨▨▣▣▣▨▨▨ — y=42 □▨▨□ ▨▨▨▣▣▣▨▨□ — y=42 □▨▨▨ * □▨▨▣▣▣▨▨▨ □▨▨□ ▨▨▨▣▣▣▨▨□ □▨▨▨ * □□□□□□▨▨▨ □▣▣□ — y=42 □□□□□□□□□ □▣▣□ — y=42 * □▣▣□ □▣▣□ * □▣▣□ □▣▣□ * ▨▨▨□ □▨▨□ * ▨▨▨□ □▨▨□ * ▨▨▨□ □□□□ * * Wir prüfen immer dieselben MapCoords im Test. * Je nach Gebäude-View sind wir dann innerhalb ..oder außerhalb des Einzugsbereichs. */ TEST(CatchmentAreaTest, isInsideCatchmentArea_Views) { Building building; building.setMapCoords(MapCoords(88, 42)); building.setView(Direction::SOUTH); RectangleData<char>* catchmentArea = new RectangleData<char>(9, 4); memcpy(catchmentArea->data, "000000000011111111011111111000000111", 36); MapObjectType mapObjectType; mapObjectType.catchmentArea.reset(catchmentArea); building.setMapObjectType(&mapObjectType); building.setMapWidth(3); building.setMapHeight(2); building.setView(Direction::SOUTH); ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(88, 42))); // Mitte ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(85, 41))); // Ecken des Quer-Rechtecks ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(93, 41))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(85, 44))); ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(93, 44))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(87, 39))); // Ecken des Hochkant-Rechtecks ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(90, 39))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(87, 47))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(90, 47))); building.setMapWidth(2); building.setMapHeight(3); building.setView(Direction::EAST); ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(88, 42))); // Mitte ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(85, 41))); // Ecken des Quer-Rechtecks ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(93, 41))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(85, 44))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(93, 44))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(87, 39))); // Ecken des Hochkant-Rechtecks ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(90, 39))); ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(87, 47))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(90, 47))); building.setMapWidth(3); building.setMapHeight(2); building.setView(Direction::NORTH); ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(88, 42))); // Mitte ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(85, 41))); // Ecken des Quer-Rechtecks ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(93, 41))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(85, 44))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(93, 44))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(87, 39))); // Ecken des Hochkant-Rechtecks ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(90, 39))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(87, 47))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(90, 47))); building.setMapWidth(2); building.setMapHeight(3); building.setView(Direction::WEST); ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(88, 42))); // Mitte ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(85, 41))); // Ecken des Quer-Rechtecks ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(93, 41))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(85, 44))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(93, 44))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(87, 39))); // Ecken des Hochkant-Rechtecks ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(90, 39))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(87, 47))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(90, 47))); }
/* Fall 2: asymmetrisch mit größerem Gebäude * * x=11 * | * □□▨▨▨▨□□ * □▨▨▨▨▨▨□ * ▨▨▣▣▣▣▨▨ — y=33 * ▨▨▣▣▣▣▨▨ * ▨▨▣▣▣▣▨▨ * □▨▨▨▨▨▨□ * □□▨▨▨▨□□ */ TEST(CatchmentAreaTest, isInsideCatchmentArea_AsymmetricLargeBuilding) { Building building; building.setMapWidth(4); building.setMapHeight(3); building.setMapCoords(MapCoords(11, 33)); building.setView(Direction::SOUTH); RectangleData<char>* catchmentArea = new RectangleData<char>(8, 7); memcpy(catchmentArea->data, "00111100011111101111111111111111111111110111111000111100", 56); MapObjectType mapObjectType; mapObjectType.catchmentArea.reset(catchmentArea); building.setMapObjectType(&mapObjectType); ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(11, 33))); // Gebäude selber ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(14, 35))); // ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(13, 34))); // ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(11, 31))); // Punkte innerhalb Einzugsbereich ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(15, 32))); ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(9, 33))); ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(16, 35))); ASSERT_TRUE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(12, 37))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(9, 31))); // Punkte außerhalb Einzugsbereich ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(9, 32))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(10, 31))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(16, 37))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(8, 33))); // Außerhalb des Rechtecks ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(17, 33))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(14, 30))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(14, 38))); ASSERT_FALSE(CatchmentArea::isInsideCatchmentArea(building, MapCoords(0, 0))); }