Example #1
0
void game_display::display_unit_hex(map_location hex)
{
	if (!hex.valid())
		return;

	wb::future_map future; /**< Lasts for whole method. */

	const unit *u = resources::gameboard->get_visible_unit(hex, dc_->teams()[viewing_team()], !dont_show_all_);
	if (u) {
		displayedUnitHex_ = hex;
		invalidate_unit();
	}
}
Example #2
0
void game_display::display_unit_hex(map_location hex)
{
	if (!hex.valid())
		return;

	wb::future_map future; //< Lasts for whole method.

	const unit *u = get_visible_unit(hex, (*teams_)[viewing_team()], !viewpoint_);
	if (u) {
		displayedUnitHex_ = hex;
		invalidate_unit();
	}
}
Example #3
0
void highlighter::set_mouseover_hex(const map_location& hex)
{
	clear();

	if(!hex.valid()) {
		return;
	}

	real_map ensure_real_map;
	mouseover_hex_ = hex;
	//if we're right over a unit, just highlight all of this unit's actions
	unit_map::iterator it = get_unit_map().find(hex);
	if(it != get_unit_map().end()) {
		selection_candidate_ = it.get_shared_ptr();

		if(resources::gameboard->teams().at(it->side()-1).get_side_actions()->unit_has_actions(*it)) {
			owner_unit_ = it.get_shared_ptr();
		}

		//commented code below is to also select the first action of this unit as
		//the main highlight; it doesn't fit too well in the UI
//		side_actions::iterator action_it = side_actions_->find_first_action_of(*it);
//		if(action_it != side_actions_->end()) {
//			main_highlight_ = *action_it;
//		}
	}

	//Set the execution/deletion/bump targets.
	if(owner_unit_) {
		side_actions::iterator itor = side_actions_->find_first_action_of(*owner_unit_);
		if(itor != side_actions_->end()) {
			selected_action_ = *itor;
		}
	}

	//Overwrite the above selected_action_ if we find a better one
	if(side_actions_->empty()) {
		return;
	}
	for(action_ptr act : boost::adaptors::reverse(*side_actions_)) {
		/**@todo "is_numbering_hex" is not the "correct" criterion by which to
		 * select the hightlighted/selected action. It's just convenient for me
		 * to use at the moment since it happens to coincide with the "correct"
		 * criterion, which is to use find_main_highlight.*/
		if(act->is_numbering_hex(hex)) {
			selected_action_ = act;
			break;
		}
	}
}
void get_tile_ring(const map_location& a, const int r, std::vector<map_location>& res)
{
	if(r <= 0) {
		return;
	}

	map_location loc = a.get_direction(map_location::SOUTH_WEST, r);

	for(int n = 0; n != 6; ++n) {
		const map_location::DIRECTION dir = static_cast<map_location::DIRECTION>(n);
		for(int i = 0; i != r; ++i) {
			res.push_back(loc);
			loc = loc.get_direction(dir, 1);
		}
	}
}
Example #5
0
void gamemap::set_special_location(const std::string& id, const map_location& loc)
{
	bool valid = loc.valid();
	auto it_left = starting_positions_.left.find(id);
	if (it_left != starting_positions_.left.end()) {
		if (valid) {
			starting_positions_.left.replace_data(it_left, loc);
		}
		else {
			starting_positions_.left.erase(it_left);
		}
	}
	else {
		starting_positions_.left.insert(it_left, std::make_pair(id, loc));
	}
}
Example #6
0
static void move_unit_between(const map_location& a, const map_location& b, unit& temp_unit,unsigned int step_num,unsigned int step_left)
{
	game_display* disp = game_display::get_singleton();
	if(!disp || disp->video().update_locked() || disp->video().faked() || (disp->fogged(a) && disp->fogged(b))) {
		return;
	}

	temp_unit.set_location(a);
	disp->invalidate(temp_unit.get_location());
	temp_unit.set_facing(a.get_relative_dir(b));
	unit_animator animator;
	animator.replace_anim_if_invalid(&temp_unit,"movement",a,b,step_num,
			false,"",0,unit_animation::INVALID,NULL,NULL,step_left);
	animator.start_animations();
        animator.pause_animation();
	disp->scroll_to_tiles(a,b,game_display::ONSCREEN,true,0.0,false);
        animator.restart_animation();

	// useless now, previous short draw() just did one
	// new_animation_frame();

	int target_time = animator.get_animation_time_potential();

		// target_time must be short to avoid jumpy move
		// std::cout << "target time: " << target_time << "\n";
	// we round it to the next multile of 200
	target_time += 200;
	target_time -= target_time%200;

	// This code causes backwards teleport because the time > 200 causes offset > 1.0
	// which will not match with the following -1.0
	// if(  target_time - animator.get_animation_time_potential() < 100 ) target_time +=200;

	animator.wait_until(target_time);
		// debug code, see unit_frame::redraw()
		// std::cout << "   end\n";
	map_location arr[6];
	get_adjacent_tiles(a, arr);
	unsigned int i;
	for (i = 0; i < 6; ++i) {
		disp->invalidate(arr[i]);
	}
	get_adjacent_tiles(b, arr);
	for (i = 0; i < 6; ++i) {
		disp->invalidate(arr[i]);
	}
}
Example #7
0
const time_of_day tod_manager::get_illuminated_time_of_day(const map_location& loc, int for_turn) const
{
	// get ToD ignoring illumination
	time_of_day tod = get_time_of_day(loc, for_turn);

	// now add illumination
	const gamemap& map = *resources::game_map;
	const unit_map& units = *resources::units;
	int light_modif =  map.get_terrain_info(map.get_terrain(loc)).light_modification();

	int light = tod.lawful_bonus + light_modif;
	int illum_light = light;

	if(loc.valid()) {
		map_location locs[7];
		locs[0] = loc;
		get_adjacent_tiles(loc,locs+1);

		for(int i = 0; i != 7; ++i) {
			const unit_map::const_iterator itor = units.find(locs[i]);
			if(itor != units.end() &&
			    itor->get_ability_bool("illuminates") &&
			    !itor->incapacitated())
			{
				unit_ability_list illum = itor->get_abilities("illuminates");
				unit_abilities::effect illum_effect(illum, light, false);

				illum_light = light + illum_effect.get_composite_value();
				//max_value and min_value control the final result
				//unless ToD + terrain effect is stronger
				int max = std::max(light, illum.highest("max_value").first);
				int min = std::min(light, illum.lowest("min_value").first);
				if(illum_light > max) {
					illum_light = max;
				} else if (illum_light < min) {
					illum_light = min;
				}

			}
		}
	}

	tod.bonus_modified = illum_light - tod.lawful_bonus;
	tod.lawful_bonus = illum_light;

	return tod;
}
Example #8
0
/**
 * Function that will add to @a result all locations exactly @a radius tiles
 * from @a center (or nothing if @a radius is not positive). @a result must be
 * a std::vector of locations.
 */
void get_tile_ring(const map_location& center, const int radius,
                   std::vector<map_location>& result)
{
	if ( radius <= 0 ) {
		return;
	}

	map_location loc = center.get_direction(map_location::SOUTH_WEST, radius);

	for(int n = 0; n != 6; ++n) {
		const map_location::DIRECTION dir = static_cast<map_location::DIRECTION>(n);
		for(int i = 0; i != radius; ++i) {
			result.push_back(loc);
			loc = loc.get_direction(dir, 1);
		}
	}
}
Example #9
0
void base_map::insert(const map_location loc, base_unit* u)
{
	std::stringstream err;
	if (!loc.valid()) {
		err << "Trying to add " << u->name() << " at an invalid location; Discarding.";
		delete u;
		VALIDATE(false, err.str());
	}
	bool base = u->base();

	if ((base && coor_map_[index(loc.x, loc.y)].base) ||
		(!base && coor_map_[index(loc.x, loc.y)].overlay)) {
		err << "trying to overwrite existing unit at (" << loc.x << ", " << loc.y << ")";
		delete u;
		VALIDATE(false, err.str());
	}

	// some application maybe require coor_map_ valid before set_location.
	// but touch_locs is got after set_location. only valid on center location.
	if (base) {
		coor_map_[index(loc.x, loc.y)].base = u;
	} else {
		coor_map_[index(loc.x, loc.y)].overlay = u;
	}

	u->set_location(loc);

	// it is called after set_location directly, use touch_locs safely.
	const std::set<map_location>& touch_locs = u->get_touch_locations();
	if (touch_locs.size() != 1) {
		for (std::set<map_location>::const_iterator itor = touch_locs.begin(); itor != touch_locs.end(); ++ itor) {
			if (base) {
				coor_map_[index(itor->x, itor->y)].base = u;
			} else {
				coor_map_[index(itor->x, itor->y)].overlay = u;
			}
		}
	}

	// insert p into time-axis.*
	u->map_index_ = map_vsize_;
	map_[map_vsize_ ++] = u;
	if (u->require_sort()) {
		sort_map(*u);
	}
}
map_location::DIRECTION map_location::get_relative_dir(map_location loc) const {
	map_location diff = loc.legacy_difference(*this);
	if(diff == map_location(0,0)) return NDIRECTIONS;
	if( diff.y < 0 && diff.x >= 0 && abs(diff.x) >= abs(diff.y)) return NORTH_EAST;
	if( diff.y < 0 && diff.x <  0 && abs(diff.x) >= abs(diff.y)) return NORTH_WEST;
	if( diff.y < 0 && abs(diff.x) < abs(diff.y)) return NORTH;

	if( diff.y >= 0 && diff.x >= 0 && abs(diff.x) >= abs(diff.y)) return SOUTH_EAST;
	if( diff.y >= 0 && diff.x <  0 && abs(diff.x) >= abs(diff.y)) return SOUTH_WEST;
	if( diff.y >= 0 && abs(diff.x) < abs(diff.y)) return SOUTH;

	// Impossible
	assert(false);
	return NDIRECTIONS;


}
Example #11
0
bool terrain_filter::match_internal(const map_location& loc, const bool ignore_xy) const
{
	//Filter Areas
	if (cfg_.has_attribute("area") &&
		resources::tod_manager->get_area_by_id(cfg_["area"]).count(loc) == 0)
		return false;

	if(cfg_.has_attribute("terrain")) {
		if(cache_.parsed_terrain == NULL) {
			cache_.parsed_terrain = new t_translation::t_match(cfg_["terrain"]);
		}
		if(!cache_.parsed_terrain->is_empty) {
			const t_translation::t_terrain letter = resources::game_map->get_terrain_info(loc).number();
			if(!t_translation::terrain_matches(letter, *cache_.parsed_terrain)) {
				return false;
			}
		}
	}

	//Allow filtering on location ranges
	if(!ignore_xy) {
		if(!loc.matches_range(cfg_["x"], cfg_["y"])) {
			return false;
		}
		//allow filtering by searching a stored variable of locations
		if(cfg_.has_attribute("find_in")) {
			variable_info vi(cfg_["find_in"], false, variable_info::TYPE_CONTAINER);
			if(!vi.is_valid) return false;
			if(vi.explicit_index) {
				if(map_location(vi.as_container(),NULL) != loc) {
					return false;
				}
			} else {
				bool found = false;
				BOOST_FOREACH(const config &cfg, vi.as_array()) {
					if (map_location(cfg, NULL) == loc) {
						found = true;
						break;
					}
				}
				if (!found) return false;
			}
		}
	}
Example #12
0
time_of_day tod_manager::get_time_of_day(int illuminated, const map_location& loc, int n_turn) const
{
	time_of_day res = get_time_of_day_turn(n_turn);

	if(loc.valid()) {
		for(std::vector<area_time_of_day>::const_iterator i = areas_.begin(); i != areas_.end(); ++i) {
			if(i->hexes.count(loc) == 1) {

				VALIDATE(i->times.size(), _("No time of day has been defined."));

				res = i->times[(n_turn-1)%i->times.size()];
				break;
			}
		}
	}

	if(illuminated) {
		res.bonus_modified=illuminated;
		res.lawful_bonus += illuminated;
	}
	return res;
}
Example #13
0
void unit_attack(display * disp, game_board & board,
                 const map_location& a, const map_location& b, int damage,
                 const attack_type& attack, const attack_type* secondary_attack,
                 int swing,std::string hit_text,int drain_amount,std::string att_text, const std::vector<std::string>* extra_hit_sounds)
{
	if(!disp ||disp->video().update_locked() || disp->video().faked() ||
			(disp->fogged(a) && disp->fogged(b)) || preferences::show_combat() == false) {
		return;
	}
	//const unit_map& units = disp->get_units();
	disp->select_hex(map_location::null_location());

	// scroll such that there is at least half a hex spacing around fighters
	disp->scroll_to_tiles(a,b,game_display::ONSCREEN,true,0.5,false);

	log_scope("unit_attack");

	const unit_map::const_iterator att = board.units().find(a);
	assert(att.valid());
	const unit& attacker = *att;

	const unit_map::iterator def = board.find_unit(b);
	assert(def.valid());
	unit &defender = *def;
	int def_hitpoints = defender.hitpoints();

	att->set_facing(a.get_relative_dir(b));
	def->set_facing(b.get_relative_dir(a));
	defender.set_facing(b.get_relative_dir(a));


	unit_animator animator;
	unit_ability_list leaders = attacker.get_abilities("leadership");
	unit_ability_list helpers = defender.get_abilities("resistance");

	std::string text   = number_and_text(damage, hit_text);
	std::string text_2 = number_and_text(abs(drain_amount), att_text);

	unit_animation::hit_type hit_type;
	if(damage >= defender.hitpoints()) {
		hit_type = unit_animation::hit_type::KILL;
	} else if(damage > 0) {
		hit_type = unit_animation::hit_type::HIT;
	}else {
		hit_type = unit_animation::hit_type::MISS;
	}
	animator.add_animation(&attacker, "attack", att->get_location(),
		def->get_location(), damage, true,  text_2,
		(drain_amount >= 0) ? display::rgb(0, 255, 0) : display::rgb(255, 0, 0),
		hit_type, &attack, secondary_attack, swing);

	// note that we take an anim from the real unit, we'll use it later
	const unit_animation *defender_anim = def->anim_comp().choose_animation(*disp,
		def->get_location(), "defend", att->get_location(), damage,
		hit_type, &attack, secondary_attack, swing);
	animator.add_animation(&defender, defender_anim, def->get_location(),
		true,  text , display::rgb(255, 0, 0));

	for (const unit_ability & ability : leaders) {
		if(ability.second == a) continue;
		if(ability.second == b) continue;
		unit_map::const_iterator leader = board.units().find(ability.second);
		assert(leader.valid());
		leader->set_facing(ability.second.get_relative_dir(a));
		animator.add_animation(&*leader, "leading", ability.second,
			att->get_location(), damage, true,  "", 0,
			hit_type, &attack, secondary_attack, swing);
	}
	for (const unit_ability & ability : helpers) {
		if(ability.second == a) continue;
		if(ability.second == b) continue;
		unit_map::const_iterator helper = board.units().find(ability.second);
		assert(helper.valid());
		helper->set_facing(ability.second.get_relative_dir(b));
		animator.add_animation(&*helper, "resistance", ability.second,
			def->get_location(), damage, true,  "", 0,
			hit_type, &attack, secondary_attack, swing);
	}


	animator.start_animations();
	animator.wait_until(0);
	int damage_left = damage;
	bool extra_hit_sounds_played = false;
	while(damage_left > 0 && !animator.would_end()) {
		if(!extra_hit_sounds_played && extra_hit_sounds != nullptr) {
			for (std::string hit_sound : *extra_hit_sounds) {
				sound::play_sound(hit_sound);
			}
			extra_hit_sounds_played = true;
		}

		int step_left = (animator.get_end_time() - animator.get_animation_time() )/50;
		if(step_left < 1) step_left = 1;
		int removed_hp =  damage_left/step_left ;
		if(removed_hp < 1) removed_hp = 1;
		defender.take_hit(removed_hp);
		damage_left -= removed_hp;
		animator.wait_until(animator.get_animation_time_potential() +50);
	}
	animator.wait_for_end();
	// pass the animation back to the real unit
	def->anim_comp().start_animation(animator.get_end_time(), defender_anim, true);
	reset_helpers(&*att, &*def);
	def->set_hitpoints(def_hitpoints);
}
Example #14
0
bool gamemap::on_board(const map_location& loc) const
{
	return loc.valid() && loc.x < w_ && loc.y < h_;
}
pathfind::plain_route pathfind::a_star_search(const map_location& src, const map_location& dst,
                            double stop_at, const cost_calculator *calc, const size_t width,
                            const size_t height,
                            const teleport_map *teleports) {
	//----------------- PRE_CONDITIONS ------------------
	assert(src.valid(width, height));
	assert(dst.valid(width, height));
	assert(calc != NULL);
	assert(stop_at <= calc->getNoPathValue());
	//---------------------------------------------------

	DBG_PF << "A* search: " << src << " -> " << dst << '\n';

	if (calc->cost(dst, 0) >= stop_at) {
		LOG_PF << "aborted A* search because Start or Dest is invalid\n";
		pathfind::plain_route locRoute;
		locRoute.move_cost = int(calc->getNoPathValue());
		return locRoute;
	}

	// increment search_counter but skip the range equivalent to uninitialized
	search_counter += 2;
	if (search_counter - bad_search_counter <= 1u)
		search_counter += 2;

	static std::vector<node> nodes;
	nodes.resize(width * height);  // this create uninitalized nodes

	indexer index(width, height);
	comp node_comp(nodes);

	nodes[index(dst)].g = stop_at + 1;
	nodes[index(src)] = node(0, src, map_location::null_location, dst, true, teleports);

	std::vector<int> pq;
	pq.push_back(index(src));

	while (!pq.empty()) {
		node& n = nodes[pq.front()];

		n.in = search_counter;

		std::pop_heap(pq.begin(), pq.end(), node_comp);
		pq.pop_back();

		if (n.t >= nodes[index(dst)].g) break;

		std::vector<map_location> locs;

		int i;
		if (teleports && !teleports->empty()) {

			std::set<map_location> allowed_teleports;
			teleports->get_adjacents(allowed_teleports, n.curr);

			i = allowed_teleports.size() +6;
			locs = std::vector<map_location>(i);

			std::copy(allowed_teleports.begin(), allowed_teleports.end(), locs.begin() + 6);
		} else
		{ locs = std::vector<map_location>(6); i = 6;}

		get_adjacent_tiles(n.curr, &locs[0]);

		for (; i-- > 0;) {
			if (!locs[i].valid(width, height)) continue;
			if (locs[i] == n.curr) continue;
			node& next = nodes[index(locs[i])];

			double thresh = (next.in - search_counter <= 1u) ? next.g : stop_at + 1;
			// cost() is always >= 1  (assumed and needed by the heuristic)
			if (n.g + 1 >= thresh) continue;
			double cost = n.g + calc->cost(locs[i], n.g);
			if (cost >= thresh) continue;

			bool in_list = next.in == search_counter + 1;

			next = node(cost, locs[i], n.curr, dst, true, teleports);

			if (in_list) {
				std::push_heap(pq.begin(), std::find(pq.begin(), pq.end(), static_cast<int>(index(locs[i]))) + 1, node_comp);
			} else {
				pq.push_back(index(locs[i]));
				std::push_heap(pq.begin(), pq.end(), node_comp);
			}
		}
	}

	pathfind::plain_route route;
	if (nodes[index(dst)].g <= stop_at) {
		DBG_PF << "found solution; calculating it...\n";
		route.move_cost = static_cast<int>(nodes[index(dst)].g);
		for (node curr = nodes[index(dst)]; curr.prev != map_location::null_location; curr = nodes[index(curr.prev)]) {
			route.steps.push_back(curr.curr);
		}
		route.steps.push_back(src);
		std::reverse(route.steps.begin(), route.steps.end());
	} else {
		LOG_PF << "aborted a* search  " << "\n";
		route.move_cost = static_cast<int>(calc->getNoPathValue());
	}

	return route;
}
Example #16
0
bool basic_unit_filter_impl::internal_matches_filter(const unit & u, const map_location& loc, const unit* u2) const
{
	if (!vcfg["name"].blank() && vcfg["name"].t_str() != u.name()) {
		return false;
	}

	if (!vcfg["id"].empty()) {
		std::vector<std::string> id_list = utils::split(vcfg["id"]);
		if (std::find(id_list.begin(), id_list.end(), u.id()) == id_list.end()) {
			return false;
		}
	}

	// Allow 'speaker' as an alternative to id, since people use it so often
	if (!vcfg["speaker"].blank() && vcfg["speaker"].str() != u.id()) {
		return false;
	}

	if (vcfg.has_child("filter_location")) {
		if (vcfg.count_children("filter_location") > 1) {
			FAIL("Encountered multiple [filter_location] children of a standard unit filter. "
				 "This is not currently supported and in all versions of wesnoth would have "
				 "resulted in the later children being ignored. You must use [and] or similar "
				 "to achieve the desired result.");
		}
		terrain_filter filt(vcfg.child("filter_location"), &fc_, use_flat_tod_);
		if (!filt.match(loc)) {
			return false;
		}
	}

	if(vcfg.has_child("filter_side")) {
		if (vcfg.count_children("filter_side") > 1) {
			FAIL("Encountered multiple [filter_side] children of a standard unit filter. "
				 "This is not currently supported and in all versions of wesnoth would have "
				 "resulted in the later children being ignored. You must use [and] or similar "
				 "to achieve the desired result.");
		}
		side_filter filt(vcfg.child("filter_side"), &fc_);
		if(!filt.match(u.side()))
			return false;
	}

	// Also allow filtering on location ranges outside of the location filter
	if (!vcfg["x"].blank() || !vcfg["y"].blank()){
		if(vcfg["x"] == "recall" && vcfg["y"] == "recall") {
			//locations on the map are considered to not be on a recall list
			if (fc_.get_disp_context().map().on_board(loc))
			{
				return false;
			}
		} else if(vcfg["x"].empty() && vcfg["y"].empty()) {
			return false;
		} else if(!loc.matches_range(vcfg["x"], vcfg["y"])) {
			return false;
		}
	}

	// The type could be a comma separated list of types
	if (!vcfg["type"].empty()) {
		std::vector<std::string> types = utils::split(vcfg["type"]);
		if (std::find(types.begin(), types.end(), u.type_id()) == types.end()) {
			return false;
		}
	}

	// Shorthand for all advancements of a given type
	if (!vcfg["type_tree"].empty()) {
		std::set<std::string> types;
		for(const std::string type : utils::split(vcfg["type_tree"])) {
			if(types.count(type)) {
				continue;
			}
			if(const unit_type* ut = unit_types.find(type)) {
				const auto& tree = ut->advancement_tree();
				types.insert(tree.begin(), tree.end());
				types.insert(type);
			}
		}
		if(types.find(u.type_id()) == types.end()) {
			return false;
		}
	}

	// The variation_type could be a comma separated list of types
	if (!vcfg["variation"].empty())
	{
		std::vector<std::string> types = utils::split(vcfg["variation"]);
		if (std::find(types.begin(), types.end(), u.variation()) == types.end()) {
			return false;
		}
	}

	// The has_variation_type could be a comma separated list of types
	if (!vcfg["has_variation"].empty())
	{
		bool match = false;
		// If this unit is a variation itself then search in the base unit's variations.
		const unit_type* const type = u.variation().empty() ? &u.type() : unit_types.find(u.type().base_id());
		assert(type);

		for (const std::string& variation_id : utils::split(vcfg["has_variation"])) {
			if (type->has_variation(variation_id)) {
				match = true;
				break;
			}
		}
		if (!match) return false;
	}

	if (!vcfg["ability"].empty())
	{
		bool match = false;

		for (const std::string& ability_id : utils::split(vcfg["ability"])) {
			if (u.has_ability_by_id(ability_id)) {
				match = true;
				break;
			}
		}
		if (!match) return false;
	}

	if (!vcfg["race"].empty()) {
		std::vector<std::string> races = utils::split(vcfg["race"]);
		if (std::find(races.begin(), races.end(), u.race()->id()) == races.end()) {
			return false;
		}
	}

	if (!vcfg["gender"].blank() && string_gender(vcfg["gender"]) != u.gender()) {
		return false;
	}

	if (!vcfg["side"].empty() && vcfg["side"].to_int(-999) != u.side()) {
		std::vector<std::string> sides = utils::split(vcfg["side"]);
		const std::string u_side = std::to_string(u.side());
		if (std::find(sides.begin(), sides.end(), u_side) == sides.end()) {
			return false;
		}
	}

	// handle statuses list
	if (!vcfg["status"].empty()) {
		bool status_found = false;

		for (const std::string status : utils::split(vcfg["status"])) {
			if(u.get_state(status)) {
				status_found = true;
				break;
			}
		}

		if(!status_found) {
			return false;
		}
	}

	if (vcfg.has_child("has_attack")) {
		const vconfig& weap_filter = vcfg.child("has_attack");
		bool has_weapon = false;
		for(const attack_type& a : u.attacks()) {
			if(a.matches_filter(weap_filter.get_parsed_config())) {
				has_weapon = true;
				break;
			}
		}
		if(!has_weapon) {
			return false;
		}
	} else if (!vcfg["has_weapon"].blank()) {
		std::string weapon = vcfg["has_weapon"];
		bool has_weapon = false;
		for(const attack_type& a : u.attacks()) {
			if(a.id() == weapon) {
				has_weapon = true;
				break;
			}
		}
		if(!has_weapon) {
			return false;
		}
	}

	if (!vcfg["role"].blank() && vcfg["role"].str() != u.get_role()) {
		return false;
	}

	if (!vcfg["ai_special"].blank() && ((vcfg["ai_special"].str() == "guardian") != u.get_state(unit::STATE_GUARDIAN))) {
		return false;
	}

	if (!vcfg["canrecruit"].blank() && vcfg["canrecruit"].to_bool() != u.can_recruit()) {
		return false;
	}

	if (!vcfg["recall_cost"].blank() && vcfg["recall_cost"].to_int(-1) != u.recall_cost()) {
		return false;
	}

	if (!vcfg["level"].blank() && vcfg["level"].to_int(-1) != u.level()) {
		return false;
	}

	if (!vcfg["defense"].blank() && vcfg["defense"].to_int(-1) != u.defense_modifier(fc_.get_disp_context().map().get_terrain(loc))) {
		return false;
	}

	if (!vcfg["movement_cost"].blank() && vcfg["movement_cost"].to_int(-1) != u.movement_cost(fc_.get_disp_context().map().get_terrain(loc))) {
		return false;
	}

	// Now start with the new WML based comparison.
	// If a key is in the unit and in the filter, they should match
	// filter only => not for us
	// unit only => not filtered
	config unit_cfg; // No point in serializing the unit once for each [filter_wml]!
	for (const vconfig& wmlcfg : vcfg.get_children("filter_wml")) {
			config fwml = wmlcfg.get_parsed_config();
			/* Check if the filter only cares about variables.
			   If so, no need to serialize the whole unit. */
			config::all_children_itors ci = fwml.all_children_range();
			if (fwml.all_children_count() == 1 && 
				fwml.attribute_count() == 1 &&
			    ci.front().key == "variables") {
				if (!u.variables().matches(ci.front().cfg))
					return false;
			} else {
				if (unit_cfg.empty())
					u.write(unit_cfg);
				if (!unit_cfg.matches(fwml))
					return false;
			}
	}

	for (const vconfig& vision : vcfg.get_children("filter_vision")) {
		std::set<int> viewers;

		// Use standard side filter
		side_filter ssf(vision, &fc_);
		std::vector<int> sides = ssf.get_teams();
		viewers.insert(sides.begin(), sides.end());

		bool found = false;
		for (const int viewer : viewers) {
			bool fogged = fc_.get_disp_context().teams()[viewer - 1].fogged(loc);
			bool hiding = u.invisible(loc, fc_.get_disp_context());
			bool unit_hidden = fogged || hiding;
			if (vision["visible"].to_bool(true) != unit_hidden) {
				found = true;
				break;
			}
		}
		if (!found) {return false;}
	}

	if (vcfg.has_child("filter_adjacent")) {
		const unit_map& units = fc_.get_disp_context().units();
		map_location adjacent[6];
		get_adjacent_tiles(loc, adjacent);

		for (const vconfig& adj_cfg : vcfg.get_children("filter_adjacent")) {
			int match_count=0;
			unit_filter filt(adj_cfg, &fc_, use_flat_tod_);

			config::attribute_value i_adjacent = adj_cfg["adjacent"];
			std::vector<map_location::DIRECTION> dirs;
			if (i_adjacent.blank()) {
				dirs = map_location::default_dirs();
			} else {
				dirs = map_location::parse_directions(i_adjacent);
			}

			std::vector<map_location::DIRECTION>::const_iterator j, j_end = dirs.end();
			for (j = dirs.begin(); j != j_end; ++j) {
				unit_map::const_iterator unit_itor = units.find(adjacent[*j]);
				if (unit_itor == units.end() || !filt(*unit_itor, u)) {
					continue;
				}
				boost::optional<bool> is_enemy;
				if (!adj_cfg["is_enemy"].blank()) {
					is_enemy = adj_cfg["is_enemy"].to_bool();
				}
				if (!is_enemy || *is_enemy ==
				    fc_.get_disp_context().teams()[u.side() - 1].is_enemy(unit_itor->side())) {
					++match_count;
				}
			}

			static std::vector<std::pair<int,int> > default_counts = utils::parse_ranges("1-6");
			config::attribute_value i_count = adj_cfg["count"];
			if(!in_ranges(match_count, !i_count.blank() ? utils::parse_ranges(i_count) : default_counts)) {
				return false;
			}
		}
	}

	if (!vcfg["find_in"].blank()) {
		// Allow filtering by searching a stored variable of units
		if (const game_data * gd = fc_.get_game_data()) {
			try
			{
				variable_access_const vi = gd->get_variable_access_read(vcfg["find_in"]);
				bool found_id = false;
				for (const config& c : vi.as_array())
				{
					if(c["id"] == u.id())
						found_id = true;
				}
				if(!found_id)
				{
					return false;
				}
			}
			catch(const invalid_variablename_exception&)
			{
				return false;
			}
		}
	}
	if (!vcfg["formula"].blank()) {
		try {
			const unit_callable main(loc,u);
			game_logic::map_formula_callable callable(&main);
			if (u2) {
				std::shared_ptr<unit_callable> secondary(new unit_callable(*u2));
				callable.add("other", variant(secondary.get()));
				// It's not destroyed upon scope exit because the variant holds a reference
			}
			const game_logic::formula form(vcfg["formula"]);
			if(!form.evaluate(callable).as_bool()) {
				return false;
			}
			return true;
		} catch(game_logic::formula_error& e) {
			lg::wml_error() << "Formula error in unit filter: " << e.type << " at " << e.filename << ':' << e.line << ")\n";
			// Formulae with syntax errors match nothing
			return false;
		}
	}

	if (!vcfg["lua_function"].blank()) {
		if (game_lua_kernel * lk = fc_.get_lua_kernel()) {
			bool b = lk->run_filter(vcfg["lua_function"].str().c_str(), u);
			if (!b) return false;
		}
	}

	return true;
}
Example #17
0
void unit_attack(
                 const map_location& a, const map_location& b, int damage,
                 const attack_type& attack, const attack_type* secondary_attack,
		  int swing,std::string hit_text,bool drain,std::string att_text)
{
	game_display* disp = game_display::get_singleton();
	if(!disp ||disp->video().update_locked() || disp->video().faked() ||
			(disp->fogged(a) && disp->fogged(b)) || preferences::show_combat() == false) {
		return;
	}
	unit_map& units = disp->get_units();
	disp->select_hex(map_location::null_location);

	// scroll such that there is at least half a hex spacing around fighters
	disp->scroll_to_tiles(a,b,game_display::ONSCREEN,true,0.5,false);

	log_scope("unit_attack");

	const unit_map::iterator att = units.find(a);
	assert(att != units.end());
	unit& attacker = *att;

	const unit_map::iterator def = units.find(b);
	assert(def != units.end());
	unit &defender = *def;
	int def_hitpoints = defender.hitpoints();

	att->set_facing(a.get_relative_dir(b));
	def->set_facing(b.get_relative_dir(a));
	defender.set_facing(b.get_relative_dir(a));


	unit_animator animator;
	unit_ability_list leaders = attacker.get_abilities("leadership");
	unit_ability_list helpers = defender.get_abilities("resistance");

	std::string text ;
	if(damage) text = lexical_cast<std::string>(damage);
	if(!hit_text.empty()) {
		text.insert(text.begin(),hit_text.size()/2,' ');
		text = text + "\n" + hit_text;
	}

	std::string text_2 ;
	if(drain && damage) text_2 = lexical_cast<std::string>(std::min<int>(damage,defender.hitpoints())/2);
	if(!att_text.empty()) {
		text_2.insert(text_2.begin(),att_text.size()/2,' ');
		text_2 = text_2 + "\n" + att_text;
	}

	unit_animation::hit_type hit_type;
	if(damage >= defender.hitpoints()) {
		hit_type = unit_animation::KILL;
	} else if(damage > 0) {
		hit_type = unit_animation::HIT;
	}else {
		hit_type = unit_animation::MISS;
	}
	animator.add_animation(&attacker, "attack", att->get_location(),
		def->get_location(), damage, true,  text_2,
		display::rgb(0, 255, 0), hit_type, &attack, secondary_attack,
		swing);

	// note that we take an anim from the real unit, we'll use it later
	const unit_animation *defender_anim = def->choose_animation(*disp,
		def->get_location(), "defend", att->get_location(), damage,
		hit_type, &attack, secondary_attack, swing);
	animator.add_animation(&defender, defender_anim, def->get_location(),
		true,  text , display::rgb(255, 0, 0));

	for (std::vector<std::pair<const config *, map_location> >::iterator itor = leaders.cfgs.begin(); itor != leaders.cfgs.end(); ++itor) {
		if(itor->second == a) continue;
		if(itor->second == b) continue;
		unit_map::iterator leader = units.find(itor->second);
		assert(leader != units.end());
		leader->set_facing(itor->second.get_relative_dir(a));
		animator.add_animation(&*leader, "leading", itor->second,
			att->get_location(), damage, true,  "", 0,
			hit_type, &attack, secondary_attack, swing);
	}
	for (std::vector<std::pair<const config *, map_location> >::iterator itor = helpers.cfgs.begin(); itor != helpers.cfgs.end(); ++itor) {
		if(itor->second == a) continue;
		if(itor->second == b) continue;
		unit_map::iterator helper = units.find(itor->second);
		assert(helper != units.end());
		helper->set_facing(itor->second.get_relative_dir(b));
		animator.add_animation(&*helper, "resistance", itor->second,
			def->get_location(), damage, true,  "", 0,
			hit_type, &attack, secondary_attack, swing);
	}


	animator.start_animations();
	animator.wait_until(0);
	int damage_left = damage;
	while(damage_left > 0 && !animator.would_end()) {
		int step_left = (animator.get_end_time() - animator.get_animation_time() )/50;
		if(step_left < 1) step_left = 1;
		int removed_hp =  damage_left/step_left ;
		if(removed_hp < 1) removed_hp = 1;
		defender.take_hit(removed_hp);
		damage_left -= removed_hp;
		animator.wait_until(animator.get_animation_time_potential() +50);
	}
	animator.wait_for_end();
	// pass the animation back to the real unit
	def->start_animation(animator.get_end_time(), defender_anim, true);
	reset_helpers(&*att, &*def);
	def->set_hitpoints(def_hitpoints);
}
map_location map_location::legacy_difference(const map_location &a) const
{
	return legacy_sum(a.legacy_negation());
}
	bool on_map(const map_location& loc) const
	{
		return loc.wml_x() >= 0 && loc.wml_x() < total_width() &&  loc.wml_y() >= 0 && loc.wml_y() < total_height();
	}
Example #20
0
void gamemap::overlay_impl(
		// const but changed via set_terrain
		const t_translation::ter_map& m1,
		starting_positions& m1_st,
		const t_translation::ter_map& m2,
		const starting_positions& m2_st,
		std::function<void (const map_location&, const t_translation::terrain_code&, terrain_type_data::merge_mode, bool)> set_terrain,
		map_location loc,
		const std::vector<overlay_rule>& rules,
		bool m_is_odd,
		bool ignore_special_locations)
{
	int xpos = loc.wml_x();
	int ypos = loc.wml_y();

	const int xstart = std::max<int>(0, -xpos);
	const int xend = std::min<int>(m2.w, m1.w -xpos);
	const int xoffset = xpos;

	const int ystart_even = std::max<int>(0, -ypos);
	const int yend_even = std::min<int>(m2.h, m1.h - ypos);
	const int yoffset_even = ypos;

	const int ystart_odd = std::max<int>(0, -ypos +(xpos & 1) -(m_is_odd ? 1 : 0));
	const int yend_odd = std::min<int>(m2.h, m1.h - ypos +(xpos & 1) -(m_is_odd ? 1 : 0));
	const int yoffset_odd = ypos -(xpos & 1) + (m_is_odd ? 1 : 0);

	for(int x1 = xstart; x1 != xend; ++x1) {
		int ystart, yend, yoffset;
		if(x1 & 1) {
			ystart = ystart_odd , yend = yend_odd , yoffset = yoffset_odd;
		}
		else {
			ystart = ystart_even, yend = yend_even, yoffset = yoffset_even;
		}
		for(int y1 = ystart; y1 != yend; ++y1) {
			const int x2 = x1 + xoffset;
			const int y2 = y1 + yoffset;

			const t_translation::terrain_code t = m2.get(x1,y1);
			const t_translation::terrain_code current = m1.get(x2, y2);

			if(t == t_translation::FOGGED || t == t_translation::VOID_TERRAIN) {
				continue;
			}

			// See if there is a matching rule
			const overlay_rule* rule = nullptr;
			for(const overlay_rule& current_rule : rules)
			{
				if(!current_rule.old_.empty() && !t_translation::terrain_matches(current, current_rule.old_)) {
					continue;
				}
				if(!current_rule.new_.empty() && !t_translation::terrain_matches(t, current_rule.new_)) {
					continue;
				}
				rule = &current_rule;
				break;
			}

			if (!rule) {
				set_terrain(map_location(x2, y2, wml_loc()), t, terrain_type_data::BOTH, false);
			}
			else if(!rule->use_old_) {
				set_terrain(map_location(x2, y2, wml_loc()), rule->terrain_ ? *rule->terrain_ : t , rule->mode_, rule->replace_if_failed_);
			}
		}
	}

	if (!ignore_special_locations) {
		for(auto& pair : m2_st.left) {

			int x = pair.second.wml_x();
			int y = pair.second.wml_y();
			if(x & 1) {
				if(x < xstart || x >= xend || y < ystart_odd || y >= yend_odd) {
					continue;
				}
			}
			else {
				if(x < xstart || x >= xend || y < ystart_even || y >= yend_even) {
					continue;
				}
			}
			int x_new = x + xoffset;
			int y_new = y + ((x & 1 ) ? yoffset_odd : yoffset_even);
			map_location pos_new = map_location(x_new, y_new, wml_loc());

			m1_st.left.erase(pair.first);
			m1_st.insert(starting_positions::value_type(pair.first, t_translation::coordinate(pos_new.x, pos_new.y)));
		}
	}
}
	bool on_map_noborder(const map_location& loc) const
	{
		return loc.wml_x() > 0 && loc.wml_x() < total_width() - 1 &&  loc.wml_y() > 0 && loc.wml_y() < total_height() - 1;
	}