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; }
/** * Returns true iff the given event passes all its filters. */ bool t_pump::filter_event(const event_handler& handler, const queued_event& ev) { const unit_map *units = resources::units; unit_map::const_iterator unit1 = units->find(ev.loc1); unit_map::const_iterator unit2 = units->find(ev.loc2); vconfig filters(handler.get_config()); BOOST_FOREACH(const vconfig &condition, filters.get_children("filter_condition")) { if (!conditional_passed(condition)) { return false; } } BOOST_FOREACH(const vconfig &f, filters.get_children("filter_side")) { side_filter ssf(f, &resources::controller->gamestate()); if ( !ssf.match(resources::controller->current_side()) ) return false; } BOOST_FOREACH(const vconfig &f, filters.get_children("filter")) { if ( !ev.loc1.matches_unit_filter(unit1, f) ) { return false; } } vconfig::child_list special_filters = filters.get_children("filter_attack"); bool special_matches = special_filters.empty(); if ( !special_matches && unit1 != units->end() ) { const bool matches_unit = ev.loc1.matches_unit(unit1); const config & attack = ev.data.child("first"); BOOST_FOREACH(const vconfig &f, special_filters) { if ( f.empty() ) special_matches = true; else if ( !matches_unit ) return false; special_matches = special_matches || matches_special_filter(attack, f); } } if(!special_matches) { return false; } BOOST_FOREACH(const vconfig &f, filters.get_children("filter_second")) { if ( !ev.loc2.matches_unit_filter(unit2, f) ) { return false; } } special_filters = filters.get_children("filter_second_attack"); special_matches = special_filters.empty(); if ( !special_matches && unit2 != units->end() ) { const bool matches_unit = ev.loc2.matches_unit(unit2); const config & attack = ev.data.child("second"); BOOST_FOREACH(const vconfig &f, special_filters) { if ( f.empty() ) special_matches = true; else if ( !matches_unit ) return false; special_matches = special_matches || matches_special_filter(attack, f); } } if(!special_matches) { return false; } // All filters passed. return true; }
bool SsfCreator::create(const QString& path, int width, int height, QImage& img) { if (!QFile::exists(path)) return false; KSsf ssf(path); if (!ssf.open(QIODevice::ReadOnly)) return false; const KArchiveEntry* entry = ssf.directory()->entry("skin.ini"); const KArchiveFile* skinini = static_cast<const KArchiveFile*>(entry); if (!skinini) { entry = ssf.directory()->entry("Skin.ini"); skinini = static_cast<const KArchiveFile*>(entry); if (!skinini) return false; } QFont preEditFont; QFont candidateFont; QColor preEditColor; QColor labelColor; QColor candidateColor; int pt = 0, pb = 0, pl = 0, pr = 0; int zt = 0, zb = 0, zl = 0, zr = 0; QByteArray data = skinini->data(); /// parse ini file content bool display = false; bool scheme_h1 = false; QPixmap skin; int hstm = 0; int sl = 0, sr = 0; int fontPixelSize = 12; QString font_ch, font_en; unsigned int color_ch, color_en; QHash<QString, OverlayPixmap> overlays; int opt = 0, opb = 0, opl = 0, opr = 0; QColor separatorColor = Qt::transparent; int sepl = 0, sepr = 0; QTextStream ss(data); QString line; QString key, value; do { line = ss.readLine(); if (line.isEmpty()) continue; if (line.at(0) == '[') { display = (line == "[Display]"); scheme_h1 = (line == "[Scheme_H1]"); continue; } if (!line.contains('=')) continue; key = line.split('=').at(0); value = line.split('=').at(1); if (value.isEmpty()) continue; if (display) { if (key == "font_size") fontPixelSize = value.trimmed().toInt(); else if (key == "font_ch") font_ch = value; else if (key == "font_en") font_en = value; else if (key == "pinyin_color") color_en = value.toUInt(0, 0); else if (key == "zhongwen_color") color_ch = value.toUInt(0, 0); } else if (scheme_h1) { if (key == "pic") { const KArchiveEntry* e = ssf.directory()->entry(value); const KArchiveFile* pix = static_cast<const KArchiveFile*>(e); if (pix) skin.loadFromData(pix->data()); } else if (key == "layout_horizontal") { QStringList list = value.split(','); hstm = list.at(0).trimmed().toInt(); sl = list.at(1).trimmed().toInt(); sr = list.at(2).trimmed().toInt(); } else if (key == "separator") { QStringList list = value.split(','); QString sep_color = list.at(0).trimmed(); separatorColor = sep_color.leftJustified(8, '0').replace("0x", "#"); sepl = list.at(1).trimmed().toInt(); sepr = list.at(2).trimmed().toInt(); } else if (key == "pinyin_marge") { QStringList list = value.split(','); pt = list.at(0).trimmed().toInt(); pb = list.at(1).trimmed().toInt(); pl = list.at(2).trimmed().toInt(); pr = list.at(3).trimmed().toInt(); } else if (key == "zhongwen_marge") { QStringList list = value.split(','); zt = list.at(0).trimmed().toInt(); zb = list.at(1).trimmed().toInt(); zl = list.at(2).trimmed().toInt(); zr = list.at(3).trimmed().toInt(); } else if (key.endsWith("_display")) { QString name = key.left(key.length() - 8); overlays.insert(name, OverlayPixmap()); } else if (key.endsWith("_align")) { QString name = key.left(key.length() - 6); QStringList numbers = value.split(','); OverlayPixmap& op = overlays[ name ]; op.mt = numbers.at(0).toInt(); op.mb = numbers.at(1).toInt(); op.ml = numbers.at(2).toInt(); op.mr = numbers.at(3).toInt(); op.alignVMode = numbers.at(4).toInt() + numbers.at(5).toInt(); /// FIXME: right or wrong? op.alignHMode = numbers.at(6).toInt() + numbers.at(7).toInt(); /// FIXME: right or wrong? op.alignArea = numbers.at(8).toInt(); op.alignTarget = numbers.at(9).toInt(); } else if (overlays.contains(key)) { const KArchiveEntry* e = ssf.directory()->entry(value); const KArchiveFile* pix = static_cast<const KArchiveFile*>(e); if (pix) overlays[ key ].pixmap.loadFromData(pix->data()); } } } while (!line.isNull()); /// calculate overlay pixmap surrounding QHash<QString, OverlayPixmap>::ConstIterator it = overlays.constBegin(); QHash<QString, OverlayPixmap>::ConstIterator end = overlays.constEnd(); while (it != end) { const OverlayPixmap& op = it.value(); switch (op.alignArea) { case 1: opl = qMax(opl, op.pixmap.width()); opt = qMax(opt, op.pixmap.height()); break; case 2: opt = qMax(opt, op.pixmap.height()); break; case 3: opr = qMax(opr, op.pixmap.width()); opt = qMax(opt, op.pixmap.height()); break; case 4: opl = qMax(opl, op.pixmap.width()); break; case 5: /// center pixmap, no addition break; case 6: opr = qMax(opr, op.pixmap.width()); break; case 7: opl = qMax(opl, op.pixmap.width()); opb = qMax(opb, op.pixmap.height()); break; case 8: opb = qMax(opb, op.pixmap.height()); break; case 9: opr = qMax(opr, op.pixmap.width()); opb = qMax(opb, op.pixmap.height()); break; default: /// never arrive here break; } ++it; } preEditFont.setFamily(font_en); preEditFont.setPixelSize(fontPixelSize); candidateFont.setFamily(font_ch); candidateFont.setPixelSize(fontPixelSize); /// swap from bgr to rgb preEditColor = QColor(qBlue(color_en), qGreen(color_en), qRed(color_en)); candidateColor = QColor(qBlue(color_ch), qGreen(color_ch), qRed(color_ch)); labelColor = candidateColor; int pinyinh = QFontMetrics(preEditFont).height(); int zhongwenh = QFontMetrics(candidateFont).height(); int pinyinw = QFontMetrics(preEditFont).width("ABC pinyin"); int zhongwenw = QFontMetrics(candidateFont).width("1candidate"); /// save target size int targetHeight = height; int targetWidth = width; height = qMax(pt + pinyinh + pb + zt + zhongwenh + zb + opt + opb, skin.height()); width = qMax(pl + pinyinw + pr, zl + zhongwenw + zr); width = qMax(width + opl + opr, targetWidth); width = qMax(width, skin.width()); QPixmap pixmap(width, height); pixmap.fill(Qt::transparent); QPainter p(&pixmap); /// left right p.drawPixmap(0, 0, sl, height, skin, 0, 0, sl, skin.height()); p.drawPixmap(width - sr, 0, sr, height, skin, skin.width() - sr, 0, sr, skin.height()); /// middle QPixmap middlepix = skin.copy(sl, 0, skin.width() - sl - sr, skin.height()); if (hstm == 0) p.drawPixmap(sl, 0, middlepix.scaled(width - sl - sr, height)); else p.drawTiledPixmap(sl, 0, width - sl - sr, height, middlepix.scaled(middlepix.width(), height)); /// draw overlay pixmap it = overlays.constBegin(); end = overlays.constEnd(); while (it != end) { const OverlayPixmap& op = it.value(); p.save(); switch (op.alignArea) { case 1: p.translate(op.ml, op.mt); break; case 2: if (op.alignHMode == 0) { p.translate((width + opl - opr - op.pixmap.width()) / 2, 0); p.translate(op.ml / 2, op.mt); } else if (op.alignHMode == 1) { p.translate(opl, 0); p.translate(op.ml, op.mt); } else if (op.alignHMode == 2) { p.translate(width - opr - op.pixmap.width(), 0); p.translate(-op.mr, op.mt); } break; case 3: p.translate(width - opr, 0); p.translate(-op.mr, op.mt); break; case 4: if (op.alignVMode == 0) { p.translate(0, (height - opb + opt - op.pixmap.height()) / 2); p.translate(op.ml, op.mt / 2); } else if (op.alignVMode == 1) { p.translate(0, opt); p.translate(op.ml, op.mt); } else if (op.alignVMode == 2) { p.translate(0, height - opb - op.pixmap.height()); p.translate(op.ml, -op.mb); } break; case 5: if (op.alignHMode == 0) { p.translate((width + opl - opr - op.pixmap.width()) / 2, 0); p.translate(op.ml / 2, 0); } else if (op.alignHMode == 1) { p.translate(opl, 0); p.translate(op.ml, 0); } else if (op.alignHMode == 2) { p.translate(width - opr - op.pixmap.width(), 0); p.translate(-op.mr, 0); } if (op.alignVMode == 0) { p.translate(0, (height - opb + opt - op.pixmap.height()) / 2); p.translate(0, op.mt / 2); } else if (op.alignVMode == 1) { p.translate(0, opt); p.translate(0, op.mt); } else if (op.alignVMode == 2) { p.translate(0, height - opb - op.pixmap.height()); p.translate(0, -op.mb); } break; case 6: if (op.alignVMode == 0) { p.translate(width - opr, (height - opb + opt - op.pixmap.height()) / 2); p.translate(-op.mr, op.mt / 2); } else if (op.alignVMode == 1) { p.translate(width - opr, opt); p.translate(-op.mr, op.mt); } else if (op.alignVMode == 2) { p.translate(width - opr, height - opb - op.pixmap.height()); p.translate(-op.mr, -op.mb); } break; case 7: p.translate(0, height - opb); p.translate(op.ml, -op.mb); break; case 8: if (op.alignHMode == 0) { p.translate((width + opl - opr - op.pixmap.width()) / 2, height - opb); p.translate(op.ml / 2, -op.mb); } else if (op.alignHMode == 1) { p.translate(opl, height - opb); p.translate(op.ml, -op.mb); } else if (op.alignHMode == 2) { p.translate(width - opr - op.pixmap.width(), height - opb); p.translate(-op.mr, -op.mb); } break; case 9: p.translate(width - opr, height - opb); p.translate(-op.mr, -op.mb); break; default: /// never arrive here break; } p.drawPixmap(0, 0, op.pixmap); p.restore(); ++it; } if (separatorColor != Qt::transparent) { /// draw separator int sepy = opt + pt + pinyinh + pb; p.drawLine(opl + sepl, sepy, width - opr - sepr, sepy); } p.translate(opl, opt); int y = 0; /// draw preedit / aux text p.save(); p.setFont(preEditFont); p.setPen(preEditColor); y += pt; p.drawText(pl, pt, width - pl - pr, pinyinh, Qt::AlignLeft, "ABC pinyin"); int pixelsWide = QFontMetrics(preEditFont).width("ABC pinyin"); p.drawLine(pl + pixelsWide, pt, pl + pixelsWide, pt + pinyinh); y += pinyinh + pb; p.restore(); /// draw lookup table p.save(); int x = zl; y += zt; int w = 0; p.setFont(candidateFont); /// draw label p.setPen(labelColor); w = p.fontMetrics().width("1"); p.drawText(x, y, w, zhongwenh, Qt::AlignCenter, "1"); x += w; /// draw candidate p.setPen(candidateColor); w = p.fontMetrics().width("candidate"); p.drawText(x, y, w, zhongwenh, Qt::AlignCenter, "candidate"); x += w; p.restore(); p.end(); if (targetWidth < width || targetHeight < height) { pixmap = pixmap.scaled(targetWidth, targetHeight, Qt::KeepAspectRatio); } img = pixmap.toImage(); return true; }