Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto store items on container based on inscribed regex #608

Open
wants to merge 38 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
15d64ae
Merge pull request #24 from Attnam/master
AquariusPower May 24, 2018
99ef7d6
Merge pull request #25 from Attnam/master
AquariusPower May 28, 2018
af8c444
Merge pull request #26 from Attnam/master
AquariusPower May 29, 2018
9979cf8
Merge pull request #27 from Attnam/master
AquariusPower May 30, 2018
8714ec6
Merge pull request #28 from Attnam/master
AquariusPower May 31, 2018
47044b9
Merge pull request #29 from Attnam/master
AquariusPower May 31, 2018
b4be00e
Merge branch 'master' of https://github.com/Attnam/ivan into Attnam-m…
AquariusPower Jun 1, 2018
a5387b8
Merge branch 'master' of https://github.com/Attnam/ivan into Attnam-m…
AquariusPower Jun 1, 2018
9f2cf80
Merge pull request #30 from Attnam/master
AquariusPower Jun 6, 2018
6d71776
Merge pull request #31 from Attnam/master
AquariusPower Jun 13, 2018
0f7bbaa
Merge pull request #32 from Attnam/master
AquariusPower Jun 19, 2018
932103d
Merge pull request #33 from Attnam/master
AquariusPower Jun 28, 2018
d5bfecc
Merge pull request #34 from Attnam/master
AquariusPower Jul 19, 2018
d028bf9
Merge pull request #35 from Attnam/master
AquariusPower Jul 19, 2018
1812c10
Merge pull request #37 from Attnam/master
AquariusPower Jul 20, 2018
cf1dc8e
Merge pull request #38 from Attnam/master
AquariusPower Jul 21, 2018
91dd7fd
Merge pull request #39 from Attnam/master
AquariusPower Aug 29, 2018
11f489a
Merge pull request #40 from Attnam/master
AquariusPower Sep 1, 2018
10b7dab
Merge pull request #41 from Attnam/master
AquariusPower Oct 2, 2018
5e97b45
Merge pull request #42 from Attnam/master
AquariusPower Oct 2, 2018
2bcac17
Merge pull request #43 from Attnam/master
AquariusPower Dec 15, 2018
2adf952
Merge pull request #44 from Attnam/master
AquariusPower Dec 17, 2018
2ea63f2
Merge pull request #45 from Attnam/master
AquariusPower Dec 21, 2018
e9ef42d
Merge pull request #46 from Attnam/master
AquariusPower Jan 9, 2019
720ec65
Merge pull request #48 from Attnam/master
AquariusPower Jan 21, 2019
57200e5
Merge pull request #49 from Attnam/master
AquariusPower Feb 6, 2019
7c5d75f
Merge branch 'master' of https://github.com/Attnam/ivan into Attnam-m…
AquariusPower Jun 5, 2020
a197cd7
NOT WORKING HERE: auto store item in container (some code is missing …
AquariusPower Jun 5, 2020
8159c3b
auto store item in container is working!
AquariusPower Jun 8, 2020
809cbe5
missing #include <iostream>
AquariusPower Jun 8, 2020
d59e521
commented helpful output as travis-ci wont compile it even with: #inc…
AquariusPower Jun 8, 2020
29752d7
pcre for igor and mihail
AquariusPower Jun 8, 2020
8965d9a
Merge branch 'master' into AutoStoreOnContainer
AquariusPower Oct 4, 2020
73c3e10
Merge branch 'master' into AutoStoreOnContainer
ryfactor Sep 14, 2021
e9735fe
Merge branch 'master' into AutoStoreOnContainer
AquariusPower Oct 31, 2021
9af0add
Merge branch 'master' into AutoStoreOnContainer
ryfactor Dec 1, 2021
4c5829a
Merge branch 'master' into AutoStoreOnContainer
ryfactor Dec 20, 2021
c9d5657
Merge branch 'master' into AutoStoreOnContainer
ryfactor Dec 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions FeLib/Include/festring.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include <climits>
#include <vector>
#include <pcre.h>

#include "felibdef.h"

Expand Down Expand Up @@ -119,6 +120,7 @@ class festring
void ExtractWord(festring&);
long GetCheckSum() const;
void EnsureOwnsData(bool = false);
static pcre* CompilePCRE(pcre *pcreExistingRegexWorker, cfestring &fsPattern, festring *pfsErrorMsg=NULL);
private:
static void InstallIntegerMap();
static void DeInstallIntegerMap();
Expand Down
51 changes: 49 additions & 2 deletions FeLib/Source/festring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <iostream>

#include "festring.h"
#include "allocate.h"
#include "error.h"
Expand Down Expand Up @@ -713,8 +715,13 @@ festring::sizetype festring::IgnoreCaseFind(cfestring& Where,
return NPos;
}

/* Replaces all occurances of What in Where after Begin with With */

/**
* Replaces all occurances of What in Where after Begin with With
* @param Where
* @param What
* @param With
* @param Begin
*/
void festring::SearchAndReplace(festring& Where, cfestring& What,
cfestring& With, sizetype Begin)
{
Expand Down Expand Up @@ -907,3 +914,43 @@ void festring::EnsureOwnsData(bool Unique)
CreateOwnData(Data, Size);
}
}

/**
*
* @param pcreExistingRegexWorker it has to be freed if was already set
* @param fsPattern
* @param bWarnOnError
* @return
*/
pcre* festring::CompilePCRE(pcre *pcreExistingRegexWorker, cfestring &fsPattern, festring *pfsErrorMsg)
{
if(pcreExistingRegexWorker)
pcre_free(pcreExistingRegexWorker);

if(fsPattern.IsEmpty())
return NULL;

const char *errMsg;
int iErrOffset;
pcreExistingRegexWorker = pcre_compile(
fsPattern.CStr(),
0, // no options
&errMsg, &iErrOffset,
0 // default char tables
);

if (!pcreExistingRegexWorker){
festring fsErr;
fsErr<<"Regex validation failed, if ignored will just not work at all.\n"
<<errMsg<<",\n"
<<"offset:"<<iErrOffset<<".";

DBG1(fsErr.CStr());
//TODO let this work with travis-ci compilation...: std::cerr<<fsErr.CStr()<<std::endl;

if(pfsErrorMsg)
(*pfsErrorMsg)=fsErr;
}

return pcreExistingRegexWorker;
}
4 changes: 3 additions & 1 deletion Main/Include/game.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ class game
static void UpdateSRegionsXBRZ(bool bIsXBRZScale);
static void RegionSilhouetteEnable(bool b);
static void RegionListItemEnable(bool b);
static cchar* StoreMatchNameKey(item* it,bool bUnarticled=false);
static void AutoStoreItemInContainer(item* itToStore,character* C);
static void UpdatePosAroundForXBRZ(v2 ScreenPos);
static void SRegionAroundDisable();
static void SRegionAroundAllow();
Expand Down Expand Up @@ -393,7 +395,7 @@ class game
static bool ToggleShowMapNotes();
static bool CheckAddAutoMapNote(square* =NULL);
static int CheckAutoPickup(square* sqr = NULL);
static void UpdateAutoPickUpMatching();
static void UpdateAutoPickUpRegex();
static int RotateMapNotes();
static char MapNoteToken();
static bool IsAutoPickupMatch(cfestring fsName);
Expand Down
1 change: 1 addition & 0 deletions Main/Include/ivandef.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ const name##prototype name::ProtoType
#define INDEFINE_BIT 4
#define INDEFINITE 6
#define STRIPPED 8
#define UNLABELED 16

#define TRANSPARENT_COLOR 0xF81F // pink

Expand Down
5 changes: 5 additions & 0 deletions Main/Include/miscitem.h
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@ ITEM(itemcontainer, lockableitem)
public:
itemcontainer();
itemcontainer(const itemcontainer&);
static truth OpenGeneric(character* Opener, stack* Stk, festring fsName, long volume, ulong ID);
virtual ~itemcontainer();
virtual truth Open(character*);
virtual void Load(inputfile&);
Expand Down Expand Up @@ -469,10 +470,14 @@ ITEM(itemcontainer, lockableitem)
virtual void SetParameters(int);
virtual void Disappear();
virtual stack* GetContained() const { return Contained; }
virtual void SetLabel(cfestring& What);
truth IsAutoStoreMatch(cfestring fs);
protected:
virtual col16 GetMaterialColorB(int) const;
virtual void PostConstruct();
stack* Contained;
pcre* pcreAutoStoreRegex;
bool bLazyInitPcre;
};

ITEM(beartrap, itemtrap<item>)
Expand Down
13 changes: 8 additions & 5 deletions Main/Source/cmdcraft.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,16 +100,16 @@ bool craftcore::EmptyContentsIfPossible(recipedata& rpd,item* itContainer, bool

/**
* Why this is important?
*
* Because if the item remain on slot, and 1 turn has not passed,
*
* Because if the item remain on slot, and 1 turn has not passed,
* what may happpen on crafting code in case user gives up on crafting action,
* it will provide inconsistent inventory contents (something that was sent to hell
* but is still on inventory as the turn has not passed to properly send it to hell).
*
*
* If all the above is correctly understood as "it is how thing work",
* then crafting should be fixed to always pass one turn even if user giveup?
* But that doesnt looks good, giveup = cancel, should not pass a turn at all.
*
*
* This shall be used for anything related to crafting until something better is coded.
*/
void craftcore::SendToHellSafely(item* it)
Expand Down Expand Up @@ -2096,7 +2096,10 @@ struct srpInspect : public recipe{
material* matM = it0->GetMainMaterial();
material* matS = it0->GetSecondaryMaterial();
festring fs;
fs<<it0->GetName(DEFINITE)<<" is made of ";
fs << it0->GetName(DEFINITE)
<< " (" << game::StoreMatchNameKey(it0) << " or " //used by auto-store items on containers, so here is the place to determine it's value
<< game::StoreMatchNameKey(it0,true) << ")"
<< " is made of ";
if(matM)fs<<matM->GetName(UNARTICLED);
if(matS){
if(matM)fs<<" and "; //actually, there is only 2nd material if there is main but anyway...
Expand Down
5 changes: 4 additions & 1 deletion Main/Source/command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,8 @@ truth commandsystem::PickUp(character* Char)
if(game::IsAutoPickupMatch(PileVector[0][c]->GetName(DEFINITE))){
PileVector[0][c]->ClearTag('d'); //intentionally drop tag dismissed for autopickup regex match
}

game::AutoStoreItemInContainer(PileVector[0][c],Char);
}

ADD_MESSAGE("%s picked up.", PileVector[0][0]->GetName(INDEFINITE, Amount).CStr());
Expand Down Expand Up @@ -1145,7 +1147,8 @@ truth commandsystem::WhatToEngrave(character* Char,bool bEngraveMapNote,v2 v2Eng
break;

festring What = ToAddLabel[0]->GetLabel();
if(game::StringQuestion(What, CONST_S("What would you like to inscribe on this item?"), WHITE, 0, 20, true) == NORMAL_EXIT)
int iMaxChars=150; // item labels can contain user custom hints to let the algorithm use these to perform automatic actions
if(game::StringQuestion(What, CONST_S("What would you like to inscribe on this item?"), WHITE, 0, iMaxChars, true) == NORMAL_EXIT)
for(int i=0;i<ToAddLabel.size();i++)
ToAddLabel[i]->SetLabel(What);
}
Expand Down
115 changes: 71 additions & 44 deletions Main/Source/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1324,40 +1324,70 @@ int game::RotateMapNotes()
return iMapNotesRotation;
}

std::vector<festring> afsAutoPickupMatch;
pcre *reAutoPickup=NULL;
void game::UpdateAutoPickUpMatching() //simple matching syntax
/**
*
* @param it
* @param bUnarticled if false is GetNameSingular()
* @return
*/
cchar* game::StoreMatchNameKey(item* it,bool bUnarticled)
{
afsAutoPickupMatch.clear();

bool bSimple=false;
if(bSimple){ //TODO just drop the simple code? or start the string with something to let it be used instead of regex? tho is cool to let ppl learn regex :)
if(ivanconfig::GetAutoPickUpMatching().GetSize()==0 || ivanconfig::GetAutoPickUpMatching()[0]=='!')return;
static festring fsRet,fsSpace=" ",fsEmpty="";
static cchar* cToken="+";

fsRet="";
fsRet<<cToken;
if(bUnarticled)
fsRet<<it->GetName(UNARTICLED|UNLABELED);
else
fsRet<<it->GetNameSingular()<<cToken;

festring::SearchAndReplace(fsRet,fsSpace,fsEmpty,0);

return fsRet.CStr();
}

std::stringstream ss(ivanconfig::GetAutoPickUpMatching().CStr());
std::string match;
while(std::getline(ss,match,'|'))
afsAutoPickupMatch.push_back(festring(match.c_str()));
}else{
//TODO test regex about: ignoring broken lanterns and bottles, ignore sticks on fire but pickup scrolls on fire
// static bool bDummyInit = [](){reAutoPickup=NULL;return true;}();
const char *errMsg;
int iErrOffset;
if(reAutoPickup)pcre_free(reAutoPickup);
reAutoPickup = pcre_compile(
ivanconfig::GetAutoPickUpMatching().CStr(), //pattern
0, //no options
&errMsg, &iErrOffset,
0); // default char tables
if (!reAutoPickup){
std::vector<festring> afsFullProblems;
afsFullProblems.push_back(festring(errMsg));
afsFullProblems.push_back(festring()+"offset:"+iErrOffset);
bool bDummy = iosystem::AlertConfirmMsg("regex validation failed, if ignored will just not work at all",afsFullProblems,false);
void game::AutoStoreItemInContainer(item* itToStore,character* C)
{
if(!C->IsPlayer())
return;

static itemvector vit;vit.clear();
C->GetStack()->FillItemVector(vit);
for(int i=0;i<vit.size();i++){
DBGITEM(vit[i],"checkingIfIsAContainer");
itemcontainer* itc = dynamic_cast<itemcontainer*>(vit[i]);
if(itc){
long lRemainingVol = itc->GetStorageVolume() - itc->GetContained()->GetVolume();
DBG3(lRemainingVol,itToStore->GetVolume(),itc->GetLabel().CStr());
if(lRemainingVol<itToStore->GetVolume())
continue;

if(itc->IsAutoStoreMatch(itToStore->GetName(DEFINITE))){
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think changing this line to
if(!itc->IsLocked() && itc->IsAutoStoreMatch(itToStore->GetName(DEFINITE))){
suffices to solve #608 (comment) request

itToStore->RemoveFromSlot();
itc->GetContained()->AddItem(itToStore);
ADD_MESSAGE("%s was safely stored in %s",itToStore->GetName(DEFINITE).CStr(),itc->GetName(DEFINITE).CStr());
break;
}
}
}
}

pcre *reAutoPickup=NULL;
void game::UpdateAutoPickUpRegex()
{
//TODO test regex about: ignoring broken lanterns and bottles, ignore sticks on fire but pickup scrolls on fire
festring fsErr;
reAutoPickup = festring::CompilePCRE(reAutoPickup,ivanconfig::GetAutoPickUpMatching(),&fsErr);
if(!fsErr.IsEmpty()){
std::vector<festring> afsFullProblems;
afsFullProblems.push_back(fsErr);
bool bDummy = iosystem::AlertConfirmMsg("Failed updating auto-pickup regex.",afsFullProblems,false);
}
}
bool game::IsAutoPickupMatch(cfestring fsName) {
if(!reAutoPickup)
return false;
return pcre_exec(reAutoPickup, 0, fsName.CStr(), fsName.GetSize(), 0, 0, NULL, 0) >= 0;
}
int game::CheckAutoPickup(square* sqr)
Expand All @@ -1370,34 +1400,31 @@ int game::CheckAutoPickup(square* sqr)

lsquare* lsqr = (lsquare*)sqr;

static bool bDummyInit = [](){UpdateAutoPickUpMatching();return true;}();
static bool bDummyInit = [](){UpdateAutoPickUpRegex();return true;}();
itemvector iv;
lsqr->GetStack()->FillItemVector(iv);
int iTot=0;
for(int i=0;i<iv.size();i++){
item* it = iv[i];
if(it->GetRoom() && it->GetRoom()->GetMaster())continue; //not from owned rooms
if(it->GetSpoilLevel()>0)continue;
if(it->GetSpoilLevel()>0)continue; //just a guess no one auto-wants it

bool b=false;
if(!b && ivanconfig::IsAutoPickupThrownItems() && it->HasTag('t') )b=true; //was thrown
if(!b && !it->HasTag('d')){
if(reAutoPickup!=NULL){
if(IsAutoPickupMatch(it->GetName(DEFINITE))){
b=true;
}
}
}
if(!b){ //TODO use player's perception, in case of a stack of items, to allow random pickup based on item volume (size) where smaller = harder like tiny rings, to compensate for the easiness of not losing a round having to pick up the item interactively
for(int i=0;i<afsAutoPickupMatch.size();i++){ //each simple match
if(it->GetNameSingular().Find(afsAutoPickupMatch[i].CStr(),0) != festring::NPos){
b=true;
break; //each simple match loop
}
}
if(!b && !it->HasTag('d')){ //was NOT intentionally dropped (dropping adds such tag)
/**
* TODO ?
* Use player's perception, in case of a stack of items,
* to allow random pickup based on item volume (size) where smaller = harder like tiny rings,
* to compensate for the easiness of not losing a round having to pick up the item interactively.
* But it may just be annnoying...
*/
b = IsAutoPickupMatch(it->GetName(DEFINITE));
}
if(b){
it->MoveTo(PLAYER->GetStack());
ADD_MESSAGE("%s picked up.", it->GetName(INDEFINITE).CStr());
AutoStoreItemInContainer(it,PLAYER);
iTot++;
}
}
Expand Down
9 changes: 7 additions & 2 deletions Main/Source/iconf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@ stringoption ivanconfig::SelectedBkgColor("SelectedBkgColor",
&SelectedBkgColorChanger);
stringoption ivanconfig::AutoPickUpMatching("AutoPickUpMatching",
"Auto pick up regex",
"Automatically pick up items according to a regular expression. To disable something, you can invalidate it with '_' without removing it from the expression (eg. '_dagger'). To disable everything at once, begin this config option with '!'. Due to current constraints on length of options, editing is easier to do externally for now.", //TODO if multiline text editing is implemented, remove the last help statement.
"Automatically pick up items according to a regular expression.\n"
" To disable something, you can invalidate it with '_' without removing it from the expression (eg. '_dagger').\n"
" To disable everything at once, begin this config option with '!'.\n"
" Containers inscribed with eg. '+key+ring+scroll' will auto store such items,\n"
" and you can determine what to inscribe by craft/inspecting the items.\n"
" Due to current constraints on length of options, editing is easier to do externally for now.", //TODO if multiline text editing is implemented, remove the last help statement.
"!((book|can|dagger|grenade|horn of|kiwi|key|ring|scroll|wand|whistle)|^(?:(?!(broken|empty)).)*(bottle|vial)|sol stone)",
&configsystem::NormalStringDisplayer,
&AutoPickUpMatchingChangeInterface,
Expand Down Expand Up @@ -911,7 +916,7 @@ void ivanconfig::AutoPickUpMatchingChanger(stringoption* O, cfestring& What)
if(O!=NULL){
O->Value.Empty();
O->Value<<What;
game::UpdateAutoPickUpMatching();
game::UpdateAutoPickUpRegex();
}
}

Expand Down
2 changes: 1 addition & 1 deletion Main/Source/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ void item::AddName(festring& Name, int Case) const
{
object::AddName(Name,Case);

if(label.GetSize())
if(!(Case&UNLABELED) && label.GetSize())
Name << " inscribed " << label;
}

Expand Down
Loading