diff options
-rw-r--r-- | assets/FanwoodText.otf | bin | 0 -> 127932 bytes | |||
-rw-r--r-- | assets/LiberationMono-Regular.ttf | bin | 313408 -> 0 bytes | |||
-rw-r--r-- | src/common.hpp | 43 | ||||
-rw-r--r-- | src/game/game.cpp | 3 | ||||
-rw-r--r-- | src/game/game.hpp | 18 | ||||
-rw-r--r-- | src/game/interface.cpp | 31 | ||||
-rw-r--r-- | src/game/units.cpp | 63 | ||||
-rw-r--r-- | src/main.cpp | 3 | ||||
-rw-r--r-- | src/render.cpp | 20 | ||||
-rw-r--r-- | src/text.cpp | 61 |
10 files changed, 192 insertions, 50 deletions
diff --git a/assets/FanwoodText.otf b/assets/FanwoodText.otf Binary files differnew file mode 100644 index 0000000..73d559f --- /dev/null +++ b/assets/FanwoodText.otf diff --git a/assets/LiberationMono-Regular.ttf b/assets/LiberationMono-Regular.ttf Binary files differdeleted file mode 100644 index 1a39bc7..0000000 --- a/assets/LiberationMono-Regular.ttf +++ /dev/null diff --git a/src/common.hpp b/src/common.hpp index 2d2af4a..49166d3 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -5,6 +5,7 @@ #include <map> #include <list> #include <unordered_set> +#include <sstream> #include <stack> #include <SFML/Graphics.hpp> #include "math.hpp" @@ -177,6 +178,10 @@ namespace world { }; } +namespace interface { + class state_t; +} + namespace game { bool load_assets(void); @@ -189,6 +194,7 @@ namespace game { public: world::world_t world; + interface::state_t *interface; double now, dt; void start(void); @@ -206,6 +212,8 @@ namespace interface { sf::RenderWindow *window; game::state_t *game; + float em; + struct { sf::Vector2f center; int target_zoom = 3; @@ -219,10 +227,19 @@ namespace interface { rectf_t rect; } select; + typedef struct { + double time; + std::string text; + } log_entry_t; + + std::list<log_entry_t> log; + public: state_t(sf::RenderWindow *window_, game::state_t *game); void tick(double dt); void render_to(render::state_t *render); + + void print(std::string str); }; } @@ -263,6 +280,7 @@ namespace render { }; typedef enum { + ALIGN_LEFT_TOP, ALIGN_CENTER_BOTTOM } text_align_t; @@ -285,7 +303,7 @@ namespace render { void render(animated_texture_t *anim, rectf_t bounds, bool mirror = false); void render(oriented_sprite_t *sprite, rectf_t bounds, float angle); - void render_text(v2f_t x, float height, const wchar_t *wstr, text_align_t align, sf::Color color); + void render_text(v2f_t x, float height, std::string str, text_align_t align, sf::Color color); void render_rect(rectf_t rect, sf::Color color); void render_hlrect(rectf_t rect, sf::Color color); void render_arrow(v2f_t x0, v2f_t x1, sf::Color color); @@ -297,10 +315,27 @@ namespace render { extern render::state_t *debug_render; namespace text { - extern const wchar_t *unit_no_path; - extern const wchar_t *unit_blocked; + typedef enum { + LANG_ENGLISH + } language_t; - void load_strings(std::string lang); + extern language_t language; + + typedef enum { + SAY_NO_PATH, + SAY_BLOCKED, + UNIT_ALIEN, + UNIT_HUMAN, + UNIT_DEATH, + UNIT_ATTACK, + UNIT_MISS, + UNIT_CRITICAL_MISS, + UNIT_HIT, + UNIT_CRITICAL_HIT, + UNIT_DAMAGE + } index_t; + + std::string get(index_t index); } // Divide and round to minus infinity. diff --git a/src/game/game.cpp b/src/game/game.cpp index c2c2c19..f5f57bf 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -70,7 +70,8 @@ void state_t::command(v2f_t x) if (unit->dead) continue; - unit->start_moving(snap); + if (!unit->start_moving(snap)) + unit->say(text::get(text::SAY_NO_PATH)); } } diff --git a/src/game/game.hpp b/src/game/game.hpp index 107bfbf..55e3c45 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -59,6 +59,7 @@ namespace game { } type_t; type_t type; + std::string name; unit_t(game::state_t *game_, type_t type_); @@ -88,12 +89,13 @@ namespace game { bool dead = false; double death_time = -INFINITY; int health = 1, max_health = 1; - void damage(int points); + void damage(int points, unit_t *attacker); + void try_attack(unit_t *target); virtual void die() = 0; - const wchar_t *say_text; + std::string say_text; double say_time = -INFINITY; - void say(const wchar_t *wstr); + void say(std::string str); void render_to(render::state_t *render); @@ -124,4 +126,14 @@ 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/interface.cpp b/src/game/interface.cpp index 854b620..a367607 100644 --- a/src/game/interface.cpp +++ b/src/game/interface.cpp @@ -131,4 +131,35 @@ void state_t::tick(double dt) select.rect[1] = wmouse; } +void state_t::print(std::string str) +{ + log.push_back((log_entry_t){game->now, str}); + std::cout << str << std::endl; +} + +void state_t::render_to(render::state_t *render) +{ + size_t w = window->getSize().x, h = window->getSize().y; + v2f_t x; + + window->setView(sf::View(sf::FloatRect(0, 0, w, h))); + em = std::min(w, h) * 0.04; + + if (select.selecting) + render->render_hlrect(select.rect, sf::Color(200, 100, 50)); + + for (auto i = log.begin(); i != log.end(); ) { + if (i->time + 3 < game->now) + i = log.erase(i); + else + i++; + } + + x = v2f_t(0.0f, 0.0f); + for (log_entry_t &entry : log) { + render->render_text(x, em, entry.text, render::ALIGN_LEFT_TOP, sf::Color::White); + x[1] += em; + } +} + } // namespace interface diff --git a/src/game/units.cpp b/src/game/units.cpp index 5563124..5efab65 100644 --- a/src/game/units.cpp +++ b/src/game/units.cpp @@ -60,11 +60,11 @@ void unit_t::render_to(render::state_t *render) render->debug_path(&move.path); } -void unit_t::say(const wchar_t *wstr) +void unit_t::say(std::string str) { - say_text = wstr; + say_text = str; say_time = game->now; - std::cout << (void*)this << ": " << wstr << "\n"; + game->interface->print(name + ": " + str); } void unit_t::place(world::world_t *world_, v2f_t x_) @@ -82,12 +82,13 @@ void unit_t::place(world::world_t *world_, v2f_t x_) bool unit_t::keep_moving(double speed) { float time; + bool rv = true; if (!move.moving) - return false; + return true; if (move.blocked && game->now < move.next_attempt) - return false; + return true; time = game->dt * speed; @@ -126,7 +127,7 @@ bool unit_t::keep_moving(double speed) move.next_attempt = game->now + 0.2f; } else { if ((x - move.dst).len() > 1.5f) - say(text::unit_blocked); + rv = false; move.moving = false; } break; @@ -135,7 +136,7 @@ bool unit_t::keep_moving(double speed) unlink(); compute_bounds(); link(world); - return true; + return rv; } bool unit_t::start_moving(v2f_t dst) @@ -149,7 +150,6 @@ bool unit_t::start_moving(v2f_t dst) move.path.clear(); if (!world->find_path(x, move.dst, &cmodel, this, &move.path)) { - say(text::unit_no_path); move.moving = false; return false; } @@ -159,15 +159,14 @@ bool unit_t::start_moving(v2f_t dst) move.blocked = false; move.attempts_left = 10; move.next_attempt = -INFINITY; - return true; } -void unit_t::damage(int points) +void unit_t::damage(int points, unit_t *attacker) { health -= points; if (health < 0) { - printf("%p died\n", this); + game->interface->print(name + ": " + text::get(text::UNIT_DEATH) + "."); dead = true; death_time = game->now; cflags = 0; @@ -175,6 +174,38 @@ void unit_t::damage(int points) } } +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; + + ss << name << " " << text::get(text::UNIT_ATTACK) << " " << target->name << ": "; + + hit_roll = roll(1, 20); + ss << hit_roll << " vs " << hit_dc; + + if (hit_roll == 1 || hit_roll < hit_dc) { + ss << " (" << text::get((hit_roll == 1 ? text::UNIT_CRITICAL_MISS : text::UNIT_MISS)) << ")"; + game->interface->print(ss.str()); + return; + } + + 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; + + ss.str(std::string()); + ss << name << " " << text::get(text::UNIT_DAMAGE) << " " << target->name << ": "; + ss << dmg_roll << " + " << dmg_bonus << " = " << dmg_total; + game->interface->print(ss.str()); + + target->damage(dmg_total, this); +} + human_t::human_t(game::state_t *game) : unit_t(game, UNIT_HUMAN) { cflags = CF_HUMAN; @@ -184,6 +215,7 @@ 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); render_layer = -1; + name = text::get(text::UNIT_HUMAN); } void human_t::wake(unit_t *by_whom) @@ -196,7 +228,8 @@ void human_t::sleep(void) void human_t::think(void) { - keep_moving(4.0); + if (!keep_moving(4.0)) + say(text::get(text::SAY_BLOCKED)); } void human_t::die(void) @@ -244,6 +277,7 @@ alien_t::alien_t(game::state_t *game) : unit_t(game, UNIT_ALIEN) size[1] = v2f_t(+0.2f, +0.2f); render_size[0] = v2f_t(-0.3f, -0.3f); render_size[1] = v2f_t(+0.3f, +0.3f); + name = text::get(text::UNIT_ALIEN); } void alien_t::wake(unit_t *by_whom) @@ -258,7 +292,6 @@ void alien_t::sleep(void) void alien_t::die(void) { - } static unit_t *find_target(world::world_t *world, v2f_t x, float r, @@ -308,9 +341,9 @@ void alien_t::attack(unit_t *target, float range) trace = world->trace(x, target->x, CF_SOLID); if (!trace.hit) - target->damage(rand() % 6 + rand() % 6 + 2); + try_attack(target); - next_attack = game->now + 0.4; + next_attack = game->now + 1.0; } void alien_t::think(void) diff --git a/src/main.cpp b/src/main.cpp index 3bac2dc..e503cad 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,12 +24,11 @@ int main() size_t frame = 0; double before = NAN; + game.interface = &interface; debug_render = &render; window.setVerticalSyncEnabled(true); - text::load_strings("pl"); game::load_assets(); - game.start(); while (1) { diff --git a/src/render.cpp b/src/render.cpp index cddb6c9..2f1890e 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -1,23 +1,15 @@ #include "common.hpp" -#include <list> -#include <sstream> static sf::RectangleShape wot_rect; static sf::Font font; -void interface::state_t::render_to(render::state_t *render) -{ - if (select.selecting) - render->render_hlrect(select.rect, sf::Color(200, 100, 50)); -} - namespace render { state_t::state_t(sf::RenderWindow *window_) { window = window_; - font.loadFromFile("assets/LiberationMono-Regular.ttf"); + font.loadFromFile("assets/FanwoodText.otf"); } // FIXME: rename @@ -190,18 +182,22 @@ void state_t::render(oriented_sprite_t *sprite, rectf_t bounds, float angle) render(sprite->textures + index, bounds, mirror); } -void state_t::render_text(v2f_t x, float height, const wchar_t *wstr, +void state_t::render_text(v2f_t x, float height, std::string str, text_align_t align, sf::Color color) { - sf::Text text(wstr, font, 20); + sf::Text text(str, font, 40); sf::FloatRect rect; float scale; v2f_t offset; rect = text.getGlobalBounds(); - scale = height / 20.0f; + scale = height / 40.0f; switch (align) { + case ALIGN_LEFT_TOP: + offset = v2f_t(0, 0); + break; + case ALIGN_CENTER_BOTTOM: offset[0] = -rect.width / 2; offset[1] = -rect.height; diff --git a/src/text.cpp b/src/text.cpp index b689c99..ad6af83 100644 --- a/src/text.cpp +++ b/src/text.cpp @@ -2,24 +2,59 @@ namespace text { -const wchar_t *unit_no_path; -const wchar_t *unit_blocked; +language_t language = LANG_ENGLISH; -static void load_strings_pl(void) +static const char *human_names[] = { - unit_no_path = L"Nie wiem, jak się tam dostać."; - unit_blocked = L"Coś stoi na mojej drodze."; -} + "Kowalski", "Jackson", "Carter", "O'Neill", "Hammond", "Mitchell" +}; + +#define count(A) (sizeof(A) / sizeof((A)[0])) -void load_strings(std::string lang) +static std::string get_english(index_t index) { - if (lang == "pl") { - load_strings_pl(); - return; - } + switch (index) { + case SAY_BLOCKED: + return "Something is in my way."; + + case SAY_NO_PATH: + return "I can't get there."; + + case UNIT_ALIEN: + return "Alien"; + + case UNIT_HUMAN: + return human_names[rand() % count(human_names)]; + + case UNIT_DEATH: + return "Death"; + + case UNIT_ATTACK: + return "attacks"; - unit_no_path = L"I don't know how to get there."; - unit_blocked = L"Something's in my way."; + case UNIT_MISS: + return "miss"; + + case UNIT_CRITICAL_MISS: + return "critical miss"; + + case UNIT_HIT: + return "hit"; + + case UNIT_CRITICAL_HIT: + return "critical hit"; + + case UNIT_DAMAGE: + return "deals damage to"; + } } +std::string get(index_t index) +{ + switch (language) { + default: + return get_english(index); + } } + +} // namespace text |