Changed: Target command to support keyword search.

--HG--
branch : develop
This commit is contained in:
Nimetu 2019-02-14 16:04:07 +02:00
parent 3a5bb966a8
commit 4a31913c60
4 changed files with 120 additions and 68 deletions

View file

@ -78,17 +78,11 @@
<command name="self" action="self_target" params="" /> <command name="self" action="self_target" params="" />
<command name="target" action="target" params="entity=$" /> <command name="target" action="target" params="entity=+" ctrlchar="false" />
<command name="tar" action="target" params="entity=$" /> <command name="tar" action="target" params="entity=+" ctrlchar="false" />
<command name="target_quiet" action="target" params="entity=$|quiet=true" /> <command name="target_quiet" action="target" params="entity=+|quiet=true" ctrlchar="false" />
<command name="tarq" action="target" params="entity=$|quiet=true" /> <command name="tarq" action="target" params="entity=+|quiet=true" ctrlchar="false" />
<command name="target" action="target" params="entity=$|prefer_complete_match=$" />
<command name="tar" action="target" params="entity=$|prefer_complete_match=$" />
<command name="target_quiet" action="target" params="entity=$|prefer_complete_match=$|quiet=true" />
<command name="tarq" action="target" params="entity=$|prefer_complete_match=$|quiet=true" />
<command name="target" action="no_target" params="" /> <command name="target" action="no_target" params="" />
<command name="tar" action="no_target" params="" /> <command name="tar" action="no_target" params="" />

View file

@ -2334,7 +2334,63 @@ CEntityCL *CEntityManager::getEntityByName (uint32 stringId) const
} }
//----------------------------------------------- //-----------------------------------------------
CEntityCL *CEntityManager::getEntityByKeywords (const std::vector<ucstring> &keywords, bool onlySelectable) const
{
if (keywords.empty()) return NULL;
std::vector<ucstring> lcKeywords;
lcKeywords.resize(keywords.size());
for(uint k = 0; k < keywords.size(); k++)
{
lcKeywords[k] = toLower(keywords[k]);
}
const NLMISC::CVectorD &userPosD = UserEntity->pos();
const uint count = (uint)_Entities.size();
uint selectedEntityId = 0;
float selectedEntityDist = FLT_MAX;
for(uint i = 0; i < count; ++i)
{
if (!_Entities[i]) continue;
if (onlySelectable && !_Entities[i]->properties().selectable()) continue;
ucstring lcName;
lcName = toLower(_Entities[i]->getDisplayName());
if (lcName.empty()) continue;
bool match = true;
for (uint k = 0; k < lcKeywords.size(); ++k)
{
if (lcName.find(lcKeywords[k]) == ucstring::npos)
{
match = false;
break;
}
}
if (match)
{
const NLMISC::CVectorD &targetPosD = _Entities[i]->pos();
float deltaX = (float) targetPosD.x - (float) userPosD.x;
float deltaY = (float) targetPosD.y - (float) userPosD.y;
float dist = (float)sqrt(deltaX * deltaX + deltaY * deltaY);
if (dist < selectedEntityDist)
{
selectedEntityDist = dist;
selectedEntityId = i;
}
}
}
if (selectedEntityDist != FLT_MAX)
return _Entities[selectedEntityId];
else
return NULL;
}
//-----------------------------------------------
CEntityCL *CEntityManager::getEntityByName (const ucstring &name, bool caseSensitive, bool complete) const CEntityCL *CEntityManager::getEntityByName (const ucstring &name, bool caseSensitive, bool complete) const
{ {
ucstring source = name; ucstring source = name;

View file

@ -302,6 +302,12 @@ public:
* \param complete : if true, the name must match the full name of the entity. * \param complete : if true, the name must match the full name of the entity.
*/ */
CEntityCL *getEntityByName (const ucstring &name, bool caseSensitive, bool complete) const; CEntityCL *getEntityByName (const ucstring &name, bool caseSensitive, bool complete) const;
/**
* Case insensitive match against entity name. All listed keywords must match.
* \param keywords to match
* \param onlySelectable : if true, match only entity that can be selected
*/
CEntityCL *getEntityByKeywords (const std::vector<ucstring> &keywords, bool onlySelectable) const;
CEntityCL *getEntityBySheetName (const std::string &sheet) const; CEntityCL *getEntityBySheetName (const std::string &sheet) const;
/// Get an entity by dataset index. Returns NULL if the entity is not found. /// Get an entity by dataset index. Returns NULL if the entity is not found.
CEntityCL *getEntityByCompressedIndex(TDataSetIndex compressedIndex) const; CEntityCL *getEntityByCompressedIndex(TDataSetIndex compressedIndex) const;

View file

@ -2416,70 +2416,66 @@ class CAHTarget : public IActionHandler
{ {
virtual void execute (CCtrlBase * /* pCaller */, const string &Params) virtual void execute (CCtrlBase * /* pCaller */, const string &Params)
{ {
// Get the entity name to target
ucstring entityName; ucstring entityName;
entityName.fromUtf8 (getParam (Params, "entity")); entityName.fromUtf8(getParam(Params, "entity"));
bool preferCompleteMatch = (getParam (Params, "prefer_complete_match") != "0"); if (entityName.empty()) return;
string completeMatch = getParam(Params, "prefer_complete_match");
bool quiet = (getParam (Params, "quiet") == "true"); bool quiet = (getParam (Params, "quiet") == "true");
if (!entityName.empty()) vector<ucstring> keywords;
NLMISC::splitUCString(entityName, ucstring(" "), keywords);
if (!keywords.empty() && keywords[0].size() > 0 && keywords[0][0] == (ucchar)'"')
{ {
CEntityCL *entity = NULL; // entity name is in quotes, do old style match with 'starts with' filter
if (preferCompleteMatch) // search for optional second parameter from old command for prefer_complete_match param
{ keywords.clear();
// Try to get the entity with complete match first
entity = EntitiesMngr.getEntityByName (entityName, false, true);
}
if (entity == NULL) ucstring::size_type lastOf = entityName.rfind(ucstring("\""));
{ if (lastOf == 0)
// Get the entity with a partial match lastOf = ucstring::npos;
entity = EntitiesMngr.getEntityByName (entityName, false, false);
}
if (entity == NULL) // override the value only when there is no 'prefer_complete_match' parameter set
{ if (completeMatch.empty() && lastOf < entityName.size())
//Get the entity with a sheetName completeMatch = trim(entityName.substr(lastOf+1).toUtf8());
entity = EntitiesMngr.getEntityBySheetName(entityName.toUtf8());
}
if (entity) entityName = entityName.substr(1, lastOf-1);
{ }
CCharacterCL *character = dynamic_cast<CCharacterCL*>(entity);
if (character != NULL)
{
if(character->isSelectableBySpace())
{
nldebug("isSelectableBySpace");
}
else
{
nldebug("is not isSelectableBySpace");
}
}
if(entity->properties().selectable())
{
nldebug("is prop selectable");
}
else
{
// to avoid campfire selection exploit #316
nldebug("is not prop selectable");
CInterfaceManager *pIM= CInterfaceManager::getInstance();
if(!quiet)
pIM->displaySystemInfo(CI18N::get("uiTargetErrorCmd"));
return;
}
// Select the entity // late check because only possible if doing 'starts-with' search
UserEntity->selection(entity->slot()); bool preferCompleteMatch = (completeMatch != "0");
}
else CEntityCL *entity = NULL;
{ if (preferCompleteMatch)
CInterfaceManager *pIM= CInterfaceManager::getInstance(); {
if(!quiet) // Try to get the entity with complete match first
pIM->displaySystemInfo(CI18N::get("uiTargetErrorCmd")); entity = EntitiesMngr.getEntityByName (entityName, false, true);
} }
if (entity == NULL && !keywords.empty())
{
entity = EntitiesMngr.getEntityByKeywords(keywords, true);
}
if (entity == NULL)
{
// Get the entity with a partial match using 'starts with' search
entity = EntitiesMngr.getEntityByName(entityName, false, false);
}
if (entity == NULL)
{
//Get the entity with a sheetName
entity = EntitiesMngr.getEntityBySheetName(entityName.toUtf8());
}
if (entity && entity->properties().selectable() && !entity->getDisplayName().empty())
{
UserEntity->selection(entity->slot());
}
else if (!quiet)
{
CInterfaceManager::getInstance()->displaySystemInfo(CI18N::get("uiTargetErrorCmd"));
} }
} }
}; };