From bb2ddf1374b98d469219b7717e24a2dd030b3b61 Mon Sep 17 00:00:00 2001 From: Tiberiu Chibici Date: Sat, 10 Dec 2016 17:42:51 +0200 Subject: [PATCH] Implemented weather --- .../CMake Project Generator.launch | 1 - assets/plants/Plantable.xml | 2 +- assets/scenes/Game.scene | 1 + src/GameState.h | 5 + src/Main.cpp | 11 +- src/components/Map.cpp | 2 +- src/components/{ => environment}/GameTime.cpp | 4 +- src/components/{ => environment}/GameTime.h | 2 + src/components/environment/Weather.cpp | 122 ++++++++++++++++++ src/components/environment/Weather.h | 53 ++++++++ src/components/items/WateringCan.cpp | 34 +++-- src/components/items/WateringCan.h | 4 + src/components/plants/Plant.cpp | 6 +- src/storage/Parsers.cpp | 40 +++++- src/storage/Parsers.h | 8 +- src/utils/Assert.h | 6 +- src/utils/Random.cpp | 32 +++++ src/utils/Random.h | 30 +++++ 18 files changed, 340 insertions(+), 23 deletions(-) rename src/components/{ => environment}/GameTime.cpp (93%) rename src/components/{ => environment}/GameTime.h (95%) create mode 100644 src/components/environment/Weather.cpp create mode 100644 src/components/environment/Weather.h create mode 100644 src/utils/Random.cpp create mode 100644 src/utils/Random.h diff --git a/.externalToolBuilders/CMake Project Generator.launch b/.externalToolBuilders/CMake Project Generator.launch index f60fdce..0007d1c 100644 --- a/.externalToolBuilders/CMake Project Generator.launch +++ b/.externalToolBuilders/CMake Project Generator.launch @@ -2,7 +2,6 @@ - diff --git a/assets/plants/Plantable.xml b/assets/plants/Plantable.xml index ff4db76..4113cee 100644 --- a/assets/plants/Plantable.xml +++ b/assets/plants/Plantable.xml @@ -21,7 +21,7 @@ - + diff --git a/assets/scenes/Game.scene b/assets/scenes/Game.scene index 908e1c2..29c1821 100644 --- a/assets/scenes/Game.scene +++ b/assets/scenes/Game.scene @@ -7,6 +7,7 @@ + diff --git a/src/GameState.h b/src/GameState.h index 82d8e29..4450149 100644 --- a/src/GameState.h +++ b/src/GameState.h @@ -13,8 +13,10 @@ #include #include #include +#include #include +#include namespace farmlands { @@ -47,6 +49,9 @@ namespace farmlands { float deltaTime; + // Misc + utils::Random random; + private: static GameState s_current; }; diff --git a/src/Main.cpp b/src/Main.cpp index c318219..13a483a 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -7,9 +7,11 @@ using namespace farmlands; int main() { + int ret = 0; + try { - return controller::FarmlandsGame().run(); + ret = controller::FarmlandsGame().run(); } catch (utils::Exception& ex) { @@ -22,4 +24,11 @@ int main() std::cerr << "Panic: Caught unhandled exception!\n"; std::cerr << typeid(ex).name() << " : " << ex.what() << "\n"; } + + if (ret != 0) + { + std::cerr << "Panic: Caught non-zero exit status!\n"; + } + + return ret; } diff --git a/src/components/Map.cpp b/src/components/Map.cpp index 2947032..f280c16 100644 --- a/src/components/Map.cpp +++ b/src/components/Map.cpp @@ -35,7 +35,7 @@ MapLayer* MapLayer::clone() Cell MapLayer::get(size_t row, size_t col) const { - Assert(row < m_w && col < m_h, "Index out of bounds."); + Assert(row < m_h && col < m_w, "Index out of bounds."); return m_cells[row * m_w + col]; } diff --git a/src/components/GameTime.cpp b/src/components/environment/GameTime.cpp similarity index 93% rename from src/components/GameTime.cpp rename to src/components/environment/GameTime.cpp index 9076071..4ecb233 100644 --- a/src/components/GameTime.cpp +++ b/src/components/environment/GameTime.cpp @@ -6,7 +6,7 @@ */ #include -#include +#include #include @@ -16,6 +16,7 @@ namespace farmlands { namespace components { +namespace environment { GameTime::~GameTime() { @@ -51,5 +52,6 @@ void GameTime::onUpdateLogic() } +} } /* namespace components */ } /* namespace farmlands */ diff --git a/src/components/GameTime.h b/src/components/environment/GameTime.h similarity index 95% rename from src/components/GameTime.h rename to src/components/environment/GameTime.h index 25bd4f8..abd0a55 100644 --- a/src/components/GameTime.h +++ b/src/components/environment/GameTime.h @@ -12,6 +12,7 @@ namespace farmlands { namespace components { +namespace environment { /** * Maintains game time. @@ -27,6 +28,7 @@ namespace components { virtual void onUpdateLogic() override; }; +} } /* namespace components */ } /* namespace farmlands */ diff --git a/src/components/environment/Weather.cpp b/src/components/environment/Weather.cpp new file mode 100644 index 0000000..af9051b --- /dev/null +++ b/src/components/environment/Weather.cpp @@ -0,0 +1,122 @@ +/* + * Weather.cpp + * + * Created on: Dec 10, 2016 + * Author: tibi + */ + +#include +#include +#include +#include + +#include + +namespace farmlands { +namespace components { +namespace environment { + +Weather::Weather() + : today(WeatherType::Sunny), + tomorrow(WeatherType::Sunny), + m_map(nullptr), + m_grid(nullptr) +{ +} + +Weather::~Weather() +{ +} + +model::Component* Weather::clone() +{ + Weather* clone = new Weather(); + clone->today = today; + clone->tomorrow = tomorrow; + + return clone; +} + +void Weather::dump(unsigned level) +{ + for (unsigned i = 0; i < level; i++) + std::cout<<" "; + + std::cout << " .Component: Weather \n"; +} + +void Weather::onInitialize() +{ + model::GameObject* root = &GameState::current().scene->root; + + // Find background object + auto it = root->findByComponent(); + Assert(it != root->childrenEnd(), "Can't find background game object."); + m_map = (*it)->component(); + + auto gridIt = root->findByComponent(); + Assert(gridIt != root->childrenEnd(), "Can't find grid game object."); + m_grid = (*gridIt)->component(); +} + +void Weather::onUpdateLogic() +{ + if (GameState::current().isMidnight) + { + today = tomorrow; + + std::cout << "Today the weather is "; + if (today == WeatherType::Sunny) + std::cout << "sunny\n"; + if (today == WeatherType::Cloudy) + std::cout << "cloudy\n"; + if (today == WeatherType::Rainy) + std::cout << "rainy\n"; + + // Pick weather for next day + int r = GameState::current().random.getInt((int) WeatherType::_Count); + tomorrow = (WeatherType) r; + + // Wet/dry soil tiles + updateSoilTiles(); + updatePlants(); + } +} + +void Weather::updateSoilTiles() +{ + bool rain = (today == WeatherType::Rainy); + Cell cellWet = assets::Ground::SoilWet; + Cell cellDry = assets::Ground::SoilDry; + + for (size_t row = 0; row < m_map->height; row++) + for (size_t col = 0; col < m_map->width; col++) + { + Cell soil = m_map->layer(1).get(row, col); + if (assets::groundIsSoil(soil)) + m_map->layer(1).set(row, col, (rain) ? cellWet : cellDry); + } +} + +void Weather::updatePlants() +{ + bool rain = (today == WeatherType::Rainy); + + if (rain) + { + // Tell plants that they have been given water + for (size_t row = 0; row < m_map->height; row++) + for (size_t col = 0; col < m_map->width; col++) + { + model::GameObject* obj = m_grid->get(col, row); + plants::Plant* plant = (obj != nullptr) ? obj->component() : nullptr; + + if (plant) + plant->onWatered(); + } + } +} + +} /* namespace environment */ +} /* namespace components */ +} /* namespace farmlands */ diff --git a/src/components/environment/Weather.h b/src/components/environment/Weather.h new file mode 100644 index 0000000..f704923 --- /dev/null +++ b/src/components/environment/Weather.h @@ -0,0 +1,53 @@ +/* + * Weather.h + * + * Created on: Dec 10, 2016 + * Author: tibi + */ + +#ifndef COMPONENTS_ENVIRONMENT_WEATHER_H_ +#define COMPONENTS_ENVIRONMENT_WEATHER_H_ + +#include +#include +#include + +namespace farmlands { +namespace components { +namespace environment { + + enum class WeatherType + { + Sunny, + Cloudy, + Rainy, + _Count + }; + + class Weather: public model::Component + { + public: + Weather(); + virtual ~Weather(); + + virtual model::Component* clone() override; + virtual void dump(unsigned level) override; + + virtual void onInitialize() override; + virtual void onUpdateLogic() override; + + WeatherType today, tomorrow; + + private: + void updateSoilTiles(); + void updatePlants(); + + Map* m_map; + basic::Grid* m_grid; + }; + +} /* namespace environment */ +} /* namespace components */ +} /* namespace farmlands */ + +#endif /* COMPONENTS_ENVIRONMENT_WEATHER_H_ */ diff --git a/src/components/items/WateringCan.cpp b/src/components/items/WateringCan.cpp index 9f394ff..cdc7aed 100644 --- a/src/components/items/WateringCan.cpp +++ b/src/components/items/WateringCan.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -54,8 +55,11 @@ void WateringCan::onInitialize() // Find background object auto it = root->findByComponent(); Assert(it != root->childrenEnd(), "Can't find background game object."); - m_map = (*it)->component(); + + auto gridIt = root->findByComponent(); + Assert(gridIt != root->childrenEnd(), "Can't find grid game object."); + m_grid = (*gridIt)->component(); } void WateringCan::performAction(float x, float y, model::Direction d) @@ -73,23 +77,35 @@ void WateringCan::performAction(float x, float y, model::Direction d) Cell backCell = m_map->layer(0).get(row, col); Cell soilCell = m_map->layer(1).get(row, col); - // If there is water, fill can - if (backCell == Ground::Water) - { - amountLeft = capacity; - std::cout << "Filled can: " << amountLeft << "\n"; - } + model::GameObject* obj = m_grid->get(col, row); + plants::Plant* plant = (obj != nullptr) ? obj->component() : nullptr; - // If there is dry soil, wet it + // Fill can + if (backCell == Ground::Water) + fillCan(); + + // Wet dry soil if (groundIsDrySoil(soilCell) && amountLeft > 0) { - m_map->layer(1)[row][col] = Ground::SoilWet; --amountLeft; + // Set wet soil + m_map->layer(1)[row][col] = Ground::SoilWet; + + // If there is a plant, tell it we watered it + if (plant != nullptr) + plant->onWatered(); + std::cout << "Watering can: " << amountLeft << "\n"; } } +void WateringCan::fillCan() +{ + amountLeft = capacity; + std::cout << "Filled can: " << amountLeft << "\n"; +} + } /* namespace items */ } /* namespace components */ } /* namespace farmlands */ diff --git a/src/components/items/WateringCan.h b/src/components/items/WateringCan.h index 99cfed7..c2c93f1 100644 --- a/src/components/items/WateringCan.h +++ b/src/components/items/WateringCan.h @@ -8,6 +8,7 @@ #ifndef COMPONENTS_ITEMS_WATERINGCAN_H_ #define COMPONENTS_ITEMS_WATERINGCAN_H_ +#include #include #include #include @@ -30,12 +31,15 @@ namespace items { virtual void performAction(float x, float y, model::Direction d) override; + void fillCan(); + public: uint32_t capacity; uint32_t amountLeft; private: Map* m_map; + basic::Grid* m_grid; }; } /* namespace items */ diff --git a/src/components/plants/Plant.cpp b/src/components/plants/Plant.cpp index 119a300..b7b422b 100644 --- a/src/components/plants/Plant.cpp +++ b/src/components/plants/Plant.cpp @@ -65,7 +65,10 @@ void Plant::onUpdateLogic() // At midnight, the plant grows if (GameState::current().isMidnight) { - stateDays++; + // Plant only grows when wet + if (!needsWater || daysWithoutWater == 0) + stateDays++; + daysWithoutWater++; // Exceeded plant's survival time without water @@ -94,6 +97,7 @@ void Plant::onWatered() void Plant::die() { // TODO: implement plant death + std::cout << "Oh, no. Plant is dead\n"; } } /* namespace plants */ diff --git a/src/storage/Parsers.cpp b/src/storage/Parsers.cpp index 372c15b..dcece69 100644 --- a/src/storage/Parsers.cpp +++ b/src/storage/Parsers.cpp @@ -243,16 +243,46 @@ components::DebugController* parse (boost::property } template <> -components::GameTime* parse (boost::property_tree::ptree& root) +components::environment::GameTime* parse (boost::property_tree::ptree& root) { // Ensure we are on the correct node (property tree seems to add root of its own) if (root.front().first == "GameTime") root = root.front().second; - components::GameTime* gameTime = new components::GameTime(); + components::environment::GameTime* gameTime = new components::environment::GameTime(); return gameTime; } +components::environment::WeatherType parseWeatherType(std::string weatherType) +{ + boost::to_lower(weatherType); + components::environment::WeatherType type = components::environment::WeatherType::Sunny; + + if (weatherType == "cloudy") + type = components::environment::WeatherType::Cloudy; + + if (weatherType == "rainy") + type = components::environment::WeatherType::Rainy; + + return type; +} + +template <> +components::environment::Weather* parse (boost::property_tree::ptree& root) +{ + // Ensure we are on the correct node (property tree seems to add root of its own) + if (root.front().first == "Weather") + root = root.front().second; + + components::environment::Weather* weather = new components::environment::Weather(); + std::string today = root.get(".today", "Sunny"); + weather->today = parseWeatherType(today); + std::string tomorrow = root.get(".tomorrow", "Sunny"); + weather->tomorrow = parseWeatherType(tomorrow); + + return weather; +} + template <> components::items::Axe* parse (boost::property_tree::ptree& root) { @@ -522,8 +552,12 @@ model::GameObject* parse (boost::property_tree::ptree& root) else if (child.first == "DebugController") gameObj->addComponent(parse(child.second)); + // Environment else if (child.first == "GameTime") - gameObj->addComponent(parse(child.second)); + gameObj->addComponent(parse(child.second)); + + else if (child.first == "Weather") + gameObj->addComponent(parse(child.second)); else if (child.first == "Map") gameObj->addComponent(parse(child.second)); diff --git a/src/storage/Parsers.h b/src/storage/Parsers.h index 054f0e0..58af36c 100644 --- a/src/storage/Parsers.h +++ b/src/storage/Parsers.h @@ -13,7 +13,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -66,7 +67,10 @@ namespace storage { components::DebugController* parse (boost::property_tree::ptree& root); template <> - components::GameTime* parse (boost::property_tree::ptree& root); + components::environment::GameTime* parse (boost::property_tree::ptree& root); + + template <> + components::environment::Weather* parse (boost::property_tree::ptree& root); template <> components::items::Axe* parse (boost::property_tree::ptree& root); diff --git a/src/utils/Assert.h b/src/utils/Assert.h index 46e88e2..1aae5e9 100644 --- a/src/utils/Assert.h +++ b/src/utils/Assert.h @@ -18,10 +18,10 @@ namespace utils { void _AssertInternal(bool condition, const std::string& msg, const std::string& lineText, const std::string& file, int line); void _AssertInternalLog(bool condition, const std::string& msg, const std::string& lineText, const std::string& file, int line); -#ifdef BUILD_DEBUG -#define Assert(condition, message) farmlands::utils::_AssertInternal(condition, message, #condition, __FILE__, __LINE__) -#else +#ifdef NDEBUG #define Assert(condition, message) farmlands::utils::_AssertInternalLog(condition, message, #condition, __FILE__, __LINE__) +#else +#define Assert(condition, message) farmlands::utils::_AssertInternal(condition, message, #condition, __FILE__, __LINE__) #endif } /* namespace utils */ diff --git a/src/utils/Random.cpp b/src/utils/Random.cpp new file mode 100644 index 0000000..af6a7dd --- /dev/null +++ b/src/utils/Random.cpp @@ -0,0 +1,32 @@ +/* + * Random.cpp + * + * Created on: Dec 10, 2016 + * Author: tibi + */ + +#include + +namespace farmlands { +namespace utils { + + float Random::getFloat() + { + std::uniform_real_distribution distrib; + return distrib(m_engine); + } + + int Random::getInt(int min, int max) + { + std::uniform_int_distribution distrib(min, max); + return distrib(m_engine); + } + + int Random::getInt(int max) + { + std::uniform_real_distribution distrib(0, max); + return distrib(m_engine); + } + +} /* namespace utils */ +} /* namespace farmlands */ diff --git a/src/utils/Random.h b/src/utils/Random.h new file mode 100644 index 0000000..44d70f0 --- /dev/null +++ b/src/utils/Random.h @@ -0,0 +1,30 @@ +/* + * Random.h + * + * Created on: Dec 10, 2016 + * Author: tibi + */ + +#ifndef UTILS_RANDOM_H_ +#define UTILS_RANDOM_H_ + +#include + +namespace farmlands { +namespace utils { + + class Random + { + public: + float getFloat(); + int getInt(int min, int max); + int getInt(int max); + + private: + std::mt19937 m_engine; + }; + +} /* namespace utils */ +} /* namespace farmlands */ + +#endif /* UTILS_RANDOM_H_ */