+Memory::Memory(Creature &c)
+: c(c) {
+}
+
+Memory::~Memory() {
+}
+
+void Memory::Erase() {
+ known_types.clear();
+ known_creatures.clear();
+}
+
+bool Memory::RememberLocation(const Composition &accept, glm::dvec3 &pos) const noexcept {
+ double best_rating = -1.0;
+ for (const auto &k : known_types) {
+ const world::TileType &t = c.GetSimulation().TileTypes()[k.first];
+ auto entry = t.FindBestResource(accept);
+ if (entry != t.resources.end()) {
+ double rating = entry->ubiquity / std::max(0.125, 0.25 * glm::length2(c.GetSituation().Position() - k.second.first_loc.position));
+ if (rating > best_rating) {
+ best_rating = rating;
+ pos = k.second.first_loc.position;
+ }
+ rating = entry->ubiquity / std::max(0.125, 0.25 * glm::length2(c.GetSituation().Position() - k.second.last_loc.position));
+ if (rating > best_rating) {
+ best_rating = rating;
+ pos = k.second.last_loc.position;
+ }
+ }
+ }
+ if (best_rating > 0.0) {
+ glm::dvec3 error(
+ c.GetSimulation().Assets().random.SNorm(),
+ c.GetSimulation().Assets().random.SNorm(),
+ c.GetSimulation().Assets().random.SNorm());
+ pos += error * (4.0 * (1.0 - c.IntelligenceFactor()));
+ pos = glm::normalize(pos) * c.GetSituation().GetPlanet().Radius();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void Memory::TrackCollision(Creature &other) {
+ // TODO: find out whose fault it was
+ // TODO: source values from personality
+ Profile &p = known_creatures[&other];
+ p.annoyance += 0.1;
+ const double annoy_fact = p.annoyance / (p.annoyance + 1.0);
+ if (c.GetSimulation().Assets().random.UNorm() > annoy_fact * 0.1 * (1.0 - c.GetStats().Damage().value)) {
+ AttackGoal *g = new AttackGoal(c, other);
+ g->SetDamageTarget(annoy_fact);
+ g->Urgency(annoy_fact);
+ c.AddGoal(std::unique_ptr<Goal>(g));
+ p.annoyance *= 0.5;
+ }
+}
+
+void Memory::Tick(double dt) {
+ Situation &s = c.GetSituation();
+ if (s.OnSurface()) {
+ TrackStay({ &s.GetPlanet(), s.Position() }, dt);
+ }
+ // TODO: forget
+}
+
+void Memory::TrackStay(const Location &l, double t) {
+ const world::TileType &type = l.planet->TileTypeAt(l.position);
+ auto entry = known_types.find(type.id);
+ if (entry != known_types.end()) {
+ if (c.GetSimulation().Time() - entry->second.last_been > c.GetProperties().Lifetime() * 0.1) {
+ // "it's been ages"
+ if (entry->second.time_spent > c.Age() * 0.25) {
+ // the place is very familiar
+ c.GetStats().Boredom().Add(-0.2);
+ } else {
+ // infrequent stays
+ c.GetStats().Boredom().Add(-0.1);
+ }
+ }
+ entry->second.last_been = c.GetSimulation().Time();
+ entry->second.last_loc = l;
+ entry->second.time_spent += t;
+ } else {
+ known_types.emplace(type.id, Stay{
+ c.GetSimulation().Time(),
+ l,
+ c.GetSimulation().Time(),
+ l,
+ t
+ });
+ // completely new place, interesting
+ // TODO: scale by personality trait
+ c.GetStats().Boredom().Add(-0.25);
+ }
+}
+
+
+NameGenerator::NameGenerator()
+: counter(0) {
+}
+
+NameGenerator::~NameGenerator() {
+}
+
+std::string NameGenerator::Sequential() {
+ std::stringstream ss;
+ ss << "Blob " << ++counter;
+ return ss.str();
+}
+
+