From d7a484f58d9a5fc15c3c5857e1550653b5ff0b05 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Mon, 19 Aug 2024 03:09:51 +0300 Subject: [PATCH] Wip --- source/application.cpp | 448 +++++++++++++++++++++++++---------------- 1 file changed, 277 insertions(+), 171 deletions(-) diff --git a/source/application.cpp b/source/application.cpp index 21f0137..baea048 100644 --- a/source/application.cpp +++ b/source/application.cpp @@ -19,8 +19,6 @@ #include #include -#include - namespace gmtk { @@ -47,6 +45,13 @@ namespace gmtk (factory) ) + psemek_declare_enum(card_type, std::uint32_t, + (crossing) + (furnace) + (factory) + (zoomer) + ) + gfx::color_rgba color_of(resource_type c) { switch (c) @@ -268,37 +273,59 @@ namespace gmtk return l.coords[0] >= 0 && l.coords[0] < max && l.coords[1] >= 0 && l.coords[1] < max; } - struct timestamp - { - int trunc = 0; - float frac = 0.f; - - timestamp & operator += (float dt) - { - frac += dt; - int t = std::floor(frac); - trunc += t; - frac -= t; - return *this; - } - - friend auto operator <=> (timestamp const & x, timestamp const & y) = default; - }; - struct lab { psemek_ecs_declare_uuid("lab") - - util::hash_map count = {}; }; struct map { ecs::container world; - timestamp time = {}; + util::hash_map cards = {}; + + int stage = 0; + + int resource_count = 0; float spawn_timer = 0.f; + + bool take_card(card_type type) + { + if (!cards.contains(type)) + return false; + + if (cards.at(type) == 0) + return false; + + cards.at(type) -= 1; + return true; + } + + void put_card(card_type type) + { + cards[type] += 1; + } + }; + + struct stage_info + { + resource_type type; + int count; + + std::vector cards; + std::vector sources; + }; + + static stage_info stages[] + { + {resource_type::stone, 0, {}, {resource_type::stone}}, + {resource_type::stone, 10, {card_type::furnace}, {resource_type::coal}}, + {resource_type::stone_brick, 30, {card_type::furnace}, {resource_type::iron_ore}}, + {resource_type::iron_plate, 30, {card_type::factory, card_type::crossing, card_type::crossing}, {resource_type::copper_ore}}, + {resource_type::red_science_pack, 30, {card_type::furnace, card_type::factory, card_type::crossing, card_type::crossing, card_type::zoomer, card_type::zoomer, card_type::zoomer}, {}}, + {resource_type::inserter, 60, {card_type::factory, card_type::factory, card_type::factory, card_type::factory, card_type::crossing, card_type::crossing, card_type::zoomer, card_type::zoomer, card_type::zoomer}, {resource_type::coal}}, + {resource_type::green_science_pack, 60, {}, {}}, }; template @@ -417,61 +444,31 @@ namespace gmtk sink(world, c, m); } - map starting_map(random::generator & rng) + map starting_map() { map result; result.world.index(); result.world.index(); - result.world.create( - vertex{{0, {-1, 1}}}, - source{resource_type::stone} - ); - - result.world.create( - vertex{{0, {-1, 2}}}, - source{resource_type::iron_ore} - ); - - result.world.create( - vertex{{0, {1, 3}}}, - source{resource_type::coal} - ); - - result.world.create( - vertex{{0, {3, 2}}}, - source{resource_type::copper_ore} - ); - result.world.create( vertex{{0, {1, -1}}}, lab{} ); - (void)rng; - return result; } - void draw_grid(location origin, float view_level, gfx::painter & painter, bool in_construction) + void draw_grid(geom::box const & box, float view_level, gfx::painter & painter) { - origin.level += 1; - origin.coords[0] *= 3; - origin.coords[1] *= 3; - - float const grid_width = 0.1f * std::pow(3.f, -std::max(view_level + 1.f, origin.level)); - - auto box = origin.bbox(); + float const grid_width = 0.1f * std::min(box[0].length() / 3.f, std::pow(3.f, -1.f - view_level)); auto color = gfx::black.as_color_rgba(); - if (in_construction) - color[3] = 127; for (int x = 0; x <= 3; ++x) { - painter.line(box.corner(x, 0), box.corner(x, 3), grid_width, color, true); - painter.line(box.corner(0, x), box.corner(3, x), grid_width, color, true); + painter.line(box.corner(x / 3.f, 0.f), box.corner(x / 3.f, 1.f), grid_width, color, true); + painter.line(box.corner(0.f, x / 3.f), box.corner(1.f, x / 3.f), grid_width, color, true); } } @@ -527,13 +524,63 @@ namespace gmtk } } + void draw_structure(geom::box const & bbox, transformer const & t, gfx::painter & painter) + { + auto box = geom::shrink(bbox, bbox[0].length() * 0.2f); + + auto p0 = box.corner(0, 0); + auto p1 = box.corner(1, 0); + auto p2 = box.corner(0.8f, 1); + auto p3 = box.corner(0.2f, 1); + + gfx::color_rgba color = {255, 0, 255, 255}; + switch (t.type) + { + case transformer_type::furnace: color = color_of(resource_type::stone); break; + case transformer_type::factory: color = color_of(resource_type::iron_ore); break; + } + + painter.triangle(p0, p1, p2, color); + painter.triangle(p0, p2, p3, color); + } + + void draw_structure(geom::box const & bbox, crossing const &, gfx::painter & painter) + { + auto wbox = geom::shrink(bbox, bbox[0].length() * 0.2f); + auto sbox = geom::shrink(bbox, bbox[0].length() * 0.3f); + + gfx::color_rgba color{64, 64, 64, 255}; + + painter.rect({wbox[0], sbox[1]}, color); + painter.rect({sbox[0], wbox[1]}, color); + } + + void draw_card(geom::box const & bbox, card_type type, gfx::painter & painter) + { + switch (type) + { + case card_type::crossing: + draw_structure(bbox, crossing{}, painter); + break; + case card_type::furnace: + draw_structure(bbox, transformer{transformer_type::furnace}, painter); + break; + case card_type::factory: + draw_structure(bbox, transformer{transformer_type::factory}, painter); + break; + case card_type::zoomer: + draw_grid(bbox, -1.f, painter); + break; + } + } + void draw(map & map, float view_level, gfx::painter & painter) { - draw_grid({-1, {0, 0}}, view_level, painter, false); + draw_grid({{{0.f, 3.f}, {0.f, 3.f}}}, view_level, painter); map.world.apply([&](vertex const & v, zoomer const &) { - draw_grid(v.location, view_level, painter, false); + draw_grid(v.location.bbox(), view_level, painter); }); map.world.apply([&](path_vertex const & vertex) @@ -576,46 +623,17 @@ namespace gmtk // painter.text(v.location.center(), "180/m", {.scale = {vs, -vs}, .c = {0, 0, 0, 255}}); }); - auto draw_transformer = [&](location const & l, transformer_type type, bool in_construction) - { - auto box = l.bbox(-0.2f); - - auto p0 = box.corner(0, 0); - auto p1 = box.corner(1, 0); - auto p2 = box.corner(0.8f, 1); - auto p3 = box.corner(0.2f, 1); - - gfx::color_rgba color = {255, 0, 255, 255}; - switch (type) - { - case transformer_type::furnace: color = color_of(resource_type::stone); break; - case transformer_type::factory: color = color_of(resource_type::iron_ore); break; - } - - if (in_construction) - color[3] = 127; - - painter.triangle(p0, p1, p2, color); - painter.triangle(p0, p2, p3, color); - }; - map.world.apply([&](vertex const & v, transformer const & t) { - draw_transformer(v.location, t.type, false); + draw_structure(v.location.bbox(), t, painter); }); - map.world.apply([&](vertex const & v, crossing const &) + map.world.apply([&](vertex const & v, crossing const & c) { - auto wbox = v.location.bbox(-0.2f); - auto sbox = v.location.bbox(-0.3f); - - gfx::color_rgba color{64, 64, 64, 255}; - - painter.rect({wbox[0], sbox[1]}, color); - painter.rect({sbox[0], wbox[1]}, color); + draw_structure(v.location.bbox(), c, painter); }); - map.world.apply([&](vertex const & v, lab const & l) + map.world.apply([&](vertex const & v, lab const &) { painter.rect(v.location.bbox(-0.2f), {128, 192, 255, 255}); @@ -623,14 +641,11 @@ namespace gmtk float vs = std::pow(3.f, - v.location.level) * 0.01f; - for (auto type : {resource_type::red_science_pack, resource_type::green_science_pack}) - { - if (l.count.contains(type)) - { - painter.text(pen, std::to_string(l.count.at(type)), {.scale = {vs, -vs}, .c = color_of(type)}); - pen[1] -= 12.f * vs; - } - } + draw_item(stages[map.stage].type, pen, 1.f, painter); + + pen[1] -= 24.f * vs; + + painter.text(pen, std::format("{}/{}", map.resource_count, stages[map.stage].count), {.scale = {vs, -vs}, .c = {0, 0, 0, 255}}); }); map.world.apply([&](item const & i) @@ -650,13 +665,22 @@ namespace gmtk painter.line(b.corner(0, 1), b.corner(0, 0), s, color, true); } + std::uint64_t make_seed() + { + random::device d; + return (std::uint64_t(d()) << 32) | d(); + } + struct application : app::application { application(options const &, context const &) - : rng_{random::device{}} - , map_(starting_map(rng_)) + : seed_(make_seed()) + , map_rng_{seed_, 0xf24130ddef6fb31full} + , item_rng_{seed_, 0xb9fc3979f9860bbdull} + , map_(starting_map()) { + log::info() << "Starting seed: " << seed_; view_stack_.push_back({-1, {0, 0}}); } @@ -665,32 +689,14 @@ namespace gmtk screen_size_ = event.size; } - void on_event(app::mouse_move_event const & event) override + void on_event(app::mouse_wheel_event const & event) override { - mouse_ = event.position; - } - - void on_event(app::mouse_button_event const & event) override - { - if (event.down && event.button == app::mouse_button::left) + if (event.delta > 0) { - bool destroyed_item = false; - bool transitioned = false; - - if (selected_item_) + if (!selected_item_ && selected_ && !view_transition_) { - auto const & i = map_.world.get(*selected_item_).get(); - if (i.target) - map_.world.detach(i.target); - else - map_.world.detach(map_.world.index().get(i.start)); - map_.world.destroy(*selected_item_); - selected_item_ = std::nullopt; - destroyed_item = true; - } + bool transitioned = false; - if (!destroyed_item && selected_ && !view_transition_) - { if (auto entity = map_.world.index().find(*selected_)) if (map_.world.get(*entity).contains()) { @@ -708,8 +714,31 @@ namespace gmtk transitioned = true; } } + } - if (!destroyed_item && !transitioned && selected_ && !belt_start_) + if (event.delta < 0) + { + if (!view_transition_ && view_stack_.size() > 1) + { + view_transition_ = {view_stack_.back()}; + view_stack_.pop_back(); + selected_ = std::nullopt; + } + } + } + + void on_event(app::mouse_move_event const & event) override + { + mouse_ = event.position; + } + + void on_event(app::mouse_button_event const & event) override + { + if (event.down && event.button == app::mouse_button::left) + { + lmb_down_ = true; + + if (!selected_item_ && selected_ && !belt_start_) { belt_start_ = *selected_; } @@ -717,6 +746,8 @@ namespace gmtk if (!event.down && event.button == app::mouse_button::left) { + lmb_down_ = false; + if (selected_ && belt_start_ && selected_->level == belt_start_->level) { auto d = selected_->coords - belt_start_->coords; @@ -753,28 +784,20 @@ namespace gmtk } belt_start_ = std::nullopt; } - - if (event.down && event.button == app::mouse_button::right) - { - if (!view_transition_ && view_stack_.size() > 1) - { - view_transition_ = {view_stack_.back()}; - view_stack_.pop_back(); - selected_ = std::nullopt; - } - } } void on_event(app::key_event const & event) override { + if (event.down && event.key == app::keycode::F) { if (selected_ && !map_.world.index().find(*selected_)) { - map_.world.create( - vertex{*selected_}, - transformer{transformer_type::furnace} - ); + if (map_.take_card(card_type::furnace)) + map_.world.create( + vertex{*selected_}, + transformer{transformer_type::furnace} + ); } } @@ -782,10 +805,11 @@ namespace gmtk { if (selected_ && !map_.world.index().find(*selected_)) { - map_.world.create( - vertex{*selected_}, - transformer{transformer_type::factory} - ); + if (map_.take_card(card_type::factory)) + map_.world.create( + vertex{*selected_}, + transformer{transformer_type::factory} + ); } } @@ -793,10 +817,11 @@ namespace gmtk { if (selected_ && !map_.world.index().find(*selected_)) { - map_.world.create( - vertex{*selected_}, - crossing{} - ); + if (map_.take_card(card_type::crossing)) + map_.world.create( + vertex{*selected_}, + crossing{} + ); } } @@ -804,17 +829,20 @@ namespace gmtk { if (selected_ && !map_.world.index().find(*selected_)) { - map_.world.create( - vertex{*selected_}, - zoomer{} - ); + if (map_.take_card(card_type::zoomer)) + { + map_.world.create( + vertex{*selected_}, + zoomer{} + ); - auto c = selected_->down(); + 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()); + sink_belt(map_.world, c.left()); + sink_belt(map_.world, c.right()); + sink_belt(map_.world, c.bottom()); + sink_belt(map_.world, c.top()); + } } } @@ -826,7 +854,20 @@ namespace gmtk { auto acc = map_.world.get(*entity); if (!acc.contains() && !acc.contains() && !acc.contains()) + { + if (acc.contains()) + map_.put_card(card_type::crossing); + else if (acc.contains()) + map_.put_card(card_type::zoomer); + else if (auto t = acc.get_if()) + { + if (t->type == transformer_type::furnace) + map_.put_card(card_type::furnace); + else if (t->type == transformer_type::factory) + map_.put_card(card_type::factory); + } map_.world.destroy(*entity); + } } } } @@ -846,8 +887,6 @@ namespace gmtk { float const dt = clock_.restart().count(); - map_.time += dt; - map_.spawn_timer += 3.f * dt; if (map_.spawn_timer >= 1.f) { @@ -872,6 +911,41 @@ namespace gmtk ); } + if (map_.stage + 1 < std::size(stages) && map_.resource_count >= stages[map_.stage].count) + { + for (auto card : stages[map_.stage].cards) + map_.cards[card] += 1; + + for (auto type : stages[map_.stage].sources) + { + util::hash_set spots; + + auto add = [&](location l) + { + if (!map_.world.index().find(l)) + spots.insert(l); + }; + + for (int i = 0; i < 3; ++i) + { + add({0, {-1, i}}); + add({0, {3, i}}); + add({0, {i, 3}}); + } + + if (!spots.empty()) + { + map_.world.create( + vertex{random::uniform_from(map_rng_, spots)}, + source{type} + ); + } + } + + map_.stage += 1; + map_.resource_count = 0; + } + map_.world.apply([&](vertex const & v, transformer const & t) { boost::container::flat_map has_inputs; @@ -928,14 +1002,6 @@ namespace gmtk if (!crafted && !has_inputs.empty()) { return; - - auto p = random::uniform_from(rng_, has_inputs); - - auto e = map_.world.index().get(p.second); - auto re = map_.world.get(e).get().entity; - - map_.world.detach(e); - map_.world.destroy(re); } }); @@ -978,10 +1044,17 @@ namespace gmtk if (auto cell = map_.world.index().find(i.start.up())) { - if (auto l = map_.world.get(*cell).get_if()) + if (map_.world.get(*cell).get_if()) { - l->count[i.type] += 1; - map_.world.destroy(entity); + if (i.type == stages[map_.stage].type) + { + map_.resource_count += 1; + map_.world.destroy(entity); + } + else + { + map_.world.attach(map_.world.index().get(i.start), occupied{entity}); + } return; } @@ -1032,7 +1105,7 @@ namespace gmtk targets.push_back(b); if (!targets.empty()) - i.target = random::uniform_from(rng_, targets); + i.target = random::uniform_from(item_rng_, targets); if (i.target) map_.world.attach(i.target, occupied{entity}); @@ -1082,6 +1155,17 @@ namespace gmtk selected_item_ = entity; }); + if (selected_item_ && lmb_down_) + { + auto const & i = map_.world.get(*selected_item_).get(); + if (i.target) + map_.world.detach(i.target); + else + map_.world.detach(map_.world.index().get(i.start)); + map_.world.destroy(*selected_item_); + selected_item_ = std::nullopt; + } + { float s = std::pow(3.f, 1 + view_stack_.back().level); @@ -1208,19 +1292,41 @@ namespace gmtk } } + { + float const step = std::pow(3.f, - 2.f - view_level); + float vs = std::pow(3.f, - 1.f - view_level) * 0.01f; + + geom::point pen = view_box_.corner(1, 1) + geom::vector{-1.f, -1.f} * view_box_[1].length() / 10.f; + + for (auto type : card_type_values()) + { + if (!map_.cards.contains(type)) + continue; + + draw_card(geom::expand(geom::box::singleton(pen), step), type, painter_); + + painter_.text(pen, std::to_string(map_.cards.at(type)), {.scale = {vs, -vs}, .c = {0, 0, 0, 255}}); + + pen[1] -= step * 2.f; + } + } + painter_.render(geom::orthographic_camera{view_box_}.transform()); } private: bool running_ = true; - random::generator rng_; + std::uint64_t seed_; + random::generator map_rng_; + random::generator item_rng_; map map_; util::clock<> clock_; geom::vector screen_size_{1, 1}; geom::point mouse_{0, 0}; + bool lmb_down_ = false; gfx::painter painter_;