#include "common.hpp" namespace game { static size_t selection_cookie = 1; enum { ET_UNIT }; class unit_t : public world::entity_t { world::world_t *world; world::cmodel_t make_cmodel(v2f_t at) { world::cmodel_t cmodel; cmodel.bounds[0] = at + size[0]; cmodel.bounds[1] = at + size[1]; cmodel.cflags = cflags; return cmodel; } void compute_bounds() { render_bounds[0] = x + render_size[0]; render_bounds[1] = x + render_size[1]; } public: v2f_t x; rectf_t size, render_size; world::cflags_t cflags; size_t selected = 0; unit_t() : entity_t(ET_UNIT) { } struct { bool moving = false; v2f_t dst; float angle = 0.0f; std::list path; bool blocked; size_t attempts_left; float next_attempt; } move; void say(std::string str) { //TODO std::cout << (void*)this << ": " << str << "\n"; } void place(world::world_t *world_, v2f_t x_) { world = world_; x = x_; move.moving = false; cflags = 1; unlink(); cmodel = make_cmodel(x); compute_bounds(); link(world); } void keep_moving(double now) { float time; if (!move.moving) return; if (move.blocked && now < move.next_attempt) return; time = 0.15; // FIXME while (time > 0.0f) { v2f_t delta, next, x_new; world::cmodel_t cmodel_next; if (!move.path.size()) { move.moving = false; break; } next = *move.path.begin(); delta = next - x; move.angle = delta.angle(); if (delta.len() >= time) { x_new = x + delta * time / delta.len(); time -= delta.len(); } else { x_new = next; time -= delta.len(); move.path.pop_front(); } cmodel_next = make_cmodel(x_new); if (!world->test_rect(&cmodel_next, this)) { x = x_new; cmodel = cmodel_next; continue; } if (move.attempts_left) { move.blocked = true; move.attempts_left--; move.next_attempt = now + 0.5f; } else { if ((x - move.dst).len() > 1.5f) say(text::unit_blocked); move.moving = false; } break; } unlink(); compute_bounds(); link(world); } bool start_moving(v2f_t dst_) { if (!world) { printf("unit_t::start_moving: entity is not linked\n"); return false; } move.dst = dst_; move.path.clear(); if (!world->find_path(x, move.dst, &cmodel, this, &move.path)) { say(text::unit_no_path); move.moving = false; return false; } move.moving = true; move.blocked = false; move.attempts_left = 10; move.next_attempt = -INFINITY; return true; } }; class human_t : public unit_t { public: double last_follow = -INFINITY; void render_to(render::state_t *render) { bool moving; if (selected == selection_cookie) render->render_hlrect(render_bounds, sf::Color::Blue); moving = move.moving && !move.blocked; render->render((moving ? &assets::human.legs_walking : &assets::human.legs_idle), render_bounds, move.angle); render->render(&assets::human.body_idle, render_bounds, move.angle); render->render(&assets::human.head_idle, render_bounds, move.angle); if (move.moving && debug_draw_paths) render->debug_path(&move.path); } }; static human_t human, human2; void state_t::start(void) { human.size[0] = v2f_t(-0.4f, -0.4f); human.size[1] = v2f_t(+0.4f, +0.4f); human.render_size[0] = v2f_t(-0.5f, -1.0f); human.render_size[1] = v2f_t(+0.5f, +0.5f); human.place(&world, v2f_t(2.5f, -3.5f)); human2.size[0] = v2f_t(-0.4f, -0.4f); human2.size[1] = v2f_t(+0.4f, +0.4f); human2.render_size[0] = v2f_t(-0.5f, -1.0f); human2.render_size[1] = v2f_t(+0.5f, +0.5f); human2.place(&world, v2f_t(3.5f, 0.5f)); } void state_t::select(rectf_t x) { selection_cookie++; selected_units.clear(); for (world::entity_t *ent : world.get_render_entities(x, -1)) { unit_t *unit; if (ent->type != ET_UNIT) continue; unit = (unit_t*)ent; unit->selected = selection_cookie; selected_units.insert(unit); } } void state_t::command(v2f_t x) { for (unit_t *unit : selected_units) unit->start_moving(x); } void state_t::tick(double now) { human.keep_moving(now); human2.keep_moving(now); } } //namespace game