summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaweł Redman <pawel.redman@gmail.com>2017-12-14 22:16:48 +0100
committerPaweł Redman <pawel.redman@gmail.com>2017-12-14 22:16:48 +0100
commit47ac1b7868b8bfb3e5fe71395a34124bf9f7209a (patch)
tree4bb1361ac664a3267344f6cf8230621be9c6feed
parentb914d67b4e683c2d3e43c1854d6ef48b1878e4b6 (diff)
Improve combat.
-rw-r--r--assets/units/alien/dead_0.pngbin2219 -> 1822 bytes
-rw-r--r--src/common.hpp14
-rw-r--r--src/game/game.cpp39
-rw-r--r--src/game/game.hpp24
-rw-r--r--src/game/units.cpp75
5 files changed, 104 insertions, 48 deletions
diff --git a/assets/units/alien/dead_0.png b/assets/units/alien/dead_0.png
index 0c94f17..bde771b 100644
--- a/assets/units/alien/dead_0.png
+++ b/assets/units/alien/dead_0.png
Binary files differ
diff --git a/src/common.hpp b/src/common.hpp
index 54f9804..d4cebf5 100644
--- a/src/common.hpp
+++ b/src/common.hpp
@@ -187,11 +187,23 @@ namespace game {
class unit_t;
+ class roll_params_t {
+ public:
+ size_t count = 1, sides = 20, bonus = 0;
+
+ roll_params_t(void) = default;
+ roll_params_t(size_t sides_);
+ roll_params_t(size_t count_, size_t sides_);
+ roll_params_t(size_t count_, size_t sides_, size_t bonus_);
+ };
+
class state_t {
std::unordered_set<unit_t*> units;
std::unordered_set<unit_t*> selected_units;
std::unordered_set<unit_t*> awake_units;
+ procgen::prng_t dice_prng;
+
public:
world::world_t world;
interface::state_t *interface;
@@ -204,6 +216,8 @@ namespace game {
// These are called by the interface.
void select(rectf_t rect);
void command(v2f_t x);
+
+ size_t roll(roll_params_t *P);
};
}
diff --git a/src/game/game.cpp b/src/game/game.cpp
index 5067df7..96f76d3 100644
--- a/src/game/game.cpp
+++ b/src/game/game.cpp
@@ -84,9 +84,20 @@ void state_t::command(v2f_t x)
void state_t::tick(double now_, double dt_)
{
+ union {
+ double d;
+ uint32_t i;
+ } u;
+
now = now_;
dt = dt_;
+ // FIXME: Is this non-deterministic enough?
+ u.d = now;
+ dice_prng.seed(dice_prng.next() ^ u.i);
+ u.d = dt;
+ dice_prng.seed(dice_prng.next() ^ u.i);
+
for (unit_t *unit : units) {
rectf_t wake_range;
@@ -136,6 +147,34 @@ void state_t::tick(double now_, double dt_)
}
}
+roll_params_t::roll_params_t(size_t sides_)
+{
+ sides = sides_;
+}
+
+roll_params_t::roll_params_t(size_t count_, size_t sides_)
+{
+ count = count_;
+ sides = sides_;
+}
+
+roll_params_t::roll_params_t(size_t count_, size_t sides_, size_t bonus_)
+{
+ count = count_;
+ sides = sides_;
+ bonus = bonus_;
+}
+
+size_t state_t::roll(roll_params_t *P)
+{
+ size_t total = 0;
+
+ for (size_t i = 0; i < P->count; i++)
+ total += dice_prng.next() % P->sides + 1;
+
+ return total + P->bonus;
+}
+
bool load_assets(void)
{
assets::load();
diff --git a/src/game/game.hpp b/src/game/game.hpp
index d4aed5d..57dbb07 100644
--- a/src/game/game.hpp
+++ b/src/game/game.hpp
@@ -49,6 +49,9 @@ namespace game {
world::cmodel_t make_cmodel(v2f_t at);
void compute_bounds();
+ double next_targetting = -INFINITY;
+ double last_attack = -INFINITY;
+
public:
v2f_t x;
rectf_t size, render_size;
@@ -88,6 +91,12 @@ namespace game {
virtual void wake(unit_t *by_whom) = 0;
virtual void sleep(void) = 0;
+ struct {
+ size_t armor_class;
+ roll_params_t hit_roll;
+ roll_params_t damage_roll;
+ } cs;
+
bool dead = false;
double death_time = -INFINITY;
int health = 1, max_health = 1;
@@ -99,15 +108,14 @@ namespace game {
double say_time = -INFINITY;
void say(std::string str);
+
void render_to(render::state_t *render);
};
class human_t : public unit_t {
- double next_targetting = -INFINITY;
double last_target_time = -INFINITY;
v2f_t last_target_x;
- double last_attack = -INFINITY;
public:
human_t(game::state_t *game);
@@ -121,9 +129,7 @@ namespace game {
class alien_t : public unit_t {
double next_targetting = -INFINITY;
- double next_attack = -INFINITY;
- void attack(unit_t *target, float range);
public:
alien_t(game::state_t *game);
void render_to(render::state_t *render);
@@ -133,14 +139,4 @@ namespace game {
void think(void);
void die(void);
};
-
- static inline size_t roll(size_t count, size_t sides)
- {
- size_t total = 0;
-
- for (size_t i = 0; i < count; i++)
- total += rand() % sides + 1;
-
- return total;
- }
};
diff --git a/src/game/units.cpp b/src/game/units.cpp
index 2eb5dbe..d1648d7 100644
--- a/src/game/units.cpp
+++ b/src/game/units.cpp
@@ -103,7 +103,9 @@ bool unit_t::keep_moving(double speed)
next = *move.path.begin();
delta = next - x;
- move.angle = delta.angle();
+
+ if (delta.len() != 0.0f)
+ move.angle = delta.angle();
if (delta.len() >= time) {
x_new = x + delta * time / delta.len();
@@ -182,15 +184,15 @@ void unit_t::damage(int points, unit_t *attacker)
void unit_t::try_attack(unit_t *target)
{
std::stringstream ss;
- int hit_roll, hit_dc = 10 /* FIXME */;
- int dmg_roll, dmg_bonus, dmg_total;
+ size_t hit_roll;
+ size_t dmg_roll;
ss << name << " " << text::get(text::UNIT_ATTACK) << " " << target->name << ": ";
- hit_roll = roll(1, 20);
- ss << hit_roll << " vs " << hit_dc;
+ hit_roll = game->roll(&cs.hit_roll);
+ ss << hit_roll << " vs " << target->cs.armor_class;
- if (hit_roll == 1 || hit_roll < hit_dc) {
+ if (hit_roll == 1 || hit_roll < target->cs.armor_class) {
ss << " (" << text::get((hit_roll == 1 ? text::UNIT_CRITICAL_MISS : text::UNIT_MISS)) << ")";
game->interface->print(ss.str());
return;
@@ -199,16 +201,14 @@ void unit_t::try_attack(unit_t *target)
ss << " (" << text::get((hit_roll == 20 ? text::UNIT_CRITICAL_HIT : text::UNIT_HIT)) << ")";
game->interface->print(ss.str());
- dmg_roll = roll(2, 6);
- dmg_bonus = 2;
- dmg_total = dmg_roll + dmg_bonus;
+ dmg_roll = game->roll(&cs.damage_roll);
ss.str(std::string());
ss << name << " " << text::get(text::UNIT_DAMAGE) << " " << target->name << ": ";
- ss << dmg_roll << " + " << dmg_bonus << " = " << dmg_total;
+ ss << dmg_roll - cs.damage_roll.bonus << " + " << cs.damage_roll.bonus << " = " << dmg_roll;
game->interface->print(ss.str());
- target->damage(dmg_total, this);
+ target->damage(dmg_roll, this);
}
static unit_t *find_target(world::world_t *world, v2f_t x, float r,
@@ -255,6 +255,10 @@ human_t::human_t(game::state_t *game) : unit_t(game, UNIT_HUMAN)
render_size[0] = v2f_t(-0.5f, -1.0f);
render_size[1] = v2f_t(+0.5f, +0.5f);
name = text::get(text::UNIT_HUMAN);
+
+ cs.armor_class = 10;
+ cs.hit_roll = roll_params_t(20);
+ cs.damage_roll = roll_params_t(4);
}
void human_t::wake(unit_t *by_whom)
@@ -275,9 +279,14 @@ void human_t::think(void)
last_target_time = game->now;
last_target_x = target->x;
- if (last_attack + 0.5 < game->now) {
- last_attack = game->now;
- try_attack(target);
+ if (last_attack + 1.5 < game->now) {
+ world::trace_t trace;
+
+ trace = world->trace(x, target->x, CF_SOLID);
+ if (!trace.hit) {
+ last_attack = game->now;
+ try_attack(target);
+ }
}
//start_moving(target->x, CF_SOLID);
@@ -326,7 +335,7 @@ void human_t::render_to(render::state_t *render)
render->render(legs, render_bounds, move.angle);
render->render(body, render_bounds, body_angle);
- render->render(&assets::human.head_idle, render_bounds, move.angle);
+ render->render(&assets::human.head_idle, render_bounds, body_angle);
} else
render->render(&assets::human.dead, render_bounds);
@@ -353,12 +362,16 @@ alien_t::alien_t(game::state_t *game) : unit_t(game, UNIT_ALIEN)
render_size[0] = v2f_t(-0.3f, -0.3f);
render_size[1] = v2f_t(+0.3f, +0.3f);
name = text::get(text::UNIT_ALIEN);
+
+ cs.armor_class = 5;
+ cs.hit_roll = roll_params_t(20);
+ cs.damage_roll = roll_params_t(3, 6, 1);
}
void alien_t::wake(unit_t *by_whom)
{
start_moving(by_whom->x, CF_SOLID);
- next_targetting = game->now + 0.4;
+ next_targetting = game->now + 0.2;
}
void alien_t::sleep(void)
@@ -370,23 +383,6 @@ void alien_t::die(void)
render_layer = -1;
}
-void alien_t::attack(unit_t *target, float range)
-{
- world::trace_t trace;
-
- if (game->now < next_attack)
- return;
-
- if ((x - target->x).len() > range)
- return;
-
- trace = world->trace(x, target->x, CF_SOLID);
- if (!trace.hit)
- try_attack(target);
-
- next_attack = game->now + 1.0;
-}
-
void alien_t::think(void)
{
if (game->now > next_targetting) {
@@ -394,7 +390,18 @@ void alien_t::think(void)
target = find_target(world, x, 10.0f, UNIT_HUMAN);
if (target) {
- attack(target, 1.0f);
+ if (last_attack + 0.5 < game->now) {
+ world::trace_t trace;
+
+ if ((x - target->x).len() < 1.0f) {
+ trace = world->trace(x, target->x, CF_SOLID);
+ if (!trace.hit)
+ try_attack(target);
+
+ last_attack = game->now;
+ }
+ }
+
start_moving(target->x, CF_SOLID);
}