diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/engine/app.cpp | 36 | ||||
| -rw-r--r-- | src/game/build_graph.cpp | 15 | ||||
| -rw-r--r-- | src/game/build_graph.hpp | 9 | ||||
| -rw-r--r-- | src/game/data.cpp | 4 | ||||
| -rw-r--r-- | src/game/data.hpp | 2 |
5 files changed, 59 insertions, 7 deletions
diff --git a/src/engine/app.cpp b/src/engine/app.cpp index d5001c1..2108316 100644 --- a/src/engine/app.cpp +++ b/src/engine/app.cpp @@ -226,6 +226,7 @@ void App::run() { if (input.key_pressed(SDLK_1)) { cur_mat = 0; selected_cannon = -1; place_dev = -1; } if (input.key_pressed(SDLK_2)) { cur_mat = 1; selected_cannon = -1; place_dev = -1; } if (input.key_pressed(SDLK_3)) { cur_mat = 2; selected_cannon = -1; place_dev = -1; } + if (input.key_pressed(SDLK_4)) { cur_mat = 3; selected_cannon = -1; place_dev = -1; } if (input.key_pressed(SDLK_5)) { place_dev = turbine_i; selected_cannon = -1; } if (input.key_pressed(SDLK_6)) { place_dev = mine_i; selected_cannon = -1; } if (input.key_pressed(SDLK_7)) { place_dev = battery_i; selected_cannon = -1; } @@ -279,6 +280,10 @@ void App::run() { wpn.splash_damage, wpn.splash_radius, wpn.knockback, wpn.projectile_radius, 6.0f, wpn.fire_chance }); } + // Recoil: shove the firing structure back along -aim. Radius + // picks up the nodes the weapon is sitting on. + graph.apply_recoil(c.x, c.y, 1.5f, + -std::cos(c.aim), -std::sin(c.aim), wpn.recoil); c.cooldown = wpn.reload; energy -= wpn.energy_cost; } @@ -333,22 +338,29 @@ void App::run() { // ---- Finish edge placement ---- (add_link enforces the length rules // and subdivides a long drag into segments) if (placing && !input.mouse_down(SDL_BUTTON_LEFT)) { + const auto& m = graph.materials[cur_mat]; + // Per-material cost, and you must be able to afford it. Without the + // affordability check an expensive material (armour) would be free + // whenever you are broke, since resources are clamped back to 0. + bool can_pay = metal >= m.cost_metal && energy >= m.cost_energy; int target = graph.find_nearest_node(wx, wy, 0.5f); if (target >= 0 && target != drag_node) { - if (graph.add_link(drag_node, target, cur_mat) > 0) { - metal -= 5.0f; energy -= 25.0f; + if (can_pay && graph.add_link(drag_node, target, cur_mat) > 0) { + metal -= m.cost_metal; energy -= m.cost_energy; } } else if (drag_node >= 0 && drag_node < (int)graph.nodes.size()) { bool foundation = graph.is_on_ground(wy); float ny = foundation ? graph.ground_level : wy; // Length guard first, so a rejected link leaves no orphan node. - const auto& m = graph.materials[cur_mat]; float dlen = std::hypot(wx - graph.nodes[drag_node].x, ny - graph.nodes[drag_node].y); - if (dlen >= m.min_length && dlen <= m.max_link_length) { + // A foundation node costs extra on top of the strut. + bool pay_all = metal >= m.cost_metal + (foundation ? 50.0f : 0.0f) && + energy >= m.cost_energy + (foundation ? 400.0f : 0.0f); + if (pay_all && dlen >= m.min_length && dlen <= m.max_link_length) { int new_id = graph.add_node(wx, ny, foundation); if (graph.add_link(drag_node, new_id, cur_mat) > 0) { - metal -= 5.0f; energy -= 25.0f; + metal -= m.cost_metal; energy -= m.cost_energy; if (foundation) { metal -= 50.0f; energy -= 400.0f; } } } @@ -361,9 +373,14 @@ void App::run() { if (extruding_edge >= 0 && !input.mouse_down(SDL_BUTTON_RIGHT)) { float offx = wx - extrude_start_x; float offy = wy - extrude_start_y; - if (std::sqrt(offx*offx + offy*offy) > 0.1f) { + // An extrusion sweeps out several struts, so it costs 2x the + // material's metal (for wood that is the flat 10/25 it used before). + const auto& em = graph.materials[cur_mat]; + float ex_metal = em.cost_metal * 2.0f, ex_energy = em.cost_energy; + if (std::sqrt(offx*offx + offy*offy) > 0.1f && + metal >= ex_metal && energy >= ex_energy) { graph.extrude_edge(extruding_edge, offx, offy); - metal -= 10.0f; energy -= 25.0f; + metal -= ex_metal; energy -= ex_energy; } extruding_edge = -1; } @@ -759,6 +776,10 @@ void App::run() { if (ImGui::Button("wood")) { cur_mat = 0; place_dev = -1; selected_cannon = -1; } ImGui::SameLine(); if (ImGui::Button("bg")) { cur_mat = 1; place_dev = -1; selected_cannon = -1; } ImGui::SameLine(); if (ImGui::Button("rope")) { cur_mat = 2; place_dev = -1; selected_cannon = -1; } + if ((int)graph.materials.size() > 3) { + ImGui::SameLine(); + if (ImGui::Button("armour")) { cur_mat = 3; place_dev = -1; selected_cannon = -1; } + } if (turbine_i >= 0 && ImGui::Button("turbine")) { place_dev = turbine_i; selected_cannon = -1; } if (mine_i >= 0) { ImGui::SameLine(); if (ImGui::Button("mine")) { place_dev = mine_i; selected_cannon = -1; } } if (battery_i >= 0) { ImGui::SameLine(); if (ImGui::Button("battery")) { place_dev = battery_i; selected_cannon = -1; } } @@ -787,6 +808,7 @@ void App::run() { ImGui::PushID(&wpn); if (ImGui::TreeNode(wpn.name.c_str())) { ImGui::SliderFloat("reload", &wpn.reload, 0.1f, 6.0f); + ImGui::SliderFloat("recoil", &wpn.recoil, 0.0f, 60.0f); if (wpn.is_beam) { ImGui::SliderFloat("beam_dps", &wpn.beam_dps, 10.0f, 300.0f); ImGui::SliderFloat("beam_duration", &wpn.beam_duration, 0.2f, 4.0f); diff --git a/src/game/build_graph.cpp b/src/game/build_graph.cpp index 032bbf5..a1195af 100644 --- a/src/game/build_graph.cpp +++ b/src/game/build_graph.cpp @@ -291,6 +291,21 @@ int BuildGraph::kill_grounded() { // Destruction // ============================================================================= +void BuildGraph::apply_recoil(float x, float y, float radius, + float dx, float dy, float strength) { + if (radius <= 0.0f || strength <= 0.0f) return; + + for (auto& n : nodes) { + if (n.is_foundation) continue; // pinned: the ground eats the recoil + float ox = n.x - x, oy = n.y - y; + float d = std::sqrt(ox*ox + oy*oy); + if (d >= radius) continue; + float f = 1.0f - d / radius; // linear falloff, as in apply_splash + n.vx += dx * strength * f; + n.vy += dy * strength * f; + } +} + void BuildGraph::apply_splash(float x, float y, float radius, float damage, float knockback) { if (radius <= 0.0f) return; diff --git a/src/game/build_graph.hpp b/src/game/build_graph.hpp index bf83a18..4452139 100644 --- a/src/game/build_graph.hpp +++ b/src/game/build_graph.hpp @@ -34,6 +34,8 @@ struct MaterialDef { bool blocks_projectiles; // stops cannon shells (wood yes; bg-brace/rope no) bool blocks_beam; // stops laser beams (all yes in Forts) float half_width; // visual thickness + float cost_metal; // metal spent placing one strut of this material + float cost_energy; // energy spent placing one strut of this material float r, g, b, a; // visual colour (also tints the texture) std::string name; std::string texture; // CC0 placeholder path ("" = flat colour) @@ -104,6 +106,13 @@ public: // not block splash (pure radius falloff, like Forts AoE). void apply_splash(float x, float y, float radius, float damage, float knockback); + // Directional velocity kick to free nodes within `radius` of (x,y), along the + // unit vector (dx,dy), with linear falloff. Weapon recoil uses this to shove + // the FIRING structure back (Forts' Recoil), unlike apply_splash's radial + // knockback on the target. No damage: recoil only moves the fort. + void apply_recoil(float x, float y, float radius, + float dx, float dy, float strength); + // Trace a laser beam from (ox,oy) along (dx,dy) up to `range`: damage + // optionally ignite EVERY strut it crosses, passing through beam-transparent // materials (bg-brace, ropes) and STOPPING at the first blocking one (wood). diff --git a/src/game/data.cpp b/src/game/data.cpp index 654cac6..3d9f6c0 100644 --- a/src/game/data.cpp +++ b/src/game/data.cpp @@ -36,6 +36,9 @@ MaterialDef read_material(const sol::table& m) { d.blocks_beam = m.get_or("blocks_beam", true); d.tension_only = m.get_or("tension_only", false); d.half_width = m.get_or("half_width", 0.15f); + // Defaults match the flat costs struts used before they became per-material. + d.cost_metal = m.get_or("cost_metal", 5.0f); + d.cost_energy = m.get_or("cost_energy", 25.0f); d.texture = m.get_or("texture", std::string("")); d.texture_forts = m.get_or("texture_forts", std::string("")); @@ -137,6 +140,7 @@ WeaponDef read_weapon(const sol::table& w) { d.beam_dps = w.get_or("beam_dps", 120.0f); d.beam_duration = w.get_or("beam_duration", 1.5f); d.energy_cost = w.get_or("energy_cost", 0.0f); + d.recoil = w.get_or("recoil", 0.0f); d.texture = w.get_or("texture", std::string("")); d.projectile_texture = w.get_or("projectile_texture", std::string("")); d.texture_forts = w.get_or("texture_forts", std::string("")); diff --git a/src/game/data.hpp b/src/game/data.hpp index fdf9e08..9b9aec1 100644 --- a/src/game/data.hpp +++ b/src/game/data.hpp @@ -24,6 +24,8 @@ struct WeaponDef { float beam_dps; // HP damage per second to the struck strut float beam_duration; // seconds the beam stays on float energy_cost; // energy spent per shot (Forts EnergyFireCost) + float recoil; // velocity kick shoved back into the FIRING + // structure on each shot (Forts Recoil); 0 = none std::string texture; // turret/base sprite (CC0 placeholder) std::string projectile_texture; // shell sprite (CC0 placeholder) std::string texture_forts; // preferred BYO Forts turret art |
