aboutsummaryrefslogtreecommitdiffstats
path: root/src/engine/app.cpp
diff options
context:
space:
mode:
authorEmil A. Overbeck <emil.a.overbeck@gmail.com>2026-07-19 03:14:53 +0200
committerEmil A. Overbeck <emil.a.overbeck@gmail.com>2026-07-19 03:14:53 +0200
commitc217861ab62987b798835194786dc99424e1804e (patch)
tree37baf5b0a9ae9141da4556515caccedc7b5ab6dc /src/engine/app.cpp
parentd42411ef884484c9c49482dd944a8394e78d8e15 (diff)
downloadforts_clone-c217861ab62987b798835194786dc99424e1804e.tar.gz
forts_clone-c217861ab62987b798835194786dc99424e1804e.zip
Recoil and armor
Diffstat (limited to 'src/engine/app.cpp')
-rw-r--r--src/engine/app.cpp36
1 files changed, 29 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);