Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
refactored SelectionKeyHandler filters to map of (filter name, filter…
… singleton)

pairs and added "RulesParamEquals_param_wantedValue" filter.

As name says, this can be used to filter on unit rules params, for example:
  'AllMap+_Not_RulesParamEquals_ammo_0+_ClearSelection_SelectAll'
selects all units in map for which "ammo" rules param is not equal to 0.
  • Loading branch information
tvo committed Sep 23, 2009
1 parent 914c112 commit 39b44ef
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 241 deletions.
377 changes: 136 additions & 241 deletions rts/Game/UI/SelectionKeyHandler.cpp
Expand Up @@ -137,6 +137,129 @@ std::string CSelectionKeyHandler::ReadDelimiter(std::string& s)
}


namespace
{
struct Filter
{
public:
typedef std::map<std::string, Filter*> Map;

/// Contains all existing filter singletons.
static Map& all() {
static Map instance;
return instance;
}

/// Called immediately before the filter is used.
virtual void Prepare() {}

/// Called immediately before the filter is used for every parameter.
virtual void SetParam(int index, const std::string& value) {
assert(false);
}

/// Actual filtering, should return false if unit should be removed
/// from proposed selection.
virtual bool ShouldIncludeUnit(const CUnit* unit) const = 0;

/// Number of arguments this filter has.
const int numArgs;

protected:
Filter(const std::string& name, int args) : numArgs(args) {
all().insert(Map::value_type(name, this));
}
};

// prototype / factory based approach might be better at some point?
// for now these singleton filters seem ok. (they are not reentrant tho!)

#define DECLARE_FILTER_EX(name, args, condition, extra) \
struct name ## _Filter : public Filter { \
name ## _Filter() : Filter(#name, args) {} \
bool ShouldIncludeUnit(const CUnit* unit) const { return condition; } \
extra \
} name ## _filter_instance; \

#define DECLARE_FILTER(name, condition) \
DECLARE_FILTER_EX(name, 0, condition, )

DECLARE_FILTER(Builder, unit->unitDef->buildSpeed > 0);
DECLARE_FILTER(Building, dynamic_cast<const CBuilding*>(unit) != NULL);
DECLARE_FILTER(Commander, unit->unitDef->isCommander);
DECLARE_FILTER(Transport, unit->unitDef->transportCapacity > 0);
DECLARE_FILTER(Aircraft, unit->unitDef->canfly);
DECLARE_FILTER(Weapons, !unit->weapons.empty());
DECLARE_FILTER(Idle, unit->commandAI->commandQue.empty());
DECLARE_FILTER(Waiting, !unit->commandAI->commandQue.empty() &&
(unit->commandAI->commandQue.front().id == CMD_WAIT));
DECLARE_FILTER(InHotkeyGroup, unit->group != NULL);
DECLARE_FILTER(Radar, unit->radarRadius || unit->sonarRadius || unit->jammerRadius);

DECLARE_FILTER_EX(WeaponRange, 1, unit->maxRange > minRange,
float minRange;
void SetParam(int index, const std::string& value) {
minRange = atof(value.c_str());
}
);

DECLARE_FILTER_EX(AbsoluteHealth, 1, unit->health > minHealth,
float minHealth;
void SetParam(int index, const std::string& value) {
minHealth = atof(value.c_str());
}
);

DECLARE_FILTER_EX(RelativeHealth, 1, unit->health / unit->maxHealth > minHealth,
float minHealth;
void SetParam(int index, const std::string& value) {
minHealth = atof(value.c_str()) * 0.01f; // convert from percent
}
);

// TODO: should move away from aihint
DECLARE_FILTER_EX(InPrevSel, 0, prevTypes.find(unit->aihint) != prevTypes.end(),
std::set<int> prevTypes;
void Prepare() {
const CUnitSet& tu = selectedUnits.selectedUnits;
for (CUnitSet::const_iterator si = tu.begin(); si != tu.end(); ++si) {
prevTypes.insert((*si)->aihint);
}
}
);

DECLARE_FILTER_EX(NameContain, 1, unit->unitDef->humanName.find(name) != std::string::npos,
std::string name;
void SetParam(int index, const std::string& value) {
name = value;
}
);

DECLARE_FILTER_EX(Category, 1, unit->category == cat,
unsigned int cat;
void SetParam(int index, const std::string& value) {
cat = CCategoryHandler::Instance()->GetCategory(value);
}
);

DECLARE_FILTER_EX(RulesParamEquals, 2, unit->modParamsMap.find(param) != unit->modParamsMap.end() &&
unit->modParams[unit->modParamsMap.find(param)->second] == wantedValue,
std::string param;
float wantedValue;
void SetParam(int index, const std::string& value) {
switch (index) {
case 0: param = value; break;
case 1: wantedValue = atof(value.c_str()); break;
}
}
);

#undef DECLARE_FILTER_EX
#undef DECLARE_FILTER
};



void CSelectionKeyHandler::DoSelection(std::string selectString)
{
GML_RECMUTEX_LOCK(sel); // DoSelection
Expand Down Expand Up @@ -245,255 +368,27 @@ void CSelectionKeyHandler::DoSelection(std::string selectString)
s=ReadToken(selectString);
}

if(s=="Builder"){
std::list<CUnit*>::iterator ui=selection.begin();
while(ui!=selection.end()){
bool filterTrue=false;
if((*ui)->unitDef->buildSpeed>0){
filterTrue=true;
}
if(filterTrue ^ _not){
++ui;
} else {
std::list<CUnit*>::iterator prev=ui++;
selection.erase(prev);
}
}
} else if(s=="Building"){
std::list<CUnit*>::iterator ui=selection.begin();
while(ui!=selection.end()){
bool filterTrue=false;
if(dynamic_cast<CBuilding*>(*ui)){
filterTrue=true;
}
if(filterTrue ^ _not){
++ui;
} else {
std::list<CUnit*>::iterator prev=ui++;
selection.erase(prev);
}
}
} else if(s=="Commander"){
std::list<CUnit*>::iterator ui=selection.begin();
while (ui!=selection.end()) {
bool filterTrue=false;
if((*ui)->unitDef->isCommander){
filterTrue=true;
}
if (filterTrue ^ _not) {
++ui;
} else {
std::list<CUnit*>::iterator prev=ui++;
selection.erase(prev);
}
}
} else if(s=="Transport"){
std::list<CUnit*>::iterator ui=selection.begin();
while(ui!=selection.end()){
bool filterTrue=false;
if((*ui)->unitDef->transportCapacity>0){
filterTrue=true;
}
if (filterTrue ^ _not) {
++ui;
} else {
std::list<CUnit*>::iterator prev=ui++;
selection.erase(prev);
}
}
} else if(s=="Aircraft"){

std::list<CUnit*>::iterator ui=selection.begin();
while (ui != selection.end()) {
bool filterTrue=false;
if ((*ui)->unitDef->canfly){
filterTrue=true;
}
if (filterTrue ^ _not) {
++ui;
} else {
std::list<CUnit*>::iterator prev=ui++;
selection.erase(prev);
}
}
} else if(s=="Weapons"){
std::list<CUnit*>::iterator ui=selection.begin();
while(ui!=selection.end()){
bool filterTrue=false;
if(!(*ui)->weapons.empty()){
filterTrue=true;
}
if(filterTrue ^ _not){
++ui;
} else {
std::list<CUnit*>::iterator prev=ui++;
selection.erase(prev);
}
}
} else if(s=="WeaponRange"){
ReadDelimiter(selectString);
float minRange=atof(ReadToken(selectString).c_str());

std::list<CUnit*>::iterator ui=selection.begin();
while(ui!=selection.end()){
bool filterTrue=false;
if ((*ui)->maxRange>minRange) {
filterTrue=true;
}
if (filterTrue ^ _not) {
++ui;
} else {
std::list<CUnit*>::iterator prev=ui++;
selection.erase(prev);
}
}
} else if(s=="AbsoluteHealth"){
ReadDelimiter(selectString);
float minHealth=atof(ReadToken(selectString).c_str());
Filter::Map& filters = Filter::all();
Filter::Map::iterator f = filters.find(s);

std::list<CUnit*>::iterator ui=selection.begin();
while (ui != selection.end()) {
bool filterTrue=false;
if ((*ui)->health>minHealth){
filterTrue=true;
}
if (filterTrue ^ _not){
++ui;
} else {
std::list<CUnit*>::iterator prev=ui++;
selection.erase(prev);
}
if (f != filters.end()) {
f->second->Prepare();
for (int i = 0; i < f->second->numArgs; ++i) {
ReadDelimiter(selectString);
f->second->SetParam(i, ReadToken(selectString));
}
} else if(s=="RelativeHealth"){
ReadDelimiter(selectString);
float minHealth=atof(ReadToken(selectString).c_str())*0.01f;//convert from percent

std::list<CUnit*>::iterator ui=selection.begin();
while(ui!=selection.end()){
bool filterTrue=false;
if((*ui)->health/(*ui)->maxHealth > minHealth){
filterTrue=true;
}
if(filterTrue ^ _not){
++ui;
} else {
std::list<CUnit*>::iterator prev=ui++;
selection.erase(prev);
}
}
} else if(s=="InPrevSel"){
std::set<int> prevTypes;
CUnitSet* tu=&selectedUnits.selectedUnits;
for (CUnitSet::iterator si=tu->begin();si!=tu->end();++si){
prevTypes.insert((*si)->aihint);
}
std::list<CUnit*>::iterator ui=selection.begin();
std::list<CUnit*>::iterator ui = selection.begin();
while (ui != selection.end()) {
bool filterTrue=false;
if(prevTypes.find((*ui)->aihint)!=prevTypes.end()){ //should move away from aihint
filterTrue=true;
}
if(filterTrue ^ _not){
if (f->second->ShouldIncludeUnit(*ui) ^ _not) {
++ui;
} else {
std::list<CUnit*>::iterator prev=ui++;
selection.erase(prev);
}
}
} else if(s=="NameContain"){
ReadDelimiter(selectString);
std::string name=ReadToken(selectString);

std::list<CUnit*>::iterator ui=selection.begin();
while (ui != selection.end()) {
bool filterTrue=false;
if ((*ui)->unitDef->humanName.find(name)!=std::string::npos){
filterTrue=true;
}
if (filterTrue ^ _not){
++ui;
} else {
std::list<CUnit*>::iterator prev=ui++;
else {
std::list<CUnit*>::iterator prev = ui++;
selection.erase(prev);
}
}
} else if(s=="Idle"){
std::list<CUnit*>::iterator ui=selection.begin();
while (ui != selection.end()) {
bool filterTrue=false;
if((*ui)->commandAI->commandQue.empty()){
filterTrue=true;
}
if(filterTrue ^ _not){
++ui;
} else {
std::list<CUnit*>::iterator prev=ui++;
selection.erase(prev);
}
}
} else if(s=="Waiting"){
std::list<CUnit*>::iterator ui=selection.begin();
while (ui != selection.end()) {
bool filterTrue=false;
if(!(*ui)->commandAI->commandQue.empty() &&
((*ui)->commandAI->commandQue.front().id == CMD_WAIT)){
filterTrue=true;
}
if(filterTrue ^ _not){
++ui;
} else {
std::list<CUnit*>::iterator prev=ui++;
selection.erase(prev);
}
}
} else if(s=="InHotkeyGroup"){
std::list<CUnit*>::iterator ui=selection.begin();
while (ui != selection.end()) {
bool filterTrue=false;
if((*ui)->group){
filterTrue=true;
}
if(filterTrue ^ _not){
++ui;
} else {
std::list<CUnit*>::iterator prev=ui++;
selection.erase(prev);
}
}
} else if (s == "Radar") {
std::list<CUnit*>::iterator ui=selection.begin();
while (ui != selection.end()) {
bool filterTrue=false;
if((*ui)->radarRadius || (*ui)->sonarRadius || (*ui)->jammerRadius){
filterTrue=true;
}
if(filterTrue ^ _not){
++ui;
} else {
std::list<CUnit*>::iterator prev=ui++;
selection.erase(prev);
}
}
} else if(s=="Category"){
ReadDelimiter(selectString);
std::string catname=ReadToken(selectString);
unsigned int cat=CCategoryHandler::Instance()->GetCategory(catname);

std::list<CUnit*>::iterator ui=selection.begin();
while(ui!=selection.end()){
bool filterTrue=false;
if((*ui)->category==cat){
filterTrue=true;
}
if(filterTrue ^ _not){
++ui;
} else {
std::list<CUnit*>::iterator prev=ui++;
selection.erase(prev);
}
}

} else {
}
else {
logOutput.Print("Unknown token in filter %s",s.c_str());
return;
}
Expand Down

0 comments on commit 39b44ef

Please sign in to comment.