void World::turnlyUpdate(){ boost::random::uniform_int_distribution<int> dist(1, 100); incrementElapsedTurns(); getCurrentTime().increment(); //The weather will tend to change every ~8 hours, or 480 minutes. //Ideally, something like this: //1 hour (60) -> 4% //2 hours (120) -> 6% //3 hours (180) -> 8% //4 hours (240) -> 12.5% //5 hours (300) -> 16% //6 hours (360) -> 24% //7 hours (420) -> 30% //8 hours (480) -> 40% for(auto& effect : weatherEffects){ effect.second += minutesPerTurn; } auto effect = std::begin(weatherEffects); while(effect != std::end(weatherEffects)){ int removeEffect{dist(masterManager.randomEngine)}; //For instance, if the effect has been there for 240 minutes, it will have an //40% chance of being removed. There is a hard cap of 80%. int totalChance = effect->second / 15; if(totalChance > 50){ totalChance = 50; } if(removeEffect <= totalChance){ effect = weatherEffects.erase(effect); } else{ effect++; } } int hourlyChance = 20; int turnlyChance = hourlyChance / (60/minutesPerTurn); int randomRoll{dist(masterManager.randomEngine)}; if (randomRoll <= turnlyChance){ addWeather(); } //////////////////////////////////////////////////////////////////////////////// //////////////////MUD CREATION AND REMOVAL////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //Firstly, depending on whether the rain is heavy or light, there will be a varying //amount of mud formations per turn. bool rain{false}; int minimumMudFormations{0}; for(auto& effect : weatherEffects){ if(effect.first == World::Weather::HEAVY_RAIN){ rain = true; minimumMudFormations = 4; break; } else if(effect.first == World::Weather::LIGHT_RAIN){ rain = true; minimumMudFormations = 2; break; } } //A random tile on the map that we call the origin is converted to mud (if possible). if(rain){ for (int i{0}; i < minimumMudFormations; ++i){ boost::random::uniform_int_distribution<int> randomIndexDist(0, getDimensions().x * getDimensions().y); int randomIndex{randomIndexDist(masterManager.randomEngine)}; sf::Vector2i originPosition{cartesianPosAtIndex(randomIndex)}; TerrainTile* origin = terrainAtCartesianPos(originPosition); bool originConvertedToMud{false}; if(origin->getTerrainType() == TerrainTile::TerrainType::MEADOW){ toggleMud(origin); originConvertedToMud = true; } if(!originConvertedToMud){ break; } //There is then an 4/5 chance that a neighboring tile is also converted, if possible... int randomNumber{0}; do{ boost::random::uniform_int_distribution<int> randomDist(1, 5); randomNumber = randomDist(masterManager.randomEngine); if(randomNumber >= 2){ boost::random::uniform_int_distribution<int> randomDisplacementDist(-1, 1); int randomDisplacementX{randomDisplacementDist(masterManager.randomEngine)}; int randomDisplacementY{randomDisplacementDist(masterManager.randomEngine)}; sf::Vector2i newPosition{originPosition.x + randomDisplacementX, originPosition.y + randomDisplacementY}; TerrainTile* newTerrain = terrainAtCartesianPos(newPosition); if(newTerrain != nullptr){ if(newTerrain->getTerrainType() == TerrainTile::TerrainType::MEADOW){ toggleMud(newTerrain); } } } //... and a 3/5 chance for this process to repeat. }while(randomNumber >= 3); } //While new mud tiles are formed, every old mud tile has a 1/8 chance to spread to a neighboring tile, if possible //IMPORTANT NOTE: here we use an integer-based index rather than a foreach loop, because toggleMud() //itself actually erases a mud tile from mudTiles. So if we do a foreach mudTiles loop, we end up with //messy dangling pointers and, in my case, days of debugging crashes. for(std::vector<Mud*>::size_type i{0}; i < mudTiles.size(); i++){ boost::random::uniform_int_distribution<int> randomDist(1, 8); int randomNumber = randomDist(masterManager.randomEngine); if(randomNumber == 1){ boost::random::uniform_int_distribution<int> randomDisplacementDist(-1, 1); int randomDisplacementX{randomDisplacementDist(masterManager.randomEngine)}; int randomDisplacementY{randomDisplacementDist(masterManager.randomEngine)}; sf::Vector2i originPosition = mudTiles[i]->getCartesianPos(); sf::Vector2i newPosition{originPosition.x + randomDisplacementX, originPosition.y + randomDisplacementY}; TerrainTile* newTerrain = terrainAtCartesianPos(newPosition); if(newTerrain != nullptr){ if(newTerrain->getTerrainType() == TerrainTile::TerrainType::MEADOW){ toggleMud(newTerrain); } } } } } //Finally, after the rain has stopped, each mud tile has a 9/10 chance to dry up. else if (!rain){ //IMPORTANT NOTE: here we use an integer-based index rather than a foreach loop, because toggleMud() //itself actually erases a mud tile from mudTiles. So if we do a foreach mudTiles loop, we end up with //messy dangling pointers and, in my case, days of debugging crashes. for(std::vector<Mud*>::size_type i{0}; i < mudTiles.size(); i++){ boost::random::uniform_int_distribution<int> randomDryingChanceDist(1, 10); int randomDryingChance{randomDryingChanceDist(masterManager.randomEngine)}; if(randomDryingChance <= 9){ toggleMud(mudTiles[i]); } } } unhighlightVisibleTiles(); visibleTiles.clear(); }
void GameState_Setup::getInput(){ sf::Event event; while (game->mWindow.pollEvent(event)){ switch (event.type){ case sf::Event::MouseMoved: game->mousePos.x = event.mouseMove.x; game->mousePos.y = event.mouseMove.y; break; case sf::Event::Resized: handleResize(); break; case sf::Event::MouseButtonPressed: if (event.mouseButton.button == sf::Mouse::Middle){ middleButtonHeld = true; middleButtonCoords = {event.mouseButton.x, event.mouseButton.y}; } else if (event.mouseButton.button == sf::Mouse::Left && drawUI){ //If no menu item was selectedSpawnableUnit, select it if (selectedSpawnableUnit == nullptr){ sf::Vector2f worldCoords{game->mWindow.mapPixelToCoords(game->mousePos, *game->currentView)}; sf::Vector2f uiCoords{game->mWindow.mapPixelToCoords(game->mousePos, setupUI.uiView)}; std::vector<SpawnableUnit> current{game->currentPlayer->getSpawnableUnits()}; for (size_t i{0}; i < current.size(); ++i){ if (uiCoords.x > current[i].left() && uiCoords.x < current[i].right() && uiCoords.y > current[i].top() && uiCoords.y < current[i].bottom()){ selectedSpawnableUnit = std::move(std::unique_ptr<SpawnableUnit>(new SpawnableUnit(current[i]))); break; } } if (uiCoords.x >= setupUI.getButton().left() && uiCoords.x <= setupUI.getButton().right() && uiCoords.y >= setupUI.getButton().top() && uiCoords.y <= setupUI.getButton().bottom()){ //As long as the player has at least one non-general unit if (game->currentPlayer->getDeploymentPoints() <= game->currentPlayer->getMaxDeploymentPoints() - 1){ game->currentPlayer->setReady(true); } } if(selectedSpawnableUnit == nullptr){ middleButtonHeld = true; middleButtonCoords = {event.mouseButton.x, event.mouseButton.y}; } } //Spawn a unit on the tile: else{ sf::Vector2i mouseCoords{event.mouseButton.x, event.mouseButton.y}; sf::Vector2i worldCoords{game->mWindow.mapPixelToCoords(mouseCoords, *game->currentView)}; TerrainTile* terrain = game->mWorld->terrainAtPixelPos(worldCoords); if (terrain != nullptr){ if(terrain->getTerrainType() != TerrainTile::TerrainType::WATER){ game->currentPlayer->spawnUnit(selectedSpawnableUnit->unitID, worldCoords); } } selectedSpawnableUnit = nullptr; break; } } else if (event.mouseButton.button == sf::Mouse::Right && drawUI){ //Deselect the currently selectedSpawnableUnit icon: if (selectedSpawnableUnit != nullptr){ selectedSpawnableUnit = nullptr; break; } //Delete a unit from a tile: else{ sf::Vector2i mouseCoords{event.mouseButton.x, event.mouseButton.y}; sf::Vector2i worldCoords{game->mWindow.mapPixelToCoords(mouseCoords, *game->currentView)}; auto removed = game->currentPlayer->removeUnit(worldCoords); if(removed != nullptr){ game->currentPlayer->setDeploymentPoints(game->currentPlayer->getDeploymentPoints() + removed.get()->getCost()); } break; } } break; case sf::Event::MouseButtonReleased: if (event.mouseButton.button == sf::Mouse::Middle){ middleButtonHeld = false; } else if(event.mouseButton.button == sf::Mouse::Left){ middleButtonHeld = false; } break; case sf::Event::Closed: game->exitGame(false); break; case sf::Event::KeyPressed: switch (event.key.code){ case Key::UP_KEY: cameraVelocity = {0.f, -2.f}; break; case Key::RIGHT_KEY: cameraVelocity = {2.f, 0.f}; break; case Key::DOWN_KEY: cameraVelocity = {0.f, 2.f}; break; case Key::LEFT_KEY: cameraVelocity = {-2.f, 0.f}; break; case Key::RESETZOOM_KEY: game->currentView->setSize(game->mWindow.getSize().x, game->mWindow.getSize().y); break; case Key::ZOOMIN_KEY: game->currentView->setSize(game->currentView->getSize().x - xResolution / 10, game->currentView->getSize().y - yResolution / 10); break; case Key::ZOOMOUT_KEY: game->currentView->setSize(game->currentView->getSize().x + xResolution / 10, game->currentView->getSize().y + yResolution / 10); break; case sf::Keyboard::Escape: { game->setGameState(game->SetupPauseMenuState.get()); } break; case Key::HIDE_UI_KEY: if (drawUI){ drawUI = false; } else if (!drawUI){ drawUI = true; } break; default: break; } break; case sf::Event::MouseWheelMoved: smoothZoom_zooming = true; smoothZoom_lerpFactor = 0.0085f; if (event.mouseWheel.delta > 0 && game->currentView->getSize().x > xResolution && game->currentView->getSize().y > yResolution){ //zoom in //std::cout << game->currentView->getSize().x << ',' << game->currentView->getSize().y << std::endl; //game->currentView->setSize(game->currentView->getSize().x - xResolution / 12, game->currentView->getSize().y - yResolution / 12); smoothZoom_targetZoom = 0.8f; } else if (event.mouseWheel.delta < 0 && game->currentView->getSize().x < xResolution * 4 && game->currentView->getSize().y < yResolution * 4){ //zoom out //std::cout << game->currentView->getSize().x << ',' << game->currentView->getSize().y << std::endl; //game->currentView->setSize(game->currentView->getSize().x + xResolution / 12, game->currentView->getSize().y + yResolution / 12); smoothZoom_targetZoom = 1.2f; } smoothZoom_currentZoom = 1.0f; smoothZoom_previousZoom = smoothZoom_currentZoom; smoothZoom_currentCenter = game->currentView->getCenter(); if(smoothZoom_targetZoom >= 1.f){ smoothZoom_targetCenter = game->mWindow.mapPixelToCoords(game->mousePos, *(game->currentView)); auto dist = smoothZoom_targetCenter - smoothZoom_currentCenter; dist.x /= 2; dist.y /= 2; smoothZoom_targetCenter = smoothZoom_currentCenter - dist; } else{ smoothZoom_targetCenter = game->mWindow.mapPixelToCoords(game->mousePos, *(game->currentView)); auto dist = smoothZoom_targetCenter - smoothZoom_currentCenter; dist.x /= 2; dist.y /= 2; smoothZoom_targetCenter = smoothZoom_targetCenter - dist; } break; default: break; } } }