From 5664304a1c6b5bc395ea434b838d3f80642decc8 Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Fri, 27 Oct 2017 14:47:31 +0300 Subject: [PATCH] slightly smarter stack selection lists --- src/felib/felist.cpp | 26 +++++------ src/felib/felist.h | 4 +- src/game/char.cpp | 10 ++-- src/game/command.cpp | 2 +- src/game/commands/Read.cpp | 2 +- src/game/game.h | 2 + src/game/item.h | 1 + src/game/items/lockableitem_itemcontainer.cpp | 1 + src/game/ivandef.h | 18 +++---- src/game/stack.cpp | 67 ++++++++++++++++----------- 10 files changed, 77 insertions(+), 56 deletions(-) diff --git a/src/felib/felist.cpp b/src/felib/felist.cpp index ca1b170..ddc77ac 100644 --- a/src/felib/felist.cpp +++ b/src/felib/felist.cpp @@ -36,13 +36,14 @@ truth FelistDrawController () { struct felistentry { felistentry () : ImageKey(NO_IMAGE) {} - felistentry (cfestring &String, col16 Color, uInt Marginal, uInt ImageKey, truth Selectable, feuLong udata) : + felistentry (cfestring &String, col16 Color, uInt Marginal, uInt ImageKey, truth Selectable, feuLong udata, void *uptr) : String(String), Color(Color), Marginal(Marginal), ImageKey(ImageKey), Selectable(Selectable), - UData(udata) {} + UData(udata), + UPtr(uptr) {} festring String; col16 Color; @@ -50,6 +51,7 @@ struct felistentry { uInt ImageKey; truth Selectable; feuLong UData; + void *UPtr; }; @@ -99,19 +101,13 @@ felist::~felist () { } -truth felist::IsEntrySelectable (uInt idx) const { - return (idx < Entry.size() ? Entry[idx]->Selectable : false); -} - +truth felist::IsEntrySelectable (uInt idx) const { return (idx < Entry.size() ? Entry[idx]->Selectable : false); } -feuLong felist::GetEntryUData (uInt idx) const { - return (idx < Entry.size() ? Entry[idx]->UData : 0); -} +feuLong felist::GetEntryUData (uInt idx) const { return (idx < Entry.size() ? Entry[idx]->UData : 0); } +void felist::SetEntryUData (uInt idx, feuLong udata) { if (idx < Entry.size()) Entry[idx]->UData = udata; } - -void felist::SetEntryUData (uInt idx, feuLong udata) { - if (idx < Entry.size()) Entry[idx]->UData = udata; -} +void *felist::GetEntryUPtr (uInt idx) const { return (idx < Entry.size() ? Entry[idx]->UPtr : 0); } +void felist::SetEntryUPtr (uInt idx, void *uptr) { if (idx < Entry.size()) Entry[idx]->UPtr = uptr; } void felist::Pop () { @@ -490,8 +486,8 @@ void felist::Empty () { } -void felist::AddEntry (cfestring &Str, col16 Color, uInt Marginal, uInt Key, truth Selectable, feuLong udata) { - Entry.push_back(new felistentry(Str, Color, Marginal, Key, Selectable, udata)); +void felist::AddEntry (cfestring &Str, col16 Color, uInt Marginal, uInt Key, truth Selectable, feuLong udata, void *uptr) { + Entry.push_back(new felistentry(Str, Color, Marginal, Key, Selectable, udata, uptr)); if (Maximum && Entry.size() > feuLong(Maximum)) { delete Entry[0]; Entry.erase(Entry.begin()); diff --git a/src/felib/felist.h b/src/felib/felist.h index 10fb748..767f447 100644 --- a/src/felib/felist.h +++ b/src/felib/felist.h @@ -33,7 +33,7 @@ class felist { public: felist (cfestring &Topic, col16 TopicColor=WHITE, uInt Maximum=0); ~felist (); - void AddEntry (cfestring &Str, col16 Color, uInt Marginal=0, uInt Key=NO_IMAGE, truth Selectable=true, feuLong udata=0); + void AddEntry (cfestring &Str, col16 Color, uInt Marginal=0, uInt Key=NO_IMAGE, truth Selectable=true, feuLong udata=0, void *uptr=nullptr); void AddDescription (cfestring &Str, col16 Color=WHITE); uInt Draw (); void QuickDraw (bitmap *Bitmap, uInt PageLength) const; @@ -65,6 +65,8 @@ public: truth IsEntrySelectable (uInt idx) const; feuLong GetEntryUData (uInt idx) const; void SetEntryUData (uInt idx, feuLong udata); + void *GetEntryUPtr (uInt idx) const; + void SetEntryUPtr (uInt idx, void *uptr); col16 GetColor (uInt I) const; void SetColor (uInt I, col16 What); diff --git a/src/game/char.cpp b/src/game/char.cpp index 28d4853..c76fb59 100644 --- a/src/game/char.cpp +++ b/src/game/char.cpp @@ -5900,11 +5900,13 @@ void character::SetBodyPart (int I, bodypart *What) { truth character::ConsumeItem (item *Item, cfestring &ConsumeVerb) { - if (IsPlayer() && HasHadBodyPart(Item) && !game::TruthQuestion(CONST_S("Are you sure? You may be able to put it back..."))) + if (IsPlayer() && HasHadBodyPart(Item) && !game::TruthQuestion(CONST_S("Are you sure? You may be able to put it back..."))) { return false; - if (Item->IsOnGround() && GetRoom() && !GetRoom()->ConsumeItem(this, Item, 1)) + } + if (Item->IsOnGround() && GetRoom() && !GetRoom()->ConsumeItem(this, Item, 1)) { return false; - if (IsPlayer()) ADD_MESSAGE("You begin %s %s.", ConsumeVerb.CStr(), Item->CHAR_NAME(DEFINITE)); + } + if (IsPlayer()) ADD_MESSAGE("You begin %s %s.", ConsumeVerb.CStr(), Item->CHAR_NAME(DEFINITE)); else if (CanBeSeenByPlayer()) ADD_MESSAGE("%s begins %s %s.", CHAR_NAME(DEFINITE), ConsumeVerb.CStr(), Item->CHAR_NAME(DEFINITE)); consume *Consume = consume::Spawn(this); Consume->SetDescription(ConsumeVerb); @@ -7426,7 +7428,7 @@ truth character::EquipmentScreen (stack *MainStack, stack *SecStack) { item *Equipment = GetEquipment(c); feuLong pickTm = (equippable ? HasSomethingToEquipAtRecentTime(c, false) : 0); int availEquipCount = (equippable ? HasSomethingToEquipAt(c, false) : 0); - if (pickTm > 1 && game::GetTick()-pickTm > 15+4) pickTm = 0; + if (pickTm > 1 && game::GetTick()-pickTm > game::PickTimeout) pickTm = 0; //fprintf(stderr, "c=%d; equippable=%d; availcount=%d; pickTm=%u; tick=%u\n", c, (int)equippable, availEquipCount, pickTm, game::GetTick()); if (Equipment) { Equipment->AddInventoryEntry(this, Entry, 1, true); diff --git a/src/game/command.cpp b/src/game/command.cpp index 3fe991b..2a54103 100644 --- a/src/game/command.cpp +++ b/src/game/command.cpp @@ -192,7 +192,7 @@ static truth Consume (character* Char, cchar *ConsumeVerb, sorter Sorter) { itemvector Item; festring Question = CONST_S("What do you wish to ")+ConsumeVerb+'?'; if (!game::IsInWilderness() && StackUnder->SortedItems(Char, Sorter)) - Inventory->DrawContents(Item, StackUnder, Char, Question, CONST_S("Items in your inventory"), CONST_S("Items on the ground"), CONST_S(""), 0, NO_MULTI_SELECT, Sorter); + Inventory->DrawContents(Item, StackUnder, Char, Question, CONST_S("Items in your inventory"), CONST_S("Items on the ground"), CONST_S(""), 0, NO_MULTI_SELECT|SELECT_ZEROPICK_FIRST, Sorter); else Inventory->DrawContents(Item, Char, Question, NO_MULTI_SELECT, Sorter); return !Item.empty() ? Char->ConsumeItem(Item[0], ConsumeVerb+CONST_S("ing")) : false; diff --git a/src/game/commands/Read.cpp b/src/game/commands/Read.cpp index 87d4034..91d1020 100644 --- a/src/game/commands/Read.cpp +++ b/src/game/commands/Read.cpp @@ -11,7 +11,7 @@ COMMAND(Read) { ADD_MESSAGE("It is too dark to read."); return false; } - item *Item = Char->GetStack()->DrawContents(Char, CONST_S("What do you want to read?"), 0, &item::IsReadable); + item *Item = Char->GetStack()->DrawContents(Char, CONST_S("What do you want to read?"), SELECT_MOST_RECENT, &item::IsReadable); if (Item) { if (ivanconfig::GetConfirmScrollReading() && Item->IsScroll()) { if (!game::TruthQuestion(festring("Do you really want to read ")+Item->CHAR_NAME(DEFINITE)+"?")) return false; diff --git a/src/game/game.h b/src/game/game.h index 1b3d918..c0b94ff 100644 --- a/src/game/game.h +++ b/src/game/game.h @@ -187,6 +187,8 @@ struct FuncArg { class game { public: + enum { PickTimeout = 32 }; +public: static void InitPlaces (); static truth Init(cfestring& = CONST_S("")); static void DeInit(); diff --git a/src/game/item.h b/src/game/item.h index ac906fa..95ecde2 100644 --- a/src/game/item.h +++ b/src/game/item.h @@ -328,6 +328,7 @@ class item : public object virtual truth HasLock(ccharacter*) const { return false; } virtual truth IsOnGround() const; virtual truth IsFlaming (ccharacter *) const { return CanFlame(); } + virtual truth IsLockableContainer () const { return false; } int GetResistance(int) const; virtual void Be(); int GetType() const { return GetProtoType()->GetIndex(); } diff --git a/src/game/items/lockableitem_itemcontainer.cpp b/src/game/items/lockableitem_itemcontainer.cpp index dbd1446..bf19612 100644 --- a/src/game/items/lockableitem_itemcontainer.cpp +++ b/src/game/items/lockableitem_itemcontainer.cpp @@ -32,6 +32,7 @@ ITEM(itemcontainer, lockableitem) virtual void SetParameters(int); virtual void Disappear(); virtual stack* GetContained() const { return Contained; } + virtual truth IsLockableContainer () const override { return true; } protected: virtual col16 GetMaterialColorB(int) const; virtual void PostConstruct(); diff --git a/src/game/ivandef.h b/src/game/ivandef.h index cd7bb27..1f747b4 100644 --- a/src/game/ivandef.h +++ b/src/game/ivandef.h @@ -596,14 +596,16 @@ cv2 SILHOUETTE_SIZE(48, 64); /* stack::DrawContents flags */ -#define NO_SELECT 1 // only show items -#define NO_MULTI_SELECT 2 // select only one item -#define NO_SPECIAL_INFO 4 // show only name and amount -#define REMEMBER_SELECTED 8 // if DrawContents will be called multiple times, remember the selected item -#define NONE_AS_CHOICE 16 // "none" is a choice, for instance when wielding -#define SELECT_PAIR 32 // if NO_MULTI_SELECT is on, selects a pair if appropriate -#define SKIP_FIRST_IF_NO_OLD 64 // skip first list item if `hiitem` in `stack::DrawContents()` is non-empty -#define SELECT_MOST_RECENT 128 // select most recent picked item in `stack::DrawContents()` (with timeout) +#define NO_SELECT 1 // only show items +#define NO_MULTI_SELECT 2 // select only one item +#define NO_SPECIAL_INFO 4 // show only name and amount +#define REMEMBER_SELECTED 8 // if DrawContents will be called multiple times, remember the selected item +#define NONE_AS_CHOICE 16 // "none" is a choice, for instance when wielding +#define SELECT_PAIR 32 // if NO_MULTI_SELECT is on, selects a pair if appropriate +#define SKIP_FIRST_IF_NO_OLD 64 // skip first list item if `hiitem` in `stack::DrawContents()` is non-empty +#define SELECT_MOST_RECENT 128 // select most recent picked item in `stack::DrawContents()` (with timeout) +#define SELECT_ZEROPICK_FIRST 256 // select first non-picked item in `stack::DrawContents()` +#define DONT_SELECT_CONTAINERS 512 #define RECTANGLE (game::GetGlobalConst("RECTANGLE")) #define ROUND_CORNERS (game::GetGlobalConst("ROUND_CORNERS")) diff --git a/src/game/stack.cpp b/src/game/stack.cpp index ac4e6af..b0d5f71 100644 --- a/src/game/stack.cpp +++ b/src/game/stack.cpp @@ -356,34 +356,49 @@ int stack::DrawContents (itemvector &ReturnVector, stack *MergeStack, if ((Flags&NO_SELECT) == 0) Contents.AddFlags(SELECTABLE); // `Contents.Draw()` will fix invalid selections - int selected = 0; - if (Flags&REMEMBER_SELECTED) { - if ((Flags&NONE_AS_CHOICE) && (Flags&SKIP_FIRST_IF_NO_OLD) && !hiitem && GetSelected() == 0) { - selected = 1; - } - } else { + if ((Flags&NO_SELECT) == 0) { + int selected = -1; + if ((Flags&NONE_AS_CHOICE) && (Flags&SKIP_FIRST_IF_NO_OLD) && !hiitem) { - selected = 1; + if ((Flags&REMEMBER_SELECTED) == 0 || GetSelected() == 0) selected = 1; } - } - if ((Flags&NO_SELECT) == 0 && (Flags&SELECT_MOST_RECENT)) { - int cursel = -1; - feuLong maxpt = 0; - for (uInt c = 0; c < Contents.GetLength(); ++c) { - if (!Contents.IsEntrySelectable(c)) continue; - ++cursel; - if (cursel < selected) continue; - feuLong pt = Contents.GetEntryUData(c); - if (pt <= 1 || game::GetTick()-pt > 15+4) continue; - if (pt < maxpt) continue; - maxpt = pt; - selected = cursel; + if (Flags&SELECT_MOST_RECENT) { + int cursel = -1; + feuLong maxpt = 0; + for (uInt c = 0; c < Contents.GetLength(); ++c) { + if (!Contents.IsEntrySelectable(c)) continue; + ++cursel; + if (cursel < selected) continue; + feuLong pt = Contents.GetEntryUData(c); + if (pt <= 1 || game::GetTick()-pt > game::PickTimeout) continue; + if (pt < maxpt) continue; + if (Flags&DONT_SELECT_CONTAINERS) { + item *it = (item *)Contents.GetEntryUPtr(c); + if (it && it->IsLockableContainer()) continue; + } + maxpt = pt; + selected = cursel; + } } - } - if (selected <= 0) selected = GetSelected(); - Contents.SetSelected(selected); + if (Flags&SELECT_ZEROPICK_FIRST) { + int cursel = -1; + for (uInt c = 0; c < Contents.GetLength(); ++c) { + if (!Contents.IsEntrySelectable(c)) continue; + ++cursel; + if (Flags&DONT_SELECT_CONTAINERS) { + item *it = (item *)Contents.GetEntryUPtr(c); + if (it && it->IsLockableContainer()) continue; + } + feuLong pt = Contents.GetEntryUData(c); + if (pt == 0) { selected = cursel; break; } + } + } + + if (selected <= 0) selected = GetSelected(); + Contents.SetSelected(selected); + } game::DrawEverythingNoBlit(); //doesn't prevent mirage puppies int Chosen = Contents.Draw(); @@ -446,7 +461,7 @@ void stack::AddContentsToList (felist &Contents, ccharacter *Viewer, cfestring & Entry.Empty(); Item->AddInventoryEntry(Viewer, Entry, PileVector[p].size(), !(Flags & NO_SPECIAL_INFO)); int ImageKey = game::AddToItemDrawVector(PileVector[p]); - Contents.AddEntry(Entry, (Item == hiitem ? WHITE : LIGHT_GRAY), 0, ImageKey, true, Item->pickupTime); + Contents.AddEntry(Entry, (Item == hiitem ? WHITE : LIGHT_GRAY), 0, ImageKey, true, Item->pickupTime, (void *)Item); } } @@ -796,7 +811,7 @@ truth stack::TakeSomethingFrom (character *Opener, cfestring &ContainerName) { for (;;) { itemvector ToTake; game::DrawEverythingNoBlit(); - DrawContents(ToTake, Opener, CONST_S("What do you want to take from ")+ContainerName+'?', REMEMBER_SELECTED); + DrawContents(ToTake, Opener, CONST_S("What do you want to take from ")+ContainerName+'?', REMEMBER_SELECTED|DONT_SELECT_CONTAINERS); if (ToTake.empty()) break; if (!IsOnGround() || !Room || Room->PickupItem(Opener, ToTake[0], ToTake.size())) { for (uInt c = 0; c < ToTake.size(); ++c) ToTake[c]->MoveTo(Opener->GetStack()); @@ -821,7 +836,7 @@ truth stack::PutSomethingIn (character *Opener, cfestring &ContainerName, sLong for (;;) { itemvector ToPut; game::DrawEverythingNoBlit(); - Opener->GetStack()->DrawContents(ToPut, Opener, CONST_S("What do you want to put in ")+ContainerName+'?', REMEMBER_SELECTED|SELECT_MOST_RECENT); + Opener->GetStack()->DrawContents(ToPut, Opener, CONST_S("What do you want to put in ")+ContainerName+'?', REMEMBER_SELECTED|SELECT_MOST_RECENT|DONT_SELECT_CONTAINERS); if (ToPut.empty()) break; if (ToPut[0]->GetID() == ContainerID) { ADD_MESSAGE("You can't put %s inside itself!", ContainerName.CStr()); -- 2.11.4.GIT