From 2c8e84a3d2fe93f84d0ffca63967e81a03534c00 Mon Sep 17 00:00:00 2001 From: Paweł Redman Date: Sun, 1 Apr 2018 13:56:14 +0200 Subject: Split units.cpp. --- src/game/unit_soldier.cpp | 301 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 301 insertions(+) create mode 100644 src/game/unit_soldier.cpp (limited to 'src/game/unit_soldier.cpp') diff --git a/src/game/unit_soldier.cpp b/src/game/unit_soldier.cpp new file mode 100644 index 0000000..152f475 --- /dev/null +++ b/src/game/unit_soldier.cpp @@ -0,0 +1,301 @@ +/* +This file is part of Minitrem. + +Minitrem is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +Minitrem is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Minitrem. If not, see . +*/ + +#include "game.hpp" + +namespace game { + +unit_soldier_t::unit_soldier_t(game::state_t *game) : unit_t(game, UNIT_SOLDIER) +{ + size[0] = v2f_t(-0.3f, +0.0f); + size[1] = v2f_t(+0.3f, +0.3f); + render_size[0] = v2f_t(-0.5f, -1.2f); + render_size[1] = v2f_t(+0.5f, +0.3f); + cmodel.cflags = CF_BODY; + move.cflags = CF_SOLID | CF_BODY | CF_WATER; + + name = text::get(text::UNIT_NAME_SOLDIER); + + wake(); + friendly = true; + controllable = true; + + health = max_health = 20; +} + +void unit_soldier_t::check_area(void) +{ + rectf_t bounds; + + bounds[0] = x - v2f_t(10, 10); + bounds[1] = x + v2f_t(10, 10); + + willpower_bonus = 0; + fear_dc = 0; + + for (world::entity_t *went : game->world.get_entities(bounds, -1)) { + auto ent = dynamic_cast(went); + unit_t *unit; + + // WTF? + if (!ent) + continue; + + if (ent == this) + continue; + + // Wake everything around. + if (!ent->ignore_waking) { + ent->wake_time = game->now; + + if (!ent->awake) + ent->wake(); + } + + if (ent->type != ET_UNIT) + continue; + + unit = (unit_t*)ent; + + if (unit->dead) + continue; + + if (unit->friendly) + willpower_bonus += 6; + else { + if (unit->type == UNIT_NEST) + fear_dc += 6; + else + fear_dc += 4; + } + } +} + +static v2f_t spread_aim(v2f_t aim, float cof, procgen::prng_t *prng) +{ + float t; + + t = prng->next_float(-cof / 2, cof / 2); + + return v2f_t(cos(t) * aim[0] - sin(t) * aim[1], + sin(t) * aim[0] + cos(t) * aim[1]); +} + +void unit_soldier_t::shoot(v2f_t aim) +{ + v2f_t end; + world::trace_t trace; + v2f_t muzzle_point; + fx_tracer_t *tracer; + fx_flash_t *flash; + + end = x + (aim - x).norm() * 40; + + trace = world->trace(x, end, CF_SOLID); + + muzzle_point = x + v2f_t(0, -1.0f); + + tracer = new fx_tracer_t(game, muzzle_point, trace.end); + tracer->place(&game->world); + + flash = new fx_flash_t(game, muzzle_point, 5.0f); + flash->place(&game->world); + + last_attack = game->now; + assets::soldier.fire.play_3d(x); + //target->damage(3, this); FIXME +} + +void unit_soldier_t::target_and_attack(void) +{ + unit_t *target; + v2f_t aim; + + if (manual_firing) { + aim = manual_firing_target; + last_target_x = aim; + goto skip_targetting; + } + + if (game->now < next_targetting) + return; + + next_targetting = game->now + 0.2; + + target = find_target(world, x, 5.0f, false); + if (!target) + return; + aim = target->x; + + last_target_time = game->now; + last_target_x = target->x; + +skip_targetting: + if (last_attack + game->dice_prng.next_float(1.4f, 1.6f) > game->now) + return; + + shoot(spread_aim(aim, 0.2, &game->dice_prng)); +} + +void unit_soldier_t::on_think(void) +{ + check_area(); + + if (panic && game->now > panic_end) { + move.moving = false; + move.path.clear(); + panic = false; + controllable = true; + } + + if (health == max_health) + willpower_bonus += 3; + else if (fear_dc > 1 && health < max_health / 2) + fear_dc += 3; + + if (!panic && fear_dc > 1 && game->now > next_fear_test) { + size_t roll; + bool success; + std::stringstream ss; + + roll = game->roll(die_t(20)); + success = roll + willpower_bonus >= fear_dc; + + ss << name << " " << text::get(text::UNIT_SAVING_THROW_WILLPOWER); + ss << ": " << roll << " + " << willpower_bonus << " = " << roll + willpower_bonus; + ss << " vs " << fear_dc << ": "; + + if (success) + ss << text::get(text::UNIT_SAVING_THROW_SUCCESS); + else + ss << text::get(text::UNIT_SAVING_THROW_FAILURE); + + game->interface->print(ss.str()); + + if (!success) { + say(text::get(text::SAY_PANIC)); + panic = true; + panic_end = game->now + 10; + panic_turn = -INFINITY; + controllable = false; + } + + next_fear_test = game->now + 3; + } + + if (!panic) { + target_and_attack(); + + keep_moving(2.0); + if (!move.moving) + move_marker.reset(); + } else { + move.moving = true; + keep_moving(3.0); + + if (game->now >= panic_turn) { + v2f_t t; + + t = game->dice_prng.unit_vec2(); + + move.path.clear(); + move.path.push_back(x + t * 10); + panic_turn = game->now + 0.3; + } + } + + if (move.moving && (x - move.last_step).len() > 0.5f) { + move.last_step = x; + assets::soldier.step_stone.play_3d(x); + } +} + +void unit_soldier_t::on_death(void) +{ + render_size[0] = v2f_t(-0.75f, -0.5f); + render_size[1] = v2f_t(+0.75f, +0.5f); + render_layer = -1; + cmodel.cflags = CF_BACKGROUND; + place(world, x); + controllable = false; + game->selected_units.erase(this); + move_marker.reset(); +} + +void unit_soldier_t::render_to(render::state_t *render) +{ + sf::Color selection_color; + + if (selected == selection_cookie) { + if (health == max_health) + selection_color = sf::Color::Green; + else if (health >= max_health / 2) + selection_color = sf::Color::Yellow; + else if (dead) + selection_color = sf::Color::Black; + else + selection_color = sf::Color::Red; + + if (panic && (game->now - floor(game->now) > 0.5)) + selection_color = sf::Color::Blue; + + render->render(0.0, &assets::unit_selected, cmodel.bounds, selection_color); + } + + if (!dead) { + render::oriented_sprite_t *legs, *body; + float body_angle; + + if (move.moving && !move.blocked) + legs = &assets::soldier.legs_walking; + else + legs = &assets::soldier.legs_idle; + + if (!panic && (manual_firing || last_target_time + 3 > game->now)) { + if (last_attack + 0.1 > game->now) + body = &assets::soldier.body_firing; + else + body = &assets::soldier.body_aiming; + + body_angle = (last_target_x - x).angle(); + + } else { + body = &assets::soldier.body_idle; + body_angle = move.angle; + } + + render->render(game->now * 10, legs, render_bounds, move.angle); + + if (panic) + render->render(game->now * 10, &assets::soldier.body_panic, render_bounds); + else + render->render(game->now * 10, body, render_bounds, body_angle); + + render->render(game->now * 10, &assets::soldier.head_idle, render_bounds, body_angle); + } else + render->render(game->now * 10, &assets::soldier.dead, render_bounds); + + unit_t::render_to(render); +} + +void unit_soldier_t::render_late_to(render::state_t *render) +{ + if (selected == selection_cookie) + render->render(0.0, &assets::unit_selected_halo, cmodel.bounds, selection_color); +} + +} -- cgit