static void reality_check_get_direction_helper(const map_location & loc, const map_location::DIRECTION d)
{
	map_location lz(vz.get_direction(d));

	map_location temp(loc.vector_sum(lz));
	BOOST_CHECK_EQUAL(temp, loc.get_direction(d));
	BOOST_CHECK(tiles_adjacent(loc,temp));
	BOOST_CHECK(tiles_adjacent(temp,loc));
	BOOST_CHECK_EQUAL(distance_between(loc,temp), 1);
}
/**
 * Expose map_location tiles_adjacent
 */
int intf_tiles_adjacent(lua_State* L)
{
	map_location l2 = pop_map_location(L);
	map_location l1 = pop_map_location(L);

	lua_pushboolean(L, tiles_adjacent(l1,l2));
	return 1;
}
/**
 * Expose map_location tiles_adjacent
 */
int intf_tiles_adjacent(lua_State* L)
{
	map_location l1, l2;
	if(!luaW_tolocation(L, 1, l1) || !luaW_tolocation(L, 2, l2)) {
		lua_pushstring(L, "vector_sum: requires two locations");
		return lua_error(L);
	}

	lua_pushboolean(L, tiles_adjacent(l1,l2));
	return 1;
}
Example #4
0
attack::attack(config const& cfg, bool hidden)
	: move(cfg,hidden)
	, target_hex_(cfg.child("target_hex_")["x"],cfg.child("target_hex_")["y"])
	, weapon_choice_(cfg["weapon_choice_"].to_int(-1)) //default value: -1
	, attack_movement_cost_()
	, temp_movement_subtracted_(0)
{
	// Validate target_hex
	if(!tiles_adjacent(target_hex_,get_dest_hex()))
		throw action::ctor_err("attack: Invalid target_hex_");

	// Validate weapon_choice_
	if(weapon_choice_ < 0 || weapon_choice_ >= static_cast<int>(get_unit()->attacks().size()))
		throw action::ctor_err("attack: Invalid weapon_choice_");

	// Construct attack_movement_cost_
	attack_movement_cost_ = get_unit()->attacks()[weapon_choice_].movement_used();

	this->init();
}
Example #5
0
/**
 * Visually moves a unit from the last hex we drew to the one specified by
 * @a path_index. If @a path_index points to an earlier hex, we do nothing.
 * The moving unit will only be updated if update is set to true; otherwise,
 * the provided unit is merely hidden during the movement and re-shown after.
 * (Not updating the unit can produce smoother animations in some cases.)
 * If @a wait is set to false, this returns without waiting for the final
 * animation to finish. Call wait_for_anims() to explicitly get this final
 * wait (another call to proceed_to() or finish() will implicitly wait). The
 * unit must remain valid until the wait is finished.
 */
void unit_mover::proceed_to(unit_ptr u, size_t path_index, bool update, bool wait)
{
	// Nothing to do here if animations cannot be shown.
	if ( !can_draw_ || !animate_ )
		return;

	// Handle pending visibility issues before introducing new ones.
	wait_for_anims();

	if ( update  ||  !temp_unit_ptr_ )
		// Replace the temp unit (which also hides u and shows our temporary).
		replace_temporary(u);
	else
	{
		// Just switch the display from the real unit to our fake one.
		temp_unit_ptr_->set_hidden(false);
		u->set_hidden(true);
	}

	// Safety check.
	path_index = std::min(path_index, path_.size()-1);

	for ( ; current_ < path_index; ++current_ )
		// If the unit can be seen by the viewing side while making this step:
		if ( !is_enemy_ || !temp_unit_ptr_->invisible(path_[current_]) ||
		     !temp_unit_ptr_->invisible(path_[current_+1]) )
		{
			// Wait for the previous step to complete before drawing the next one.
			wait_for_anims();

			if ( !disp_->tile_fully_on_screen(path_[current_]) ||
			     !disp_->tile_fully_on_screen(path_[current_+1]))
			{
				// prevent the unit from disappearing if we scroll here with i == 0
				temp_unit_ptr_->set_location(path_[current_]);
				disp_->invalidate(path_[current_]);
				// scroll in as much of the remaining path as possible
				if ( temp_unit_ptr_->anim_comp().get_animation() )
					temp_unit_ptr_->anim_comp().get_animation()->pause_animation();
				disp_->scroll_to_tiles(path_.begin() + current_,
				                       path_.end(), game_display::ONSCREEN,
				                       true, false, 0.0, force_scroll_);
				if ( temp_unit_ptr_->anim_comp().get_animation() )
					temp_unit_ptr_->anim_comp().get_animation()->restart_animation();
			}

			if ( tiles_adjacent(path_[current_], path_[current_+1]) )
				wait_until_ =
					move_unit_between(path_[current_], path_[current_+1],
					                  temp_unit_ptr_.get_unit_ptr(), current_,
					                  path_.size() - (current_+2), animator_,
					                  *disp_);
			else if ( path_[current_] != path_[current_+1] )
				teleport_unit_between(path_[current_], path_[current_+1],
				                      *temp_unit_ptr_, *disp_);
		}

	// Update the unit's facing.
	u->set_facing(temp_unit_ptr_->facing());
	u->anim_comp().set_standing(false);	// Need to reset u's animation so the new facing takes effect.
	// Remember the unit to unhide when the animation finishes.
	shown_unit_ = u;
	if ( wait )
		wait_for_anims();
}
Example #6
0
void attack_result::do_check_before()
{
	LOG_AI_ACTIONS << " check_before " << *this << std::endl;
	const unit *attacker = get_unit(get_info(),attacker_loc_);
	const unit *defender = get_unit(get_info(),defender_loc_);

	if(attacker==NULL)
	{
		LOG_AI_ACTIONS << "attempt to attack without attacker\n";
		set_error(E_EMPTY_ATTACKER);
		return;
	}

	if (defender==NULL)
	{
		LOG_AI_ACTIONS << "attempt to attack without defender\n";
		set_error(E_EMPTY_DEFENDER);
		return;
	}

	if(attacker->incapacitated()) {
		LOG_AI_ACTIONS << "attempt to attack with unit that is petrified\n";
		set_error(E_INCAPACITATED_ATTACKER);
		return;
	}

	if(defender->incapacitated()) {
		LOG_AI_ACTIONS << "attempt to attack unit that is petrified\n";
		set_error(E_INCAPACITATED_DEFENDER);
		return;
	}

	if(!attacker->attacks_left()) {
		LOG_AI_ACTIONS << "attempt to attack with no attacks left\n";
		set_error(E_NO_ATTACKS_LEFT);
		return;
	}

	if(attacker->side()!=get_side()) {
		LOG_AI_ACTIONS << "attempt to attack with not own unit\n";
		set_error(E_NOT_OWN_ATTACKER);
		return;
	}

	if(!get_my_team(get_info()).is_enemy(defender->side())) {
		LOG_AI_ACTIONS << "attempt to attack unit that is not enemy\n";
		set_error(E_NOT_ENEMY_DEFENDER);
		return;
	}

	if (attacker_weapon_!=-1) {
		if ((attacker_weapon_<0)||(attacker_weapon_ >= static_cast<int>(attacker->attacks().size()))) {
			LOG_AI_ACTIONS << "invalid weapon selection for the attacker\n";
			set_error(E_WRONG_ATTACKER_WEAPON);
			return;
		}
	}

	if (!tiles_adjacent(attacker_loc_,defender_loc_)) {
		LOG_AI_ACTIONS << "attacker and defender not adjacent\n";
		set_error(E_ATTACKER_AND_DEFENDER_NOT_ADJACENT);
		return;
	}
}
Example #7
0
void arrow::update_symbols()
{
	if (!valid_path(path_))
	{
		WRN_ARR << "arrow::update_symbols called with invalid path\n";
		return;
	}

	symbols_map_.clear();
	invalidate_arrow_path(path_);

	std::string const mods = "~RC(FF00FF>"+ color_ + ")"; //magenta to current color

	std::string const dirname = "arrows/";
	map_location::DIRECTION exit_dir = map_location::NDIRECTIONS;
	map_location::DIRECTION enter_dir = map_location::NDIRECTIONS;
	std::string prefix = "";
	std::string suffix = "";
	std::string image_filename = "";
	arrow_path_t::const_iterator const arrow_start_hex = path_.begin();
	arrow_path_t::const_iterator const arrow_pre_end_hex = path_.end() - 2;
	arrow_path_t::const_iterator const arrow_end_hex = path_.end() - 1;
	bool start = false;
	bool pre_end = false;
	bool end = false;
	bool teleport_out = false;
	bool teleport_in = false;

	arrow_path_t::iterator hex;
	for (hex = path_.begin(); hex != path_.end(); ++hex)
	{
		prefix = "";
		suffix = "";
		image_filename = "";
		start = pre_end = end = false;

		// teleport in if we teleported out last hex
		teleport_in = teleport_out;
		teleport_out = false;

		// Determine some special cases
		if (hex == arrow_start_hex)
			start = true;
		if (hex == arrow_pre_end_hex)
			pre_end = true;
		else if (hex == arrow_end_hex)
			end = true;
		if (hex != arrow_end_hex && !tiles_adjacent(*hex, *(hex + 1)))
			teleport_out = true;

		// calculate enter and exit directions, if available
		enter_dir = map_location::NDIRECTIONS;
		if (!start && !teleport_in)
		{
			enter_dir = hex->get_relative_dir(*(hex-1));
		}
		exit_dir = map_location::NDIRECTIONS;
		if (!end && !teleport_out)
		{
			exit_dir = hex->get_relative_dir(*(hex+1));
		}

		// Now figure out the actual images
		if (teleport_out)
		{
			prefix = "teleport-out";
			if (enter_dir != map_location::NDIRECTIONS)
			{
				suffix = map_location::write_direction(enter_dir);
			}
		}
		else if (teleport_in)
		{
			prefix = "teleport-in";
			if (exit_dir != map_location::NDIRECTIONS)
			{
				suffix = map_location::write_direction(exit_dir);
			}
		}
		else if (start)
		{
			prefix = "start";
			suffix = map_location::write_direction(exit_dir);
			if (pre_end)
			{
				suffix = suffix + "_ending";
			}
		}
		else if (end)
		{
			prefix = "end";
			suffix = map_location::write_direction(enter_dir);
		}
		else
		{
			std::string enter, exit;
			enter = map_location::write_direction(enter_dir);
			exit = map_location::write_direction(exit_dir);
			if (pre_end)
			{
				exit = exit + "_ending";
			}

			assert(abs(enter_dir - exit_dir) > 1); //impossible turn?
			if (enter_dir < exit_dir)
			{
				prefix = enter;
				suffix = exit;
			}
			else //(enter_dir > exit_dir)
			{
				prefix = exit;
				suffix = enter;
			}
		}

		image_filename = dirname + style_ + "/" + prefix;
		if (suffix != "")
		{
			image_filename += ("-" + suffix);
		}
		image_filename += ".png";
		assert(image_filename != "");

		image::locator image = image::locator(image_filename, mods);
		if (!image.file_exists())
		{
			ERR_ARR << "Image " << image_filename << " not found.\n";
			image = image::locator(game_config::images::missing);
		}
		symbols_map_[*hex] = image;
	}
}
Example #8
0
std::vector<surface> footsteps_images(const map_location& loc, const pathfind::marked_route & route_, const display_context * dc_)
{
	std::vector<surface> res;

	if (route_.steps.size() < 2) {
		return res; // no real "route"
	}

	std::vector<map_location>::const_iterator i =
	         std::find(route_.steps.begin(),route_.steps.end(),loc);

	if( i == route_.steps.end()) {
		return res; // not on the route
	}

	// Check which footsteps images of game_config we will use
	int move_cost = 1;
	const unit_map::const_iterator u = dc_->units().find(route_.steps.front());
	if(u != dc_->units().end()) {
		move_cost = u->movement_cost(dc_->map().get_terrain(loc));
	}
	int image_number = std::min<int>(move_cost, game_config::foot_speed_prefix.size());
	if (image_number < 1) {
		return res; // Invalid movement cost or no images
	}
	const std::string foot_speed_prefix = game_config::foot_speed_prefix[image_number-1];

	surface teleport = NULL;

	// We draw 2 half-hex (with possibly different directions),
	// but skip the first for the first step.
	const int first_half = (i == route_.steps.begin()) ? 1 : 0;
	// and the second for the last step
	const int second_half = (i+1 == route_.steps.end()) ? 0 : 1;

	for (int h = first_half; h <= second_half; ++h) {
		const std::string sense( h==0 ? "-in" : "-out" );

		if (!tiles_adjacent(*(i+(h-1)), *(i+h))) {
			std::string teleport_image =
			h==0 ? game_config::foot_teleport_enter : game_config::foot_teleport_exit;
			teleport = image::get_image(teleport_image, image::SCALED_TO_HEX);
			continue;
		}

		// In function of the half, use the incoming or outgoing direction
		map_location::DIRECTION dir = (i+(h-1))->get_relative_dir(*(i+h));

		std::string rotate;
		if (dir > map_location::SOUTH_EAST) {
			// No image, take the opposite direction and do a 180 rotation
			dir = i->get_opposite_dir(dir);
			rotate = "~FL(horiz)~FL(vert)";
		}

		const std::string image = foot_speed_prefix
			+ sense + "-" + i->write_direction(dir)
			+ ".png" + rotate;

		res.push_back(image::get_image(image, image::SCALED_TO_HEX));
	}

	// we draw teleport image (if any) in last
	if (teleport != NULL) res.push_back(teleport);

	return res;
}