+, stat(stat)
+, accept(Assets().data.resources)
+, locate_subtask(nullptr)
+, ingesting(false)
+, resource(-1)
+, yield(0.0) {
+ Urgency(stat.value);
+}
+
+IngestGoal::~IngestGoal() {
+}
+
+void IngestGoal::Accept(int resource, double value) {
+ accept.Add(resource, value);
+}
+
+std::string IngestGoal::Describe() const {
+ if (resource == -1) {
+ return "ingest " + summarize(accept, Assets());
+ } else {
+ const world::Resource &r = Assets().data.resources[resource];
+ if (r.state == world::Resource::SOLID) {
+ return "eat " + r.label;
+ } else {
+ return "drink " + r.label;
+ }
+ }
+}
+
+void IngestGoal::Enable() {
+}
+
+void IngestGoal::Tick(double dt) {
+ Urgency(stat.value);
+ if (locate_subtask) {
+ locate_subtask->Urgency(Urgency() + 0.1);
+ }
+ if (ingesting) {
+ if (OnSuitableTile() && !GetSituation().Moving()) {
+ GetCreature().Ingest(resource, yield * dt);
+ stat.Add(-1.0 * yield * GetCreature().GetComposition().Compatibility(resource) * dt);
+ if (stat.Empty()) {
+ SetComplete();
+ }
+ } else {
+ // left tile somehow, some idiot probably pushed us off
+ ingesting = false;
+ Interruptible(true);
+ }
+ }
+}
+
+void IngestGoal::Action() {
+ if (ingesting) {
+ // all good
+ return;
+ }
+ if (OnSuitableTile()) {
+ if (GetSituation().Moving()) {
+ // break with maximum force
+ GetSteering().Haste(1.0);
+ GetSteering().Halt();
+ } else {
+ // finally
+ // TODO: somehow this still gets interrupted
+ Interruptible(false);
+ ingesting = true;
+ }
+ } else {
+ locate_subtask = new LocateResourceGoal(GetCreature());
+ for (const auto &c : accept) {
+ locate_subtask->Accept(c.resource, c.value);
+ }
+ locate_subtask->SetMinimum(stat.gain * -1.1);
+ locate_subtask->Urgency(Urgency() + 0.1);
+ locate_subtask->WhenComplete([&](Goal &){ locate_subtask = nullptr; });
+ GetCreature().AddGoal(std::unique_ptr<Goal>(locate_subtask));
+ }
+}
+
+bool IngestGoal::OnSuitableTile() {
+ if (!GetSituation().OnGround()) {
+ return false;
+ }
+ const world::TileType &t = GetSituation().GetTileType();
+ auto found = t.FindBestResource(accept);
+ if (found != t.resources.end()) {
+ resource = found->resource;
+ yield = found->ubiquity;
+ return true;
+ } else {
+ resource = -1;
+ return false;
+ }
+}
+
+
+LocateResourceGoal::LocateResourceGoal(Creature &c)
+: Goal(c)
+, accept(Assets().data.resources)