diff options
Diffstat (limited to 'src/game/game.cpp')
-rw-r--r-- | src/game/game.cpp | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/src/game/game.cpp b/src/game/game.cpp new file mode 100644 index 0000000..eb3966d --- /dev/null +++ b/src/game/game.cpp @@ -0,0 +1,270 @@ +#include "game.hpp" + +namespace game { + +static size_t selection_cookie = 1; + +enum { + ET_UNIT +}; + +class unit_t : public world::entity_t { +protected: + 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<v2f_t> path; + + bool blocked; + size_t attempts_left; + float next_attempt; + } move; + + const wchar_t *say_text; + double say_time = -INFINITY; + + void say(const wchar_t *wstr, double now) + { + say_text = wstr; + say_time = now; + std::cout << (void*)this << ": " << wstr << "\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, double dt) + { + float time; + + if (!move.moving) + return; + + if (move.blocked && now < move.next_attempt) + return; + + time = dt * 10; + + 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.2f; + } else { + if ((x - move.dst).len() > 1.5f) + say(text::unit_blocked, now); + move.moving = false; + } + break; + } + + + unlink(); + compute_bounds(); + link(world); + } + + bool start_moving(v2f_t dst_, double now) + { + 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, now); + 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: + human_t() + { + size[0] = v2f_t(-0.4f, -0.4f); + size[1] = v2f_t(+0.4f, +0.4f); + render_size[0] = v2f_t(-0.5f, -1.0f); + render_size[1] = v2f_t(+0.5f, +0.5f); + } + + 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); + + { + v2f_t x1; + static float t = 0; + world::trace_t trace; + + t += 0.02f; + + x1[0] = x[0] + cos(t) * 5; + x1[1] = x[1] + sin(t) * 5; + trace = world->trace(x, x1, 1); + render->render_arrow(x, trace.end, sf::Color::Green); + } + + if (move.moving && debug_draw_paths) + render->debug_path(&move.path); + + if (say_time + 5.0 > render->now) { + v2f_t text_pos; + float height; + + text_pos = render_bounds[0] + v2f_t(render_bounds.dim(0) / 2, -render_bounds.dim(1) * 0.1); + height = size.dim_min() * 0.20f; + render->render_text(text_pos, height, say_text, + render::ALIGN_CENTER_BOTTOM, + sf::Color::White); + } + } +}; + +void state_t::start(void) +{ + human_t *human; + + human = new human_t; + human->place(&world, v2f_t(0.5, 0.5)); + units.insert(human); +} + +void state_t::stop(void) +{ + // FIXME + /* + for (unit_t *unit : units) + delete unit; + */ +} + +void state_t::select(rectf_t x) +{ + selection_cookie++; + selected_units.clear(); + + for (world::entity_t *ent : world.get_render_entities(x)) { + 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) +{ + v2f_t snap; + + snap[0] = std::round(x[0] - 0.5f) + 0.5f; + snap[1] = std::round(x[1] - 0.5f) + 0.5f; + + for (unit_t *unit : selected_units) + unit->start_moving(snap, now); +} + +void state_t::tick(double now_, double dt_) +{ + now = now_; + dt = dt_; + + for (unit_t *unit : units) + unit->keep_moving(now, dt); +} + +} //namespace game |