From 39b44ef610d29e30337f649a1e7d9a11bb443e79 Mon Sep 17 00:00:00 2001 From: Tobi Vollebregt Date: Wed, 23 Sep 2009 23:35:08 +0200 Subject: [PATCH] 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. --- rts/Game/UI/SelectionKeyHandler.cpp | 377 ++++++++++------------------ rts/Game/UI/SelectionKeyHandler.h | 1 + 2 files changed, 137 insertions(+), 241 deletions(-) diff --git a/rts/Game/UI/SelectionKeyHandler.cpp b/rts/Game/UI/SelectionKeyHandler.cpp index 962aab6849d..65add0e5d10 100644 --- a/rts/Game/UI/SelectionKeyHandler.cpp +++ b/rts/Game/UI/SelectionKeyHandler.cpp @@ -137,6 +137,129 @@ std::string CSelectionKeyHandler::ReadDelimiter(std::string& s) } +namespace +{ + struct Filter + { + public: + typedef std::map 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(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 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 @@ -245,255 +368,27 @@ void CSelectionKeyHandler::DoSelection(std::string selectString) s=ReadToken(selectString); } - if(s=="Builder"){ - std::list::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::iterator prev=ui++; - selection.erase(prev); - } - } - } else if(s=="Building"){ - std::list::iterator ui=selection.begin(); - while(ui!=selection.end()){ - bool filterTrue=false; - if(dynamic_cast(*ui)){ - filterTrue=true; - } - if(filterTrue ^ _not){ - ++ui; - } else { - std::list::iterator prev=ui++; - selection.erase(prev); - } - } - } else if(s=="Commander"){ - std::list::iterator ui=selection.begin(); - while (ui!=selection.end()) { - bool filterTrue=false; - if((*ui)->unitDef->isCommander){ - filterTrue=true; - } - if (filterTrue ^ _not) { - ++ui; - } else { - std::list::iterator prev=ui++; - selection.erase(prev); - } - } - } else if(s=="Transport"){ - std::list::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::iterator prev=ui++; - selection.erase(prev); - } - } - } else if(s=="Aircraft"){ - - std::list::iterator ui=selection.begin(); - while (ui != selection.end()) { - bool filterTrue=false; - if ((*ui)->unitDef->canfly){ - filterTrue=true; - } - if (filterTrue ^ _not) { - ++ui; - } else { - std::list::iterator prev=ui++; - selection.erase(prev); - } - } - } else if(s=="Weapons"){ - std::list::iterator ui=selection.begin(); - while(ui!=selection.end()){ - bool filterTrue=false; - if(!(*ui)->weapons.empty()){ - filterTrue=true; - } - if(filterTrue ^ _not){ - ++ui; - } else { - std::list::iterator prev=ui++; - selection.erase(prev); - } - } - } else if(s=="WeaponRange"){ - ReadDelimiter(selectString); - float minRange=atof(ReadToken(selectString).c_str()); - - std::list::iterator ui=selection.begin(); - while(ui!=selection.end()){ - bool filterTrue=false; - if ((*ui)->maxRange>minRange) { - filterTrue=true; - } - if (filterTrue ^ _not) { - ++ui; - } else { - std::list::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::iterator ui=selection.begin(); - while (ui != selection.end()) { - bool filterTrue=false; - if ((*ui)->health>minHealth){ - filterTrue=true; - } - if (filterTrue ^ _not){ - ++ui; - } else { - std::list::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::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::iterator prev=ui++; - selection.erase(prev); - } - } - } else if(s=="InPrevSel"){ - std::set prevTypes; - CUnitSet* tu=&selectedUnits.selectedUnits; - for (CUnitSet::iterator si=tu->begin();si!=tu->end();++si){ - prevTypes.insert((*si)->aihint); - } - std::list::iterator ui=selection.begin(); + std::list::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::iterator prev=ui++; - selection.erase(prev); } - } - } else if(s=="NameContain"){ - ReadDelimiter(selectString); - std::string name=ReadToken(selectString); - - std::list::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::iterator prev=ui++; + else { + std::list::iterator prev = ui++; selection.erase(prev); } } - } else if(s=="Idle"){ - std::list::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::iterator prev=ui++; - selection.erase(prev); - } - } - } else if(s=="Waiting"){ - std::list::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::iterator prev=ui++; - selection.erase(prev); - } - } - } else if(s=="InHotkeyGroup"){ - std::list::iterator ui=selection.begin(); - while (ui != selection.end()) { - bool filterTrue=false; - if((*ui)->group){ - filterTrue=true; - } - if(filterTrue ^ _not){ - ++ui; - } else { - std::list::iterator prev=ui++; - selection.erase(prev); - } - } - } else if (s == "Radar") { - std::list::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::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::iterator ui=selection.begin(); - while(ui!=selection.end()){ - bool filterTrue=false; - if((*ui)->category==cat){ - filterTrue=true; - } - if(filterTrue ^ _not){ - ++ui; - } else { - std::list::iterator prev=ui++; - selection.erase(prev); - } - } - - } else { + } + else { logOutput.Print("Unknown token in filter %s",s.c_str()); return; } diff --git a/rts/Game/UI/SelectionKeyHandler.h b/rts/Game/UI/SelectionKeyHandler.h index 5ea4364558e..94c63ad92b3 100644 --- a/rts/Game/UI/SelectionKeyHandler.h +++ b/rts/Game/UI/SelectionKeyHandler.h @@ -18,6 +18,7 @@ class CSelectionKeyHandler : void DoSelection(std::string selectString); +private: int selectNumber; //used to go through all possible units when selecting only a few };