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 }
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; } }
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 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"; }
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; } } }