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

Inventory view update - Show color for food in containers, show worst rot status for containers with multiple items #46329

Closed
wants to merge 14 commits into from

Conversation

NorseFTX
Copy link
Contributor

@NorseFTX NorseFTX commented Dec 25, 2020

Summary

SUMMARY: Interface "Add Blue color for inventory display of food inside sealed containers + Show 'glass jar > [Color of rot status]pickles'"

Purpose of change

These changes are for inventory interaction convenience, with four changes made as outlined below:

  1. [EDIT: This one will be added later when items have a reference to their parent container!] Due to request, added the ability to show food that is in a sealed container (and therefore not rotting) in a separate color in both inventory and [E] Eat dialogue boxes. Light blue was selected for being somewhat similar to cyan (for other comestibles) while being a bit more readable than Blue.
    [i] Inventory:
    image
    [E] Eat dialogue:
    image
  2. [EDIT: The number will also have to be added separately so that ammo won't have a buggy / double display] Added the number of stacks of an item inside of a container (if it's the only item in a container), ie.:
    glass jar > pickles (1)
  3. Added a different coloring for the second half of a container with an item if it's food to reflect its perishable status, such as:
    image
  4. Same was added for a container with multiple items, taking the worst rot state (see cargo pants, where 25 items is brown since one of the items inside is rotten; messenger bag did not contain food at 1 level in) - NOTE this only goes 1-layer deep!:
    image

Describe the solution

  1. Updates to the nc_color color_in_inventory() function were made to handle locating an item's container and sealed status. The visit_items() function was used to search surrounding squares and the player's inventory for a given item's container.
  2. An update to the tname() function allowed outputting the number of stacks of a contained item.
  3. An update to the same section of the tname() function as in (2) was made to allow insertion of <color_COLOR> tags into the second half of an item description for container contents.
  4. An update to the next section of the tname() function after (3) was made to show the worst rot state of multiple items within a container. Priority is as follows:
    Comestible (Nonperishable) < Perishable < Old < Rotten
    All of the above are superceded by Sealed
    Note that allergy / uncooked / nausea status are not shown when there are more than 1 item in the container, although support for those can be added as well.

Describe alternatives you've considered

  • Directly putting the <color_COLOR> indicator in the [E] Eat dialogue code of game_inventory around the "sealed" descriptor would be possible, although this will not color the name of the item itself, and also doesn't color the item in any other inventory screens.
  • Tried blue instead of light blue as the sealed color, it's somewhat more difficult to read:
    image
  • Tried to avoid having to search every surrounding square and player's inventory, but directly calling visit_items in the color_in_inventory() function isn't legal, and the item itself was found not to contain the parent container anyway when forcing visit_items to work by creating an item_location referencing the item, or by force-removing the const typing of the referenced item.

Testing

Testing the coloring - Load the game:

  1. Spawn 2x Canned Chicken ([f] contained)
  2. Drop one of the cans on the floor
  3. Open [i] to check coloring in inventory
  4. Open [/] and check [a] all neighboring squares to check coloring of neighboring items
  5. Open [E] to check coloring within Eat menu

Sample of how the [E] Eat dialogue currently looks:
image

Same of the [/] Advanced Inventory dialogue:
image
NOTE Notice that when a container with an item is highlighted in adv inventory, the second half doesn't get highlighted, although this doesn't happen in [i] inventory view (?), not sure if there's an easy fix for this. They also do not properly grey out when in the inactive window.

Testing multiple items in containers:

  1. Spawn a fillet of fish
  2. Spawn wheat
  3. Spawn butter
  4. Pass time until the fillet of fish's status changes to old or rotten
  5. Spawn a small cardboard box
  6. Add all items to cardboard box and take them out progressively to ensure the coloring of the "> # items" text is correct.
    Cardboard box with a rotten item:
    image
    Cardboard box with at most a perishable item:
    image

Additional context

The display bug with the advanced inventory dialogue (see testing section's "NOTE" in bold) might need fixing, suggestions are welcome.

@NorseFTX
Copy link
Contributor Author

NorseFTX commented Dec 26, 2020

Dang, looks like I can't really add in (2) the number of items in the container (gallon jug > milk (3) can't show the 3) because it appears to cause issues for ammo display. I'll remove it for now, and find a way to put that in at a later time.

src/item.cpp Outdated
}
return VisitResponse::NEXT;
} );
for( const map_cursor &checkp : nearby ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Oof, that's gonna hurt inventory performance immensely.

Try checking the following scenario:

  • open debug menu -> spawn item -> Everything
  • open inventory

@Aivean
Copy link
Contributor

Aivean commented Dec 26, 2020

This is a really cool change, and I like how it looks, however, due to how the item hierarchy is currently implemented, we probably would need to postpone parts of this PR, specifically, checking nearby map squares to find item's parent.

We discussed the possibility to add backlinks to the items (which will allow to have some nice things, like a hierarchical caches). If backlinks are added, implementing changes like this PR would be painless. But realistically that could happen only in the next dev cycle.

@Aivean Aivean added [C++] Changes (can be) made in C++. Previously named `Code` Info / User Interface Game - player communication, menus, etc. Items / Item Actions / Item Qualities Items and how they work and interact labels Dec 26, 2020
@NorseFTX
Copy link
Contributor Author

Adding backlinks for an item to its parent container would probably be the most elegant way to implement this; I'd be fine with waiting on implementing these changes until that's done (or trying to do that myself). The performance hit when viewing inventory is my biggest concern for this, and is why I really don't like this solution of having to look through everything to find a parent, although there really isn't a built-in way for an object upon being placed in a sealed container to inherit a sort of "I'm in a sealed container" flag or "this container is my parent" flag.

For now I'll remove the sealed item color indicator so that there isn't a performance hit, and just retain the color of the part after " > [item inside]".

src/item.cpp Outdated
contents_suffix_text = string_format( npgettext( "item name",

int worstrot = 0;
if( contents.get_sealed_summary() == item_contents::sealed_summary::all_sealed ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Content of sealed container may still rot if the container has a spoil multiplier larger than 0. For example bottle_plastic has "spoil_multiplier": 0.5.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Alright; can get the spoil multiplier in that case, will fix

…ng indicator. Removed sealed indicator for multiple items.
src/item.cpp Outdated
const item_pocket* const parent_pocket = contained_where(contents_item);
colorprefix = "<" + string_from_color( contents_item.color_in_inventory() ) + ">";
colorprefix.replace( 1, 1, "color" ); // changes <c_cyan> to <color_cyan>
if( contents.get_sealed_summary() == item_contents::sealed_summary::all_sealed && parent_pocket->spoil_multiplier() == 0 ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if( contents.get_sealed_summary() == item_contents::sealed_summary::all_sealed && parent_pocket->spoil_multiplier() == 0 ) {
if( parent_pocket->sealed() && parent_pocket->spoil_multiplier() == 0 ) {

sealed_summary checks all of the container's pockets, but in this case only the pocket containing the content item matters.

Copy link
Contributor

Choose a reason for hiding this comment

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

And it seems this only checks for sealed container but not rot progress, whereas the code below in the multiple-item case only checks for rot progress but not sealed container?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The top checks for rot progress by calling contents_item.color_in_inventory(), although sealed will supercede it.
The bottom only currently checks rot progress without checking sealed since multiple items in sealed containers isn't a thing right now(?) (see lower comment, if not I can put it in!)
And yes, I think checking sealed and the parent pocket are redundant, the parent pocket by itself is probably (?) fine, will fix!

src/item.cpp Outdated
Comment on lines 4639 to 4645
contents_suffix_text = string_format( pgettext( "item name",
//~ [container item name] " > [inner item name]"
" > %1$s" ),
" > %1$s%2$s" ),
/* with_contents=false for nested items to prevent excessively long names */
colorprefix, contents_item.tname( contents_count, true, 0, false )
/* with_contents=false for nested items to prevent excessively long names */
contents_item.tname( contents_count, true, 0, false ) );
) + string_format( "%s", colorsuffix );
Copy link
Contributor

Choose a reason for hiding this comment

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

Please store the color instead of the color prefix/suffix strings and use colorize( text, color ) (from color.h) to add color to the text.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh! I was not aware of that function, but will use it now!

src/item.cpp Outdated
// If container has multiple food items, take the worst rot state and use that as the color for the "# items" text.
// 0 = No food; 1 = Non-perishable (cyan); 2 = Perishable (light cyan); 3 = Old (yellow); 4 = Rotten (brown)
for( const item *it : contents.all_items_top( item_pocket::pocket_type::CONTAINER ) ) {
if( worstrot < 4 && it->rotten() ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why did you remove the check for sealed container here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is it currently possible to seal a container with multiple items in such a way that it is no longer rotting, and for the container to have multiple "pockets" in which one is sealed and no longer rotting while other pockets are not sealed and actively rotting?
I removed it due to complexity of handling the above case (and that sealing a container with multiple items in it is not something I think is supported right now (?))

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 actually would be happy to write sealed (non-rotting) support for multiple items if you have a quick way to generate a sealed + spoil modifier = 0 container with multiple items that are perishable inside so I can test it!

Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can write a unit test that creates one such item and check the name of that item, if you want.

src/item.cpp Outdated
Comment on lines 4669 to 4674
contents_suffix_text = string_format( pgettext( "item name",
//~ [container item name] " > [count] item"
" > %1$zd item", " > %1$zd items",
contents.num_item_stacks() ), contents.num_item_stacks() );
" > %1$s" ), colorprefix ) +
string_format( ngettext( "%1$zd item", "%1$zd items", contents.num_item_stacks() ),
contents.num_item_stacks() ) +
string_format( pgettext( "color suffix", "%1$s" ), colorsuffix );
Copy link
Contributor

@Qrox Qrox Dec 27, 2020

Choose a reason for hiding this comment

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

Please store the color instead of the color prefix/suffix strings and use colorize( text, color ) (from color.h) to add color to the text.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

(Oh huh, that's odd, didn't realize this comment was duplicated; addressed it in the latest commit!)

@NorseFTX NorseFTX changed the title Inventory view update - Show new color for food in sealed containers, rot status and # stacks of items in containers Inventory view update - Show color for food in containers, show worst rot status for containers with multiple items Dec 27, 2020
@8street
Copy link
Contributor

8street commented Dec 28, 2020

Hi. A week ago, I got the idea to paint items the same way. But I gave it up. The selected items are highlighted in a very strange way. I see you have the same problem. And I don't really like whats it looks. I tried remove all color tags in the text output function first, but that didn't help. I approve your solution, but it is not 100% complete.

I was poking around in the highlighting function and noticed that there are very few color combinations that can be highlighted. Perhaps adding color combinations there will be solve a problem.

@NorseFTX
Copy link
Contributor Author

NorseFTX commented Dec 30, 2020

Hi. A week ago, I got the idea to paint items the same way. But I gave it up. The selected items are highlighted in a very strange way. I see you have the same problem. And I don't really like whats it looks. I tried remove all color tags in the text output function first, but that didn't help. I approve your solution, but it is not 100% complete.

I was poking around in the highlighting function and noticed that there are very few color combinations that can be highlighted. Perhaps adding color combinations there will be solve a problem.

Yeah, I don't like the fact that the display isn't clean either. I have a feeling it's the order in which the advanced inventory menu colors items with the gray (unselected) versus selected screen, as this issue doesn't seem to appear in the normal inventory menu, which handles it fine. I may have to take a look at that; I might instead close this temporarily until I can push a fix.
(Have been busy so it would likely be easier to just remove this from the list of open pull requests until I'm able to work on it)

@NorseFTX NorseFTX closed this Dec 30, 2020
@NorseFTX
Copy link
Contributor Author

NorseFTX commented Dec 30, 2020

Nevermind, was able to find the fix after looking through the advanced_inv code.

Before fix:
image

After fix:
image

Had to strip the color tags in the same way they are stripped in the inventory_ui.cpp code using the remove_color_tags() function, similar to what you had tried; I guess it was just a matter of where the function was called. Thanks for encouraging a fix to the display bug!

NOTE: You might notice it also "fixes" (not sure if it was a problem) the green "||" still being green when in the inactive window, and probably any other instances of item coloring not graying out in the advanced inventory's inactive window.

@NorseFTX NorseFTX reopened this Dec 30, 2020
@8street
Copy link
Contributor

8street commented Dec 30, 2020

Please check the highlighting in the pickup window (g) and in the look around items window (shift-v).

@NorseFTX
Copy link
Contributor Author

Didn't realize those could be an issue, checking now!

@NorseFTX
Copy link
Contributor Author

NorseFTX commented Dec 30, 2020

Looks like when you choose to pick up with [g] Get, it highlights only the container as the object to get, which makes sense:
image

After picking it up, the message log shows up with the color:
image

Same goes for [V] View items (condiment bottle with mayonnaise is highlighted, where only the condiment bottle is green in the below), which I think is okay, since you're not viewing the mayonnaise, but instead viewing the bottle containing the mayonnaise:
image

Just to be safe, here is the [D]/[d] Multidrop dialogue:
image

The [w] Wield dialogue:
image

[e] Examine (same as [g] Get):
image

[r] Reload:
image

[t] Throw:
image

[T] Take off:
image

[W] Wear:
image

[U] Unload:
image

[i] Inventory:
image

[I] Compare Inventory:
image

[P] Log (also correctly takes history of a container's content coloring):
image

[x] Look around:
image

[B] Butcher:
image

[(] Disassemble:
image

[=] Swap Inventory Letters:
image

[+] Sort Armor (seems to ignore coloring for items inside if there is no food inside, which ...is probably fine for the purposes of this dialogue):
image

[+] Sort Armor if I put food into a bag:
image

Looks like things are okay now in all the dialogues that have items without any weird highlighting or display bugs as was in the advanced inventory menu (just went through all the keys on the keyboard, hopefully I didn't miss anything xP).

@NorseFTX
Copy link
Contributor Author

Just saw Qrox's comment about testing the sealed / spoil = 0 container with multiple items; I think I can probably just edit the jsons to make the zipper bag or something have a spoil modifier of 0 and increase its volume capacity to test multiple 'sealed' non-rotting items. May hold off on committing this until I write in the sealed color for containers with multiple items.

@actual-nh
Copy link
Contributor

You might also want to check containers within containers.

@NorseFTX
Copy link
Contributor Author

NorseFTX commented Dec 31, 2020

Oh, containers within containers were mentioned in the first post, this only goes one container deep at the moment; should I recursively go through all inner containers instead? I can see justification for doing it, since people have to carry liquids inside of a container within their primary clothing/backpack pocket, and if a liquid spoils and it's in a bag filled with other items it'd be useful to know. I might try to add that in too.

@NorseFTX
Copy link
Contributor Author

NorseFTX commented Jan 1, 2021

Looks like going more than 1 layer deep was a lot simpler than I thought it would be since there's already a function that will pull all pointers to items inside a container instead of just the top layer, bless

It now can handle containers in containers (messenger bag has a gallon jug that has old milk in it):
image

If I take out the 2nd item from the messenger bag:
image

Looks like it works!
Just need to add sealed support for a sealed + spoil-multiplier = 0 container with multiple items and it should be good.

@NorseFTX
Copy link
Contributor Author

NorseFTX commented Jan 1, 2021

As a comment on the latest commit, when looking at the code itself, it's quite messy; it would be much easier if there were a function that allowed an item to backlink to the container or pocket it was in (sigh, it always comes back to that when handling sealed items). The code as it currently is essentially is a workaround for the lack of a backlink. It's nowhere as much of a performance hit as it would be to check all items in surrounding squares for every item in the inventory, but it is a recursive check through contents of each container (if it has things inside) in a given area of "visible" inventory.
An "is this food actively spoiling"? check, without having to activate the 'time passing' functions would also probably make the code much simpler (and more efficient).

Pseudocode style, this is the logic the edited code follows:

For Single items

check item inside
is this item food or does this item have food inside? if yes, check if the item is in a nonspoiling pocket. If so, return light blue (and strip color tags), if not return item color as default
otherwise, color as default

For Multi Items

check all items inside top level
do any of the items in top level have food in them? if yes, then check if that top level item is in a nonspoiling pocket. If so, return lightblue. If at least one with food is not in a sealed container, return as not sealed.
if none of the items in top level have food, then sealed is not returned, use default coloring
if sealed use light blue coloring for "> # items"
if not sealed, will get worst rot state only for pockets that can spoil

The below 9 test cases were used on a test container where I edited the zipper bag to instead have two pockets of much larger size and weight capacity:
Pocket 1: Spoil Multiplier = 0
Pocket 2: Spoil Multiplier = 1

Test Zipper bag (in containers.json):

  {
    "id": "bag_zipper",
    "type": "GENERIC",
    "category": "container",
    "name": { "str": "zipper bag" },
    "looks_like": "bag_plastic",
    "description": "An inexpensive flexible rectangular storage bag on its typical small size.  Transparent and made of plastic, it can be sealed and opened by a slider which works in a similar way to a zip fastener.",
    "weight": "2 g",
    "volume": "10 ml",
    "longest_side": "40 cm",
    "price": 0,
    "price_postapoc": 10,
    "material": [ "plastic" ],
    "pocket_data": [
      {
        "pocket_type": "CONTAINER",
        "watertight": true,
        "max_contains_volume": "1250 ml",
        "max_contains_weight": "2000 g",
        "spoil_multiplier": 0.0,
        "moves": 400
      },
      {
        "pocket_type": "CONTAINER",
        "watertight": true,
        "max_contains_volume": "1250 ml",
        "max_contains_weight": "2000 g",
        "spoil_multiplier": 1.0,
        "moves": 400
      }
    ],
    "symbol": ")",
    "color": "light_gray",
    "flags": [ "TRADER_AVOID" ]
  }

Test cases below;
light_blue = sealed
cyan = nonperishable consumable
light_cyan = perishable consumable

Case 1:
P1: Dandelions + Lemon
P2: Empty

Result: 
zipper bag [c_light_blue]> 2 items[/c]
(All perishables are in a nonspoiling pocket)

Case 2:
P1: Dandelions + Lemon
P2: Rock

Result
zipper bag [c_light_blue]> 3 items[/c]
(All perishables are in a nonspoiling pocket)

Case 3:
P1: Dandelions + Lemon
P2: Dandelions

Result
zipper bag [c_light_cyan]> 3 items[/c]
(One perishable is in a spoiling pocket)

Case 4:
P1: Dandelions + Lemon
P2: Buckwheat

Result
zipper bag [c_cyan]> 3 items[/c]
(One non-perishable food is in a spoiling pocket)

Case 5:
P1: Empty
P2: Buckwheat + Dandelions

Result
zipper bag [c_light_cyan]> 3 items[/c]
(One perishable is in a spoiling pocket)

Case 6:
P1: Glass Jar > Dandelions
P2: Empty

Result
zipper bag [c_light_blue]> glass jar > 1 item[/c]
(Perishable in jar is in a sealed pocket)

Case 7:
P1: Empty
P2: Glass Jar > Dandelions

Result
zipper bag > glass jar [c_light_cyan]> 1 item[/c]
(Perishable in jar is in spoiling pocket)

Case 8:
P1: Glass Jar > Dandelions
P2: Glass Jar > Dandelions

Result
zipper bag [c_light_cyan]> 2 items[/c]
(At least one of the perishables in jar is in a spoiling pocket)

Case 9:
P1: Glass Jar > Milk (Old)
P2: Dandelions

Result
zipper bag [c_light_cyan] > 2 items[/c]
(A perishable is in the spoiling pocket, and although there is an old item, it is in a non-spoiling pocket, so that pocket is skipped.)

The current code as it is now passes all nine of the test cases (the code became as complex as it is in order to handle all the scenarios properly).

That should cover everything regarding adding color indicators for consumables within pockets/containers (hopefully!)

@jbytheway
Copy link
Contributor

If possible, it would be great to have these test cases enshrined in the unit tests.

@Tairesh
Copy link
Contributor

Tairesh commented Jun 12, 2021

image
Here is a small bug with this, <color> tag in the right top corner of vending machine

@Night-Pryanik
Copy link
Contributor

@NorseFTX could you please resolve conflicts?

@I-am-Erk
Copy link
Member

I am marking this project as "abandoned" but, since it is doing something we want, I have put it in an Abandoned PR list to hopefully be reinitiated at some point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[C++] Changes (can be) made in C++. Previously named `Code` Info / User Interface Game - player communication, menus, etc. Items / Item Actions / Item Qualities Items and how they work and interact
Projects
Status: Abandoned PRs with no one to pick them up
Development

Successfully merging this pull request may close these issues.

10 participants