summaryrefslogtreecommitdiff
path: root/src/game
diff options
context:
space:
mode:
Diffstat (limited to 'src/game')
-rw-r--r--src/game/game.hpp2
-rw-r--r--src/game/unit_nest.cpp96
-rw-r--r--src/game/unit_soldier.cpp301
-rw-r--r--src/game/unit_spider.cpp104
-rw-r--r--src/game/units.cpp436
5 files changed, 504 insertions, 435 deletions
diff --git a/src/game/game.hpp b/src/game/game.hpp
index 331c1d1..517f74a 100644
--- a/src/game/game.hpp
+++ b/src/game/game.hpp
@@ -164,6 +164,8 @@ namespace game {
class fx_move_marker_t;
+ unit_t *find_target(world::world_t *world, v2f_t x, float r, bool friendly);
+
class unit_t : public entity_t {
protected:
double next_targetting = -INFINITY;
diff --git a/src/game/unit_nest.cpp b/src/game/unit_nest.cpp
new file mode 100644
index 0000000..326741e
--- /dev/null
+++ b/src/game/unit_nest.cpp
@@ -0,0 +1,96 @@
+/*
+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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "game.hpp"
+
+namespace game {
+
+
+unit_nest_t::unit_nest_t(game::state_t *game_) : unit_t(game_, UNIT_NEST)
+{
+ size[0] = {-0.6f, +0.2f};
+ size[1] = {+0.6f, +0.6f};
+ render_size[0] = {-0.6f, -0.6f};
+ render_size[1] = {+0.6f, +0.6f};
+ cmodel.cflags = CF_BACKGROUND;
+
+ name = text::get(text::UNIT_NAME_NEST);
+
+ ignore_waking = false;
+
+ health = max_health = 45;
+
+ next_spawning = game->now + 5.0;
+}
+
+void spawn_spider(game::state_t *game, v2f_t nest)
+{
+ for (size_t i = 0; i < 5; i++) { // Try a few times before giving up.
+ v2f_t offset, x;
+ world::cmodel_t cmodel;
+ unit_spider_t *spider;
+
+ offset = game->dice_prng.unit_vec2();
+ x = nest + offset * (game->dice_prng.next_float() * 0.2 + 0.4);
+
+ cmodel.bounds = rectf_t(v2f_t(-0.5f, -0.5f), v2f_t(0.5f, 0.5f)) + x;
+ cmodel.cflags = CF_SOLID | CF_WATER | CF_BODY_SMALL;
+ if (game->world.test_rect(&cmodel, NULL))
+ continue;
+
+ spider = new unit_spider_t(game);
+ spider->place(&game->world, x);
+ return;
+ }
+}
+
+void unit_nest_t::on_think(void)
+{
+ if (wake_time + 30 > game->now)
+ sleep();
+
+ if (next_spawning > game->now)
+ return;
+
+ spawn_spider(game, x);
+ next_spawning = game->now + game->dice_prng.next_float() * 10 + 5;
+}
+
+void unit_nest_t::on_spawn(void)
+{
+ spawn_spider(game, x);
+ spawn_spider(game, x);
+ spawn_spider(game, x);
+}
+
+void unit_nest_t::on_death(void)
+{
+ render_layer = -1;
+ cmodel.cflags = CF_BACKGROUND;
+}
+
+void unit_nest_t::render_to(render::state_t *render)
+{
+ if (!dead)
+ render->render(game->now, &assets::nest.idle, render_bounds);
+ else
+ render->render(game->now, &assets::nest.dead, render_bounds);
+
+ unit_t::render_to(render);
+}
+
+}
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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<game::entity_t*>(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);
+}
+
+}
diff --git a/src/game/unit_spider.cpp b/src/game/unit_spider.cpp
new file mode 100644
index 0000000..ed6b0f0
--- /dev/null
+++ b/src/game/unit_spider.cpp
@@ -0,0 +1,104 @@
+/*
+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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "game.hpp"
+
+namespace game {
+
+unit_spider_t::unit_spider_t(game::state_t *game) : unit_t(game, UNIT_SPIDER)
+{
+ size[0] = v2f_t(-0.2f, +0.0f);
+ size[1] = v2f_t(+0.2f, +0.3f);
+ render_size[0] = v2f_t(-0.3f, -0.3f);
+ render_size[1] = v2f_t(+0.3f, +0.3f);
+ cmodel.cflags = CF_BODY_SMALL;
+ move.cflags = CF_SOLID | CF_WATER | CF_BODY_SMALL;
+
+ name = text::get(text::UNIT_NAME_SPIDER);
+
+ ignore_waking = false;
+
+ health = max_health = 4;
+}
+
+void unit_spider_t::target_and_attack(void)
+{
+ unit_t *target;
+ world::trace_t trace;
+
+ if (game->now < next_targetting)
+ return;
+
+ target = find_target(world, x, 10.0f, true);
+ if (!target)
+ return;
+
+ start_moving(target->x);
+ next_targetting = game->now + game->dice_prng.next_float(0.2f, 0.4f);
+
+ if (last_attack + 0.5 > game->now)
+ return;
+
+ if ((x - target->x).len() >= 1.0f)
+ return;
+
+ trace = world->trace(x, target->x, CF_SOLID);
+ if (trace.hit)
+ return;
+
+ last_attack = game->now;
+ target->damage(15, this);
+}
+
+void unit_spider_t::on_think(void)
+{
+ return;
+
+ target_and_attack();
+
+ keep_moving(4.0);
+
+ if (!move.moving && wake_time + 5 < game->now)
+ sleep();
+}
+
+void unit_spider_t::on_wake(void)
+{
+}
+
+void unit_spider_t::on_death(void)
+{
+ render_layer = -1;
+ cmodel.cflags = CF_BACKGROUND;
+}
+
+void unit_spider_t::render_to(render::state_t *render)
+{
+ bool moving;
+
+ moving = move.moving && !move.blocked;
+
+ if (!dead)
+ render->render(game->now * 20, (moving ? &assets::spider.walking :
+ &assets::spider.idle), render_bounds, move.angle);
+ else
+ render->render(game->now * 20, &assets::spider.dead, render_bounds);
+
+ unit_t::render_to(render);
+}
+
+}
diff --git a/src/game/units.cpp b/src/game/units.cpp
index 63c16db..bbddd93 100644
--- a/src/game/units.cpp
+++ b/src/game/units.cpp
@@ -222,7 +222,7 @@ void unit_t::die(unit_t *killer)
on_death();
}
-static unit_t *find_target(world::world_t *world, v2f_t x, float r,
+unit_t *find_target(world::world_t *world, v2f_t x, float r,
bool friendly)
{
rectf_t rect;
@@ -257,438 +257,4 @@ static unit_t *find_target(world::world_t *world, v2f_t x, float r,
return nearest;
}
-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<game::entity_t*>(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);
-}
-
-unit_spider_t::unit_spider_t(game::state_t *game) : unit_t(game, UNIT_SPIDER)
-{
- size[0] = v2f_t(-0.2f, +0.0f);
- size[1] = v2f_t(+0.2f, +0.3f);
- render_size[0] = v2f_t(-0.3f, -0.3f);
- render_size[1] = v2f_t(+0.3f, +0.3f);
- cmodel.cflags = CF_BODY_SMALL;
- move.cflags = CF_SOLID | CF_WATER | CF_BODY_SMALL;
-
- name = text::get(text::UNIT_NAME_SPIDER);
-
- ignore_waking = false;
-
- health = max_health = 4;
-}
-
-void unit_spider_t::target_and_attack(void)
-{
- unit_t *target;
- world::trace_t trace;
-
- if (game->now < next_targetting)
- return;
-
- target = find_target(world, x, 10.0f, true);
- if (!target)
- return;
-
- start_moving(target->x);
- next_targetting = game->now + game->dice_prng.next_float(0.2f, 0.4f);
-
- if (last_attack + 0.5 > game->now)
- return;
-
- if ((x - target->x).len() >= 1.0f)
- return;
-
- trace = world->trace(x, target->x, CF_SOLID);
- if (trace.hit)
- return;
-
- last_attack = game->now;
- target->damage(15, this);
-}
-
-void unit_spider_t::on_think(void)
-{
- return;
-
- target_and_attack();
-
- keep_moving(4.0);
-
- if (!move.moving && wake_time + 5 < game->now)
- sleep();
-}
-
-void unit_spider_t::on_wake(void)
-{
-}
-
-void unit_spider_t::on_death(void)
-{
- render_layer = -1;
- cmodel.cflags = CF_BACKGROUND;
-}
-
-void unit_spider_t::render_to(render::state_t *render)
-{
- bool moving;
-
- moving = move.moving && !move.blocked;
-
- if (!dead)
- render->render(game->now * 20, (moving ? &assets::spider.walking :
- &assets::spider.idle), render_bounds, move.angle);
- else
- render->render(game->now * 20, &assets::spider.dead, render_bounds);
-
- unit_t::render_to(render);
-}
-
-unit_nest_t::unit_nest_t(game::state_t *game_) : unit_t(game_, UNIT_NEST)
-{
- size[0] = {-0.6f, +0.2f};
- size[1] = {+0.6f, +0.6f};
- render_size[0] = {-0.6f, -0.6f};
- render_size[1] = {+0.6f, +0.6f};
- cmodel.cflags = CF_BACKGROUND;
-
- name = text::get(text::UNIT_NAME_NEST);
-
- ignore_waking = false;
-
- health = max_health = 45;
-
- next_spawning = game->now + 5.0;
-}
-
-void spawn_spider(game::state_t *game, v2f_t nest)
-{
- for (size_t i = 0; i < 5; i++) { // Try a few times before giving up.
- v2f_t offset, x;
- world::cmodel_t cmodel;
- unit_spider_t *spider;
-
- offset = game->dice_prng.unit_vec2();
- x = nest + offset * (game->dice_prng.next_float() * 0.2 + 0.4);
-
- cmodel.bounds = rectf_t(v2f_t(-0.5f, -0.5f), v2f_t(0.5f, 0.5f)) + x;
- cmodel.cflags = CF_SOLID | CF_WATER | CF_BODY_SMALL;
- if (game->world.test_rect(&cmodel, NULL))
- continue;
-
- spider = new unit_spider_t(game);
- spider->place(&game->world, x);
- return;
- }
-}
-
-void unit_nest_t::on_think(void)
-{
- if (wake_time + 30 > game->now)
- sleep();
-
- if (next_spawning > game->now)
- return;
-
- spawn_spider(game, x);
- next_spawning = game->now + game->dice_prng.next_float() * 10 + 5;
-}
-
-void unit_nest_t::on_spawn(void)
-{
- spawn_spider(game, x);
- spawn_spider(game, x);
- spawn_spider(game, x);
-}
-
-void unit_nest_t::on_death(void)
-{
- render_layer = -1;
- cmodel.cflags = CF_BACKGROUND;
-}
-
-void unit_nest_t::render_to(render::state_t *render)
-{
- if (!dead)
- render->render(game->now, &assets::nest.idle, render_bounds);
- else
- render->render(game->now, &assets::nest.dead, render_bounds);
-
- unit_t::render_to(render);
-}
-
} // namespace game