summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaweł Redman <pawel.redman@gmail.com>2018-04-26 11:44:23 +0200
committerPaweł Redman <pawel.redman@gmail.com>2018-04-26 11:44:23 +0200
commit86872106dc9aa960b417b5ff7f4a175c81058411 (patch)
treee8da47396f7f7eb37efe80b559e68d84aec9e818 /src
parentd04e1b48bd934f8d9d91aab13e9e51393fd7b6ba (diff)
Add the replicator.
Diffstat (limited to 'src')
-rw-r--r--src/game/assets.cpp6
-rw-r--r--src/game/game.cpp58
-rw-r--r--src/game/game.hpp27
-rw-r--r--src/game/interface.cpp4
-rw-r--r--src/game/unit_builder.cpp18
-rw-r--r--src/game/unit_replicator.cpp106
-rw-r--r--src/game/unit_soldier.cpp66
7 files changed, 278 insertions, 7 deletions
diff --git a/src/game/assets.cpp b/src/game/assets.cpp
index 35e9880..e2b9664 100644
--- a/src/game/assets.cpp
+++ b/src/game/assets.cpp
@@ -25,6 +25,7 @@ builder_assets_t builder;
spider_assets_t spider;
nest_assets_t nest;
teleporter_assets_t teleporter;
+replicator_assets_t replicator;
fx_assets_t fx;
deco_assets_t deco;
audio::ambient_t ambients[AMBIENT_COUNT];
@@ -103,6 +104,11 @@ void load(void)
teleporter.damage.load("assets/units/teleporter/damage2.ogg");
teleporter.damage.load("assets/units/teleporter/damage3.ogg");
+ replicator.idle.load("assets/units/replicator/idle_", 1);
+ replicator.working.load("assets/units/replicator/working_", 3);
+ replicator.unfinished.load("assets/units/replicator/unfinished_", 1);
+ replicator.avatar.load("assets/units/replicator/avatar_", 1);
+
fx.blood.load("assets/units/blood_", 4);
fx.flash.load("assets/units/flash_", 1);
diff --git a/src/game/game.cpp b/src/game/game.cpp
index 2e15024..b10bc08 100644
--- a/src/game/game.cpp
+++ b/src/game/game.cpp
@@ -182,6 +182,8 @@ enum {
COMMAND_FIRE,
COMMAND_THROW_GRENADE,
COMMAND_STOP,
+ COMMAND_RESTOCK_SHELLS,
+ COMMAND_RESTOCK_GRENADES,
COMMAND_HIRE_SOLDIER,
COMMAND_HIRE_SCIENTIST,
@@ -190,13 +192,18 @@ enum {
COMMAND_GATHER,
COMMAND_REPAIR,
- COMMAND_BUILD_TELEPORTER
+ COMMAND_BUILD_TELEPORTER,
+ COMMAND_BUILD_REPLICATOR,
+
+ COMMAND_REPLICATE_SHELLS,
+ COMMAND_REPLICATE_GRENADES,
};
bool state_t::populate_pie_menu(std::vector<interface::pie_item_t> &items)
{
bool soldiers = false, teleporters = false, grenades = false,
- scientists = false, builders = false;
+ scientists = false, builders = false, replicators = false,
+ restock_shells = false, restock_grenades = false;
items.clear();
@@ -212,6 +219,10 @@ bool state_t::populate_pie_menu(std::vector<interface::pie_item_t> &items)
soldiers = true;
if (unit->storage.grenades)
grenades = true;
+ if (unit->storage.shells < unit->storage.max_shells)
+ restock_shells = true;
+ if (unit->storage.grenades < unit->storage.max_grenades)
+ restock_grenades = true;
break;
case unit_t::UNIT_SCIENTIST:
@@ -226,6 +237,10 @@ bool state_t::populate_pie_menu(std::vector<interface::pie_item_t> &items)
teleporters = true;
break;
+ case unit_t::UNIT_REPLICATOR:
+ replicators = true;
+ break;
+
default:;
}
}
@@ -239,6 +254,10 @@ bool state_t::populate_pie_menu(std::vector<interface::pie_item_t> &items)
items.push_back((interface::pie_item_t){"Fire", COMMAND_FIRE});
if (grenades)
items.push_back((interface::pie_item_t){"Throw a grenade", COMMAND_THROW_GRENADE});
+ if (restock_shells)
+ items.push_back((interface::pie_item_t){"Restock shells", COMMAND_RESTOCK_SHELLS});
+ if (restock_grenades)
+ items.push_back((interface::pie_item_t){"Restock grenades", COMMAND_RESTOCK_GRENADES});
}
if (scientists)
@@ -247,6 +266,7 @@ bool state_t::populate_pie_menu(std::vector<interface::pie_item_t> &items)
if (builders) {
items.push_back((interface::pie_item_t){"Repair", COMMAND_REPAIR});
items.push_back((interface::pie_item_t){"Build a teleporter", COMMAND_BUILD_TELEPORTER});
+ items.push_back((interface::pie_item_t){"Build a replicator", COMMAND_BUILD_REPLICATOR});
}
if (teleporters) {
@@ -255,6 +275,11 @@ bool state_t::populate_pie_menu(std::vector<interface::pie_item_t> &items)
items.push_back((interface::pie_item_t){"Hire a builder", COMMAND_HIRE_BUILDER});
}
+ if (replicators) {
+ items.push_back((interface::pie_item_t){"Replicate shells", COMMAND_REPLICATE_SHELLS});
+ items.push_back((interface::pie_item_t){"Replicate grenades", COMMAND_REPLICATE_GRENADES});
+ }
+
return true;
}
@@ -286,6 +311,14 @@ static void command_soldier(unit_soldier_t *soldier, v2f_t x, int number)
case COMMAND_THROW_GRENADE:
soldier->command_throw_grenade(x);
break;
+
+ case COMMAND_RESTOCK_SHELLS:
+ soldier->command_restock(false);
+ break;
+
+ case COMMAND_RESTOCK_GRENADES:
+ soldier->command_restock(true);
+ break;
}
}
@@ -339,6 +372,10 @@ static void command_builder(unit_builder_t *builder, v2f_t x, int number)
case COMMAND_BUILD_TELEPORTER:
builder->command_build(x, unit_t::UNIT_TELEPORTER);
break;
+
+ case COMMAND_BUILD_REPLICATOR:
+ builder->command_build(x, unit_t::UNIT_REPLICATOR);
+ break;
}
}
@@ -359,6 +396,19 @@ static void command_teleporter(unit_teleporter_t *teleporter, v2f_t x, int numbe
}
}
+static void command_replicator(unit_replicator_t *replicator, v2f_t x, int number)
+{
+ switch (number) {
+ case COMMAND_REPLICATE_SHELLS:
+ replicator->activate(false);
+ break;
+
+ case COMMAND_REPLICATE_GRENADES:
+ replicator->activate(true);
+ break;
+ }
+}
+
void state_t::command(v2f_t x, int number)
{
bool unlink;
@@ -397,6 +447,10 @@ void state_t::command(v2f_t x, int number)
x, number);
break;
+ case unit_t::UNIT_REPLICATOR:
+ command_replicator(dynamic_cast<unit_replicator_t*>(unit),
+ x, number);
+
default:;
}
}
diff --git a/src/game/game.hpp b/src/game/game.hpp
index f630c54..387df1a 100644
--- a/src/game/game.hpp
+++ b/src/game/game.hpp
@@ -239,6 +239,10 @@ namespace game {
} teleporter_assets_t;
typedef struct {
+ render::animated_texture_t idle, working, unfinished, avatar;
+ } replicator_assets_t;
+
+ typedef struct {
render::animated_texture_t blood, flash, explosion, ricochet, water_splash;
audio::sound_t gibbing, corpse_hit;
audio::sound_t explosion_sound, ricochet_sound, water_splash_sound;
@@ -265,6 +269,7 @@ namespace game {
extern spider_assets_t spider;
extern nest_assets_t nest;
extern teleporter_assets_t teleporter;
+ extern replicator_assets_t replicator;
extern fx_assets_t fx;
extern deco_assets_t deco;
extern audio::ambient_t ambients[AMBIENT_COUNT];
@@ -324,7 +329,8 @@ namespace game {
UNIT_BUILDER,
UNIT_SPIDER,
UNIT_NEST,
- UNIT_TELEPORTER
+ UNIT_TELEPORTER,
+ UNIT_REPLICATOR
} type_t;
game::state_t *game;
@@ -413,6 +419,7 @@ namespace game {
void on_death(void);
void command_throw_grenade(v2f_t at);
+ void command_restock(bool grenades);
};
class unit_scientist_t : public unit_t {
@@ -518,6 +525,24 @@ namespace game {
void activate(unit_t::type_t type);
};
+ class unit_replicator_t : public unit_t {
+ ntime_t last_activation = 0;
+
+ public:
+ unit_replicator_t(game::state_t *game_);
+ ~unit_replicator_t(void) {};
+ void render_to(render::state_t *render);
+ void render_late_to(render::state_t *render) {};
+
+ void on_think(void) {};
+ void on_spawn(void) {};
+ void on_wake(void) {};
+ void on_damage(unit_t *attacker);
+ void on_death(void);
+
+ void activate(bool grenades);
+ };
+
class effect_t : public game::entity_t {
public:
double ttl = +INFINITY;
diff --git a/src/game/interface.cpp b/src/game/interface.cpp
index 6375a3c..f6106e2 100644
--- a/src/game/interface.cpp
+++ b/src/game/interface.cpp
@@ -393,6 +393,10 @@ static void render_avatar(render::state_t *render, game::unit_t *unit, v2f_t at,
image = &assets::teleporter.avatar;
break;
+ case game::unit_t::UNIT_REPLICATOR:
+ image = &assets::replicator.avatar;
+ break;
+
default:
image = &assets::deco.eyething;
break;
diff --git a/src/game/unit_builder.cpp b/src/game/unit_builder.cpp
index 0deae3c..801639e 100644
--- a/src/game/unit_builder.cpp
+++ b/src/game/unit_builder.cpp
@@ -95,6 +95,11 @@ void unit_builder_t::command_build(v2f_t where, type_t what)
price = 250;
break;
+ case UNIT_REPLICATOR:
+ built = new unit_replicator_t(game);
+ price = 200;
+ break;
+
default:
abort();
}
@@ -107,7 +112,7 @@ void unit_builder_t::command_build(v2f_t where, type_t what)
cmodel.bounds[0] = where + built->size[0];
cmodel.bounds[1] = where + built->size[1];
- cmodel.cflags = CF_SOLID|CF_SURFACE2|CF_WATER|CF_DECOS;
+ cmodel.cflags = CF_SOLID|CF_SURFACE2|CF_WATER|CF_DECOS|CF_BODY|CF_BODY_SMALL;
if (world->test_rect(&cmodel, nullptr)) {
say("Nie ma tutaj miejsca.");
@@ -131,10 +136,14 @@ void unit_builder_t::repair(void)
world::trace_t trace;
unit_t *unit;
- if (!move.moving)
+ if (!move.moving) {
+ world::cflags_t save = move.cflags;
+ move.cflags &= ~CF_SOLID;
start_moving(repairing_at);
+ move.cflags = save;
+ }
- if ((x - repairing_at).len() > 0.5f)
+ if ((x - repairing_at).len() > 1.0f)
return;
if (next_repair && next_repair > game->time)
@@ -147,7 +156,8 @@ void unit_builder_t::repair(void)
}
unit = dynamic_cast<unit_t*>(trace.ent);
- if (unit->type != UNIT_TELEPORTER || unit->health >= unit->max_health) {
+ if ((unit->type != UNIT_TELEPORTER && unit->type != UNIT_REPLICATOR)
+ || unit->health >= unit->max_health) {
repairing = false;
return;
}
diff --git a/src/game/unit_replicator.cpp b/src/game/unit_replicator.cpp
new file mode 100644
index 0000000..5d2eef5
--- /dev/null
+++ b/src/game/unit_replicator.cpp
@@ -0,0 +1,106 @@
+/*
+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_replicator_t::unit_replicator_t(game::state_t *game_) : unit_t(game_, UNIT_REPLICATOR)
+{
+ size[0] = {-0.4f, -0.2f};
+ size[1] = {+0.4f, +0.4f};
+ render_size[0] = {-0.4f, -0.666667f};
+ render_size[1] = {+0.4f, +0.4f};
+ cmodel.cflags = CF_SOLID;
+
+ name = "Replicator";
+ ignore_waking = false;
+ max_health = 30;
+ health = 4;
+
+ friendly = true;
+ controllable = true;
+ constructed = false;
+
+ storage.shells = 0;
+ storage.max_shells = 200;
+ storage.grenades = 0;
+ storage.max_grenades = 20;
+}
+
+void unit_replicator_t::on_damage(unit_t *attacker)
+{
+ assets::teleporter.damage.play_3d(x);
+}
+
+void unit_replicator_t::on_death(void)
+{
+ game->explosion(x);
+ game->deletion_list.insert(this);
+}
+
+void unit_replicator_t::activate(bool grenades)
+{
+ size_t amount, price;
+
+ if (grenades) {
+ amount = 2;
+ price = 10;
+
+ if (storage.max_grenades - storage.grenades < amount) {
+ say("Storage full.");
+ return;
+ }
+ } else {
+ amount = 15;
+ price = 8;
+
+ if (storage.max_shells - storage.shells < amount) {
+ say("Storage full.");
+ return;
+ }
+ }
+
+ if (game->crystals < price) {
+ game->interface.print("Insufficient crystals; " + std::to_string(price - game->crystals) + " more needed.");
+ return;
+ }
+
+ game->crystals -= price;
+
+ if (grenades)
+ storage.grenades += amount;
+ else
+ storage.shells += amount;
+
+ assets::teleporter.sound.play_3d(x);
+ last_activation = game->time;
+}
+
+void unit_replicator_t::render_to(render::state_t *render)
+{
+ if (!constructed)
+ render->render(game->now, &assets::replicator.unfinished, render_bounds);
+ else if (last_activation && game->time - last_activation < MSEC(300))
+ render->render(30 * game->now, &assets::replicator.working, render_bounds);
+ else
+ render->render(game->now, &assets::replicator.idle, render_bounds);
+
+ unit_t::render_to(render);
+}
+
+}
diff --git a/src/game/unit_soldier.cpp b/src/game/unit_soldier.cpp
index 4747060..1750e2e 100644
--- a/src/game/unit_soldier.cpp
+++ b/src/game/unit_soldier.cpp
@@ -250,6 +250,72 @@ void unit_soldier_t::command_throw_grenade(v2f_t at)
grenade->place(&game->world);
}
+void unit_soldier_t::command_restock(bool grenades)
+{
+ rectf_t rect;
+ bool replicators = false;
+ size_t needed, taken = 0;
+
+ if (grenades)
+ needed = storage.max_grenades - storage.grenades;
+ else
+ needed = storage.max_shells - storage.shells;
+
+ if (!needed) {
+ say("Ich kann nicht mehr tragen.");
+ return;
+ }
+
+ rect = rectf_t::around(x, 2.0f);
+ for (world::entity_t *ent : game->world.get_entities(rect, CF_SOLID)) {
+ world::trace_t trace;
+ unit_t *unit;
+ size_t take;
+
+ if (ent->type != ET_UNIT)
+ continue;
+
+ unit = dynamic_cast<unit_t*>(ent);
+ if (unit->type != UNIT_REPLICATOR)
+ continue;
+
+ trace = world->ray_v_all(x, unit->x, CF_SOLID, this);
+ if (trace.hit && trace.ent != ent)
+ continue;
+
+ replicators = true;
+
+ if (grenades) {
+ take = std::min(needed, unit->storage.grenades);
+ taken += take;
+ unit->storage.grenades -= take;
+ } else {
+ take = std::min(needed, unit->storage.shells);
+ taken += take;
+ unit->storage.shells -= take;
+ }
+ }
+
+ if (!replicators) {
+ say("Es gibt keine Replikators.");
+ return;
+ }
+
+ if (!taken) {
+ if (grenades)
+ say("Ich konnte keine Granaten finden.");
+ else
+ say("Ich konnte keine Munition finden.");
+
+ return;
+ }
+
+ if (grenades)
+ storage.grenades += taken;
+ else
+ storage.shells += taken;
+}
+
void unit_soldier_t::render_to(render::state_t *render)
{
sf::Color selection_color;