diff options
Diffstat (limited to 'src/game')
| -rw-r--r-- | src/game/game.cpp | 66 | ||||
| -rw-r--r-- | src/game/game.hpp | 12 | ||||
| -rw-r--r-- | src/game/interface.cpp | 105 | ||||
| -rw-r--r-- | src/game/text.cpp | 87 | ||||
| -rw-r--r-- | src/game/units.cpp | 68 | 
5 files changed, 231 insertions, 107 deletions
diff --git a/src/game/game.cpp b/src/game/game.cpp index ccd133d..79685cb 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -131,15 +131,48 @@ void state_t::select(rectf_t x)  		group_say(text::get(text::SAY_READY_GROUP));  } -void state_t::command(v2f_t x) +enum { +	COMMAND_MOVE, +	COMMAND_FIRE, +	COMMAND_STOP +}; + +bool state_t::populate_pie_menu(std::vector<interface::pie_item_t> &items) +{ +	items.clear(); + +	if (selected_units.size() == 0) +		return false; + +	items.push_back((interface::pie_item_t){"Move", COMMAND_MOVE}); +	items.push_back((interface::pie_item_t){"Fire", COMMAND_FIRE}); +	items.push_back((interface::pie_item_t){"Stop", COMMAND_STOP}); +	return true; +} + +void state_t::command(v2f_t x, int number)  {  	v2f_t snap; +	bool group; + +	if (!selected_units.size()) +		return;  	snap[0] = std::round(x[0] - 0.5f) + 0.5f;  	snap[1] = std::round(x[1] - 0.5f) + 0.5f; -	if (selected_units.size() > 1) +	group = selected_units.size() > 1; +	if (group) switch (number) { +	case COMMAND_MOVE:  		group_say(text::get(text::SAY_MOVING_GROUP)); +		break; +	case COMMAND_STOP: +		group_say(text::get(text::SAY_STOPPING_GROUP)); +		break; +	case COMMAND_FIRE: +		group_say(text::get(text::SAY_FIRING_GROUP)); +		break; +	}  	for (unit_t *unit : selected_units) {  		unit_soldier_t *soldier; @@ -155,13 +188,30 @@ void state_t::command(v2f_t x)  		if (!soldier->controllable)  			continue; -		if (!soldier->start_moving(snap)) -			soldier->say(text::get(text::SAY_NO_PATH)); -		else { -			soldier->move_marker = std::make_unique<fx_move_marker_t>(this, soldier->move.path.back()); +		switch (number) { +		case COMMAND_MOVE: +			if (!soldier->start_moving(snap)) +				soldier->say(text::get(text::SAY_NO_PATH)); +			else { +				soldier->move_marker = std::make_unique<fx_move_marker_t>(this, soldier->move.path.back()); +				if (!group) +					soldier->say(text::get(text::SAY_MOVING)); +			} +			break; -			if (selected_units.size() == 1) -				soldier->say(text::get(text::SAY_MOVING)); +		case COMMAND_STOP: +			soldier->stop_moving(); +			soldier->manual_firing = false; +			if (!group) +				soldier->say(text::get(text::SAY_STOPPING)); +			break; + +		case COMMAND_FIRE: +			soldier->manual_firing = true; +			soldier->manual_firing_target = x; +			if (!group) +				soldier->say(text::get(text::SAY_FIRING)); +			break;  		}  	}  } diff --git a/src/game/game.hpp b/src/game/game.hpp index 025aa12..848ba92 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -96,8 +96,7 @@ namespace game {  	namespace text {  		typedef enum { -			LANG_ENGLISH, -			LANG_POLISH +			LANG_ENGLISH  		} language_t;  		extern language_t language; @@ -113,6 +112,10 @@ namespace game {  			SAY_READY_GROUP,  			SAY_MOVING,  			SAY_MOVING_GROUP, +			SAY_STOPPING, +			SAY_STOPPING_GROUP, +			SAY_FIRING, +			SAY_FIRING_GROUP,  			SAY_PANIC,  			UNIT_NAME_SPIDER,  			UNIT_NAME_SOLDIER, @@ -195,6 +198,7 @@ namespace game {  		bool keep_moving(double speed);  		bool start_moving(v2f_t dst); +		void stop_moving(void);  		bool dead = false;  		double death_time = -INFINITY; @@ -230,7 +234,11 @@ namespace game {  		double panic_end;  		double panic_turn; +		bool manual_firing = false; +		v2f_t manual_firing_target; +  		void check_area(void); +		void shoot(v2f_t aim);  		void target_and_attack(void);  	public: diff --git a/src/game/interface.cpp b/src/game/interface.cpp index 262c3ae..d3ef661 100644 --- a/src/game/interface.cpp +++ b/src/game/interface.cpp @@ -51,6 +51,69 @@ void state_t::stop_following(void)  	print(text::get(text::FOLLOWING_OFF));  } +void pie_menu_t::open(v2f_t wmouse, v2f_t mouse) +{ +	size_t layer = 0; +	float base_radius = 50.0f; // FIXME + +	for (size_t i = 0; i < items.size(); ) { +		size_t left, layer_cap, on_layer; + +		left = items.size() - i; +		layer_cap = (layer + 1) * (layer + 1); +		on_layer = std::min(left, layer_cap); + +		for (size_t j = 0; j < on_layer; j++) { +			pie_item_t *item = &items[i + j]; +			float dt = 2 * M_PI / on_layer; + +			item->r0 = layer * base_radius;  +			item->r1 = (layer + 1) * base_radius; +			item->t0 = j * dt; +			item->t1 = (j + 1) * dt; +		} + +		i += on_layer; +		layer++; +	} + +	is_open = true; +	x_world = wmouse; +	x = mouse; +} + +void pie_menu_t::close(game::state_t *game) +{ +	if (!is_open) +		return; + +	if (selected) +		game->command(x_world, selected->action); + +	is_open = false; +	items.clear(); +} + +void pie_menu_t::update(v2f_t mouse) +{ +	v2f_t delta; +	float r, t; + +	delta = mouse - x; +	r = delta.len(); +	t = atan2(delta[1], delta[0]); +	if (t < 0) +		t += 2 * M_PI; + +	selected = nullptr; +	for (pie_item_t &i : items) { +		if (r >= i.r0 && r <= i.r1 && t >= i.t0 && t <= i.t1) { +			selected = &i; +			break; +		} +	} +} +  void state_t::tick(double dt)  {  	vec_t<int, 2> window_size; @@ -59,6 +122,7 @@ void state_t::tick(double dt)  	v2f_t view_size;  	v2f_t follow_center(0, 0), view_center, pan_delta;  	float view_scale; +	sf::Vector2i mouse;  	v2f_t wmouse; // Mouse position in world space;  	window_size = window->getSize(); @@ -101,6 +165,7 @@ void state_t::tick(double dt)  		window->setView(sf::View(view_center, view_size));  	} +	mouse = sf::Mouse::getPosition(*window);  	wmouse = window->mapPixelToCoords(sf::Mouse::getPosition(*window));  	while (window->pollEvent(event)) { @@ -119,7 +184,8 @@ void state_t::tick(double dt)  				break;  			case sf::Mouse::Button::Right: -				game->command(wmouse); +				if (game->populate_pie_menu(pie_menu.items)) +					pie_menu.open(wmouse, mouse);  				break;  			case sf::Mouse::Button::Middle: @@ -139,6 +205,10 @@ void state_t::tick(double dt)  				select.selecting = false;  				break; +			case sf::Mouse::Button::Right: +				pie_menu.close(game); +				break; +  			case sf::Mouse::Button::Middle:  				if (camera.panning)  					camera.center += pan_delta; @@ -207,6 +277,8 @@ void state_t::tick(double dt)  	if (select.selecting)  		select.rect[1] = wmouse; + +	pie_menu.update(mouse);  }  void state_t::print(std::string str) @@ -215,6 +287,35 @@ void state_t::print(std::string str)  	std::cout << str << std::endl;  } +void pie_menu_t::render_to(render::state_t *render) +{ +	if (!is_open) +		return; + +	for (pie_item_t &i : items) { +		sf::Color color; +		v2f_t rad, center; + +		if (&i == selected) +			color = sf::Color(255, 255, 255, 120); +		else +			color = sf::Color(255, 255, 255, 40); + +		render->render_ring_sect(x, i.r0, i.r1, i.t0, i.t1, color); + +		color.a = 255; + +		if (i.r0 == 0.0f) { +			center = x; +		} else { +			center = x + (i.r1 + i.r0) / 2 * +			         v2f_t::rad((i.t1 + i.t0) / 2); +		} + +		render->render_text(center, 15, i.label, render::text_align_t::ALIGN_CENTER_BOTTOM, color); +	} +} +  void state_t::render_to(render::state_t *render)  {  	size_t w = window->getSize().x, h = window->getSize().y; @@ -228,6 +329,8 @@ void state_t::render_to(render::state_t *render)  	window->setView(sf::View(sf::FloatRect(0, 0, w, h)));  	em = std::max(w, h) * 0.017; +	pie_menu.render_to(render); +  	for (auto i = log.begin(); i != log.end(); ) {  		if (i->time + 3 < game->now)  			i = log.erase(i); diff --git a/src/game/text.cpp b/src/game/text.cpp index 7e90edf..75fb032 100644 --- a/src/game/text.cpp +++ b/src/game/text.cpp @@ -56,8 +56,16 @@ static std::string get_english(index_t index)  	case SAY_MOVING_GROUP:  		return "On our way."; +	case SAY_STOPPING: +	case SAY_STOPPING_GROUP: +		return "Stopping."; + +	case SAY_FIRING: +	case SAY_FIRING_GROUP: +		return "Firing!"; +  	case SAY_PANIC: -		return "I'm not getting paid enough for this."; +		return "I'm not getting paid enough for this!";  	case UNIT_NAME_SPIDER:  		return "Spider"; @@ -100,89 +108,12 @@ static std::string get_english(index_t index)  	}  } -static std::string get_polish(index_t index) -{ -	switch (index) { -	case PAUSED: -		return "WSTRZYMANO"; - -	case UNPAUSED: -		return "WZNOWIONO"; - -	case FOLLOWING_ON: -		return "Podążanie: włączone."; - -	case FOLLOWING_OFF: -		return "Podążanie: wyłączone."; - -	case SAY_GROUP: -		return "Oddział"; - -	case SAY_NO_PATH: -		return "Nie mogę się tam dostać."; - -	case SAY_READY: -	case SAY_READY_GROUP: -		return "Gotowy na rozkaz."; - -	case SAY_MOVING: -		return "Jestem w drodze."; - -	case SAY_MOVING_GROUP: -		return "W drodze."; - -	case SAY_PANIC: -		return "Za mało mi za to płacą."; - -	case UNIT_NAME_SPIDER: -		return "Pająk"; - -	case UNIT_NAME_SOLDIER: -		return soldier_names[rand() % COUNT(soldier_names)]; - -	case UNIT_NAME_NEST: -		return "Gniazdo"; - -	case UNIT_DEATH: -		return "nie żyje"; - -	case UNIT_ATTACK: -		return "atakuje"; - -	case UNIT_MISS: -		return "chybienie"; - -	case UNIT_CRITICAL_MISS: -		return "chybienie krytyczne"; - -	case UNIT_CRITICAL_HIT: -		return "trafienie krytyczne"; - -	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(); -	} -}  std::string get(index_t index)  {  	switch (language) {  	case LANG_ENGLISH:  		return get_english(index); -	case LANG_POLISH: -		return get_polish(index); -  	default:  		abort();  	} diff --git a/src/game/units.cpp b/src/game/units.cpp index a0dcee3..f3d53d7 100644 --- a/src/game/units.cpp +++ b/src/game/units.cpp @@ -188,6 +188,12 @@ bool unit_t::start_moving(v2f_t dst)  	return true;  } +void unit_t::stop_moving(void) +{ +	move.path.clear(); +	move.moving = false; +} +  void unit_t::damage(int points, unit_t *attacker)  {  	fx_blood_t *blood; @@ -316,14 +322,52 @@ void unit_soldier_t::check_area(void)  	}  } -void unit_soldier_t::target_and_attack(void) +static v2f_t spread_aim(v2f_t aim, float cof, procgen::prng_t *prng)  { -	unit_t *target; +	float t; + +	t = prng->next_float(-cof / 2, cof / 2); + +	return v2f_t(cos(t) * aim[0] - sin(t) * aim[1], +	             sin(t) * aim[0] + cos(t) * aim[1]); +} + +void unit_soldier_t::shoot(v2f_t aim) +{ +	v2f_t end;  	world::trace_t trace;  	v2f_t muzzle_point;  	fx_tracer_t *tracer;  	fx_flash_t *flash; +	end = x + (aim - x).norm() * 40; + +	trace = world->trace(x, end, CF_SOLID); + +	muzzle_point = x + v2f_t(0, -1.0f); + +	tracer = new fx_tracer_t(game, muzzle_point, trace.end); +	tracer->place(&game->world); + +	flash = new fx_flash_t(game, muzzle_point, 5.0f); +	flash->place(&game->world); + +	last_attack = game->now; +	assets::soldier.fire.play(); +	//target->damage(3, this); FIXME +} + +void unit_soldier_t::target_and_attack(void) +{ +	unit_t *target; +	v2f_t aim; + +	if (manual_firing) { +		aim = manual_firing_target; +		last_target_x = aim; +		goto skip_targetting; +	} +  	if (game->now < next_targetting)  		return; @@ -332,28 +376,16 @@ void unit_soldier_t::target_and_attack(void)  	target = find_target(world, x, 5.0f, false);  	if (!target)  		return; +	aim = target->x;  	last_target_time = game->now;  	last_target_x = target->x; +skip_targetting:  	if (last_attack + game->dice_prng.next_float(1.4f, 1.6f) > game->now)  		return; -	trace = world->trace(x, target->x, CF_SOLID); -	if (trace.hit) -		return; - -	muzzle_point = x + v2f_t(0, -1.0f); - -	tracer = new fx_tracer_t(game, muzzle_point, target->x); -	tracer->place(&game->world); - -	flash = new fx_flash_t(game, muzzle_point, 5.0f); -	flash->place(&game->world); - -	last_attack = game->now; -	assets::soldier.fire.play(); -	target->damage(3, this); +	shoot(spread_aim(aim, 0.2, &game->dice_prng));  }  void unit_soldier_t::on_think(void) @@ -465,7 +497,7 @@ void unit_soldier_t::render_to(render::state_t *render)  		else  			legs = &assets::soldier.legs_idle; -		if (!panic && last_target_time + 3 > game->now) { +		if (!panic && (manual_firing || last_target_time + 3 > game->now)) {  			if (last_attack + 0.1 > game->now)  				body = &assets::soldier.body_firing;  			else  | 
