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

Restore packed item state when regenerating an item using heroitem data #6567

Merged
merged 2 commits into from
Nov 19, 2023

Conversation

StephenCWills
Copy link
Member

@StephenCWills StephenCWills commented Sep 4, 2023

Mirrors the logic in UnPackItem() to restore and validate the values of fields that would have been restored during unpacking if the item didn't need to be regenerated in LoadHeroItems().

devilutionX/Source/pack.cpp

Lines 405 to 411 in 49c5aea

item._iIdentified = (packedItem.bId & 1) != 0;
item._iMaxDur = packedItem.bMDur;
item._iDurability = ClampDurability(item, packedItem.bDur);
item._iMaxCharges = std::clamp<int>(packedItem.bMCh, 0, item._iMaxCharges);
item._iCharges = std::clamp<int>(packedItem.bCh, 0, item._iMaxCharges);
RemoveInvalidItem(item);

This resolves #6561
Introduced in 1.5.1 (#6258)
Unrelated to #5580

@StephenCWills
Copy link
Member Author

Hang on, there are some potential issues I need to check into. Converting to draft.

@StephenCWills
Copy link
Member Author

In Diablo, if a packed item is regenerated for the wrong game, it's going to be a Hellfire item regenerated as a Diablo item. In this case, the regenerated item should be considered valid for Diablo because the erroneous data wouldn't include Hellfire-only base items or item powers. This could result in false positives (invalid items look valid), but cannot result in false negatives (valid items look invalid).

In Hellfire, if a packed item is regenerated for the wrong game, it doesn't really matter. All items are considered valid in Hellfire so we still don't need to worry about false negatives. Since we don't need to worry about false negatives in either case, we don't need to worry about accidentally deleting valid items in UnPackItem().

To handle the false positive case, it would stand to reason that we should invoke RemoveInvalidItem() in LoadMatchingItems(). However, we don't really need to because RemoveInvalidItem() was already called on the heroitem data when we called LoadItemData(). If the item was invalid, we'd never make it past the check for heroItem.isEmpty(), except maybe in very specific edge cases where the save data was tampered with to make it look valid.

I removed the code to adjust CF_HELLFIRE in UnPackItem() because I determined it's unnecessary. All branches in RecreateItem() lead to either InitializeItem() or GetItemAttrs(), either of which will set the flag if necessary based on the value of isHellfire that gets passed in.

@StephenCWills StephenCWills marked this pull request as ready for review September 4, 2023 01:16
@StephenCWills
Copy link
Member Author

In Diablo, if a packed item is regenerated for the wrong game, it's going to be a Hellfire item regenerated as a Diablo item.

Actually, this assertion seems to be wrong. If you take a Diablo item to Hellfire, the idx gets adjusted and the item is repacked as a Hellfire item. If that item is ever returned to Diablo, it could end up being unpacked as a Hellfire item with Hellfire affixes. That could result in false negatives. This is easy to reproduce with Demonspike Coat.

@StephenCWills
Copy link
Member Author

I decided the best way to deal with this was to eliminate the possibility of both false positives and false negatives. RemoveInvalidItem() is called after loading all the heroitem data and matching it up with unpacked item data. Other items, like ground items for example, don't need the call to RemoveInvalidItem() to be deferred because heroitems only contains data from the player's inventory. So I kept them the same by calling LoadAndValidateItemData().

Demonspike Coat can now make the round-trip through Hellfire and back. This PR should be in good shape now.

@AJenbo AJenbo added this to the 1.6.0 milestone Sep 20, 2023
@AJenbo AJenbo modified the milestones: 1.6.0, 1.5.2 Nov 19, 2023
Copy link
Member

@AJenbo AJenbo left a comment

Choose a reason for hiding this comment

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

This code (not the PR) is nightmare fule, lets hope it all goes well.

@AJenbo AJenbo merged commit c4792be into diasurgical:master Nov 19, 2023
18 checks passed
@StephenCWills StephenCWills deleted the heroitem-regen branch November 25, 2023 16:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Converting from Diablo to Hellfire resets item state
2 participants