#include "../graphics/glm.hpp"
#include "../graphics/SimpleVAO.hpp"
+#include <memory>
#include <string>
#include <vector>
void Health(double h) noexcept { health = h; }
double Health() const noexcept { return health; }
+ void Hurt(double d) noexcept;
- void AddNeed(const Need &n) { needs.push_back(n); }
- const std::vector<Need> &Needs() const noexcept { return needs; }
+ void AddNeed(std::unique_ptr<Need> &&n) { needs.emplace_back(std::move(n)); }
+ const std::vector<std::unique_ptr<Need>> &Needs() const noexcept { return needs; }
void Tick(double dt);
private:
std::string name;
double health;
- std::vector<Need> needs;
+ std::vector<std::unique_ptr<Need>> needs;
Situation situation;
--- /dev/null
+#ifndef BLOBS_CREATURE_INGESTNEED_HPP_
+#define BLOBS_CREATURE_INGESTNEED_HPP_
+
+#include "Need.hpp"
+
+
+namespace blobs {
+namespace creature {
+
+class Need;
+
+class IngestNeed
+: public Need {
+
+public:
+ IngestNeed(int resource, double speed, double damage);
+ ~IngestNeed() override;
+
+public:
+ void ApplyEffect(Creature &, double dt) override;
+
+private:
+ int resource;
+ double speed;
+ double damage;
+
+};
+
+}
+}
+
+#endif
--- /dev/null
+#ifndef BLOBS_CREATURE_INHALENEED_HPP_
+#define BLOBS_CREATURE_INHALENEED_HPP_
+
+#include "Need.hpp"
+
+
+namespace blobs {
+namespace creature {
+
+class Need;
+
+class InhaleNeed
+: public Need {
+
+public:
+ InhaleNeed(int resource, double speed, double damage);
+ ~InhaleNeed() override;
+
+public:
+ void ApplyEffect(Creature &, double dt) override;
+
+private:
+ int resource;
+ double speed;
+ double damage;
+
+};
+
+}
+}
+
+#endif
#ifndef BLOBS_CREATURE_NEED_HPP_
#define BLOBS_CREATURE_NEED_HPP_
+#include <string>
+
+
namespace blobs {
namespace creature {
+class Creature;
+class Effect;
+
struct Need {
- int resource = -1;
+ std::string name;
+
double value = 0.0;
// how fast value grows per second
double gain = 0.0;
// the value at which this need is no longer satisfied
+ double inconvenient = 0.0;
+ // the value at which this need starts to hurt
double critical = 0.0;
- // the price to pay for not satsfying the need
- double penalty = 0.0;
+
+ virtual ~Need() noexcept;
void Tick(double dt) noexcept;
- bool IsSatisfied() const noexcept { return value < critical; }
+ bool IsSatisfied() const noexcept { return value < inconvenient; }
+ bool IsInconvenient() const noexcept { return value >= inconvenient && value < critical; }
+ bool IsCritical() const noexcept { return value >= critical; }
+
+ virtual void ApplyEffect(Creature &, double dt) = 0;
};
#include "Creature.hpp"
-#include "Need.hpp"
#include "Situation.hpp"
+#include "InhaleNeed.hpp"
+#include "IngestNeed.hpp"
+#include "Need.hpp"
#include "../app/Assets.hpp"
#include "../world/Body.hpp"
#include "../world/Planet.hpp"
Creature::~Creature() {
}
+void Creature::Hurt(double dt) noexcept {
+ health = std::max(0.0, health - dt);
+}
void Creature::Tick(double dt) {
- for (Need &need : needs) {
- need.Tick(dt);
- if (!need.IsSatisfied()) {
- health = std::max(0.0, health - need.penalty * dt);
- }
+ // update needs
+ for (auto &need : needs) {
+ need->Tick(dt);
+ }
+ // do background stuff
+ for (auto &need : needs) {
+ need->ApplyEffect(*this, dt);
}
}
if (p.HasAtmosphere()) {
std::cout << "require breathing " << assets.data.resources[p.Atmosphere()].label << std::endl;
- Need need;
- need.resource = p.Atmosphere();
- need.gain = 0.25;
- need.critical = 0.95;
- need.penalty = 0.1;
- c.AddNeed(need);
+ std::unique_ptr<Need> need(new InhaleNeed(p.Atmosphere(), 0.25, 0.1));
+ need->name = assets.data.resources[p.Atmosphere()].label;
+ need->gain = 0.25;
+ need->inconvenient = 0.4;
+ need->critical = 0.95;
+ c.AddNeed(std::move(need));
}
if (liquid > -1) {
std::cout << "require drinking " << assets.data.resources[liquid].label << std::endl;
- Need need;
- need.resource = liquid;
- need.gain = 0.0001;
- need.critical = 0.95;
- need.penalty = 0.01;
- c.AddNeed(need);
+ std::unique_ptr<Need> need(new IngestNeed(liquid, 0.2, 0.01));
+ need->name = assets.data.resources[liquid].label;
+ need->gain = 0.0001;
+ need->inconvenient = 0.6;
+ need->critical = 0.95;
+ c.AddNeed(std::move(need));
}
if (solid > -1) {
std::cout << "require eating " << assets.data.resources[solid].label << std::endl;
- Need need;
- need.resource = solid;
- need.gain = 0.00001;
- need.critical = 0.95;
- need.penalty = 0.001;
- c.AddNeed(need);
+ std::unique_ptr<Need> need(new IngestNeed(solid, 0.03, 0.001));
+ need->name = assets.data.resources[solid].label;
+ need->gain = 0.00001;
+ need->inconvenient = 0.6;
+ need->critical = 0.95;
+ c.AddNeed(std::move(need));
}
}
-
-void Need::Tick(double dt) noexcept {
- value = std::min(1.0, value + gain * dt);
-}
-
-
Situation::Situation()
: planet(nullptr)
, position(0.0)
--- /dev/null
+#include "Need.hpp"
+#include "InhaleNeed.hpp"
+#include "IngestNeed.hpp"
+
+#include "Creature.hpp"
+#include "../world/Planet.hpp"
+
+
+namespace blobs {
+namespace creature {
+
+Need::~Need() {
+}
+
+void Need::Tick(double dt) noexcept {
+ value = std::min(1.0, value + gain * dt);
+}
+
+
+IngestNeed::IngestNeed(int resource, double speed, double damage)
+: resource(resource)
+, speed(speed)
+, damage(damage) {
+}
+
+IngestNeed::~IngestNeed() {
+}
+
+void IngestNeed::ApplyEffect(Creature &c, double dt) {
+ if (!IsSatisfied()) {
+ // TODO: find resource and start ingest task
+ }
+ if (IsCritical()) {
+ c.Hurt(damage * dt);
+ }
+}
+
+
+InhaleNeed::InhaleNeed(int resource, double speed, double damage)
+: resource(resource)
+, speed(speed)
+, damage(damage) {
+}
+
+InhaleNeed::~InhaleNeed() {
+}
+
+void InhaleNeed::ApplyEffect(Creature &c, double dt) {
+ if (!IsSatisfied()) {
+ // TODO: make condition more natural with thresholds and stuff
+ if (c.GetSituation().OnPlanet() && c.GetSituation().GetPlanet().Atmosphere() == resource) {
+ value = std::max(0.0, value - (speed * dt));
+ } else {
+ // TODO: panic
+ }
+ }
+ if (IsCritical()) {
+ c.Hurt(damage * dt);
+ }
+}
+
+}
+}
Panel *needs;
Panel panel;
- std::vector<Meter *> meters;
+ Meter *health_meter;
+ std::vector<Meter *> need_meters;
};
#include "Meter.hpp"
#include "../app/Assets.hpp"
#include "../creature/Creature.hpp"
+#include "../creature/Need.hpp"
#include "../graphics/Viewport.hpp"
#include <glm/gtx/transform.hpp>
, c(nullptr)
, name(new Label(assets.fonts.large))
, needs(new Panel)
-, panel() {
+, panel()
+, health_meter(new Meter)
+, need_meters() {
+ Label *health_label = new Label(assets.fonts.medium);
+ health_label->Text("Health");
+ health_meter
+ ->Size(glm::vec2(100.0f, assets.fonts.medium.Height() + assets.fonts.medium.Descent()))
+ ->Padding(glm::vec2(1.0f))
+ ->Border(1.0f)
+ ->FillColor(glm::vec4(0.9f, 0.0f, 0.0f, 1.0f))
+ ->BorderColor(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
+ Panel *health_panel = new Panel;
+ health_panel
+ ->Add(health_label)
+ ->Add(health_meter)
+ ->Direction(Panel::HORIZONTAL);
panel
.Add(name)
+ ->Add(health_panel)
->Add(needs)
->Padding(glm::vec2(10.0f))
->Spacing(10.0f)
void CreaturePanel::CreateNeeds() {
needs->Clear()->Reserve(c->Needs().size());
- meters.clear();
- meters.reserve(c->Needs().size());
+ need_meters.clear();
+ need_meters.reserve(c->Needs().size());
for (auto &need : c->Needs()) {
Label *label = new Label(assets.fonts.medium);
- label
- ->Text(assets.data.resources[need.resource].label);
+ label->Text(need->name);
Meter *meter = new Meter;
meter
- ->Value(1.0f - need.value)
+ ->Value(1.0f - need->value)
->Size(glm::vec2(100.0f, assets.fonts.medium.Height() + assets.fonts.medium.Descent()))
->Padding(glm::vec2(1.0f))
->Border(1.0f)
->Add(label)
->Add(meter);
needs->Add(need_panel);
- meters.push_back(meter);
+ need_meters.push_back(meter);
}
panel.Relayout();
}
void CreaturePanel::Draw(app::Assets &assets, graphics::Viewport &viewport) noexcept {
if (!c) return;
- if (meters.size() != c->Needs().size()) {
+ health_meter->Value(c->Health());
+
+ if (need_meters.size() != c->Needs().size()) {
CreateNeeds();
} else {
auto need = c->Needs().begin();
auto need_end = c->Needs().end();
- auto meter = meters.begin();
+ auto meter = need_meters.begin();
for (; need != need_end; ++need, ++meter) {
- (*meter)->Value(1.0f - need->value)->FillColor(need->IsSatisfied()
- ? glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)
- : glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));
+ (*meter)->Value(1.0f - (*need)->value);
+ if ((*need)->IsSatisfied()) {
+ (*meter)->FillColor(glm::vec4(0.0f, 0.7f, 0.0f, 1.0f));
+ } else if ((*need)->IsInconvenient()) {
+ (*meter)->FillColor(glm::vec4(0.7f, 0.5f, 0.0f, 1.0f));
+ } else {
+ (*meter)->FillColor(glm::vec4(0.9f, 0.0f, 0.0f, 1.0f));
+ }
}
}