#include "entities/camera.hpp" #include "entities/player.hpp" #include "pult_system.hpp" #include "rendering/gl_renderer.hpp" #include "systems/physics_system.hpp" #include "wall/label.hpp" #include "wall/wall.hpp" namespace Nimbin { void PultSystem::init(DynArray& scenery, DynArray& buttons_out, float world_scale) { const float floor_y = -world_scale; const float pult_y = floor_y + Pult::H; const double inset = 3.0; const float btn_dy = Pult::H + 0.10f + 0.04f; const float lane_1 = -5.5f; const float lane_2 = 8.5f; const float lane_3 = 5.5f; auto make_pult_pos = [&](Wall::Role role, float along) -> Vec3 { const Wall::Transform wall = Wall::get_Transform(role, world_scale); switch (wall.wall_position) { case Wall::Position::PosX: return { wall.position.x - inset, pult_y, along }; case Wall::Position::NegX: return { wall.position.x + inset, pult_y, along }; case Wall::Position::PosZ: return { along, pult_y, wall.position.z - inset }; case Wall::Position::NegZ: default: return { along, pult_y, wall.position.z + inset }; } }; auto spawn_pult = [&](const std::string& name, Wall::Role role, float along) -> Pult* { auto owned = cpputils::make_unique(name, make_pult_pos(role, along)); Pult* raw = owned.get(); _pults.push_back(raw); scenery.push_back(std::move(owned)); return raw; }; auto add_btn = [&](Pult* pult, const std::string& lbl, PultAction act, float dx, float dz) { Vec3 bpos { pult->pos.x + static_cast(dx), pult->pos.y + static_cast(btn_dy), pult->pos.z + static_cast(dz) }; auto owned = cpputils::make_unique(lbl, act, bpos); PultButton* raw = owned.get(); buttons_out.push_back(raw); pult->buttons.push_back(raw); scenery.push_back(std::move(owned)); }; Pult* scroll = spawn_pult("Scroll", Wall::Role::Editor, lane_1); add_btn(scroll, "UP", PultAction::ScrollEditorUp, 0.0f, -0.42f); add_btn(scroll, "DOWN", PultAction::ScrollEditorDown, 0.0f, 0.42f); Pult* clr = spawn_pult("Clear", Wall::Role::Editor, lane_2); add_btn(clr, "CLEAR", PultAction::ClearEditor, 0.0f, 0.0f); Pult* compile = spawn_pult("Compile", Wall::Role::Compiler, lane_3); add_btn(compile, "BUILD", PultAction::Compile, 0.0f, 0.0f); Pult* run = spawn_pult("Run", Wall::Role::Program, lane_2); add_btn(run, "RUN", PultAction::RunProgram, 0.0f, 0.0f); Pult* connp = spawn_pult("Connect", Wall::Role::Program, lane_3); add_btn(connp, "CONN", PultAction::ConnectProgram, 0.0f, 0.0f); _connect_program = connp; Pult* conne = spawn_pult("Edit", Wall::Role::Editor, lane_3); add_btn(conne, "EDIT", PultAction::ConnectEditor, 0.0f, 0.0f); _connect_editor = conne; } std::optional PultSystem::try_Activate(GameObject* obj, const DynArray& buttons) { if (!obj) return std::nullopt; for (PultButton* btn : buttons) { if (btn == obj) { btn->press(); return btn->action; } } return std::nullopt; } std::optional PultSystem::handle_ProjectileContact(const ProjectileContactEvent& ev, const DynArray& buttons) { if (!ev.other) return std::nullopt; for (PultButton* btn : buttons) { if (!btn->pressed && btn == ev.other) { btn->press(); return btn->action; } } return std::nullopt; } static bool player_OnButton(const Player& p, const PultButton& b) { constexpr double TOL = 0.10; const double hx = b.shape.half_extents.x; const double hy = b.shape.half_extents.y; const double hz = b.shape.half_extents.z; if (std::fabs(p.pos.x - b.pos.x) > hx + TOL) return false; if (std::fabs(p.pos.z - b.pos.z) > hz + TOL) return false; const double dy = p.pos.y - (b.pos.y + hy); return dy >= -0.10 && dy <= 1.8; } std::optional PultSystem::handle_PlayerContact(const Player& player, const DynArray& buttons) { std::optional fired; for (PultButton* btn : buttons) { const bool over = player_OnButton(player, *btn); if (over && !btn->player_on) { btn->press(); if (!fired) fired = btn->action; } btn->player_on = over; } return fired; } void PultSystem::update(double dt, const Camera& camera) { for (Pult* p : _pults) { p->tick(dt); p->label.update(dt, camera); } } void PultSystem::draw_Labels(GlRenderer& gl, const Camera& camera, const Light& light) const { for (const Pult* p : _pults) p->label.draw(gl, camera, light); } DynArray PultSystem::get_Labels() const { DynArray out; out.reserve(_pults.size()); for (Pult* p : _pults) out.push_back(&p->label); return out; } Vec3 PultSystem::get_ConnectProgramPos() const { return _connect_program ? _connect_program->pos : Vec3{}; } Vec3 PultSystem::get_ConnectEditorPos() const { return _connect_editor ? _connect_editor->pos : Vec3{}; } } // namespace Nimbin