Skip to content
Permalink
Browse files

Settlers now eat in their idle time. Part 1 of eating, until dining r…

…ooms are implented.
  • Loading branch information...
thebracket committed Apr 14, 2018
1 parent 3d979c6 commit f2ccba950dc4560195916b1ab49f10c1e4f5df21
@@ -261,6 +261,7 @@
<ClCompile Include="..\..\src\systems\ai\sentient_ai_system.cpp" />
<ClCompile Include="..\..\src\systems\ai\settler\ai_deconstruct.cpp" />
<ClCompile Include="..\..\src\systems\ai\settler\ai_idle_time.cpp" />
<ClCompile Include="..\..\src\systems\ai\settler\ai_leisure_eat.cpp" />
<ClCompile Include="..\..\src\systems\ai\settler\ai_leisure_time.cpp" />
<ClCompile Include="..\..\src\systems\ai\settler\ai_new_arrival.cpp" />
<ClCompile Include="..\..\src\systems\ai\settler\ai_scheduler.cpp" />
@@ -349,6 +350,7 @@
<ItemGroup>
<ClInclude Include="..\..\src\components\ai_tags\ai_mode_idle.hpp" />
<ClInclude Include="..\..\src\components\ai_tags\ai_settler_new_arrival.hpp" />
<ClInclude Include="..\..\src\components\ai_tags\ai_tag_leisure_eat.hpp" />
<ClInclude Include="..\..\src\components\ai_tags\ai_tag_leisure_shift.hpp" />
<ClInclude Include="..\..\src\components\ai_tags\ai_tag_my_turn.hpp" />
<ClInclude Include="..\..\src\components\ai_tags\ai_tag_sleep_shift.hpp" />
@@ -498,6 +500,7 @@
<ClInclude Include="..\..\src\systems\ai\settler\ai_deconstruct.hpp" />
<ClInclude Include="..\..\src\systems\ai\settler\ai_idle.hpp" />
<ClInclude Include="..\..\src\systems\ai\settler\ai_idle_time.hpp" />
<ClInclude Include="..\..\src\systems\ai\settler\ai_leisure_eat.hpp" />
<ClInclude Include="..\..\src\systems\ai\settler\ai_leisure_time.hpp" />
<ClInclude Include="..\..\src\systems\ai\settler\ai_new_arrival.hpp" />
<ClInclude Include="..\..\src\systems\ai\settler\ai_scheduler.hpp" />
@@ -523,6 +526,7 @@
<ClInclude Include="..\..\src\systems\ai\settler\ai_work_template.hpp" />
<ClInclude Include="..\..\src\systems\ai\settler\ai_work_time.hpp" />
<ClInclude Include="..\..\src\systems\ai\settler\jobs_board.hpp" />
<ClInclude Include="..\..\src\systems\ai\settler\templated_idle_steps_t.hpp" />
<ClInclude Include="..\..\src\systems\ai\settler\templated_work_steps_t.hpp" />
<ClInclude Include="..\..\src\systems\ai\stockpile_system.hpp" />
<ClInclude Include="..\..\src\systems\ai\wildlife_population.hpp" />
@@ -500,6 +500,9 @@
<ClCompile Include="..\..\src\systems\scheduler\hunger_system.cpp">
<Filter>Source Files\systems\scheduler</Filter>
</ClCompile>
<ClCompile Include="..\..\src\systems\ai\settler\ai_leisure_eat.cpp">
<Filter>Source Files\systems\ai\settler</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\components\calendar.hpp">
@@ -1225,5 +1228,14 @@
<ClInclude Include="..\..\src\systems\scheduler\hunger_system.hpp">
<Filter>Header Files\systems\scheduler</Filter>
</ClInclude>
<ClInclude Include="..\..\src\systems\ai\settler\templated_idle_steps_t.hpp">
<Filter>Header Files\systems\ai\settler</Filter>
</ClInclude>
<ClInclude Include="..\..\src\systems\ai\settler\ai_leisure_eat.hpp">
<Filter>Header Files\systems\ai\settler</Filter>
</ClInclude>
<ClInclude Include="..\..\src\components\ai_tags\ai_tag_leisure_eat.hpp">
<Filter>Header Files\components\ai_tags</Filter>
</ClInclude>
</ItemGroup>
</Project>
@@ -0,0 +1,11 @@
#pragma once

struct ai_tag_leisure_eat_t {

enum eat_steps { FIND_FOOD, GOTO_FOOD, EAT_FOOD };

eat_steps step = FIND_FOOD;
std::size_t tool_id = 0;
std::shared_ptr<navigation_path_t> current_path; // Not serialized
};

@@ -111,6 +111,7 @@
#include "machinery/node_graph_position.hpp"
#include "buildings/construct_provides_support.hpp"
#include "hunger_t.hpp"
#include "ai_tags/ai_tag_leisure_eat.hpp"

namespace bengine {
template<class ... Components>
@@ -133,7 +134,7 @@ namespace bengine {
item_topsoil_t, item_t, item_carried_t, item_creator_t, item_quality_t, item_stored_t, item_wear_t, designated_miner_t,
mining_designations_t, ai_tag_work_stockpiles_t, item_food_prepared_t, flying_t, ai_tag_work_deconstruct, sends_signal_t,
signal_processor_t, float_gauge_t, pressure_plate_t, proximity_sensor_t, oscillator_t, node_graph_position_t, construct_support_t,
hunger_t
hunger_t, ai_tag_leisure_eat_t
>;
}
}
@@ -76,6 +76,12 @@ void serialize(Archive & archive, ai_tag_leisure_shift_t &tag)
archive(tag.dummy);
}

template<class Archive>
void serialize(Archive & archive, ai_tag_leisure_eat_t &tag)
{
// Nothing to save
archive(tag.tool_id, tag.step);
}

template<class Archive>
void serialize(Archive & archive, ai_tag_my_turn_t &tag)
@@ -0,0 +1,98 @@
#include "ai_leisure_eat.hpp"
#include "templated_idle_steps_t.hpp"
#include "../../gui/log_system.hpp"

namespace systems {
namespace ai_leisure_eat {
using namespace bengine;
using namespace jobs_board;
using namespace region;

namespace jobs_board {
void evaluate_hunger(job_board_t &board, entity_t &e, position_t &pos, job_evaluator_base_t *jt) {
const auto hunger = e.component<hunger_t>();
if (!hunger) return;
if (!hunger->is_hungry) return;
if (!inventory::is_item_category_available<item_food_prepared_t>()) return;
board.insert(std::make_pair(2, jt)); // Eating is a high priority!
}
}

static const char * job_tag = "Eating";
static work::templated_idle_steps_t<ai_tag_leisure_eat_t> work;

inline void find_food(entity_t &e, ai_tag_leisure_eat_t &h, ai_tag_my_turn_t &t, position_t &pos) {
h.current_path.reset();
const auto food_id = inventory::find_closest_unclaimed_item_by_category_and_claim_it_immediately<item_food_prepared_t>(e.id, pos);
if (food_id > 0) {
const auto food_pos = inventory::get_item_location(food_id);
if (!food_pos) {
inventory::unclaim_by_id(food_id);
work.cancel_work_tag(e);
}
else {
h.tool_id = food_id;
h.current_path = find_path(pos, *food_pos);
if (!h.current_path->success) {
inventory::unclaim_by_id(food_id);
work.cancel_work_tag(e);
}
else {
h.step = ai_tag_leisure_eat_t::eat_steps::GOTO_FOOD;
}
}
}
else {
work.cancel_work_tag(e);
}
}

inline void goto_food(entity_t &e, ai_tag_leisure_eat_t &h, ai_tag_my_turn_t &t, position_t &pos) {
work.follow_path(h, pos, e, [&h]() {
// Cancel
h.current_path.reset();
h.step = ai_tag_leisure_eat_t::eat_steps::FIND_FOOD;
inventory::unclaim_by_id(h.tool_id);
return;
}, [&h, &e]() {
// Success
h.current_path.reset();
h.step = ai_tag_leisure_eat_t::eat_steps::EAT_FOOD;

inventory_system::pickup_item(h.tool_id, e.id);
return;
});
}

inline void eat_food(entity_t &e, ai_tag_leisure_eat_t &h, ai_tag_my_turn_t &t, position_t &pos) {
work.cancel_work_tag(e);
const auto hunger = e.component<hunger_t>();
if (hunger) {
hunger->is_hungry = false;
hunger->hunger_clock = 24 * 60;
}
const auto food_entity = entity(h.tool_id);
if (food_entity) {
const auto name = food_entity->component<item_t>();
if (name) {
logging::log_message lmsg{ LOG{}.settler_name(e.id)->text(std::string(" eats "))->text(name->item_name)->chars };
logging::log(lmsg);
}
inventory::delete_item(h.tool_id);
}
}

void dispatch(entity_t &e, ai_tag_leisure_eat_t &h, ai_tag_my_turn_t &t, position_t &pos) {
switch (h.step) {
case ai_tag_leisure_eat_t::eat_steps::FIND_FOOD: find_food(e, h, t, pos); break;
case ai_tag_leisure_eat_t::eat_steps::GOTO_FOOD: goto_food(e, h, t, pos); break;
case ai_tag_leisure_eat_t::eat_steps::EAT_FOOD: eat_food(e, h, t, pos); break;
}
}

void run(const double &duration_ms)
{
work.do_idle(jobs_board::evaluate_hunger, dispatch, job_tag);
}
}
}
@@ -0,0 +1,7 @@
#pragma once

namespace systems {
namespace ai_leisure_eat {
void run(const double &duration_ms);
}
}
@@ -1,20 +1,46 @@
#include "stdafx.h"
#include "ai_leisure_time.hpp"
#include "../../physics/movement_system.hpp"
#include "templated_work_steps_t.hpp"
#include "jobs_board.hpp"

namespace systems {
namespace ai_leisure_time {

using namespace bengine;
using namespace jobs_board;

namespace jobs_board {
job_board_t idle_evaluations(entity_t &e, position_t &pos) {
job_board_t board;
evaluate_idle(board, e, pos);

return board;
}
}

void run(const double &duration_ms) {
each<settler_ai_t, ai_tag_leisure_shift_t>([](entity_t &e, settler_ai_t &ai, ai_tag_leisure_shift_t &leisure) {
delete_component<ai_tag_leisure_shift_t>(e.id);
delete_component<ai_tag_my_turn_t>(e.id);
e.assign(ai_mode_idle_t{});
each<settler_ai_t, ai_tag_leisure_shift_t, position_t>([](entity_t &e, settler_ai_t &ai, ai_tag_leisure_shift_t &leisure, position_t &pos) {
// Do we already have a leisure job? If so, then return to doing it!
if (is_working_on_leisure(e)) return;

// Build a job candidates list, goal is to pick the easiest job to complete.
auto available_jobs = jobs_board::idle_evaluations(e, pos);

if (available_jobs.empty()) {
// Nothing to do here
e.assign(ai_mode_idle_t{});
delete_component<ai_tag_leisure_shift_t>(e.id);
delete_component<ai_tag_my_turn_t>(e.id);
movement::request_random_move(e.id);
return;
}
else {
delete_component<ai_tag_work_shift_t>(e.id);
}

// We don't have any leisure activities yet, so move randomly.
movement::request_random_move(e.id);
auto job_type = available_jobs.begin()->second;
job_type->set_tag(e);
});
}
}
@@ -5,6 +5,7 @@ namespace jobs_board {

namespace impl {
std::vector<std::unique_ptr<job_evaluator_base_t>> evaluators;
std::vector<std::unique_ptr<job_evaluator_base_t>> idle_evaluators;
}

bool is_working(bengine::entity_t &e) {
@@ -14,10 +15,24 @@ namespace jobs_board {
return false;
}

bool is_working_on_leisure(bengine::entity_t &e) {
for (const auto &job : impl::idle_evaluators) {
if (job->has_tag(e)) return true;
}
return false;
}

void evaluate(job_board_t &board, bengine::entity_t &entity, position_t &pos) {
std::for_each(impl::evaluators.begin(), impl::evaluators.end(),
[&board, &entity, &pos](const auto &j) {
j->exec(board, entity, pos);
});
}

void evaluate_idle(job_board_t &board, bengine::entity_t &entity, position_t &pos) {
std::for_each(impl::idle_evaluators.begin(), impl::idle_evaluators.end(),
[&board, &entity, &pos](const auto &j) {
j->exec(board, entity, pos);
});
}
}
@@ -46,6 +46,7 @@ namespace jobs_board {

namespace impl {
extern std::vector<std::unique_ptr<job_evaluator_base_t>> evaluators;
extern std::vector<std::unique_ptr<job_evaluator_base_t>> idle_evaluators;
}

template <typename T>
@@ -55,6 +56,15 @@ namespace jobs_board {
impl::evaluators.emplace_back(std::move(base));
}

template <typename T>
inline void register_idle_offer(job_evaluator_t evaluator) {
std::unique_ptr<job_evaluator_base_t> base = std::make_unique<job_evaluator_concrete<T>>(evaluator);

impl::idle_evaluators.emplace_back(std::move(base));
}

bool is_working(bengine::entity_t &e);
bool is_working_on_leisure(bengine::entity_t &e);
void evaluate(job_board_t &board, bengine::entity_t &entity, position_t &pos);
void evaluate_idle(job_board_t &board, bengine::entity_t &entity, position_t &pos);
}
Oops, something went wrong.

0 comments on commit f2ccba9

Please sign in to comment.
You can’t perform that action at this time.