-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Eating same food repeatedly gives less fun #35910
Eating same food repeatedly gives less fun #35910
Conversation
Needs more work. I realized I can't safely use item pointers, since the items will probably go out of scope (thus the Travis failure). Also, I want to make foods with different ingredients count as different from each other. |
91e8a62
to
4d6a5da
Compare
Okay, instead of keeping track of the items themselves, this now keeps track of a history of item IDs and hashes of their associated components. |
The consumption history doesn't seem to be saved? |
I coded up the serialization/deserialization as per Qrox's astute observation, unfortunately, the |
|
||
consumption_event( const item &food ) { | ||
time = calendar::turn; | ||
type_id = food.typeId(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this could be included in the hash. You don't actually do anything but compare it, just like the hash.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
KorGgenT expressed interest in using this consumption history for other things (like a in-game nutrient-tracking device) later, so I figured I'd store the item type separately.
if( fun > 0 || comest.has_flag( "NEGATIVE_MONOTONY_OK" ) ) { | ||
for( const consumption_event &event : consumption_history ) { | ||
if( event.time > calendar::turn - 2_days && event.type_id == comest.typeId() && | ||
event.component_hash == comest.make_component_hash() ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since comest.make_component_hash()
is always calculated here each time and not cached, you might just as well compare the component list directly, which actually might be faster, and you don't have to worry about hash collision and serialization too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had it like that, but it would require storing the entire items in event
which would be making a ton of unnecessary item copies.
std::multiset<std::string> id_set; | ||
for( const item &it : components ) { | ||
id_set.insert( it.typeId() ); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand this correctly, food with even the slightly different components will not suffer from the monotony penalty, and food with the same components but completely different sub-components will still suffer from the penalty? I think ideally there should be a metric to determine how similar two foods are, but I'm not sure how (or whether) that could be done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just have another idea, though it might actually belong to a separate PR: count the fun bonus and monotony penalty from sub-components and cooking recipes separately, so making different foods from the same materials, and making the same food from different materials will both impose a penalty, while eating the same food made from the same materials gives the most penalty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a bad idea, but again, I don't see a way of doing that without storing copies of the items themselves in the consumption_event
struct. Doing this for every NPC as well as the player would be a huge performance overhead for a relatively small feature.
I will say that these problems:
Bother me too. I thought about making some exceptions, like not counting If you (or anyone) can think of a solution that improves on these two problems, while keeping the stored |
Primarily to expand support for very large integers. Before, precision was being lost due to conversion to float, and then back to integer. I also made integer loading more strict. An error will now be thrown if: 1. An unsigned integer is provided with a negative value. 2. The supplied integer is too big (we now have int64 support, but even that has its limits) 3. An integer is supplied with a decimal (previously it was truncated) 4. The above rules hold even when scientific notation is used (yes, we have support for using scientific notation in JSON fields) Number 3 immediately caused a lot of errors in both the base game and in mods. I went through and fixed these.
ef00aa2
to
16ad3dc
Compare
Well, serialization is done. As far as the component comparison issues go, we discussed it on discord, and:
I am now satisfied with this (though it does now require #35999). |
The way the absolute value of INT_MIN was being determined before may have given inconsistent results on different platforms. Also, switched to using std::numeric_limits rather than the corresponding macro constants.
8f2d6bf
to
d3fe69c
Compare
I wanted to be absolutely sure that these functions never risked overflow at any point on any compiler, because I know that if at any point they return an incorrect value, saved games will fail to load due to incorrectly thinking it's unsafe to read INT_MIN from JSON. Also, Qrox pointed out that they should be constexpr.
Introduces a new JSON comestible property, "monotony_penalty", that is subtracted from a food item's fun score for every identical meal you've eaten in the last 48 hours. Foods are considered identical if the have the same id, and their components also have the same ids. The penalty can't take a food's fun below 0 or reduce fun for foods that already had negative fun, unless that food has the "NEGATIVE_MONOTONY_OK" flag. Default "monotony_penalty" is 2, except for junk food where it's 0.
The first method was just using bitwise XOR of the string hashes of the components' type IDs. This could be prone to collisions. Instead, this method sorts, concatenates, and then hashes the IDs.
So that monotony penalties carry over upon save/load.
d3fe69c
to
fccacad
Compare
Requires #35999.
Summary
SUMMARY: Features "Eating same food repeatedly gives less fun"
Purpose of change
Simulates food getting less exciting when you eat it repeatedly.
Intended to be used for nutrient bars in #35872.
Describe the solution
Introduces a new JSON comestible property, "monotony_penalty", that is subtracted from a food item's fun score for every food like it you've eaten in the last 48 hours. The penalty can't take a food's fun below 0 or reduce fun for foods that already had negative fun, unless that food has the "NEGATIVE_MONOTONY_OK" flag.
Foods are only considered similar for this purpose if their type IDs, and the type IDs of their components, match.
Default "monotony_penalty" is 2, except for junk food where it's 0.
Describe alternatives you've considered
Testing
Additional context