diff options
Diffstat (limited to 'src/game')
| -rw-r--r-- | src/game/assets.cpp | 6 | ||||
| -rw-r--r-- | src/game/game.cpp | 58 | ||||
| -rw-r--r-- | src/game/game.hpp | 27 | ||||
| -rw-r--r-- | src/game/interface.cpp | 4 | ||||
| -rw-r--r-- | src/game/unit_builder.cpp | 18 | ||||
| -rw-r--r-- | src/game/unit_replicator.cpp | 106 | ||||
| -rw-r--r-- | src/game/unit_soldier.cpp | 66 | 
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;  | 
