summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaweł Redman <pawel.redman@gmail.com>2017-12-18 17:33:49 +0000
committerPaweł Redman <pawel.redman@gmail.com>2017-12-18 17:33:49 +0000
commitc6489d36f6de7464c555f04d5d4324f50fa6c51f (patch)
treefde3f3d3a0d720a328f8b74ac2d0d14a0d463f02
parent41bebb262aa8f346ce6cdaefd854c9077ae84f97 (diff)
Start experimenting with fear.
-rw-r--r--assets/units/soldier/body_panic_0.pngbin0 -> 1883 bytes
-rw-r--r--assets/units/soldier/body_panic_1.pngbin0 -> 1828 bytes
-rw-r--r--src/common.hpp2
-rw-r--r--src/game/assets.cpp1
-rw-r--r--src/game/game.cpp31
-rw-r--r--src/game/game.hpp24
-rw-r--r--src/game/text.cpp24
-rw-r--r--src/game/units.cpp129
8 files changed, 167 insertions, 44 deletions
diff --git a/assets/units/soldier/body_panic_0.png b/assets/units/soldier/body_panic_0.png
new file mode 100644
index 0000000..d8f4136
--- /dev/null
+++ b/assets/units/soldier/body_panic_0.png
Binary files differ
diff --git a/assets/units/soldier/body_panic_1.png b/assets/units/soldier/body_panic_1.png
new file mode 100644
index 0000000..d2baf51
--- /dev/null
+++ b/assets/units/soldier/body_panic_1.png
Binary files differ
diff --git a/src/common.hpp b/src/common.hpp
index 4b20ced..f136487 100644
--- a/src/common.hpp
+++ b/src/common.hpp
@@ -232,8 +232,6 @@ namespace game {
void command(v2f_t x);
size_t roll(die_t die);
-
- void wake_everything(v2f_t x, float range);
};
}
diff --git a/src/game/assets.cpp b/src/game/assets.cpp
index e4d6475..a96a535 100644
--- a/src/game/assets.cpp
+++ b/src/game/assets.cpp
@@ -14,6 +14,7 @@ void load(void)
soldier.body_idle.load("assets/units/soldier/body_idle", 2, 2, 2);
soldier.body_aiming.load("assets/units/soldier/body_aiming", 2, 2, 2);
soldier.body_firing.load("assets/units/soldier/body_firing", 2, 2, 2);
+ soldier.body_panic.load("assets/units/soldier/body_panic_", 2);
soldier.legs_idle.load("assets/units/soldier/legs_idle", 2, 2);
soldier.legs_walking.load("assets/units/soldier/legs_walking", 2, 2);
soldier.dead.load("assets/units/soldier/dead_", 1);
diff --git a/src/game/game.cpp b/src/game/game.cpp
index e5f32f5..9d184ea 100644
--- a/src/game/game.cpp
+++ b/src/game/game.cpp
@@ -117,7 +117,10 @@ void state_t::command(v2f_t x)
if (unit->dead)
continue;
- if (!unit->start_moving(snap, CF_SOLID | CF_WATER))
+ if (!unit->controllable)
+ continue;
+
+ if (!unit->start_moving(snap))
unit->say(text::get(text::SAY_NO_PATH));
else
unit->say(text::get(text::SAY_MOVING));
@@ -152,32 +155,6 @@ void state_t::tick(double now_, double dt_)
}
}
-void state_t::wake_everything(v2f_t x, float range)
-{
- rectf_t wake_range;
-
- wake_range[0] = x - v2f_t(range, range);
- wake_range[1] = x + v2f_t(range, range);
-
- for (world::entity_t *went : world.get_entities(wake_range, -1)) {
- auto ent = dynamic_cast<game::entity_t*>(went);
-
- // WTF?
- if (!ent)
- continue;
-
- if (ent->ignore_waking)
- continue;
-
- ent->wake_time = now;
-
- if (ent->awake)
- continue;
-
- ent->wake();
- }
-}
-
die_t::die_t(size_t sides_)
{
sides = sides_;
diff --git a/src/game/game.hpp b/src/game/game.hpp
index 0bc2da2..aea381c 100644
--- a/src/game/game.hpp
+++ b/src/game/game.hpp
@@ -31,6 +31,7 @@ namespace game {
typedef struct {
render::oriented_sprite_4M_t head_idle, body_idle;
render::oriented_sprite_4M_t body_aiming, body_firing;
+ render::animated_texture_t body_panic;
render::oriented_sprite_4M2_t legs_idle, legs_walking;
render::animated_texture_t dead;
} soldier_assets_t;
@@ -77,6 +78,7 @@ namespace game {
SAY_BLOCKED,
SAY_READY,
SAY_MOVING,
+ SAY_PANIC,
UNIT_NAME_SPIDER,
UNIT_NAME_SOLDIER,
UNIT_NAME_NEST,
@@ -85,7 +87,10 @@ namespace game {
UNIT_MISS,
UNIT_CRITICAL_MISS,
UNIT_CRITICAL_HIT,
- UNIT_DAMAGE
+ UNIT_DAMAGE,
+ UNIT_SAVING_THROW_WILLPOWER,
+ UNIT_SAVING_THROW_SUCCESS,
+ UNIT_SAVING_THROW_FAILURE
} index_t;
std::string get(index_t index);
@@ -138,6 +143,8 @@ namespace game {
bool controllable = false;
struct {
+ world::cflags_t cflags;
+
bool moving = false;
v2f_t dst;
float angle = 0.0f;
@@ -150,7 +157,7 @@ namespace game {
} move;
bool keep_moving(double speed);
- bool start_moving(v2f_t dst, world::cflags_t cflags);
+ bool start_moving(v2f_t dst);
struct {
size_t armor_class;
@@ -177,13 +184,22 @@ namespace game {
double last_target_time = -INFINITY;
v2f_t last_target_x;
+ double next_fear_test = -INFINITY;
+ size_t willpower_bonus;
+ size_t fear_dc;
+
+ bool panic = false;
+ double panic_end;
+ double panic_turn;
+
+ void check_area(void);
+ void target_and_attack(void);
+
public:
unit_soldier_t(game::state_t *game_);
~unit_soldier_t(void) {};
void render_to(render::state_t *render);
- void target_and_attack(void);
-
void on_think(void);
void on_spawn(void) {};
void on_wake(void) {};
diff --git a/src/game/text.cpp b/src/game/text.cpp
index 00441f8..3da39ff 100644
--- a/src/game/text.cpp
+++ b/src/game/text.cpp
@@ -29,6 +29,9 @@ static std::string get_english(index_t index)
case SAY_MOVING:
return "On my way.";
+ case SAY_PANIC:
+ return "I'm not getting paid enough for this.";
+
case UNIT_NAME_SPIDER:
return "Spider";
@@ -56,6 +59,15 @@ static std::string get_english(index_t index)
case UNIT_DAMAGE:
return "deals damage";
+ case UNIT_SAVING_THROW_WILLPOWER:
+ return "makes a saving throw for willpower";
+
+ case UNIT_SAVING_THROW_SUCCESS:
+ return "success";
+
+ case UNIT_SAVING_THROW_FAILURE:
+ return "failure";
+
default:
abort();
}
@@ -82,6 +94,9 @@ static std::string get_polish(index_t index)
case SAY_MOVING:
return "Jestem w drodze.";
+ case SAY_PANIC:
+ return "Za mało mi za to płacą.";
+
case UNIT_NAME_SPIDER:
return "Pająk";
@@ -109,6 +124,15 @@ static std::string get_polish(index_t index)
case UNIT_DAMAGE:
return "zadaje obrażenia";
+ case UNIT_SAVING_THROW_WILLPOWER:
+ return "wykonuje rzut obronny na siłę woli";
+
+ case UNIT_SAVING_THROW_SUCCESS:
+ return "sukces";
+
+ case UNIT_SAVING_THROW_FAILURE:
+ return "porażka";
+
default:
abort();
}
diff --git a/src/game/units.cpp b/src/game/units.cpp
index cbc3f1a..24b9567 100644
--- a/src/game/units.cpp
+++ b/src/game/units.cpp
@@ -46,7 +46,7 @@ void unit_t::render_to(render::state_t *render)
float height;
text_pos = render_bounds[0] + v2f_t(render_bounds.dim(0) / 2, -render_bounds.dim(1) * 0.1);
- height = size.dim_min() * 0.20f;
+ height = size.dim_min() * 0.50f;
render->render_text(text_pos, height, say_text,
render::ALIGN_CENTER_BOTTOM,
sf::Color::White);
@@ -65,6 +65,9 @@ void unit_t::render_to(render::state_t *render)
else
ss << "S";
+ if (controllable)
+ ss << "C";
+
text_pos = render_bounds[0] + v2f_t(render_bounds.dim(0) / 2, -render_bounds.dim(1) * 0.1);
height = size.dim_min() * 0.40f;
text_pos[1] -= height;
@@ -119,7 +122,7 @@ bool unit_t::keep_moving(double speed)
}
cmodel_next.bounds = size + x_new;
- cmodel_next.cflags = cmodel.cflags;
+ cmodel_next.cflags = move.cflags;
if (!world->test_rect(&cmodel_next, this)) {
x = x_new;
cmodel = cmodel_next;
@@ -142,7 +145,7 @@ bool unit_t::keep_moving(double speed)
return rv;
}
-bool unit_t::start_moving(v2f_t dst, world::cflags_t cflags)
+bool unit_t::start_moving(v2f_t dst)
{
world::cmodel_t rep;
@@ -154,7 +157,7 @@ bool unit_t::start_moving(v2f_t dst, world::cflags_t cflags)
move.dst = dst;
move.path.clear();
- rep.cflags = cflags;
+ rep.cflags = move.cflags;
rep.bounds = cmodel.bounds;
if (!world->find_path(x, move.dst, &rep, this, &move.path)) {
@@ -270,6 +273,7 @@ unit_soldier_t::unit_soldier_t(game::state_t *game) : unit_t(game, UNIT_SOLDIER)
render_size[0] = v2f_t(-0.5f, -1.0f);
render_size[1] = v2f_t(+0.5f, +0.5f);
cmodel.cflags = CF_BODY;
+ move.cflags = CF_SOLID | CF_BODY | CF_WATER;
name = text::get(text::UNIT_NAME_SOLDIER);
@@ -283,6 +287,51 @@ unit_soldier_t::unit_soldier_t(game::state_t *game) : unit_t(game, UNIT_SOLDIER)
cs.hit_die = die_t(8);
}
+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;
+
+ // 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 += 3;
+ else {
+ if (unit->type == UNIT_NEST)
+ fear_dc += 4;
+ else
+ fear_dc += 2;
+ }
+ }
+}
+
void unit_soldier_t::target_and_attack(void)
{
unit_t *target;
@@ -317,12 +366,64 @@ void unit_soldier_t::target_and_attack(void)
void unit_soldier_t::on_think(void)
{
- game->wake_everything(x, 10);
+ check_area();
- target_and_attack();
+ 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 && game->now > panic_end) {
+ move.moving = false;
+ move.path.clear();
+ panic = false;
+ controllable = true;
+ }
+
+ if (!panic) {
+ target_and_attack();
+
+ if (!keep_moving(4.0))
+ say(text::get(text::SAY_BLOCKED));
+ } else {
+ if (!keep_moving(4.0))
+ panic_turn = -INFINITY;
+
+ if (game->now >= panic_turn) {
+ v2f_t t;
- if (!keep_moving(4.0))
- say(text::get(text::SAY_BLOCKED));
+ t = game->dice_prng.unit_vec2();
+
+ move.path.clear();
+ move.path.push_back(x + t * 10);
+ panic_turn = game->now + 0.5;
+ }
+ }
}
void unit_soldier_t::on_death(void)
@@ -345,7 +446,7 @@ void unit_soldier_t::render_to(render::state_t *render)
else
legs = &assets::soldier.legs_idle;
- if (last_target_time + 3 > game->now) {
+ if (!panic && last_target_time + 3 > game->now) {
if (last_attack + 0.1 > game->now)
body = &assets::soldier.body_firing;
else
@@ -359,7 +460,12 @@ void unit_soldier_t::render_to(render::state_t *render)
}
render->render(game->now * 10, legs, render_bounds, move.angle);
- render->render(game->now * 10, body, render_bounds, body_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);
@@ -374,6 +480,7 @@ unit_spider_t::unit_spider_t(game::state_t *game) : unit_t(game, UNIT_SPIDER)
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;
name = text::get(text::UNIT_NAME_SPIDER);
@@ -394,7 +501,7 @@ void unit_spider_t::target_and_attack(void)
if (!target)
return;
- start_moving(target->x, CF_SOLID | CF_WATER);
+ start_moving(target->x);
next_targetting = game->now + 0.2;
if (last_attack + 0.5 > game->now)