diff --git a/source/application.cpp b/source/application.cpp index cc1bc73..d0ad292 100644 --- a/source/application.cpp +++ b/source/application.cpp @@ -60,6 +60,31 @@ namespace gmtk return {{{(coords[0] - extra) * s, (coords[0] + 1.f + extra) * s}, {(coords[1] - extra) * s, (coords[1] + 1.f + extra) * s}}}; } + location left() const + { + return {level, {coords[0] - 1, coords[1]}}; + } + + location right() const + { + return {level, {coords[0] + 1, coords[1]}}; + } + + location bottom() const + { + return {level, {coords[0], coords[1] - 1}}; + } + + location top() const + { + return {level, {coords[0], coords[1] + 1}}; + } + + location moved(geom::vector const & delta) const + { + return {level, coords + delta}; + } + location down() const { return {level + 1, {coords[0] * 3 + 1, coords[1] * 3 + 1}}; @@ -115,9 +140,22 @@ namespace gmtk struct location location; - boost::container::flat_set belts = {}; + boost::container::flat_set belts_to = {}; + boost::container::flat_set belts_from = {}; }; + void add_belt(ecs::container & world, ecs::handle from, ecs::handle to) + { + world.get(from).get().belts_to.insert(to); + world.get(to).get().belts_from.insert(from); + } + + void remove_belt(ecs::container & world, ecs::handle from, ecs::handle to) + { + world.get(from).get().belts_to.erase(to); + world.get(to).get().belts_from.erase(from); + } + struct occupied { psemek_ecs_declare_uuid("occupied") @@ -226,6 +264,75 @@ namespace gmtk using index = index_base; using path_index = index_base; + void sink_belt(ecs::container & world, location m) + { + if (auto entity = world.index().find(m.up()); !entity || !world.get(*entity).contains()) + return; + + auto & index = world.index(); + + auto c = m.up().down(); + + auto d = m.coords - c.coords; + + auto ce = index.get(c); + auto me = index.get(m); + + auto & cv = world.get(ce).get(); + + if (cv.belts_to.contains(me)) + { + auto & mv = world.get(me).get(); + auto ne = *mv.belts_to.begin(); + + remove_belt(world, ce, me); + remove_belt(world, me, ne); + + auto cd = m.down(); + auto md = cd.moved(d); + + auto cde = index.get(cd); + auto mde = index.get(md); + + add_belt(world, cde, mde); + add_belt(world, mde, ne); + + sink_belt(world, md); + } + else if (cv.belts_from.contains(me)) + { + auto & mv = world.get(me).get(); + auto ne = *mv.belts_from.begin(); + + remove_belt(world, ne, me); + remove_belt(world, me, ce); + + auto cd = m.down(); + auto md = cd.moved(d); + + auto cde = index.get(cd); + auto mde = index.get(md); + + add_belt(world, ne, mde); + add_belt(world, mde, cde); + + sink_belt(world, md); + } + } + + void sink(ecs::container & world, location & c, location & m) + { + if (auto entity = world.index().find(m.up()); !entity || !world.get(*entity).contains()) + return; + + auto d = m.coords - c.coords; + + c = m.down(); + m = c.moved(d); + + sink(world, c, m); + } + void generate_next_task(random::generator & rng, map & map) { color type; @@ -307,7 +414,7 @@ namespace gmtk map.world.apply([&](path_vertex const & vertex) { - for (auto b : vertex.belts) + for (auto b : vertex.belts_to) { auto q = map.world.get(b).get().location; float w0 = 0.3f * std::pow(3.f, 1.f - vertex.location.level); @@ -319,7 +426,7 @@ namespace gmtk map.world.apply([&](path_vertex const & vertex) { - for (auto b : vertex.belts) + for (auto b : vertex.belts_to) { auto q = map.world.get(b).get().location; @@ -381,15 +488,15 @@ namespace gmtk }); } - void draw_selection(location const & l, gfx::painter & painter) + void draw_selection(location const & l, gfx::painter & painter, gfx::color_rgba const & color) { auto b = l.bbox(); float s = std::pow(3.f, -l.level) * 0.1f; - painter.line(b.corner(0, 0), b.corner(1, 0), s, {255, 0, 255, 255}, true); - painter.line(b.corner(1, 0), b.corner(1, 1), s, {255, 0, 255, 255}, true); - painter.line(b.corner(1, 1), b.corner(0, 1), s, {255, 0, 255, 255}, true); - painter.line(b.corner(0, 1), b.corner(0, 0), s, {255, 0, 255, 255}, true); + painter.line(b.corner(0, 0), b.corner(1, 0), s, color, true); + painter.line(b.corner(1, 0), b.corner(1, 1), s, color, true); + painter.line(b.corner(1, 1), b.corner(0, 1), s, color, true); + painter.line(b.corner(0, 1), b.corner(0, 0), s, color, true); } struct application @@ -474,58 +581,31 @@ namespace gmtk auto d = selected_->coords - belt_start_->coords; if (std::abs(d[0]) + std::abs(d[1]) == 1) { - bool from_zoom = false; - bool to_zoom = false; + auto s = belt_start_->down(); - if (auto entity = map_.world.index().find(*belt_start_)) - if (map_.world.get(*entity).contains()) - from_zoom = true; - (void)from_zoom; - - if (auto entity = map_.world.index().find(*selected_)) - if (map_.world.get(*entity).contains()) - to_zoom = true; - - auto vx = [&](int i) - { - auto p = belt_start_->down(); - - if (i < 2 && from_zoom) - { - p.coords += d; - p = p.down(); - } - - if (i >= 2 && to_zoom) - { - p.coords += d; - p = p.down(); - } - - p.coords += d * i; - - return p; - }; + location belt[4]; + for (int i = 0; i <= 3; ++i) + belt[i] = s.moved(d * i); + sink(map_.world, belt[0], belt[1]); + sink(map_.world, belt[3], belt[2]); auto & index = map_.world.index(); for (int i = 0; i < 3; ++i) { - auto p = vx(i); - auto q = vx(i + 1); + auto p = belt[i]; + auto q = belt[i + 1]; auto s = index.get(p); auto t = index.get(q); auto & sv = map_.world.get(s).get(); - auto & tv = map_.world.get(t).get(); - if (sv.belts.contains(t)) - sv.belts.erase(t); + if (sv.belts_to.contains(t)) + remove_belt(map_.world, s, t); else { - if (tv.belts.contains(s)) - tv.belts.erase(s); - sv.belts.insert(t); + remove_belt(map_.world, t, s); + add_belt(map_.world, s, t); } } } @@ -575,6 +655,13 @@ namespace gmtk vertex{*selected_}, zoomer{} ); + + auto c = selected_->down(); + + sink_belt(map_.world, c.left()); + sink_belt(map_.world, c.right()); + sink_belt(map_.world, c.bottom()); + sink_belt(map_.world, c.top()); } } @@ -648,7 +735,7 @@ namespace gmtk { { auto & v = map_.world.get(map_.world.index().get(i.start)).get(); - if (!v.belts.contains(i.target)) + if (!v.belts_to.contains(i.target)) { map_.world.detach(i.target); map_.world.destroy(entity); @@ -672,19 +759,10 @@ namespace gmtk map_.world.detach(s); auto & v = map_.world.get(s).get(); - if (v.belts.empty()) + if (v.belts_to.empty() && v.belts_from.empty()) { - bool should_destroy = true; - map_.world.apply([&](path_vertex const & v){ - if (v.belts.contains(s)) - should_destroy = false; - }); - - if (should_destroy) - { - map_.world.destroy(entity); - return; - } + map_.world.destroy(entity); + return; } } @@ -707,7 +785,7 @@ namespace gmtk std::vector targets; - for (auto b : map_.world.get(map_.world.index().get(i.start)).get().belts) + for (auto b : map_.world.get(map_.world.index().get(i.start)).get().belts_to) if (!map_.world.get(b).contains()) targets.push_back(b); @@ -787,7 +865,10 @@ namespace gmtk draw(map_, view_level, painter_); if (selected_) - draw_selection(*selected_, painter_); + draw_selection(*selected_, painter_, {255, 0, 255, 255}); + + if (belt_start_) + draw_selection(*belt_start_, painter_, {255, 255, 0, 255}); painter_.render(geom::orthographic_camera{view_box_}.transform()); }