Refactor Fishsanity (#4268)
* Move Fishsanity hooks out of mods.cpp * Assign fish check flags. * Clean up location_list for fish * Prevent fishing from giving double items. * Remove no-longer-used mPendingFish * Override draw function for fishing This allows the draw functions in the source overlay to match the decomp. * Override draw function for EnFish * Overwrite grotto fish params based on respawn data This allows the randomizer to identify them automatically without any special logic. The catch (pun not intended) is that grotto fish don't respawn, and they were previously identified for such by a params value of 1, so the logic to take care of that needed to be duplicated. Thankfully it wasn't very much. * Add a VB for catching actors in bottles. * Clean up remaining code after conversion to VB This breaks fast FastDrops for bottle pickups, though readding it shouldn't be too hard with the VB hook. * Remove fishsanityParams from Fishing It was previously used to track exactly which fish would be released after a catch, but since both candidate fish would've been caught, they both wouldn't give checks anyways. * Update soh/soh/Enhancements/randomizer/hook_handlers.cpp Co-authored-by: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> * Re-add FastDrops for bottle pickups. While this does diverge from the vanilla decomp, I'm uncertain of the order that hooks are run, so I put it back into z_player.c just to be safe. A future commit can do a more proper implementation using VB hooks. * Move initialisation of fishsanity hooks into hook_handlers * Change location constructor to take RandomizerInf instead of uint8_t This shouldn't have an effect as-is, but other changes can add additional randomizer flags that can end up pushing fishsanity check flags out of the range of a uint8_t, causing the cast to overflow and not be stored correctly. With this change, it could still overflow when writing to the flag field of Location, but said field is unused and the parameter is really only for setting the flag for the SpoilerCollectionCheck. * Render uncaught overworld fish as randomized item * Fix windows build by zeroing unused field * Fix scene parameter type This resolves a build error on Mac and Windows, but Linux instead buries it in the sea of warnings, meaning I can't see it until it fails CI. --------- Co-authored-by: Pepe20129 <72659707+Pepe20129@users.noreply.github.com>
This commit is contained in:
@@ -7,7 +7,6 @@
|
||||
#include "z_en_fish.h"
|
||||
#include "objects/gameplay_keep/gameplay_keep.h"
|
||||
#include "vt.h"
|
||||
#include "soh/Enhancements/randomizer/fishsanity.h"
|
||||
|
||||
#define FLAGS 0
|
||||
|
||||
@@ -37,7 +36,6 @@ void EnFish_Unique_SwimIdle(EnFish* this, PlayState* play);
|
||||
static Actor* D_80A17010 = NULL;
|
||||
static f32 D_80A17014 = 0.0f;
|
||||
static f32 D_80A17018 = 0.0f;
|
||||
static Color_RGBA16 fsPulseColor = { 30, 240, 200 };
|
||||
|
||||
static ColliderJntSphElementInit sJntSphElementsInit[1] = {
|
||||
{
|
||||
@@ -762,31 +760,10 @@ void EnFish_Update(Actor* thisx, PlayState* play) {
|
||||
}
|
||||
}
|
||||
|
||||
// #region SOH [Randomizer]
|
||||
s32 EnFish_FishsanityOverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot,
|
||||
void* thisx) {
|
||||
EnFish* this = (EnFish*)thisx;
|
||||
Fishsanity_OpenGreyscaleColor(play, &fsPulseColor, ABS(this->actor.params) * 20);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EnFish_FishPostLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
|
||||
Fishsanity_CloseGreyscaleColor(play);
|
||||
}
|
||||
// #endregion
|
||||
|
||||
void EnFish_Draw(Actor* thisx, PlayState* play) {
|
||||
EnFish* this = (EnFish*)thisx;
|
||||
|
||||
Gfx_SetupDL_25Opa(play->state.gfxCtx);
|
||||
// #region SOH [Randomizer]
|
||||
// Modify drawing for uncollected fish, having a shadowDraw implies this is being given uncollected FX
|
||||
if (IS_RANDO && Randomizer_GetOverworldFishShuffled() && this->actor.shape.shadowDraw != NULL) {
|
||||
SkelAnime_DrawSkeletonOpa(play, &this->skelAnime, EnFish_FishsanityOverrideLimbDraw, EnFish_FishPostLimbDraw, this);
|
||||
Collider_UpdateSpheres(0, &this->collider);
|
||||
return;
|
||||
}
|
||||
// #endregion
|
||||
SkelAnime_DrawSkeletonOpa(play, &this->skelAnime, NULL, NULL, NULL);
|
||||
Collider_UpdateSpheres(0, &this->collider);
|
||||
}
|
||||
@@ -15,8 +15,6 @@
|
||||
#define FLAGS ACTOR_FLAG_UPDATE_WHILE_CULLED
|
||||
|
||||
#define WATER_SURFACE_Y(play) play->colCtx.colHeader->waterBoxes->ySurface
|
||||
#define IS_FISHSANITY (IS_RANDO && Randomizer_GetPondFishShuffled())
|
||||
#define FISHID(params) (Randomizer_IdentifyFish(play->sceneNum, params))
|
||||
bool getShouldSpawnLoaches();
|
||||
|
||||
void Fishing_Init(Actor* thisx, PlayState* play);
|
||||
@@ -433,7 +431,6 @@ static f32 sFishGroupAngle3;
|
||||
static FishingEffect sFishingEffects[FISHING_EFFECT_COUNT];
|
||||
static Vec3f sStreamSoundProjectedPos;
|
||||
static s16 sFishOnHandParams;
|
||||
static Color_RGBA16 fsPulseColor = { 30, 240, 200 };
|
||||
|
||||
u8 AllHyruleLoaches() {
|
||||
return CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFishing"), 0) && CVarGetInteger(CVAR_ENHANCEMENT("AllHyruleLoaches"), 0);
|
||||
@@ -3998,9 +3995,6 @@ void Fishing_UpdateFish(Actor* thisx, PlayState* play2) {
|
||||
sFishOnHandLength = this->fishLength;
|
||||
sFishOnHandIsLoach = (this->isLoach || AllHyruleLoaches());
|
||||
sLureCaughtWith = sLureEquipped;
|
||||
if (IS_FISHSANITY) {
|
||||
sFishOnHandParams = this->fishsanityParams;
|
||||
}
|
||||
Actor_Kill(&this->actor);
|
||||
} else if (getShouldConfirmKeep() && (this->isLoach == 0 && !AllHyruleLoaches()) && (sFishOnHandIsLoach == 0) &&
|
||||
((s16)this->fishLength < (s16)sFishOnHandLength)) {
|
||||
@@ -4015,11 +4009,6 @@ void Fishing_UpdateFish(Actor* thisx, PlayState* play2) {
|
||||
sLureCaughtWith = sLureEquipped;
|
||||
this->fishLength = lengthTemp;
|
||||
this->isLoach = loachTemp;
|
||||
if (IS_FISHSANITY) {
|
||||
s16 paramsTemp = sFishOnHandParams;
|
||||
sFishOnHandParams = this->fishsanityParams;
|
||||
this->fishsanityParams = paramsTemp;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this->keepState == 0) {
|
||||
@@ -4040,11 +4029,6 @@ void Fishing_UpdateFish(Actor* thisx, PlayState* play2) {
|
||||
sLureCaughtWith = sLureEquipped;
|
||||
this->fishLength = temp1;
|
||||
this->isLoach = temp2;
|
||||
if (IS_FISHSANITY) {
|
||||
s16 paramsTemp = sFishOnHandParams;
|
||||
sFishOnHandParams = this->fishsanityParams;
|
||||
this->fishsanityParams = paramsTemp;
|
||||
}
|
||||
}
|
||||
sRodCastState = 0;
|
||||
}
|
||||
@@ -4310,13 +4294,6 @@ s32 Fishing_FishOverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Ve
|
||||
void* thisx) {
|
||||
Fishing* this = (Fishing*)thisx;
|
||||
|
||||
// #region SOH [Randomizer]
|
||||
// A fish having a shadowDraw implies that it is being given uncollected FX
|
||||
if (IS_FISHSANITY && this->actor.shape.shadowDraw != NULL) {
|
||||
Fishsanity_OpenGreyscaleColor(play, &fsPulseColor, (this->actor.params - 100) * 20);
|
||||
}
|
||||
// #endregion
|
||||
|
||||
if (limbIndex == 0xD) {
|
||||
rot->z -= this->fishLimbDRotZDelta - 11000;
|
||||
} else if ((limbIndex == 2) || (limbIndex == 3)) {
|
||||
@@ -4339,13 +4316,6 @@ s32 Fishing_FishOverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Ve
|
||||
void Fishing_FishPostLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
|
||||
Fishing* this = (Fishing*)thisx;
|
||||
|
||||
// #region SOH [Randomizer]
|
||||
// A fish having a shadowDraw implies that it is being given uncollected FX
|
||||
if (IS_FISHSANITY && this->actor.shape.shadowDraw != NULL) {
|
||||
Fishsanity_CloseGreyscaleColor(play);
|
||||
}
|
||||
// #endregion
|
||||
|
||||
if (limbIndex == 0xD) {
|
||||
Matrix_MultVec3f(&sFishMouthOffset, &this->fishMouthPos);
|
||||
}
|
||||
@@ -4355,13 +4325,6 @@ s32 Fishing_LoachOverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, V
|
||||
void* thisx) {
|
||||
Fishing* this = (Fishing*)thisx;
|
||||
|
||||
// #region SOH [Randomizer]
|
||||
// A fish having a shadowDraw implies that it is being given uncollected FX
|
||||
if (IS_FISHSANITY && this->actor.shape.shadowDraw != NULL) {
|
||||
Fishsanity_OpenGreyscaleColor(play, &fsPulseColor, (this->actor.params - 100) * 20);
|
||||
}
|
||||
// #endregion
|
||||
|
||||
if (limbIndex == 3) {
|
||||
rot->y += this->loachRotYDelta[0];
|
||||
} else if (limbIndex == 4) {
|
||||
@@ -4377,13 +4340,6 @@ void Fishing_LoachPostLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3
|
||||
static Vec3f sLoachMouthOffset = { 500.0f, 500.0f, 0.0f };
|
||||
Fishing* this = (Fishing*)thisx;
|
||||
|
||||
// #region SOH [Randomizer]
|
||||
// A fish having a shadowDraw implies that it is being given uncollected FX
|
||||
if (IS_FISHSANITY && this->actor.shape.shadowDraw != NULL) {
|
||||
Fishsanity_CloseGreyscaleColor(play);
|
||||
}
|
||||
// #endregion
|
||||
|
||||
if (limbIndex == 0xB) {
|
||||
Matrix_MultVec3f(&sLoachMouthOffset, &this->fishMouthPos);
|
||||
}
|
||||
|
||||
@@ -57,7 +57,6 @@ typedef struct Fishing {
|
||||
/* 0x0220 */ LightInfo lightInfo;
|
||||
/* 0x0230 */ ColliderJntSph collider;
|
||||
/* 0x0250 */ ColliderJntSphElement colliderElements[12];
|
||||
/* */ s16 fishsanityParams;
|
||||
} Fishing; // size = 0x0550
|
||||
|
||||
#define EN_FISH_OWNER 1 // param for owner of pond. default if params<100
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "soh/Enhancements/enhancementTypes.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
#include "soh/Enhancements/randomizer/randomizer_grotto.h"
|
||||
#include "soh/Enhancements/randomizer/fishsanity.h"
|
||||
#include "soh/frame_interpolation.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
@@ -13955,33 +13954,9 @@ void Player_Action_8084ECA4(Player* this, PlayState* play) {
|
||||
|
||||
func_8083721C(this);
|
||||
|
||||
// TODO: Rework the bottle rando code in vanilla behavior overhaul
|
||||
if (LinkAnimation_Update(play, &this->skelAnime)) {
|
||||
if (this->av1.actionVar1 != 0) {
|
||||
if (IS_RANDO && this->av1.actionVar1 < 0) {
|
||||
rc = this->av2.actionVar2;
|
||||
// Award rando item; this should only give us GI_NONE if something went wrong during the catch setup
|
||||
gi = Randomizer_GetItemFromKnownCheck(rc, GI_NONE);
|
||||
temp = Randomizer_GetRandomizerInfFromCheck(rc);
|
||||
// Either we can't give an item, we can't tell if we've gotten the check, or we have definitely gotten the check
|
||||
if (gi.getItemId == GI_NONE || temp == RAND_INF_MAX || Flags_GetRandomizerInf(temp)) {
|
||||
this->av1.actionVar1 = 0;
|
||||
if (this->interactRangeActor != NULL)
|
||||
this->interactRangeActor->parent = NULL;
|
||||
}
|
||||
// Item get cutscene hasn't played yet
|
||||
else if((this->interactRangeActor == NULL && !(this->stateFlags1 & PLAYER_STATE1_ITEM_OVER_HEAD)) || !Actor_HasParent(this->interactRangeActor, play)) {
|
||||
// Can't guarantee that whatever we "caught" is actually going to still exist
|
||||
if (GiveItemEntryWithoutActor(play, gi)) {
|
||||
// have to set this flag manually to prevent interactRangeActor from being wiped out
|
||||
this->stateFlags1 |= PLAYER_STATE1_ITEM_OVER_HEAD;
|
||||
this->pendingFlag.flagID = temp;
|
||||
this->pendingFlag.flagType = FLAG_RANDOMIZER_INF;
|
||||
Flags_SetRandomizerInf(temp);
|
||||
}
|
||||
|
||||
}
|
||||
} else if (this->av2.actionVar2 == 0) {
|
||||
if (this->av2.actionVar2 == 0) {
|
||||
if (CVarGetInteger(CVAR_ENHANCEMENT("FastDrops"), 0)) {
|
||||
this->av1.actionVar1 = 0;
|
||||
} else {
|
||||
@@ -14017,42 +13992,15 @@ void Player_Action_8084ECA4(Player* this, PlayState* play) {
|
||||
}
|
||||
}
|
||||
|
||||
if (i < 4) {
|
||||
if (GameInteractor_Should(VB_BOTTLE_ACTOR, i < 4, this->interactRangeActor)) {
|
||||
this->av1.actionVar1 = i + 1;
|
||||
this->av2.actionVar2 = 0;
|
||||
this->interactRangeActor->parent = &this->actor;
|
||||
// TODO: this should probably be refactored a bit, maybe rehome some of this to rando instead
|
||||
if (IS_RANDO) {
|
||||
// Check if fishsanity applies for this actor
|
||||
if (Randomizer_GetOverworldFishShuffled()) {
|
||||
fish = Randomizer_IdentifyFish(play->sceneNum, this->interactRangeActor->params);
|
||||
if (fish.randomizerCheck != RC_UNKNOWN_CHECK && !Flags_GetRandomizerInf(fish.randomizerInf)) {
|
||||
gi = Randomizer_GetItemFromKnownCheck(fish.randomizerCheck, GI_FISH);
|
||||
rc = fish.randomizerCheck;
|
||||
// check if the item is a bottle item anyway
|
||||
catchInfo = NULL;
|
||||
for (j = 0; j < 4; j++) {
|
||||
if (D_80854A04[j].itemId == gi.itemId) {
|
||||
catchInfo = &D_80854A04[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Vanilla behavior/rando gave a bottle item
|
||||
if (!IS_RANDO || catchInfo != NULL) {
|
||||
Player_UpdateBottleHeld(play, this, catchInfo->itemId, ABS(catchInfo->itemAction));
|
||||
if (!CVarGetInteger(CVAR_ENHANCEMENT("FastDrops"), 0)) {
|
||||
this->stateFlags1 |= PLAYER_STATE1_IN_ITEM_CS | PLAYER_STATE1_IN_CUTSCENE;
|
||||
Player_AnimPlayOnceAdjusted(play, this, sp24->unk_04);
|
||||
func_80835EA4(play, 4);
|
||||
}
|
||||
} else if (IS_RANDO && gi.itemId != ITEM_NONE) {
|
||||
// Non-bottle item found from rando, flag for special behavior
|
||||
this->av1.actionVar1 = -1;
|
||||
this->av2.actionVar2 = rc;
|
||||
Player_UpdateBottleHeld(play, this, catchInfo->itemId, ABS(catchInfo->itemAction));
|
||||
if (!CVarGetInteger(CVAR_ENHANCEMENT("FastDrops"), 0)) {
|
||||
this->stateFlags1 |= PLAYER_STATE1_IN_ITEM_CS | PLAYER_STATE1_IN_CUTSCENE;
|
||||
Player_AnimPlayOnceAdjusted(play, this, sp24->unk_04);
|
||||
func_80835EA4(play, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user