Пример #1
0
static std::shared_ptr<unit_filter_abstract_impl> construct(const vconfig & vcfg, const filter_context & fc, bool flat_tod)
{
	if (vcfg.empty()) {
		return std::make_shared<null_unit_filter_impl> (fc);
	}
	if (vcfg.get_config().attribute_count() == 1 && vcfg.get_config().all_children_count() == 0 && vcfg.has_attribute("limit")) {
		return std::make_shared<null_unit_filter_impl> (fc);
	}
	return std::make_shared<basic_unit_filter_impl>(vcfg, fc, flat_tod);
	//TODO: Add more efficient implementations for special cases
}
Пример #2
0
/**
 * Updates *this based on @a vcfg.
 * This corresponds to what can appear in [set_menu_item].
 */
void wml_menu_item::update(const vconfig & vcfg)
{
	const bool old_use_hotkey = use_hotkey_;
	// Tracks whether or not the hotkey has been updated.
	bool hotkey_updated = false;

	if ( vcfg.has_attribute("image") )
		image_ = vcfg["image"].str();

	if ( vcfg.has_attribute("description") ) {
		description_ = vcfg["description"].t_str();
		hotkey_updated = true;
	}

	if ( vcfg.has_attribute("needs_select") )
		needs_select_ = vcfg["needs_select"].to_bool();

	if ( const vconfig & child = vcfg.child("show_if") ) {
		show_if_ = child;
		show_if_.make_safe();
	}

	if ( const vconfig & child = vcfg.child("filter_location") ) {
		filter_location_ = child;
		filter_location_.make_safe();
	}

	if ( const vconfig & child = vcfg.child("default_hotkey") ) {
		default_hotkey_ = child.get_parsed_config();
		hotkey_updated = true;
	}

	if ( vcfg.has_attribute("use_hotkey") ) {
		const config::attribute_value & use_hotkey_av = vcfg["use_hotkey"];

		use_hotkey_ = use_hotkey_av.to_bool(true);
		use_wml_menu_ = use_hotkey_av.str() != "only";
	}

	if ( const vconfig & cmd = vcfg.child("command") ) {
		const bool delayed = cmd["delayed_variable_substitution"].to_bool(true);
		update_command(delayed ? cmd.get_config() : cmd.get_parsed_config());
	}


	// Update the registered hotkey?

	if ( use_hotkey_ && !old_use_hotkey )
		// The hotkey needs to be enabled.
		hotkey::add_wml_hotkey(hotkey_id_, description_, default_hotkey_);

	else if ( use_hotkey_ && hotkey_updated )
		// The hotkey needs to be updated.
		hotkey::add_wml_hotkey(hotkey_id_, description_, default_hotkey_);

	else if ( !use_hotkey_ && old_use_hotkey )
		// The hotkey needs to be disabled.
		hotkey::remove_wml_hotkey(hotkey_id_);
}
Пример #3
0
void handle_event_command(const std::string &cmd,
                          const queued_event &event_info, const vconfig &cfg)
{
	log_scope2(log_engine, "handle_event_command");
	LOG_NG << "handling command '" << cmd << "' from "
		<< (cfg.is_volatile()?"volatile ":"") << "cfg 0x"
		<< std::hex << std::setiosflags(std::ios::uppercase)
		<< reinterpret_cast<uintptr_t>(&cfg.get_config()) << std::dec << "\n";

	if (!resources::lua_kernel->run_wml_action(cmd, cfg, event_info))
	{
		ERR_NG << "Couldn't find function for wml tag: "<< cmd <<"\n";
	}

	DBG_NG << "done handling command...\n";
}
Пример #4
0
	/**
	 * Implements the lifting and resetting of fog via WML.
	 * Keeping affect_normal_fog as false causes only the fog override to be affected.
	 * Otherwise, fog lifting will be implemented similar to normal sight (cannot be
	 * individually reset and ends at the end of the turn), and fog resetting will, in
	 * addition to removing overrides, extend the specified teams' normal fog to all
	 * hexes.
	 */
	void toggle_fog(const bool clear, const vconfig& cfg, const bool affect_normal_fog=false)
	{
		// Filter the sides.
		const vconfig &ssf = cfg.child("filter_side");
		const side_filter s_filter(ssf.null() ? vconfig::empty_vconfig() : ssf, resources::filter_con);
		const std::vector<int> sides = s_filter.get_teams();

		// Filter the locations.
		std::set<map_location> locs;
		const terrain_filter t_filter(cfg, resources::filter_con);
		t_filter.get_locations(locs, true);

		// Loop through sides.
		BOOST_FOREACH(const int &side_num, sides)
		{
			team &t = (*resources::teams)[side_num-1];
			if ( !clear )
			{
				// Extend fog.
				t.remove_fog_override(locs);
				if ( affect_normal_fog )
					t.refog();
			}
			else if ( !affect_normal_fog )
				// Force the locations clear of fog.
				t.add_fog_override(locs);
			else
				// Simply clear fog from the locations.
				BOOST_FOREACH(const map_location &hex, locs)
					t.clear_fog(hex);
		}
Пример #5
0
void verify_and_set_global_variable(const vconfig &pcfg)
{
	bool valid = true;
	if (!pcfg.has_attribute("to_global")) {
		LOG_PERSIST << "Error: [set_global_variable] missing required attribute \"from_global\"";
		valid = false;
	}
	if (!pcfg.has_attribute("from_local")) {
		LOG_PERSIST << "Warning: [set_global_variable] missing attribute \"to_local\", global variable will be cleared";
	}
	// TODO: allow for global namespace.
	if (!pcfg.has_attribute("namespace")) {
		LOG_PERSIST << "Error: [set_global_variable] missing attribute \"namespace\" and no global namespace provided.";
		valid = false;
	}
	if (network::nconnections() != 0) {
		if (!pcfg.has_attribute("side")) {
			LOG_PERSIST << "Error: [set_global_variable] missing attribute \"side\" required in multiplayer context.";
			valid = false;
		} else {
			config::attribute_value pcfg_side = pcfg["side"];
			int side = pcfg_side;
			//Check side matching only if the side is not "global".
			if (pcfg_side.str() != "global") {
				//Ensure that the side is valid.
				if (unsigned(side-1) > resources::teams->size()) {
					LOG_PERSIST << "Error: [set_global_variable] attribute \"side\" specifies invalid side number.";
					valid = false;
				} else {
					//Set the variable only if it is meant for a side we control
					valid = (*resources::teams)[side - 1].is_local();
				}
			}
		}
	}
	if (valid)
	{
		persist_context &ctx = resources::persist->get_context((pcfg["namespace"]));
		if (ctx.valid()) {
			set_global_variable(ctx,pcfg);
		} else {
			LOG_PERSIST << "Error: [set_global_variable] attribute \"namespace\" is not valid.";
		}
	}
}
Пример #6
0
void verify_and_get_global_variable(const vconfig &pcfg)
{
	bool valid = true;
	if (!pcfg.has_attribute("from_global")) {
		LOG_PERSIST << "Error: [get_global_variable] missing required attribute \"from_global\"";
		valid = false;
	}
	if (!pcfg.has_attribute("to_local")) {
		LOG_PERSIST << "Error: [get_global_variable] missing required attribute \"to_local\"";
		valid = false;
	}
	// TODO: allow for global namespace.
	if (!pcfg.has_attribute("namespace")) {
		LOG_PERSIST << "Error: [get_global_variable] missing attribute \"namespace\" and no global namespace provided.";
		valid = false;
	}
	if (network::nconnections() != 0) {
		if (!pcfg.has_attribute("side")) {
			LOG_PERSIST << "Error: [get_global_variable] missing attribute \"side\" required in multiplayer context.";
			valid = false;
		}
		else {
			DBG_PERSIST << "verify_and_get_global_variable with from_global=" << pcfg["from_global"] << " from side " << pcfg["side"] << "\n";
			config::attribute_value pcfg_side = pcfg["side"];
			int side = pcfg_side.str() == "global" ? resources::controller->current_side() : pcfg_side.to_int();
			if (unsigned (side - 1) >= resources::teams->size()) {
				LOG_PERSIST << "Error: [get_global_variable] attribute \"side\" specifies invalid side number." << "\n";
				valid = false;
			} 
			else 
			{
			}
			DBG_PERSIST <<  "end verify_and_get_global_variable with from_global=" << pcfg["from_global"] << " from side " << pcfg["side"] << "\n";
		}
	}
	if (valid)
	{
		persist_context &ctx = resources::persist->get_context((pcfg["namespace"]));
		if (ctx.valid()) {
			get_global_variable(ctx,pcfg);
		} else {
			LOG_PERSIST << "Error: [get_global_variable] attribute \"namespace\" is not valid.";
		}
	}
}
Пример #7
0
bool have_location(const vconfig& cfg)
{
    std::set<map_location> res;
    terrain_filter(cfg, resources::filter_con).get_locations(res);

    std::vector<std::pair<int,int> > counts = cfg.has_attribute("count")
            ? utils::parse_ranges(cfg["count"]) : default_counts;
    return in_ranges<int>(res.size(), counts);
}
Пример #8
0
void verify_and_set_global_variable(const vconfig &pcfg)
{
	bool valid = true;
	if (!pcfg.has_attribute("to_global")) {
		ERR_PERSIST << "[set_global_variable] missing required attribute \"to_global\"";
		valid = false;
	}
	if (!pcfg.has_attribute("from_local")) {
		LOG_PERSIST << "Warning: [set_global_variable] missing attribute \"from_local\", global variable will be cleared";
	}
	// TODO: allow for global namespace.
	if (!pcfg.has_attribute("namespace")) {
		ERR_PERSIST << "[set_global_variable] missing attribute \"namespace\" and no global namespace provided.";
		valid = false;
	}
	if (resources::controller->is_networked_mp()) {
		config::attribute_value pcfg_side = pcfg["side"];
		int side = pcfg_side;
		//Check side matching only if the side is not "global" or empty.
		if (pcfg_side.str() != "global" && !pcfg_side.empty()) {
			//Ensure that the side is valid.
			if (unsigned(side-1) > resources::gameboard->teams().size()) {
				ERR_PERSIST << "[set_global_variable] attribute \"side\" specifies invalid side number.";
				valid = false;
			} else if (resources::gameboard->teams()[side - 1].is_empty()) {
				LOG_PERSIST << "[set_global_variable] attribute \"side\" specifies a null-controlled side number.";
				valid = false;
			} else {
				//Set the variable only if it is meant for a side we control
				valid = resources::gameboard->teams()[side - 1].is_local();
			}
		}
	}
	if (valid)
	{
		persist_context &ctx = resources::persist->get_context((pcfg["namespace"]));
		if (ctx.valid()) {
			set_global_variable(ctx,pcfg);
		} else {
			LOG_PERSIST << "Error: [set_global_variable] attribute \"namespace\" is not valid.";
		}
	}
}
Пример #9
0
bool matches_special_filter(const config &cfg, const vconfig& filter)
{
	if (!cfg) {
		WRN_NG << "attempt to filter attack for an event with no attack data." << std::endl;
		// better to not execute the event (so the problem is more obvious)
		return false;
	}
	const attack_type attack(cfg);
	return attack.matches_filter(filter.get_parsed_config());
}
Пример #10
0
	basic_unit_filter_impl(const vconfig & vcfg, const filter_context & fc, bool flat_tod)
		: fc_(fc)
		, vcfg(vcfg)
		, use_flat_tod_(flat_tod)
		, cond_children_()
		, cond_child_types_()
	{
		// Handle [and], [or], and [not] with in-order precedence
		vconfig::all_children_iterator cond = vcfg.ordered_begin();
		vconfig::all_children_iterator cond_end = vcfg.ordered_end();
		while(cond != cond_end)
		{
			const std::string& cond_name = cond.get_key();
			conditional::TYPE type;
			if(type.parse(cond_name)) {
				const vconfig& cond_filter = cond.get_child();

				cond_children_.push_back(unit_filter(cond_filter, &fc_, use_flat_tod_));
				cond_child_types_.push_back(type);
			}
			else {
				static const int NUM_VALID_TAGS = 5;
				static const std::string valid_tags[NUM_VALID_TAGS] = {
					"filter_vision",
					"filter_adjacent",
					"filter_location",
					"filter_side",
					"filter_wml",
				};
				static const std::string* const valid_tags_end = valid_tags + NUM_VALID_TAGS;

				if (std::find(valid_tags, valid_tags_end, cond_name) == valid_tags_end){
					std::stringstream errmsg;
					errmsg << "encountered a child [" << cond_name << "] of a standard unit filter, it is being ignored";
					DBG_CF << errmsg.str() << std::endl; //FAIL( errmsg.str() );
				}

			}
			++cond;
		}
		this->vcfg.make_safe();
	}
Пример #11
0
pathfind::teleport_group::teleport_group(const vconfig& cfg, bool reversed) : cfg_(cfg.get_config()), reversed_(reversed), id_()
{
	assert(cfg_.child_count("source") == 1);
	assert(cfg_.child_count("target") == 1);
	assert(cfg_.child_count("filter") == 1);
	if (cfg["id"].empty()) {
		id_ = resources::tunnels->next_unique_id();
	} else {
		id_ = cfg["id"].str();
		if (reversed_) // Differentiate the reverse tunnel from the forward one
			id_ += reversed_suffix;
	}
}
Пример #12
0
void verify_and_clear_global_variable(const vconfig &pcfg)
{
	bool valid = true;
	if (!pcfg.has_attribute("global")) {
		ERR_PERSIST << "[clear_global_variable] missing required attribute \"from_global\"";
		valid = false;
	}
	if (!pcfg.has_attribute("namespace")) {
		ERR_PERSIST << "[clear_global_variable] missing attribute \"namespace\" and no global namespace provided.";
		valid = false;
	}
	if (network::nconnections() != 0) {
		config::attribute_value pcfg_side = pcfg["side"];
		const int side = pcfg_side.to_int();
		//Check side matching only if the side is not "global" or empty.
		if (pcfg_side.str() != "global" && !pcfg_side.empty()) {
			//Ensure that the side is valid.
			if (unsigned(side-1) > resources::teams->size()) {
				ERR_PERSIST << "[clear_global_variable] attribute \"side\" specifies invalid side number.";
				valid = false;
			} else if ((*resources::teams)[side - 1].is_empty()) {
				LOG_PERSIST << "[clear_global_variable] attribute \"side\" specifies a null-controlled side number.";
				valid = false;
			} else {
				//Clear the variable only if it is meant for a side we control
				valid = (*resources::teams)[side - 1].is_local();
			}
		}
	}
	if (valid)
	{
		persist_context &ctx = resources::persist->get_context((pcfg["namespace"]));
		if (ctx.valid()) {
			clear_global_variable(ctx,pcfg);
		} else {
			LOG_PERSIST << "Error: [clear_global_variable] attribute \"namespace\" is not valid.";
		}
	}
}
Пример #13
0
void verify_and_get_global_variable(const vconfig &pcfg)
{
	bool valid = true;
	if (!pcfg.has_attribute("from_global")) {
		ERR_PERSIST << "[get_global_variable] missing required attribute \"from_global\"";
		valid = false;
	}
	if (!pcfg.has_attribute("to_local")) {
		ERR_PERSIST << "[get_global_variable] missing required attribute \"to_local\"";
		valid = false;
	}
	// TODO: allow for global namespace.
	if (!pcfg.has_attribute("namespace")) {
		ERR_PERSIST << "[get_global_variable] missing attribute \"namespace\"";
		valid = false;
	}
	if (resources::controller->is_networked_mp()) {
			DBG_PERSIST << "verify_and_get_global_variable with from_global=" << pcfg["from_global"] << " from side " << pcfg["side"] << "\n";
			config::attribute_value pcfg_side = pcfg["side"];
			int side = (pcfg_side.str() == "global" || pcfg_side.empty()) ? resources::controller->current_side() : pcfg_side.to_int();
			if (unsigned (side - 1) >= resources::gameboard->teams().size()) {
				ERR_PERSIST << "[get_global_variable] attribute \"side\" specifies invalid side number." << "\n";
				valid = false;
			}
			DBG_PERSIST <<  "end verify_and_get_global_variable with from_global=" << pcfg["from_global"] << " from side " << pcfg["side"] << "\n";
	}
	if (valid)
	{
		persist_context &ctx = resources::persist->get_context((pcfg["namespace"]));
		if (ctx.valid()) {
			get_global_variable(ctx,pcfg);
		} else {
			LOG_PERSIST << "Error: [get_global_variable] attribute \"namespace\" is not valid.";
		}
	}
}
Пример #14
0
/**
 * Determines if @a un_it matches @a filter. If the filter is not empty,
 * the unit is required to additionally match the unit that was supplied
 * when this was constructed.
 */
bool entity_location::matches_unit_filter(const unit_map::const_iterator & un_it,
                                          const vconfig & filter) const
{
	if ( !un_it.valid() )
		return false;

	if ( filter.empty() )
		// Skip the check for un_it matching *this.
		return true;

	// Filter the unit at the filter location (should be the unit's
	// location if no special filter location was specified).
	return unit_filter(filter).matches(*un_it, filter_loc_)  &&
	       matches_unit(un_it);
}
Пример #15
0
bool have_unit(const vconfig& cfg)
{
    if(resources::units == nullptr) {
        return false;
    }
    std::vector<std::pair<int,int> > counts = cfg.has_attribute("count")
            ? utils::parse_ranges(cfg["count"]) : default_counts;
    int match_count = 0;
    const unit_filter ufilt(cfg, resources::filter_con);
    for(const unit &i : *resources::units) {
        if(i.hitpoints() > 0 && ufilt(i)) {
            ++match_count;
            if(counts == default_counts) {
                // by default a single match is enough, so avoid extra work
                break;
            }
        }
    }
    if(cfg["search_recall_list"].to_bool()) {
        for(const team& team : resources::gameboard->teams()) {
            if(counts == default_counts && match_count) {
                break;
            }
            for(size_t t = 0; t < team.recall_list().size(); ++t) {
                if(counts == default_counts && match_count) {
                    break;
                }
                scoped_recall_unit auto_store("this_unit", team.save_id(), t);
                if(ufilt(*team.recall_list()[t])) {
                    ++match_count;
                }
            }
        }
    }
    return in_ranges(match_count, counts);
}
Пример #16
0
void wml_animation_internal(unit_animator &animator, const vconfig &cfg, const map_location &default_location)
{
	unit_const_ptr u;

	unit_map::const_iterator u_it = resources::units->find(default_location);
	if (u_it.valid()) {
		u = u_it.get_shared_ptr();
	}

	// Search for a valid unit filter,
	// and if we have one, look for the matching unit
	vconfig filter = cfg.child("filter");
	if(!filter.null()) {
		const unit_filter ufilt(filter, resources::filter_con);
		u = ufilt.first_match_on_map();
	}

	// We have found a unit that matches the filter
	if (u && !resources::screen->fogged(u->get_location()))
	{
		attack_type *primary = nullptr;
		attack_type *secondary = nullptr;
		Uint32 text_color;
		unit_animation::hit_type hits=  unit_animation::hit_type::INVALID;
		std::vector<attack_type> attacks = u->attacks();
		std::vector<attack_type>::iterator itor;
		std::unique_ptr<attack_type> dummy_primary;
		std::unique_ptr<attack_type> dummy_secondary;

		// death and victory animations are handled here because usually
		// the code iterates through all the unit's attacks
		// but in these two specific cases we need to create dummy attacks
		// to fire correctly certain animations
		// this is especially evident with the Wose's death animations
		if (cfg["flag"] == "death" || cfg["flag"] == "victory") {
			filter = cfg.child("primary_attack");
			if(!filter.null()) {
				dummy_primary.reset(new attack_type(filter.get_config()));
				primary = dummy_primary.get();
			}
			filter = cfg.child("secondary_attack");
			if(!filter.null()) {
				dummy_secondary.reset(new attack_type(filter.get_config()));
				secondary = dummy_secondary.get();
			}
		}

		else {
			filter = cfg.child("primary_attack");
			if(!filter.null()) {
				for(itor = attacks.begin(); itor != attacks.end(); ++itor){
					if(itor->matches_filter(filter.get_parsed_config())) {
						primary = &*itor;
						break;
					}
				}
			}

			filter = cfg.child("secondary_attack");
			if(!filter.null()) {
				for(itor = attacks.begin(); itor != attacks.end(); ++itor){
					if(itor->matches_filter(filter.get_parsed_config())) {
						secondary = &*itor;
						break;
					}
				}
			}
		}

		if(cfg["hits"] == "yes" || cfg["hits"] == "hit") {
			hits = unit_animation::hit_type::HIT;
		}
		if(cfg["hits"] == "no" || cfg["hits"] == "miss") {
			hits = unit_animation::hit_type::MISS;
		}
		if( cfg["hits"] == "kill" ) {
			hits = unit_animation::hit_type::KILL;
		}
		if(cfg["red"].empty() && cfg["green"].empty() && cfg["blue"].empty()) {
			text_color = display::rgb(0xff,0xff,0xff);
		} else {
			text_color = display::rgb(cfg["red"], cfg["green"], cfg["blue"]);
		}
		resources::screen->scroll_to_tile(u->get_location(), game_display::ONSCREEN, true, false);
		vconfig t_filter = cfg.child("facing");
		map_location secondary_loc = map_location::null_location();
		if(!t_filter.empty()) {
			terrain_filter filter(t_filter, resources::filter_con);
			std::set<map_location> locs;
			filter.get_locations(locs);
			if (!locs.empty() && u->get_location() != *locs.begin()) {
				map_location::DIRECTION dir =u->get_location().get_relative_dir(*locs.begin());
				u->set_facing(dir);
				secondary_loc = u->get_location().get_direction(dir);
			}
		}
		config::attribute_value text = u->gender() == unit_race::FEMALE ? cfg["female_text"] : cfg["male_text"];
		if(text.blank()) {
			text = cfg["text"];
		}
		animator.add_animation(&*u, cfg["flag"], u->get_location(),
			secondary_loc, cfg["value"], cfg["with_bars"].to_bool(),
			text.str(), text_color, hits, primary, secondary,
			cfg["value_second"]);
	}
	const vconfig::child_list sub_anims = cfg.get_children("animate");
	vconfig::child_list::const_iterator anim_itor;
	for(anim_itor = sub_anims.begin(); anim_itor != sub_anims.end();++anim_itor) {
		wml_animation_internal(animator, *anim_itor);
	}

}
Пример #17
0
void unit_filter_compound::fill(vconfig cfg)
	{
		const config& literal = cfg.get_config();

		//optimisation
		if(literal.empty()) { return; }

		create_attribute(literal["name"],
			[](const config::attribute_value& c) { return c.t_str(); },
			[](const t_string& str, const unit_filter_args& args) { return str == args.u.name(); }
		);

		create_attribute(literal["id"],
			[](const config::attribute_value& c) { return utils::split(c.str()); },
			[](const std::vector<std::string>& id_list, const unit_filter_args& args)
			{
				return std::find(id_list.begin(), id_list.end(), args.u.id()) != id_list.end();
			}
		);

		create_attribute(literal["speaker"],
			[](const config::attribute_value& c) { return c.str(); },
			[](const std::string& speaker, const unit_filter_args& args)
			{
				return speaker == args.u.id();
			}
		);

		create_attribute(literal["type"],
			[](const config::attribute_value& c) { return utils::split(c.str()); },
			[](const std::vector<std::string>& types, const unit_filter_args& args)
			{
				return std::find(types.begin(), types.end(), args.u.type_id()) != types.end();
			}
		);

		create_attribute(literal["type_adv_tree"],
			[](const config::attribute_value& c) { return utils::split(c.str()); },
			[](const std::vector<std::string>& types, const unit_filter_args& args)
			{
				std::set<std::string> types_expanded;
				for(const std::string& type : types) {
					if(types_expanded.count(type)) {
						continue;
					}
					if(const unit_type* ut = unit_types.find(type)) {
						const auto& tree = ut->advancement_tree();
						types_expanded.insert(tree.begin(), tree.end());
						types_expanded.insert(type);
					}
				}
				return types_expanded.find(args.u.type_id()) != types_expanded.end();
			}
		);

		create_attribute(literal["variation"],
			[](const config::attribute_value& c) { return utils::split(c.str()); },
			[](const std::vector<std::string>& types, const unit_filter_args& args)
			{
				return std::find(types.begin(), types.end(), args.u.variation()) != types.end();
			}
		);

		create_attribute(literal["has_variation"],
			[](const config::attribute_value& c) { return utils::split(c.str()); },
			[](const std::vector<std::string>& types, const unit_filter_args& args)
			{
				// If this unit is a variation itself then search in the base unit's variations.
				const unit_type* const type = args.u.variation().empty() ? &args.u.type() : unit_types.find(args.u.type().base_id());
				assert(type);

				for(const std::string& variation_id : types) {
					if (type->has_variation(variation_id)) {
						return true;
					}
				}
				return false;
			}
		);

		create_attribute(literal["ability"],
			[](const config::attribute_value& c) { return utils::split(c.str()); },
			[](const std::vector<std::string>& abilities, const unit_filter_args& args)
			{
				for(const std::string& ability_id : abilities) {
					if (args.u.has_ability_by_id(ability_id)) {
						return true;
					}
				}
				return false;
			}
		);

		create_attribute(literal["ability_type"],
			[](const config::attribute_value& c) { return utils::split(c.str()); },
			[](const std::vector<std::string>& abilities, const unit_filter_args& args)
			{
				for(const std::string& ability : abilities) {
					if (args.u.has_ability_type(ability)) {
						return true;
					}
				}
				return false;
			}
		);

		create_attribute(literal["ability_type_active"],
			[](const config::attribute_value& c) { return utils::split(c.str()); },
			[](const std::vector<std::string>& abilities, const unit_filter_args& args)
			{
				for(const std::string& ability : abilities) {
					if (!args.u.get_abilities(ability, args.loc).empty()) {
						return true;
					}
				}
				return false;
			}
		);

		create_attribute(literal["trait"],
			[](const config::attribute_value& c)
			{
				auto res = utils::split(c.str());
				std::sort(res.begin(), res.end());
				return res;

			},
			[](const std::vector<std::string>& check_traits, const unit_filter_args& args)
			{

				std::vector<std::string> have_traits = args.u.get_traits_list();
				std::vector<std::string> isect;
				std::sort(have_traits.begin(), have_traits.end());
				std::set_intersection(check_traits.begin(), check_traits.end(), have_traits.begin(), have_traits.end(), std::back_inserter(isect));
				return !isect.empty();
			}
		);

		create_attribute(literal["race"],
			[](const config::attribute_value& c) { return utils::split(c.str()); },
			[](const std::vector<std::string>& races, const unit_filter_args& args)
			{
				return std::find(races.begin(), races.end(), args.u.race()->id()) != races.end();
			}
		);

		create_attribute(literal["gender"],
			[](const config::attribute_value& c) { return string_gender(c.str()); },
			[](unit_race::GENDER gender, const unit_filter_args& args)
			{
				return gender == args.u.gender();
			}
		);

		create_attribute(literal["side"],
			[](const config::attribute_value& c)
			{
				std::vector<int> res;
				for(const std::string& s : utils::split(c.str())) {
					res.push_back(std::stoi(s));
				}
				return res;
			},
			[](const std::vector<int>& sides, const unit_filter_args& args)
			{
				return std::find(sides.begin(), sides.end(), args.u.side()) != sides.end();
			}
		);

		create_attribute(literal["status"],
			[](const config::attribute_value& c) { return utils::split(c.str()); },
			[](const std::vector<std::string>& statuses, const unit_filter_args& args)
			{
				for(const std::string& status : statuses) {
					if (args.u.get_state(status)) {
						return true;
					}
				}
				return false;
			}
		);

		create_attribute(literal["has_weapon"],
			[](const config::attribute_value& c) { return c.str(); },
			[](const std::string& weapon, const unit_filter_args& args)
			{

				for(const attack_type& a : args.u.attacks()) {
					if(a.id() == weapon) {
						return true;
					}
				}
				return false;
			}
		);

		create_attribute(literal["role"],
			[](const config::attribute_value& c) { return c.str(); },
			[](const std::string& role, const unit_filter_args& args)
			{
				return args.u.get_role() == role;
			}
		);

		create_attribute(literal["ai_special"],
			[](const config::attribute_value& c) { return c.str(); },
			[](const std::string& ai_special, const unit_filter_args& args)
			{
				return (ai_special == "guardian") == args.u.get_state(unit::STATE_GUARDIAN);
			}
		);

		create_attribute(literal["canrecruit"],
			[](const config::attribute_value& c) { return c.to_bool(); },
			[](bool canrecruit, const unit_filter_args& args)
			{
				return args.u.can_recruit() == canrecruit;
			}
		);

		create_attribute(literal["recall_cost"],
			[](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
			[](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
			{
				for(auto cost : ranges) {
					if(cost.first <= args.u.recall_cost() && args.u.recall_cost() <= cost.second) {
						return true;
					}
				}
				return false;
			}
		);

		create_attribute(literal["level"],
			[](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
			[](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
			{
				for(auto lvl : ranges) {
					if(lvl.first <= args.u.level() && args.u.level() <= lvl.second) {
						return true;
					}
				}
				return false;
			}
		);

		create_attribute(literal["defense"],
			[](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
			[](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
			{
				int actual_defense = args.u.defense_modifier(args.fc->get_disp_context().map().get_terrain(args.loc));
				for(auto def : ranges) {
					if(def.first <= actual_defense && actual_defense <= def.second) {
						return true;
					}
				}
				return false;
			}
		);

		create_attribute(literal["movement_cost"],
			[](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
			[](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
			{
				int actual_cost = args.u.movement_cost(args.fc->get_disp_context().map().get_terrain(args.loc));
				for(auto cost : ranges) {
					if(cost.first <= actual_cost && actual_cost <= cost.second) {
						return true;
					}
				}
				return false;
			}
		);

		create_attribute(literal["vision_cost"],
			[](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
			[](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
			{
				int actual_cost = args.u.vision_cost(args.fc->get_disp_context().map().get_terrain(args.loc));
				for(auto cost : ranges) {
					if(cost.first <= actual_cost && actual_cost <= cost.second) {
						return true;
					}
				}
				return false;
			}
		);

		create_attribute(literal["jamming_cost"],
			[](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
			[](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
			{
				int actual_cost = args.u.jamming_cost(args.fc->get_disp_context().map().get_terrain(args.loc));
				for(auto cost : ranges) {
					if(cost.first <= actual_cost && actual_cost <= cost.second) {
						return true;
					}
				}
				return false;
			}
		);

		create_attribute(literal["lua_function"],
			[](const config::attribute_value& c) { return c.str(); },
			[](const std::string& lua_function, const unit_filter_args& args)
			{
				if (game_lua_kernel * lk = args.fc->get_lua_kernel()) {
					return lk->run_filter(lua_function.c_str(), args.u);
				}
				return true;
			}
		);

		create_attribute(literal["formula"],
			[](const config::attribute_value& c)
			{
				//TODO: catch syntax error.
				return wfl::formula(c, new wfl::gamestate_function_symbol_table());
			},
			[](const wfl::formula& form, const unit_filter_args& args)
			{
				try {
					const wfl::unit_callable main(args.loc, args.u);
					wfl::map_formula_callable callable(main.fake_ptr());
					if (args.u2) {
						std::shared_ptr<wfl::unit_callable> secondary(new wfl::unit_callable(*args.u2));
						callable.add("other", wfl::variant(secondary));
						// It's not destroyed upon scope exit because the variant holds a reference
					}
					if(!form.evaluate(callable).as_bool()) {
						return false;
					}
					return true;
				} catch(wfl::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;
				}
			}
		);

		create_attribute(literal["find_in"],
			[](const config::attribute_value& c) { return c.str(); },
			[](const std::string& find_in, const unit_filter_args& args)
			{
				// Allow filtering by searching a stored variable of units
				if (const game_data * gd = args.fc->get_game_data()) {
					try
					{
						for (const config& c : gd->get_variable_access_read(find_in).as_array())
						{
							if(c["id"] == args.u.id()) {
								return true;
							}
						}
						return false;
					}
					catch(const invalid_variablename_exception&)
					{
						return false;
					}
				}
				return true;
			}
		);

		if (!literal["x"].blank() || !literal["y"].blank()) {
			children_.emplace_back(new unit_filter_xy(literal["x"], literal["y"]));
		}

		for(auto child : cfg.all_ordered()) {
			CONDITIONAL_TYPE cond;
			if(cond.parse(child.first)) {
				cond_children_.emplace_back(std::piecewise_construct_t(), std::make_tuple(cond), std::make_tuple(child.second));
			}
			else if (child.first == "filter_wml") {
				create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
					config fwml = c.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") {
						return args.u.variables().matches(ci.front().cfg);
					} else {
						config ucfg;
						args.u.write(ucfg);
						return ucfg.matches(fwml);
					}
				});
			}
			else if (child.first == "filter_vision") {
				create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
					std::set<int> viewers;
					side_filter ssf(c, args.fc);
					std::vector<int> sides = ssf.get_teams();
					viewers.insert(sides.begin(), sides.end());

					for (const int viewer : viewers) {
						bool fogged = args.fc->get_disp_context().get_team(viewer).fogged(args.loc);
						bool hiding = args.u.invisible(args.loc, args.fc->get_disp_context()) && args.fc->get_disp_context().get_team(viewer).is_enemy(args.u.side());
						bool unit_hidden = fogged || hiding;
						if (c["visible"].to_bool(true) != unit_hidden) {
							return true;
						}
					}
					return false;
				});
			}
			else if (child.first == "filter_adjacent") {
				children_.emplace_back(new unit_filter_adjacent(child.second));
			}
			else if (child.first == "filter_location") {
				create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
					return terrain_filter(c, args.fc, args.use_flat_tod).match(args.loc);
				});
			}
			else if (child.first == "filter_side") {
				create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
					return side_filter(c, args.fc).match(args.u.side());
				});
			}
			else if (child.first == "has_attack") {
				create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
					for(const attack_type& a : args.u.attacks()) {
						if(a.matches_filter(c.get_parsed_config())) {
							return true;
						}
					}
					return false;
				});
			}
			else {
				std::stringstream errmsg;
				errmsg << "encountered a child [" << child.first << "] of a standard unit filter, it is being ignored";
				DBG_CF << errmsg.str() << std::endl;
			}

		}
	}
Пример #18
0
void part::resolve_wml(const vconfig &cfg)
{
	if(cfg.null()) {
		return;
	}

	// Converts shortcut syntax to members of [background_layer]
	background_layer bl;

	if(cfg.has_attribute("background")) {
		bl.set_file(cfg["background"].str());
	}
	if(cfg.has_attribute("scale_background")) {
		bl.set_scale_horizontally(cfg["scale_background"].to_bool(true));
		bl.set_scale_vertically(cfg["scale_background"].to_bool(true));
	} else {
		if(cfg.has_attribute("scale_background_vertically")) {
			bl.set_scale_vertically(cfg["scale_background_vertically"].to_bool(true));
		}
		if(cfg.has_attribute("scale_background_horizontally")) {
			bl.set_scale_horizontally(cfg["scale_background_horizontally"].to_bool(true));
		}
	}
	if(cfg.has_attribute("tile_background")) {
		bl.set_tile_horizontally(cfg["tile_background"].to_bool(false));
		bl.set_tile_vertically(cfg["tile_background"].to_bool(false));
	} else {
		if(cfg.has_attribute("tile_background_vertically")) {
			bl.set_tile_vertically(cfg["tile_background_vertically"].to_bool(false));
		}
		if(cfg.has_attribute("tile_background_horizontally")) {
			bl.set_tile_vertically(cfg["tile_background_horizontally"].to_bool(false));
		}
	}
	if(cfg.has_attribute("keep_aspect_ratio")) {
		bl.set_keep_aspect_ratio(cfg["keep_aspect_ratio"].to_bool(true));
	}
	background_layers_.push_back(bl);


	if(cfg.has_attribute("show_title")) {
		show_title_ = cfg["show_title"].to_bool();
	}
	if(cfg.has_attribute("story")) {
		text_ = cfg["story"].str();
	}
	if(cfg.has_attribute("title")) {
		text_title_ = cfg["title"].str();
		if(!cfg.has_attribute("show_title")) {
			show_title_ = true;
		}
	}
	if(cfg.has_attribute("text_layout")) {
		text_block_loc_ = string_tblock_loc(cfg["text_layout"]);
	}
	if(cfg.has_attribute("title_alignment")) {
		title_alignment_ = string_title_align(cfg["title_alignment"]);
	}
	if(cfg.has_attribute("music")) {
		music_ = cfg["music"].str();
	}
	if(cfg.has_attribute("sound")) {
		sound_ = cfg["sound"].str();
	}

	// Execution flow/branching/[image]
	for(vconfig::all_children_iterator i = cfg.ordered_begin(); i != cfg.ordered_end(); ++ i) {
		// i->first and i->second are goddamn temporaries; do not make references
		const std::string key = i->first;
		const vconfig node = i->second;

		// [background_layer]
		if (key == "background_layer") {
			background_layers_.push_back(node.get_parsed_config());
		}
		// [image]
		else if(key == "image") {
			floating_images_.push_back(node.get_parsed_config());
		}
		// [if]
		else if(key == "if") {
			// check if the [if] tag has a [then] child;
			// if we try to execute a non-existing [then], we get a segfault
			if (game_events::conditional_passed(node)) {
				if (node.has_child("then")) {
					resolve_wml(node.child("then"));
				}
			}
			// condition not passed, check [elseif] and [else]
			else {
				// get all [elseif] children and set a flag
				vconfig::child_list elseif_children = node.get_children("elseif");
				bool elseif_flag = false;
				// for each [elseif]: test if it has a [then] child
				// if the condition matches, execute [then] and raise flag
				for (vconfig::child_list::const_iterator elseif = elseif_children.begin(); elseif != elseif_children.end(); ++elseif) {
					if (game_events::conditional_passed(*elseif)) {
						if (elseif->has_child("then")) {
							resolve_wml(elseif->child("then"));
						}
						elseif_flag = true;
						break;
					}
				}
				// if we have an [else] tag and no [elseif] was successful (flag not raised), execute it
				if (node.has_child("else") && !elseif_flag) {
					resolve_wml(node.child("else"));
				}
			}
		}
		// [switch]
		else if(key == "switch") {
			const std::string var_name = node["variable"];
			const std::string var_actual_value = resources::gamedata->get_variable_const(var_name);
			bool case_not_found = true;

			for(vconfig::all_children_iterator j = node.ordered_begin(); j != node.ordered_end(); ++j) {
				if(j->first != "case") continue;

				// Enter all matching cases.
				const std::string var_expected_value = (j->second)["value"];
			    if(var_actual_value == var_expected_value) {
					case_not_found = false;
					resolve_wml(j->second);
			    }
			}

			if(case_not_found) {
				for(vconfig::all_children_iterator j = node.ordered_begin(); j != node.ordered_end(); ++j) {
					if(j->first != "else") continue;

					// Enter all elses.
					resolve_wml(j->second);
				}
			}
		}
		// [deprecated_message]
		else if(key == "deprecated_message") {
			// Won't appear until the scenario start event finishes.
			lg::wml_error() << node["message"] << '\n';
		}
		// [wml_message]
		else if(key == "wml_message") {
			// As with [deprecated_message],
			// it won't appear until the scenario start event is complete.
			resources::game_events->pump().put_wml_message(node["logger"],node["message"],node["in_chat"]);
		}
	}
}
Пример #19
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;
}
Пример #20
0
void part::resolve_wml(const vconfig &cfg)
{
	if(cfg.null()) {
		return;
	}

	if(cfg.has_attribute("background")) {
		background_file_ = cfg["background"].str();
	}
	if(cfg.has_attribute("scale_background")) {
		scale_background_ = cfg["scale_background"].to_bool(true);
	}
	if(cfg.has_attribute("show_title")) {
		show_title_ = cfg["show_title"].to_bool();
	}
	if(cfg.has_attribute("story")) {
		text_ = cfg["story"].str();
	}
	if(cfg.has_attribute("title")) {
		text_title_ = cfg["title"].str();
		if(!cfg.has_attribute("show_title")) {
			show_title_ = true;
		}
	}
	if(cfg.has_attribute("text_layout")) {
		text_block_loc_ = string_tblock_loc(cfg["text_layout"]);
	}
	if(cfg.has_attribute("title_alignment")) {
		title_alignment_ = string_title_align(cfg["title_alignment"]);
	}
	if(cfg.has_attribute("music")) {
		music_ = cfg["music"].str();
	}
	if(cfg.has_attribute("sound")) {
		sound_ = cfg["sound"].str();
	}

	// Execution flow/branching/[image]
	for(vconfig::all_children_iterator i = cfg.ordered_begin(); i != cfg.ordered_end(); ++ i) {
		// i->first and i->second are goddamn temporaries; do not make references
		const std::string key = i->first;
		const vconfig node = i->second;

		// [image]
		if(key == "image") {
			floating_images_.push_back(node.get_parsed_config());
		}
		// [if]
		else if(key == "if") {
			const std::string branch_label =
				game_events::conditional_passed(node) ?
				"then" : "else";
			if(node.has_child(branch_label)) {
				const vconfig branch = node.child(branch_label);
				resolve_wml(branch);
			}
		}
		// [switch]
		else if(key == "switch") {
			const std::string var_name = node["variable"];
			const std::string var_actual_value = resources::state_of_game->get_variable_const(var_name);
			bool case_not_found = true;

			for(vconfig::all_children_iterator j = node.ordered_begin(); j != node.ordered_end(); ++j) {
				if(j->first != "case") continue;

				// Enter all matching cases.
				const std::string var_expected_value = (j->second)["value"];
			    if(var_actual_value == var_expected_value) {
					case_not_found = false;
					resolve_wml(j->second);
			    }
			}

			if(case_not_found) {
				for(vconfig::all_children_iterator j = node.ordered_begin(); j != node.ordered_end(); ++j) {
					if(j->first != "else") continue;

					// Enter all elses.
					resolve_wml(j->second);
				}
			}
		}
		// [deprecated_message]
		else if(key == "deprecated_message") {
			// Won't appear until the scenario start event finishes.
			game_events::handle_deprecated_message(node.get_parsed_config());
		}
		// [wml_message]
		else if(key == "wml_message") {
			// Pass to game events handler. As with [deprecated_message],
			// it won't appear until the scenario start event is complete.
			game_events::handle_wml_log_message(node.get_parsed_config());
		}
	}
}
Пример #21
0
void controller::resolve_wml(const vconfig& cfg)
{
	for(vconfig::all_children_iterator i = cfg.ordered_begin(); i != cfg.ordered_end(); ++i)
	{
		// i->first and i->second are goddamn temporaries; do not make references
		const std::string key = i->first;
		const vconfig node = i->second;

		if(key == "part" && !node.empty()) {
			part_pointer_type const story_part(new part(node));
			// Use scenario name as part title if the WML doesn't supply a custom one.
			if((*story_part).show_title() && (*story_part).title().empty()) {
				(*story_part).set_title( scenario_name_ );
			}
			parts_.push_back(story_part);
		}
		// [if]
		else if(key == "if") {
			// check if the [if] tag has a [then] child;
			// if we try to execute a non-existing [then], we get a segfault
			if (game_events::conditional_passed(node)) {
				if (node.has_child("then")) {
					resolve_wml(node.child("then"));
				}
			}
			// condition not passed, check [elseif] and [else]
			else {
				// get all [elseif] children and set a flag
				vconfig::child_list elseif_children = node.get_children("elseif");
				bool elseif_flag = false;
				// for each [elseif]: test if it has a [then] child
				// if the condition matches, execute [then] and raise flag
				for (vconfig::child_list::const_iterator elseif = elseif_children.begin(); elseif != elseif_children.end(); ++elseif) {
					if (game_events::conditional_passed(*elseif)) {
						if (elseif->has_child("then")) {
							resolve_wml(elseif->child("then"));
						}
						elseif_flag = true;
						break;
					}
				}
				// if we have an [else] tag and no [elseif] was successful (flag not raised), execute it
				if (node.has_child("else") && !elseif_flag) {
					resolve_wml(node.child("else"));
				}
			}
		}
		// [switch]
		else if(key == "switch") {
			const std::string var_name = node["variable"];
			const std::string var_actual_value = resources::gamedata->get_variable_const(var_name);
			bool case_not_found = true;

			for(vconfig::all_children_iterator j = node.ordered_begin(); j != node.ordered_end(); ++j) {
				if(j->first != "case") continue;

				// Enter all matching cases.
				const std::string var_expected_value = (j->second)["value"];
			    if(var_actual_value == var_expected_value) {
					case_not_found = false;
					resolve_wml(j->second);
			    }
			}

			if(case_not_found) {
				for(vconfig::all_children_iterator j = node.ordered_begin(); j != node.ordered_end(); ++j) {
					if(j->first != "else") continue;

					// Enter all elses.
					resolve_wml(j->second);
				}
			}
		}
		// [deprecated_message]
		else if(key == "deprecated_message") {
			// Won't appear until the scenario start event finishes.
			game_events::handle_deprecated_message(node.get_parsed_config());
		}
		// [wml_message]
		else if(key == "wml_message") {
			// Pass to game events handler. As with [deprecated_message],
			// it won't appear until the scenario start event is complete.
			game_events::handle_wml_log_message(node.get_parsed_config());
		}
	}
}