-
Notifications
You must be signed in to change notification settings - Fork 513
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
Gravedigging tour fix #388
Gravedigging tour fix #388
Conversation
Basically just causes Dampe's Gravedigging Tour Heart Piece to set a Collect flag on the Graveyard Scene when collected instead of a GetItemInf flag when it's spawned. I did this by simply the result of Item_DropCollectible to a variable called reward and running reward->collectibleFlag = 0x19 if the reward was a heartpiece. There may be a better way to do this. This is unlike most of the other dropped items with collectible flags in the game, which have some binary operations performed on the item to be dropped before passing it into Item_DropCollectible. See z_en_geldb.c and z_bg_haka_tubo.c for examples of this. I tried to find some way to do something more like that here but I was unable to wrap my head around the binary operations being performed. I may revisit this in the future.
Tooltip is long enough that it could use a newline or two to break it up |
Oh, for some reason I just didn't even think about newlines in the tooltips being a thing at all. I'll add one or two. |
Ok I added some new lines to that tooltip. |
I think |
You're probably right, I didn't know about the bug before I started fixing it, so I felt the need to explain what the bug was, but interested parties can just Google it. One thing I forgot to mention is that I currently set the old flag no matter whether the cvar is set or not, but the new flag only gets set if the cvar is on, and the cvar also determines which flag gets checked. The idea was that a player couldn't duplicate the heart piece by checking the box, getting the heart piece, and then unchecking the box, but I just realized the way it is currently still possible to duplicate it if you get it with the box unchecked and then check the box. I could fix this by also setting the new flag regardless of cvar value, but that feels a bit weird to do. Should I do that and just let the cvar determine which flag gets checked? Or should I give up on the anticheat mechanisms and just check and set one flag or the other? EDIT: changed set to checked in the second to last sentence. |
I also just realized I accidentally left in the |
I almost said something about that since I thought that was weird! My view on anti-cheating is that, if it wasn't possible to dupe the heart pieces before your change, then it shouldn't be possible after your change, which means doing whatever you need to in order to enforce that. |
Ok, that's kinda what I was thinking, I was just hesitant since it requires setting a flag that wasn't set in vanilla whether the cvar introduced is set to on or off, which felt a bit weird to do. Although I suppose the check for that flag is the only thing that actually changes any behavior and that check would still be locked behind the cvar being nonzero. So that's 3 changes for tonight then:
If there's anything else I'd be happy to add it to the list! |
Ok, that should fix the above points. |
Resolved some merge conflicts resulting from the recent commits to the develop branch. |
If this were to get merged, should this be on by default, like the Deku Nut Upgrade fix is, or off by default? |
I don't see why it should be off, there's not really a case where you'd want to lock yourself out of a heart piece. |
OK, I guess I just wasn't sure if you all would be OK with the default experience differing from the vanilla N64 experience in that way. |
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.
LGTM
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.
LGTM
// Initialized with bugfixed condition, overriden with original check if bugfix cvar is 0 (which is default). | ||
bool condition = Flags_GetCollectible(globalCtx, 0x19) == 0; | ||
if (CVar_GetS32("gGravediggingTourFix", 0) == 0) { | ||
condition = !(gSaveContext.itemGetInf[1] & 0x1000); | ||
} | ||
if (condition) { | ||
this->currentReward = 4; | ||
gSaveContext.itemGetInf[1] |= 0x1000; | ||
} | ||
} |
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.
// Initialized with bugfixed condition, overriden with original check if bugfix cvar is 0 (which is default). | |
bool condition = Flags_GetCollectible(globalCtx, 0x19) == 0; | |
if (CVar_GetS32("gGravediggingTourFix", 0) == 0) { | |
condition = !(gSaveContext.itemGetInf[1] & 0x1000); | |
} | |
if (condition) { | |
this->currentReward = 4; | |
gSaveContext.itemGetInf[1] |= 0x1000; | |
} | |
} | |
if (!(gSaveContext.itemGetInf[1] & 0x1000) | |
|| (CVar_GetS32("gGravediggingTourFix", 0) != 0 && !Flags_GetCollectible(globalCtx, 0x19))) { | |
gSaveContext.itemGetInf[1] |= 0x1000; | |
this->currentReward = 4; | |
} | |
} |
This should make the logic look a little cleaner. if the itemGetInf flag isn't set, it should always enter the if statement (assuming nothing else sets that flag), otherwise we check if the fix should be applied and that the collectible flag hasn't been set yet. Not familiar with how CVar_GetS32
is used, but I imagine the != 0
isn't necessary unless it's needed for style reasons.
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.
You are correct that the != 0
probably isn't required. I didn't feel like experimenting with whether or not C automatically saw zero as false and nonzero as true so I just went explicit with the boolean expression. I have since double checked that it does so I could change that.
As for the larger change here, wouldn't this make it so that if someone triggered the glitch with the box unchecked by getting the heart piece and leaving, they would then be unable to get the Heart Piece by checking the box and trying again? The old flag still gets set to preserve the vanilla behavior, and the OR
clause in your change would then return true
with that flag set whether the CVar
for the fix is 1
or 0
. My current code already covers this case, by not checking the vanilla flag if the fix is enabled, but if it would be better for readability I could take your check and add another &&
for the CVar being 0. So the full condition check would be
if (!(CVar_GetS32("gGravediggingTourFix", 0)) && !(gSaveContext.itemGetInf[1] & 0x1000)
|| CVar_GetS32("gGravediggingTourFix", 0) && !(Flags_GetCollectible(globalCtx, 0x19))) {
I have doubts if that is really more readable though. That's a pretty lengthy boolean expression and has multiple calls to CVar_GetS32("gGravediggingTourFix, 0)
whereas my current code only has one.
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.
As for the larger change here, wouldn't this make it so that if someone triggered the glitch with the box unchecked by getting the heart piece and leaving, they would then be unable to get the Heart Piece by checking the box and trying again?
it shouldn't. the simplified pseudocode here is this:
if (!itemGetInf) OR (fixEnabled AND !collectibleFlag) {
set itemGetInf true
set reward to heart container
}
The optimization here is that if the itemGetInf flag is false, it is safe to assume that the collectibleFlag is also false regardless of whether the fix should be applied or not. This is because itemGetInf flips to true when the heart container is spawned for the first time, and if the heart container hasn't ever spawned, then collectibleFlag can't be true. The OR here simply introduces an extra alternative condition for spawning the heart container.
Toggling the option should not lead to duplicates or making the heart permanently skippable; this is mainly because with the code written this way, the itemGetInf state and collectibleFlag state is always set the same way, independent of the state of the fix flag.
Lastly, writing things this way has the additional side effect where if someone wanted to reset the heart piece, they would only have to zero the original flag, rather than two different flags depending on which setting was enabled.
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.
OH I see, you're right, I think I misinterpreted the check on the old flag as it being collected returning true rather than not collected. That is a good point that I didn't see right away and the last point you made is also good.
…into gravedigging-tour-fix
This originally introduced a bug where the player could spawn multiple heart pieces by simply not collecting the one that spawns and continuing to dig up spots. This fixes that by checking a temp clear flag before spawning the heart piece and setting it when the heart piece spawns. Since this is a temp clear flag it will not stay set if the player exits the scene, so this still does fix the bug of locking the player out of the heart piece when spawning it and leaving without picking it up. As far as I can tell this temp clear flag isn't used anywhere else in this scene. The only one used in this scene I could find is that killing the first Poe in this scene sets flag 0x02 (or maybe it's 0x01, not sure if the flags start at 1 or 0).
…into gravedigging-tour-fix
I implemented @mzxrules suggestion to simplify the check condition for whether or not to spawn the heart piece, and also added an additional check to prevent players from spawning multiple heart pieces by not collecting the piece and not leaving the scene, but continuing to play the Gravedigging Tour. See commit a4c7833 for details. |
you can probably just create a new local variable in z_en_tk that stores whether the heart piece has been spawned, instead of reserving a second collectible flag. |
Tested the windows version of that fixes from https://builds.shipofharkinian.com/job/SoH_Multibranch/view/change-requests/job/PR-388/ that has been recently built with your recent changes and crashes instantly on Windows |
Yeah I'm seeing the crash too, I definitely had it working a few minutes ago though, trying to figure out which commit started crashing. |
As far as I can tell, something in the most recent commit to the develop branch causes my code to crash the game. Develop apparently works fine without this PR, and my PR works without the most recent commit from develop, but something about the combo of the two is causing the game to crash. Working on figuring out why now. |
Well what I reserved was a TempClear flag rather than a collectible flag to be clear, but I guess the point still stands that a local variable might be better. |
Apparently Develop was crashing on Windows for several people, as we found out on the Discord channel, so turns out the crash was not caused by my code. The fix has been identified, just waiting for it to get put in. |
Looks like that fix is in #425 |
I didn't even think of having bug fixes togglable leading to problems when being switching them during gameplay and contributors also having to prevent those problems. |
#define COLLECTFLAG_GRAVEDIGGING_HEART_PIECE 0x19 | ||
#define ITEMGETINFFLAG_GRAVEDIGGING_HEART_PIECE 0x1000 | ||
|
||
bool heartPieceSpawned; |
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.
This needs to be added to the save states. I'd also give it a more specific name so there are no clashes and make it a s32
type
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.
Hmm, can I add that to save states? It's a local variable to that actor right? Or did I inadvertently make a global variable when I did that.
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.
Nice job with this.
* Fixes the Gravedigging Tour heartpiece bug. Basically just causes Dampe's Gravedigging Tour Heart Piece to set a Collect flag on the Graveyard Scene when collected instead of a GetItemInf flag when it's spawned. I did this by simply the result of Item_DropCollectible to a variable called reward and running reward->collectibleFlag = 0x19 if the reward was a heartpiece. There may be a better way to do this. This is unlike most of the other dropped items with collectible flags in the game, which have some binary operations performed on the item to be dropped before passing it into Item_DropCollectible. See z_en_geldb.c and z_bg_haka_tubo.c for examples of this. I tried to find some way to do something more like that here but I was unable to wrap my head around the binary operations being performed. I may revisit this in the future. * Reimplements vanilla bug, adds cvar and checkbox for the fix. * Adds some newlines to the Tooltip * Shortens ImGui tooltip. * Removes the hardcoded Purple Rupee/Heart Piece reward. * Sets collectibleFlag whether cvar is on or not to prevent duping. * Sets Gravedigging Tour Fix to enabled by default * Simplifies logic for whether or not to spawn heart piece * Adds TempClear flag set and check for heart piece. This originally introduced a bug where the player could spawn multiple heart pieces by simply not collecting the one that spawns and continuing to dig up spots. This fixes that by checking a temp clear flag before spawning the heart piece and setting it when the heart piece spawns. Since this is a temp clear flag it will not stay set if the player exits the scene, so this still does fix the bug of locking the player out of the heart piece when spawning it and leaving without picking it up. As far as I can tell this temp clear flag isn't used anywhere else in this scene. The only one used in this scene I could find is that killing the first Poe in this scene sets flag 0x02 (or maybe it's 0x01, not sure if the flags start at 1 or 0). * Replaces magic numbers with constants defined in z_en_tk.h * Updates comment explaining changed code. * Replaces another magic number I forgot to replace last commit. * Replaces TempClear flag with local variable * Removes TempClearFlag const and moves others out of .h to .c (felt like they made more sense there)
* Fixes the Gravedigging Tour heartpiece bug. Basically just causes Dampe's Gravedigging Tour Heart Piece to set a Collect flag on the Graveyard Scene when collected instead of a GetItemInf flag when it's spawned. I did this by simply the result of Item_DropCollectible to a variable called reward and running reward->collectibleFlag = 0x19 if the reward was a heartpiece. There may be a better way to do this. This is unlike most of the other dropped items with collectible flags in the game, which have some binary operations performed on the item to be dropped before passing it into Item_DropCollectible. See z_en_geldb.c and z_bg_haka_tubo.c for examples of this. I tried to find some way to do something more like that here but I was unable to wrap my head around the binary operations being performed. I may revisit this in the future. * Reimplements vanilla bug, adds cvar and checkbox for the fix. * Adds some newlines to the Tooltip * Shortens ImGui tooltip. * Removes the hardcoded Purple Rupee/Heart Piece reward. * Sets collectibleFlag whether cvar is on or not to prevent duping. * Sets Gravedigging Tour Fix to enabled by default * Simplifies logic for whether or not to spawn heart piece * Adds TempClear flag set and check for heart piece. This originally introduced a bug where the player could spawn multiple heart pieces by simply not collecting the one that spawns and continuing to dig up spots. This fixes that by checking a temp clear flag before spawning the heart piece and setting it when the heart piece spawns. Since this is a temp clear flag it will not stay set if the player exits the scene, so this still does fix the bug of locking the player out of the heart piece when spawning it and leaving without picking it up. As far as I can tell this temp clear flag isn't used anywhere else in this scene. The only one used in this scene I could find is that killing the first Poe in this scene sets flag 0x02 (or maybe it's 0x01, not sure if the flags start at 1 or 0). * Replaces magic numbers with constants defined in z_en_tk.h * Updates comment explaining changed code. * Replaces another magic number I forgot to replace last commit. * Replaces TempClear flag with local variable * Removes TempClearFlag const and moves others out of .h to .c (felt like they made more sense there)
Basically just causes Dampe's Gravedigging Tour Heart Piece to set a Collect flag on the Graveyard Scene when collected instead of a GetItemInf flag when it's spawned. I did this by simply saving the result of Item_DropCollectible to a variable called reward and running reward->collectibleFlag = 0x19 if the reward was a heartpiece. As far as I can tell, the only other collectible in Spot02_Graveyard (the crate heart piece that you need the flying magic bean plant for) does not share this flag, so it should be safe to use.
There may be a better way to do this. This is unlike most of the other dropped items with collectible flags in the game, which have some binary operations performed on the item to be dropped before passing it into Item_DropCollectible. See z_en_geldb.c and z_bg_haka_tubo.c for examples of this. I tried to find some way to do something more like that here but I was unable to wrap my head around the binary operations being performed. I may revisit this in the future.