testing out item replacement (#416)

* skip learning song of storms

* don't set flag when getting goron tunic as child

* Initiates prelude check when master sword unloads.

Not quite how N64 rando does it but so far it's the only way I've found to make it trigger without also triggering the time travel again.

* Stops Shadow Temple lore prompts from appearing in rando.

* Skips cutscene of royal tomb explosion in rando.

Explosion sound doesn't play correctly and I think the debris appears in the wrong place, but the functionality is here.

* Improves visual of exploding gravestone.

* Adds some comments explaining the rando differences

* Skip ruto text box in jabu blue warp

For rando

* skip intro cutscene in dodongo's cavern

* load spoiler files on boot, fix spoilerfile existing check when making new saves

* name entry dropped spoiler logic

* make sure to actually init the cvar

* no chime on load

* uncomment

* Skip ganondrof cutscene

Skip to scream part of the death animation, skipping the text boxes etc. For rando

* Update z_boss_ganondrof.c

* skip owl flight cutscenes in rando

* Fixes skipped text so it only applies to shadow temple.

Earlier fix inadvertently applied to some other text as well, changed logic so that only specified sceneNums and textIds can have this enabled, and text skipped by sceneNum can have the skip overriden by textId if needed. Currently there are no overrides so the textId section of the logic is commented out to avoid compilation errors.

* Adds a default to the switch case statements that leaves the randoSkipText variable unchanged, just in case.

* TEST: Text for item

* Adding ganon flavor text

* ADD: AMMO Count

* format ganon text/hint text

* Autoskip the tower cutscene if settings call for tower collapse.

* ganon hint text logic

* Improved prelude after time travel fix

* swapped the sizes between ganon hint text and ganon text, as they were set to the wrong things.

* this is all i did

* not the cleanest code ever but it's working

* ADD: GS Count

* ADD: Wallter (crash for now)

* TWEAK: Wallet check

* FIX: Use DrawItem instread of DrawUpgrade... b-baka!

* Fixes some vanilla bugs introduced by rando code.

* Added cutscene skip for zelda escaping

Using the debug cutscene skipping function. Also added a conditional so the bridge doesn't spawn closed when cutscene is ready to trigger

* ADD: X Spacing + Placeholders for song

* ADD: default case for items

* TWEAK: Spacing

* FIX: Light Arrow

* ADD: Ammo Option

* use groups instead

* ADD: More spacing logic

* songs and names

* TWEAK: Color on wallet

* colors

* Added flags cutscene before nabooru fight

* ADD: ChromaKey text

* First attempt skip cs after nabooru defeat

* Better implementation for specific rando cutscene skips

* use pulseaudio defaults

* spaces/tabs

* move color push/pop to stop crash

* make the colors work again

* the real bottle fix

* pulseaudio values tuned for n64 audio at 44.1khz

* update tlength

* remove one hardcoded samplerate

* Cleaned up and fixed zelda escape skip

The if statement is a freaking monster, but unless we want to skip more cutscenes in the same way later, this is the most compact way of doing it that I know of.

* Revert one line to match original

nothing functional

* another hint line that breaks autonewline logic

* don't autospawn epona if we don't have the song/ocarina

* Trying to use iron knuckle death effects

not working yet

* Streamlined OoT cutscene skip for future additions

Also cleaned up if statement in general

* Made if statement more readable

Also added clarity for what cutscene was skipped

* Fixed typo in comment

* Janky nabooru defeat cs skip

* altar text formatting (gonna need help shortening some of the french ones)

* more altar text formatting

* english altar text formatting complete

* make gtg blocking guard check for card not bridge

* FIX: Typo!

* FIX: Uppercases

* FIX: Typo

* TWEAK: Alter + some names

* TWEAK: More caps!

* ADD: Missing string

TWEAK more uppercases and namefixe
s

* Hide nabooru death by covering her in flames

* bandaid fix for death crash issue

* Twinrova defeat cs skip

Skips the animation and manually calls the function to show the "beam" around the sisters

* fix crash

* fix caps to match

* fix great fairy reward mashing/shielding issue

* TWEAK : Typo clé to Clé

* TWEAK: Some Altar hints

TWEAK: Some capitals

* TWEAK: Unmatching text + some cap again

* TWEAK: More tweaks

* fix build

* remove extra json.hpp, add hint

* Update randomizer_item_tracker.cpp

* TWEAK: Double Defense with RedParticles instead of white

* make sure we don't optimize out the check to ensure a spoilerfile exists

* vanilla ganon boss key hint formatting

* TWEAK: FR- better way of the hero text

* fix

* and again

* Initializes dungeonsDone items in gSaveContext to 0.

* Replaces sizeof calculation with a NUM_DUNGEONS constant.

* Fixes Saria's Gift on the LW Bridge from getting killed when holding shield.

* More airtight fix for Saria's Gift on the Bridge.

* Lifts one of the conditions in the if statement a little higher to prevent unnecessary lookups of getItemId.

* Invalidate text box icon before drawing

* Fixes the case where Saria's gift is an Ice Trap.

We still get the Ice Trap once, but never again. This does mean you can now hold R while walking in to avoid the ice trap, but everything else seems to work fine.

* Initial commit

Might need changing when we change the settings in the future

* Fixes Door of Time opening cutscene after warping with prelude.

* Initial waterfall skip

Very rudimentary way of doing things but it seems to work so 🤷

* inital rework

* fixed default rotation for 2D sprites

* fix tab/space issues

* 3d drops rando merge fix again

* Allows Impa to appear in the Lullaby check post drawbridge escape.

* Changes Ganon's Trials Count setting to a checkbox

The checkbox is whether or not to skip all of them. Leaving the box unchecked will mean doing all of them. Eventually this will be switched back to a slider once we implement the logic for which trials start out completed.

* Sets all Ganon's Trials to incomplete in new saves.

Fixes https://github.com/briaguya-ai/rando-issue-tracker/issues/131

* fix castle guards when oot throw cutscene has already played in rando

* Properly removes the beams when trials are cleared.

* Removes Question Mark from Skip Ganon's Trials UI.

* Adds a todo comment about when to change back to slider.

* make deku seeds check for bullet bag

* Various tweaks

TWEAK: Altar Text
TWEAK: Hint names
TWEAK: Replace more problematic œ to oe

* upgrade ocarina on both child and adult equips

* FIX: Jabu Item

* update equipped hookshot/longshot when obtained as other age

* add hint

* don't give the bgs check without the claim check

* Skips Darunia Cutscene in Fire Temple

* Added a TODO note about not skipping the cutscene.

There is a setting we will want to have eventually that will require this cutscene to not be skipped since it is used during a glitch.

* remove todo

* restore fast ocarina option in imgui that was lost in merge

* Fixes grey screen issue + tooltip for 2 handed shield

* update to use dg instead of g for textures in item tracker

* TWEAK: Default color for cosmetic RAND button was not the corect one

* fix texture crash, remove unused item tracker code

* don't open mask shop until we get zelda's letter

* Update README.md

* Prevents "correct" chime under incorrect conditions.

* Fixes typo in conditional and adds "bonk" sound effect.

"Bonk" sound is NA_SE_SY_OCARINA_ERROR and it plays when conditions for the Door of Time have not been met after playing Song of Time. This is only possible in rando's "Intended" Door of Time option, in which the Ocarina of Time and all 3 spritual stones are required to open the door, instead of the vanilla requirements of just having the song of time.

* remove modify dpad equips toggle, replace with checks for dpad menu

* remove extra check

* add ability to hold c-up to assign to dpad when dpad menuing is enabled

* disable d-pad navigation on item menu when holding c-up to equip

* dpad+c-up stuff for equipment menu

* ADD: Checbox for songs colors

* TWEAK: RandoColors for normal songs

* kind of quick and dirty but it works

* TWEAK: Clarity of the tooltip

Co-authored-by: briaguya <briaguya@alice>
Co-authored-by: Christopher Leggett <chris@leggett.dev>
Co-authored-by: aMannus <mannusmenting@gmail.com>
Co-authored-by: PurpleHato <linkvssangoku.jr@gmail.com>
Co-authored-by: Dog <5172592+Dog@users.noreply.github.com>
Co-authored-by: Vague Rant <vaguerant@users.noreply.github.com>
Co-authored-by: Baoulettes <perlouzerie@hotmail.fr>
Co-authored-by: Ada <60364512+GreatArgorath@users.noreply.github.com>
This commit is contained in:
briaguya
2022-07-11 20:11:07 -04:00
committed by GitHub
parent 0fd779f002
commit c25089b98f
206 changed files with 53442 additions and 525 deletions

View File

@@ -1971,6 +1971,24 @@ u32 Actor_HasParent(Actor* actor, GlobalContext* globalCtx) {
}
}
s32 GiveItemWithoutActor(GlobalContext* globalCtx, s32 getItemId) {
Player* player = GET_PLAYER(globalCtx);
if (!(player->stateFlags1 & 0x3C7080) && Player_GetExplosiveHeld(player) < 0) {
if (((player->heldActor != NULL) && (getItemId > GI_NONE) && (getItemId < GI_MAX)) ||
(!(player->stateFlags1 & 0x20000800))) {
if ((getItemId != GI_NONE)) {
player->getItemId = getItemId;
player->interactRangeActor = &player->actor;
player->getItemDirection = player->actor.shape.rot.y;
return true;
}
}
}
return false;
}
s32 func_8002F434(Actor* actor, GlobalContext* globalCtx, s32 getItemId, f32 xzRange, f32 yRange) {
Player* player = GET_PLAYER(globalCtx);
@@ -5963,3 +5981,58 @@ s32 func_80038290(GlobalContext* globalCtx, Actor* actor, Vec3s* arg2, Vec3s* ar
return true;
}
s32 GetChestGameRandoGetItemId(s8 room, s16 ogDrawId, GlobalContext* globalCtx) {
if (GetRandoSettingValue(RSK_SHUFFLE_CHEST_MINIGAME)) {
// RANDOTODO update this logic when we implement keysanity
// because 3drando replaces the keys not the rupees
if (ogDrawId == GID_RUPEE_GREEN ||
ogDrawId == GID_RUPEE_BLUE ||
ogDrawId == GID_RUPEE_RED)
{
switch(room) {
case 1:
if(!Flags_GetCollectible(globalCtx, 0x1B)) {
return GetRandomizedItemIdFromKnownCheck(RC_MARKET_TREASURE_CHEST_GAME_ITEM_1, GI_RUPEE_GREEN);
}
break;
case 2:
if(!Flags_GetCollectible(globalCtx, 0x1C)) {
return GetRandomizedItemIdFromKnownCheck(RC_MARKET_TREASURE_CHEST_GAME_ITEM_2, GI_RUPEE_GREEN);
}
break;
case 3:
if(!Flags_GetCollectible(globalCtx, 0x1D)) {
return GetRandomizedItemIdFromKnownCheck(RC_MARKET_TREASURE_CHEST_GAME_ITEM_3, GI_RUPEE_BLUE);
}
break;
case 4:
if(!Flags_GetCollectible(globalCtx, 0x1E)) {
return GetRandomizedItemIdFromKnownCheck(RC_MARKET_TREASURE_CHEST_GAME_ITEM_4, GI_RUPEE_BLUE);
}
break;
case 5:
if(!Flags_GetCollectible(globalCtx, 0x1F)) {
return GetRandomizedItemIdFromKnownCheck(RC_MARKET_TREASURE_CHEST_GAME_ITEM_5, GI_RUPEE_RED);
}
break;
}
}
}
if(ogDrawId == GID_HEART_PIECE) {
return GetRandomizedItemIdFromKnownCheck(RC_MARKET_TREASURE_CHEST_GAME_REWARD, GI_HEART_PIECE);
}
return GI_NONE;
}
s16 GetChestGameRandoGiDrawId(s8 room, s16 ogDrawId, GlobalContext* globalCtx) {
s32 randoGetItemId = GetChestGameRandoGetItemId(room, ogDrawId, globalCtx);
if(randoGetItemId != GI_NONE) {
return GetItemModelFromId(randoGetItemId);
}
return ogDrawId;
}

View File

@@ -244,7 +244,7 @@ void func_80064824(GlobalContext* globalCtx, CutsceneContext* csCtx, CsCmdBase*
case 3:
if (sp3F != 0) {
Flags_SetEnv(globalCtx, 0);
if (gSaveContext.entranceIndex == 0x0053) {
if (gSaveContext.entranceIndex == 0x0053 || (gSaveContext.n64ddFlag && gSaveContext.entranceIndex == 0x05F4)) {
Flags_SetEnv(globalCtx, 2);
}
}
@@ -491,6 +491,12 @@ void Cutscene_Command_Terminator(GlobalContext* globalCtx, CutsceneContext* csCt
Player* player = GET_PLAYER(globalCtx);
s32 temp = 0;
// Automatically skip certain cutscenes when in rando
// cmd->base == 33: Zelda escaping with impa cutscene
bool randoCsSkip = (gSaveContext.n64ddFlag && cmd->base == 33);
bool debugCsSkip = (CHECK_BTN_ALL(globalCtx->state.input[0].press.button, BTN_START) &&
(gSaveContext.fileNum != 0xFEDC) && CVar_GetS32("gDebugEnabled", 0));
if ((gSaveContext.gameMode != 0) && (gSaveContext.gameMode != 3) && (globalCtx->sceneNum != SCENE_SPOT00) &&
(csCtx->frames > 20) &&
(CHECK_BTN_ALL(globalCtx->state.input[0].press.button, BTN_A) ||
@@ -501,9 +507,8 @@ void Cutscene_Command_Terminator(GlobalContext* globalCtx, CutsceneContext* csCt
temp = 1;
}
if ((csCtx->frames == cmd->startFrame) || (temp != 0) ||
((csCtx->frames > 20) && CHECK_BTN_ALL(globalCtx->state.input[0].press.button, BTN_START) &&
(gSaveContext.fileNum != 0xFEDC)) && CVar_GetS32("gDebugEnabled", 0)) {
if ((csCtx->frames == cmd->startFrame) || (temp != 0) || ((csCtx->frames > 20) && (randoCsSkip || debugCsSkip))) {
csCtx->state = CS_STATE_UNSKIPPABLE_EXEC;
Audio_SetCutsceneFlag(0);
gSaveContext.unk_1410 = 1;
@@ -2047,6 +2052,18 @@ void Cutscene_HandleEntranceTriggers(GlobalContext* globalCtx) {
u8 requiredAge;
s16 i;
if (gSaveContext.n64ddFlag &&
// don't skip epona escape cutscenes
gSaveContext.entranceIndex != 650 &&
gSaveContext.entranceIndex != 654 &&
gSaveContext.entranceIndex != 658 &&
gSaveContext.entranceIndex != 1142 &&
// don't skip nabooru iron knuckle cs
gSaveContext.entranceIndex != 141) {
gSaveContext.showTitleCard = false;
return;
}
for (i = 0; i < ARRAY_COUNT(sEntranceCutsceneTable); i++) {
entranceCutscene = &sEntranceCutsceneTable[i];
@@ -2073,29 +2090,43 @@ void Cutscene_HandleConditionalTriggers(GlobalContext* globalCtx) {
if ((gSaveContext.gameMode == 0) && (gSaveContext.respawnFlag <= 0) && (gSaveContext.cutsceneIndex < 0xFFF0)) {
if ((gSaveContext.entranceIndex == 0x01E1) && !Flags_GetEventChkInf(0xAC)) {
Flags_SetEventChkInf(0xAC);
gSaveContext.entranceIndex = 0x0123;
gSaveContext.cutsceneIndex = 0xFFF0;
if (!gSaveContext.n64ddFlag) {
Flags_SetEventChkInf(0xAC);
gSaveContext.entranceIndex = 0x0123;
gSaveContext.cutsceneIndex = 0xFFF0;
}
} else if ((gSaveContext.entranceIndex == 0x00DB) && LINK_IS_ADULT && (gSaveContext.eventChkInf[4] & 0x0100) &&
(gSaveContext.eventChkInf[4] & 0x0200) && (gSaveContext.eventChkInf[4] & 0x0400) &&
!Flags_GetEventChkInf(0xAA)) {
Flags_SetEventChkInf(0xAA);
gSaveContext.cutsceneIndex = 0xFFF0;
if (!gSaveContext.n64ddFlag) {
Flags_SetEventChkInf(0xAA);
gSaveContext.cutsceneIndex = 0xFFF0;
}
} else if ((gSaveContext.entranceIndex == 0x05E0) && !Flags_GetEventChkInf(0xC1)) {
Flags_SetEventChkInf(0xC1);
Item_Give(globalCtx, ITEM_OCARINA_FAIRY);
gSaveContext.entranceIndex = 0x011E;
gSaveContext.cutsceneIndex = 0xFFF0;
if (!gSaveContext.n64ddFlag) {
Flags_SetEventChkInf(0xC1);
Item_Give(globalCtx, ITEM_OCARINA_FAIRY);
gSaveContext.entranceIndex = 0x011E;
gSaveContext.cutsceneIndex = 0xFFF0;
}
} else if (CHECK_QUEST_ITEM(QUEST_MEDALLION_SPIRIT) && CHECK_QUEST_ITEM(QUEST_MEDALLION_SHADOW) &&
LINK_IS_ADULT && !Flags_GetEventChkInf(0xC4) &&
(gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_TOKINOMA)) {
Flags_SetEventChkInf(0xC4);
gSaveContext.entranceIndex = 0x0053;
gSaveContext.cutsceneIndex = 0xFFF8;
if (!gSaveContext.n64ddFlag) {
Flags_SetEventChkInf(0xC4);
gSaveContext.entranceIndex = 0x0053;
gSaveContext.cutsceneIndex = 0xFFF8;
}
} else if (!Flags_GetEventChkInf(0xC7) &&
(gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_GANON_DEMO)) {
Flags_SetEventChkInf(0xC7);
gSaveContext.entranceIndex = 0x0517;
// If we are rando and tower escape skip is on, then set the flag to say we saw the towers fall
// and exit.
if (gSaveContext.n64ddFlag && GetRandoSettingValue(RSK_SKIP_TOWER_ESCAPE)) {
return;
}
gSaveContext.cutsceneIndex = 0xFFF0;
}
}

View File

@@ -105,6 +105,11 @@ void GetItem_DrawSmallRupee(GlobalContext* globalCtx, s16 drawId);
void GetItem_DrawScale(GlobalContext* globalCtx, s16 drawId);
void GetItem_DrawBulletBag(GlobalContext* globalCtx, s16 drawId);
void GetItem_DrawWallet(GlobalContext* globalCtx, s16 drawId);
void GetItem_DrawJewel(GlobalContext* globalCtx, s16 drawId);
void GetItem_DrawJewelKokiri(GlobalContext* globalCtx, s16 drawId);
void GetItem_DrawJewelGoron(GlobalContext* globalCtx, s16 drawId);
void GetItem_DrawJewelZora(GlobalContext* globalCtx, s16 drawId);
void GetItem_DrawGenericMusicNote(GlobalContext* globalCtx, s16 drawId);
typedef struct {
/* 0x00 */ void (*drawFunc)(GlobalContext*, s16);
@@ -367,6 +372,19 @@ DrawItemTableEntry sDrawItemTable[] = {
{ GetItem_DrawOpa0, { gGiKokiriSwordDL } },
// gold skulltula token, OBJECT_ST
{ GetItem_DrawSkullToken, { object_st_DL_004DB0, object_st_DL_004EB8 } },
{ GetItem_DrawJewelKokiri, { gGiKokiriEmeraldGemDL, gGiKokiriEmeraldSettingDL } },
{ GetItem_DrawJewelGoron, { gGiGoronRubyGemDL, gGiGoronRubySettingDL } },
{ GetItem_DrawJewelZora, { gGiZoraSapphireGemDL, gGiZoraSapphireSettingDL } },
{ GetItem_DrawGenericMusicNote, { gGiSongNoteDL } }, //Generic
{ GetItem_DrawGenericMusicNote, { gGiSongNoteDL } }, //Zelda's Lullaby
{ GetItem_DrawGenericMusicNote, { gGiSongNoteDL } }, //Epona's song
{ GetItem_DrawGenericMusicNote, { gGiSongNoteDL } }, //Saria's song
{ GetItem_DrawGenericMusicNote, { gGiSongNoteDL } }, //Sun's song
{ GetItem_DrawGenericMusicNote, { gGiSongNoteDL } }, //Song of time
{ GetItem_DrawGenericMusicNote, { gGiSongNoteDL } } //Song of storms
};
/**
@@ -379,6 +397,96 @@ void GetItem_Draw(GlobalContext* globalCtx, s16 drawId) {
// All remaining functions in this file are draw functions referenced in the table and called by the function above
/* 0x0178 */ u8 primXluColor[3];
/* 0x017B */ u8 envXluColor[3];
/* 0x017E */ u8 primOpaColor[3];
/* 0x0181 */ u8 envOpaColor[3];
void GetItem_DrawJewelKokiri(GlobalContext* globalCtx, s16 drawId) {
primXluColor[2] = 160;
primXluColor[0] = 255;
primXluColor[1] = 255;
envXluColor[0] = 0;
envXluColor[1] = 255;
envXluColor[2] = 0;
primOpaColor[2] = 170;
primOpaColor[0] = 255;
primOpaColor[1] = 255;
envOpaColor[1] = 120;
envOpaColor[0] = 150;
envOpaColor[2] = 0;
GetItem_DrawJewel(globalCtx, drawId);
}
void GetItem_DrawJewelGoron(GlobalContext* globalCtx, s16 drawId) {
primXluColor[1] = 170;
primXluColor[0] = 255;
primXluColor[2] = 255;
envXluColor[2] = 100;
envXluColor[0] = 255;
envXluColor[1] = 0;
primOpaColor[2] = 170;
primOpaColor[0] = 255;
primOpaColor[1] = 255;
envOpaColor[1] = 120;
envOpaColor[0] = 150;
envOpaColor[2] = 0;
GetItem_DrawJewel(globalCtx, drawId);
}
void GetItem_DrawJewelZora(GlobalContext* globalCtx, s16 drawId) {
primXluColor[0] = 50;
primXluColor[1] = 255;
primXluColor[2] = 255;
envXluColor[2] = 150;
envXluColor[0] = 50;
envXluColor[1] = 0;
primOpaColor[2] = 170;
primOpaColor[0] = 255;
primOpaColor[1] = 255;
envOpaColor[1] = 120;
envOpaColor[0] = 150;
envOpaColor[2] = 0;
GetItem_DrawJewel(globalCtx, drawId);
}
void GetItem_DrawJewel(GlobalContext* globalCtx, s16 drawId) {
OPEN_DISPS(globalCtx->state.gfxCtx);
gSPSegment(POLY_XLU_DISP++, 9,
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0 % 256, (256 - (0 % 256)) - 1, 64, 64, 1, 0 % 256,
(256 - (0 % 256)) - 1, 16, 16));
gSPSegment(POLY_OPA_DISP++, 8, Gfx_TexScroll(globalCtx->state.gfxCtx, (u8)0, (u8)0, 16, 16));
Matrix_Push();
Matrix_RotateZYX(0, -0x4000, 0x4000, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_demo_effect.c", 2597),
G_MTX_NOPUSH | G_MTX_LOAD);
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_demo_effect.c", 2599),
G_MTX_NOPUSH | G_MTX_LOAD);
func_80093D84(globalCtx->state.gfxCtx);
// func_8002ED80(&this->actor, globalCtx, 0);
gDPSetPrimColor(POLY_XLU_DISP++, 0, 128, primXluColor[0], primXluColor[1], primXluColor[2], 255);
gDPSetEnvColor(POLY_XLU_DISP++, envXluColor[0], envXluColor[1], envXluColor[2], 255);
gSPDisplayList(POLY_XLU_DISP++, sDrawItemTable[drawId].dlists[0]);
func_80093D18(globalCtx->state.gfxCtx);
// func_8002EBCC(&this->actor, globalCtx, 0);
gDPSetPrimColor(POLY_OPA_DISP++, 0, 128, primOpaColor[0], primOpaColor[1], primOpaColor[2], 255);
gDPSetEnvColor(POLY_OPA_DISP++, envOpaColor[0], envOpaColor[1], envOpaColor[2], 255);
gSPDisplayList(POLY_OPA_DISP++, sDrawItemTable[drawId].dlists[1]);
Matrix_Pop();
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
void GetItem_DrawMaskOrBombchu(GlobalContext* globalCtx, s16 drawId) {
s32 pad;
@@ -690,6 +798,31 @@ void GetItem_DrawOpa0Xlu1(GlobalContext* globalCtx, s16 drawId) {
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
void GetItem_DrawGenericMusicNote(GlobalContext* globalCtx, s16 drawId) {
s32 pad;
s16 color_slot = drawId-120; //0 = generic
s16* colors[7][3] = {
{255,255,255}, //Generic Song (full white)
{109, 73,143}, //Lullaby
{217,110, 48}, //Epona
{ 62,109, 23}, //Saria
{237,231, 62}, //Sun
{ 98,177,211}, //Time
{146,146,146} //Storms
};
OPEN_DISPS(globalCtx->state.gfxCtx);
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, __FILE__, __LINE__), G_MTX_MODELVIEW | G_MTX_LOAD);
gsDPSetGrayscaleColor(POLY_OPA_DISP++, colors[color_slot][0], colors[color_slot][1], colors[color_slot][2], 255);
gsSPGrayscale(POLY_OPA_DISP++, true);
func_80093D18(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_OPA_DISP++, sDrawItemTable[drawId].dlists[0]);
gsSPGrayscale(POLY_OPA_DISP++, false);
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
void GetItem_DrawXlu01(GlobalContext* globalCtx, s16 drawId) {
s32 pad;

View File

@@ -338,6 +338,8 @@ void EnItem00_Init(Actor* thisx, GlobalContext* globalCtx) {
s16 spawnParam8000 = this->actor.params & 0x8000;
s32 pad1;
this->ogParams = this->actor.params;
this->collectibleFlag = (this->actor.params & 0x3F00) >> 8;
this->actor.params &= 0xFF;
@@ -506,7 +508,8 @@ void EnItem00_Init(Actor* thisx, GlobalContext* globalCtx) {
break;
}
if ((getItemId != GI_NONE) && !Actor_HasParent(&this->actor, globalCtx)) {
if ((gSaveContext.n64ddFlag || getItemId != GI_NONE) && !Actor_HasParent(&this->actor, globalCtx)) {
getItemId = GetRandomizedItemId(getItemId, this->actor.id, this->ogParams, globalCtx->sceneNum);
func_8002F554(&this->actor, globalCtx, getItemId);
}
@@ -545,13 +548,17 @@ void func_8001DFC8(EnItem00* this, GlobalContext* globalCtx) {
}
if (this->actor.params == ITEM00_HEART_PIECE) {
if (CVar_GetS32("gNewDrops", 0)) {
if ((CVar_GetS32("gNewDrops", 0) !=0) && !gSaveContext.n64ddFlag) {
this->actor.shape.yOffset = Math_SinS(this->actor.shape.rot.y) * 20.0f + 50.0f;
} else {
this->actor.shape.yOffset = Math_SinS(this->actor.shape.rot.y) * 150.0f + 850.0f;
}
}
if (gSaveContext.n64ddFlag && this->actor.params == ITEM00_SMALL_KEY) {
this->actor.shape.yOffset = 600.0f;
}
Math_SmoothStepToF(&this->actor.speedXZ, 0.0f, 1.0f, 0.5f, 0.0f);
if (this->unk_154 == 0) {
@@ -873,6 +880,9 @@ void EnItem00_Update(Actor* thisx, GlobalContext* globalCtx) {
params = &this->actor.params;
if ((getItemId != GI_NONE) && !Actor_HasParent(&this->actor, globalCtx)) {
if (gSaveContext.n64ddFlag) {
getItemId = GetRandomizedItemId(getItemId, this->actor.id, this->ogParams, globalCtx->sceneNum);
}
func_8002F554(&this->actor, globalCtx, getItemId);
}
@@ -995,7 +1005,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) {
break;
}
case ITEM00_HEART_PIECE:
if (CVar_GetS32("gNewDrops", 0)) {
if (CVar_GetS32("gNewDrops", 0) && !gSaveContext.n64ddFlag) {
Actor_SetScale(&this->actor, 0.5f);
this->scale = 0.5f;
this->actor.shape.yOffset = 50.0f;
@@ -1159,7 +1169,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) {
break;
}
case ITEM00_SMALL_KEY:
if (CVar_GetS32("gNewDrops", 0)) {
if (CVar_GetS32("gNewDrops", 0) && !gSaveContext.n64ddFlag) {
Actor_SetScale(&this->actor, 0.2f);
this->scale = 0.2f;
this->actor.shape.yOffset = 50.0f;
@@ -1194,6 +1204,67 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) {
}
}
void EnItem00_CustomItemsParticles(Actor* Parent, GlobalContext* globalCtx, s16 getItemId) {
s16 color_slot;
switch (getItemId) {
case GI_MINUET_OF_FOREST:
case GI_SINGLE_MAGIC:
case GI_DOUBLE_MAGIC:
color_slot = 0;
break;
case GI_BOLERO_OF_FIRE:
case GI_DOUBLE_DEFENSE:
color_slot = 1;
break;
case GI_SERENADE_OF_WATER:
color_slot = 2;
break;
case GI_REQUIEM_OF_SPIRIT:
color_slot = 3;
break;
case GI_NOCTURNE_OF_SHADOW:
color_slot = 4;
break;
case GI_PRELUDE_OF_LIGHT:
color_slot = 5;
break;
}
s16* colors[7][3] = {
{ 34, 255, 76 }, // Minuet and Magic Upgrades Colors
{ 177, 35, 35 }, // Bolero and Double Defense Colors
{ 115, 251, 253 }, // Serenade Color
{ 177, 122, 35 }, // Requiem Color
{ 177, 28, 212 }, // Nocturne Color
{ 255, 255, 92 }, // Prelude Color
{ 255, 255, 255} // White Color placeholder
};
s16* colorsEnv[7][3] = {
{ 30, 110, 30 }, // Minuet and Magic Upgrades Colors
{ 90, 10, 10 }, // Bolero and Double Defense Colors
{ 35, 35, 177 }, // Serenade Color
{ 70, 20, 10 }, // Requiem Color
{ 100, 20, 140 }, // Nocturne Color
{ 100, 100, 10 }, // Prelude Color
{ 154, 154, 154 } // White Color placeholder
};
static Vec3f velocity = { 0.0f, 0.2f, 0.0f };
static Vec3f accel = { 0.0f, 0.05f, 0.0f };
Color_RGBA8 primColor = { colors[color_slot][0], colors[color_slot][1], colors[color_slot][2], 0 };
Color_RGBA8 envColor = { colors[color_slot][0], colors[color_slot][1], colors[color_slot][2], 0 };
Vec3f pos;
// velocity.x = Rand_CenteredFloat(3.0f);
// velocity.z = Rand_CenteredFloat(3.0f);
velocity.y = -0.05f;
accel.y = -0.025f;
pos.x = Rand_CenteredFloat(32.0f) + Parent->world.pos.x;
pos.y = (Rand_ZeroOne() * 6.0f) + Parent->world.pos.y + 25;
pos.z = Rand_CenteredFloat(32.0f) + Parent->world.pos.z;
EffectSsKiraKira_SpawnDispersed(globalCtx, &pos, &velocity, &accel, &primColor, &envColor, 1000, 50);
}
/**
* Draw Function used for Rupee types of En_Item00.
*/
@@ -1226,27 +1297,37 @@ void EnItem00_DrawRupee(EnItem00* this, GlobalContext* globalCtx) {
* Draw Function used for most collectible types of En_Item00 (ammo, bombs, sticks, nuts, magic...).
*/
void EnItem00_DrawCollectible(EnItem00* this, GlobalContext* globalCtx) {
s32 texIndex = this->actor.params - 3;
if ((gSaveContext.n64ddFlag && this->getItemId != GI_NONE) || this->actor.params == ITEM00_SMALL_KEY) {
f32 mtxScale = 16.0f;
Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY);
s32 randoGetItemId = GetRandomizedItemId(this->getItemId, this->actor.id, this->ogParams, globalCtx->sceneNum);
if (randoGetItemId >= GI_MINUET_OF_FOREST && randoGetItemId <= GI_DOUBLE_DEFENSE) {
EnItem00_CustomItemsParticles(&this->actor, globalCtx, randoGetItemId);
}
GetItem_Draw(globalCtx, GetItemModelFromId(randoGetItemId));
} else {
s32 texIndex = this->actor.params - 3;
OPEN_DISPS(globalCtx->state.gfxCtx);
OPEN_DISPS(globalCtx->state.gfxCtx);
POLY_OPA_DISP = Gameplay_SetFog(globalCtx, POLY_OPA_DISP);
POLY_OPA_DISP = Gameplay_SetFog(globalCtx, POLY_OPA_DISP);
if (this->actor.params == ITEM00_BOMBS_SPECIAL) {
texIndex = 1;
} else if (this->actor.params >= ITEM00_ARROWS_SMALL) {
texIndex -= 3;
if (this->actor.params == ITEM00_BOMBS_SPECIAL) {
texIndex = 1;
} else if (this->actor.params >= ITEM00_ARROWS_SMALL) {
texIndex -= 3;
}
POLY_OPA_DISP = func_800946E4(POLY_OPA_DISP);
gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sItemDropTex[texIndex]));
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_MODELVIEW | G_MTX_LOAD);
gSPDisplayList(POLY_OPA_DISP++, gItemDropDL);
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
POLY_OPA_DISP = func_800946E4(POLY_OPA_DISP);
gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sItemDropTex[texIndex]));
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_MODELVIEW | G_MTX_LOAD);
gSPDisplayList(POLY_OPA_DISP++, gItemDropDL);
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
/**
@@ -1276,17 +1357,27 @@ void EnItem00_DrawHeartContainer(EnItem00* this, GlobalContext* globalCtx) {
* Draw Function used for the Piece of Heart type of En_Item00.
*/
void EnItem00_DrawHeartPiece(EnItem00* this, GlobalContext* globalCtx) {
s32 pad;
if (gSaveContext.n64ddFlag) {
f32 mtxScale = 16.0f;
Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY);
s32 randoGetItemId = GetRandomizedItemId(GI_HEART_PIECE, this->actor.id, this->ogParams, globalCtx->sceneNum);
if (randoGetItemId >= GI_MINUET_OF_FOREST && randoGetItemId <= GI_DOUBLE_DEFENSE) {
EnItem00_CustomItemsParticles(&this->actor, globalCtx, randoGetItemId);
}
GetItem_Draw(globalCtx, GetItemModelFromId(randoGetItemId));
} else {
s32 pad;
OPEN_DISPS(globalCtx->state.gfxCtx);
OPEN_DISPS(globalCtx->state.gfxCtx);
func_80093D84(globalCtx->state.gfxCtx);
func_8002ED80(&this->actor, globalCtx, 0);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_MODELVIEW | G_MTX_LOAD);
gSPDisplayList(POLY_XLU_DISP++, gHeartPieceInteriorDL);
func_80093D84(globalCtx->state.gfxCtx);
func_8002ED80(&this->actor, globalCtx, 0);
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_MODELVIEW | G_MTX_LOAD);
gSPDisplayList(POLY_XLU_DISP++, gHeartPieceInteriorDL);
CLOSE_DISPS(globalCtx->state.gfxCtx);
CLOSE_DISPS(globalCtx->state.gfxCtx);
}
}
/**

View File

@@ -72,7 +72,9 @@ void func_8006D0EC(GlobalContext* globalCtx, Player* player) {
Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_HORSE, -25.0f, 0.0f, -1600.0f, 0, -0x4000, 0, 1);
ASSERT(horseActor != NULL);
} else if ((globalCtx->sceneNum == gSaveContext.horseData.scene) &&
(Flags_GetEventChkInf(0x18) != 0 || DREG(1) != 0)) {
(((Flags_GetEventChkInf(0x18) != 0) && (!gSaveContext.n64ddFlag ||
(gSaveContext.n64ddFlag && CHECK_QUEST_ITEM(QUEST_SONG_EPONA) &&
(INV_CONTENT(ITEM_OCARINA_FAIRY) != ITEM_NONE)))) || DREG(1) != 0)) {
// "Set by existence of horse %d %d %d"
osSyncPrintf("馬存在によるセット %d %d %d\n", gSaveContext.horseData.scene, Flags_GetEventChkInf(0x18),
DREG(1));

View File

@@ -162,7 +162,9 @@ void Lights_BindAll(Lights* lights, LightNode* listHead, Vec3f* vec) {
while (listHead != NULL) {
info = listHead->info;
bindFuncs[info->type](lights, &info->params, vec);
if (info->type < 3) { // bandaid fix for death crash issue
bindFuncs[info->type](lights, &info->params, vec);
}
listHead = listHead->next;
}
}

View File

@@ -1673,9 +1673,73 @@ void Message_OpenText(GlobalContext* globalCtx, u16 textId) {
//font->msgLength, __FILE__, __LINE__);
} else {
Message_FindMessage(globalCtx, textId);
msgCtx->msgLength = font->msgLength;
char* src = (uintptr_t)font->msgOffset;
memcpy(font->msgBuf, src, font->msgLength);
// if we're rando'd and talking to a gossip stone
if (gSaveContext.n64ddFlag &&
textId == 0x2053 &&
GetRandoSettingValue(RSK_GOSSIP_STONE_HINTS) != 0 &&
(GetRandoSettingValue(RSK_GOSSIP_STONE_HINTS) == 1 ||
(GetRandoSettingValue(RSK_GOSSIP_STONE_HINTS) == 2 &&
Player_GetMask(globalCtx) == PLAYER_MASK_TRUTH) ||
(GetRandoSettingValue(RSK_GOSSIP_STONE_HINTS) == 3 &&
CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY)))) {
s16 actorParams = msgCtx->talkActor->params;
// if we're in a generic grotto
if (globalCtx->sceneNum == 62 && actorParams == 14360) {
// look for the chest in the actorlist to determine
// which grotto we're in
int numOfActorLists = sizeof(globalCtx->actorCtx.actorLists)/sizeof(globalCtx->actorCtx.actorLists[0]);
for(int i = 0; i < numOfActorLists; i++) {
if(globalCtx->actorCtx.actorLists[i].length) {
if(globalCtx->actorCtx.actorLists[i].head->id == 10) {
// set the params for the hint check to be negative chest params
actorParams = 0 - globalCtx->actorCtx.actorLists[i].head->params;
}
}
}
}
RandomizerCheck hintCheck = GetCheckFromActor(globalCtx->sceneNum, msgCtx->talkActor->id, actorParams);
// Pass the sizeof the message buffer so we don't hardcode any sizes and can rely on globals.
// If no hint can be found, this just returns 0 size and doesn't modify the buffer, so no worries.
msgCtx->msgLength = font->msgLength = CopyHintFromCheck(hintCheck, font->msgBuf, sizeof(font->msgBuf));
} else if (gSaveContext.n64ddFlag && (textId == 0x7040 || textId == 0x7088)) {
// rando hints at altar
msgCtx->msgLength = font->msgLength = CopyAltarMessage(font->msgBuf, sizeof(font->msgBuf));
} else if (textId == 0x00b4 && CVar_GetS32("gInjectSkulltulaCount", 0) != 0) {
switch (gSaveContext.language) {
case LANGUAGE_FRA:
strcpy(font->msgBuf, "\x08\x13\x71Vous obtenez un \x05\x41Symbole de\x01Skulltula d'or\x05\x40! "
"Vous avez\x01\collect\x96 "
"\x05\x41\x19\x05\x40 symboles en tout!\x02");
break;
case LANGUAGE_GER:
strcpy(font->msgBuf, "\x08\x13\x71\Du erh\x93lst ein \x05\x41Goldene\x01Skulltula-Symbol\x05\x40\! "
"Du hast\x01insgesamt "
"\x05\x41\x19\x05\x40 symbol gesammelt!\x02");
break;
case LANGUAGE_ENG: default:
strcpy(font->msgBuf,
"\x08\x13\x71You got a \x05\x41Gold Skulltula Token\x05\x40!\x01You've collected "
"\x05\x41\x19\x05\x40 tokens\x01in total!\x02");
break;
}
msgCtx->msgLength = font->msgLength = strlen(font->msgBuf);
} else if (gSaveContext.n64ddFlag && (textId == 0x10A2 || textId == 0x10DC || textId == 0x10DD)) {
msgCtx->msgLength = font->msgLength = CopyScrubMessage(textId, font->msgBuf, sizeof(font->msgBuf));
} else if (gSaveContext.n64ddFlag && textId == 0x70CC) {
if (INV_CONTENT(ITEM_ARROW_LIGHT) == ITEM_ARROW_LIGHT) {
msgCtx->msgLength = font->msgLength = CopyGanonText(font->msgBuf, sizeof(font->msgBuf));
} else {
msgCtx->msgLength = font->msgLength = CopyGanonHintText(font->msgBuf, sizeof(font->msgBuf));
}
} else {
msgCtx->msgLength = font->msgLength;
char* src = (uintptr_t)font->msgOffset;
memcpy(font->msgBuf, src, font->msgLength);
}
}
msgCtx->textBoxProperties = font->charTexBuf[0];
@@ -1725,8 +1789,15 @@ void Message_StartTextbox(GlobalContext* globalCtx, u16 textId, Actor* actor) {
osSyncPrintf(VT_RST);
msgCtx->ocarinaAction = 0xFFFF;
Message_OpenText(globalCtx, textId);
msgCtx->talkActor = actor;
// we need the talkActor for gossip stones in rando
// so we need to switch the order of these lines
if (gSaveContext.n64ddFlag && textId == 0x2053) {
msgCtx->talkActor = actor;
Message_OpenText(globalCtx, textId);
} else {
Message_OpenText(globalCtx, textId);
msgCtx->talkActor = actor;
}
msgCtx->msgMode = MSGMODE_TEXT_START;
msgCtx->stateTimer = 0;
msgCtx->textDelayTimer = 0;
@@ -2579,10 +2650,18 @@ void Message_DrawMain(GlobalContext* globalCtx, Gfx** p) {
}
break;
case MSGMODE_SETUP_DISPLAY_SONG_PLAYED:
Message_DrawText(globalCtx, &gfx);
Audio_OcaSetInstrument(1);
Audio_OcaSetInstrument(1);
Audio_OcaSetSongPlayback(msgCtx->lastPlayedSong + 1, 1);
if (CVar_GetS32("gFastOcarinaPlayback", 0) == 0 ||
globalCtx->msgCtx.lastPlayedSong == OCARINA_SONG_TIME ||
globalCtx->msgCtx.lastPlayedSong == OCARINA_SONG_STORMS ||
globalCtx->msgCtx.lastPlayedSong == OCARINA_SONG_SUNS) {
Message_DrawText(globalCtx, &gfx);
Audio_OcaSetInstrument(1);
Audio_OcaSetInstrument(1);
Audio_OcaSetSongPlayback(msgCtx->lastPlayedSong + 1, 1);
} else {
Audio_OcaSetInstrument(1);
Audio_OcaSetInstrument(1);
}
if (msgCtx->lastPlayedSong != OCARINA_SONG_SCARECROW) {
Audio_PlayFanfare(sOcarinaSongFanfares[msgCtx->lastPlayedSong]);
Audio_SetSoundBanksMute(0x20);
@@ -2625,7 +2704,15 @@ void Message_DrawMain(GlobalContext* globalCtx, Gfx** p) {
Message_ContinueTextbox(globalCtx, msgCtx->lastPlayedSong + 0x893); // You played [song name]
Message_Decode(globalCtx);
msgCtx->msgMode = MSGMODE_DISPLAY_SONG_PLAYED_TEXT;
msgCtx->stateTimer = 20;
if (CVar_GetS32("gFastOcarinaPlayback", 0) == 0 || globalCtx->msgCtx.lastPlayedSong == OCARINA_SONG_TIME
|| globalCtx->msgCtx.lastPlayedSong == OCARINA_SONG_STORMS ||
globalCtx->msgCtx.lastPlayedSong == OCARINA_SONG_SUNS) {
msgCtx->stateTimer = 20;
} else {
msgCtx->stateTimer = 1;
}
Message_DrawText(globalCtx, &gfx);
break;
case MSGMODE_DISPLAY_SONG_PLAYED_TEXT:
@@ -2732,7 +2819,11 @@ void Message_DrawMain(GlobalContext* globalCtx, Gfx** p) {
msgCtx->ocarinaStaff->state);
msgCtx->lastPlayedSong = msgCtx->ocarinaStaff->state;
msgCtx->msgMode = MSGMODE_SONG_PLAYBACK_SUCCESS;
Item_Give(globalCtx, ITEM_SONG_MINUET + gOcarinaSongItemMap[msgCtx->ocarinaStaff->state]);
if (!gSaveContext.n64ddFlag) {
Item_Give(globalCtx, ITEM_SONG_MINUET + gOcarinaSongItemMap[msgCtx->ocarinaStaff->state]);
}
osSyncPrintf(VT_FGCOL(YELLOW));
// "z_message.c Song Acquired"
osSyncPrintf("z_message.c 取得メロディ=%d\n", ITEM_SONG_MINUET + msgCtx->ocarinaStaff->state);

View File

@@ -791,7 +791,12 @@ s32 OnePointCutscene_SetInfo(GlobalContext* globalCtx, s16 camIdx, s16 csId, Act
break;
case 4100:
csInfo->keyFrames = D_801225D4;
csInfo->keyFrameCnt = 5;
// RANDO: Waterfall opening cutscene skips to the end of the cutscene data earlier by doing this
if (!(gSaveContext.n64ddFlag)) {
csInfo->keyFrameCnt = 5;
} else {
csInfo->keyFrameCnt = 2;
}
player->actor.shape.rot.y = player->actor.world.rot.y = player->currentYaw = 0x3FFC;
func_800C0808(globalCtx, camIdx, player, CAM_SET_CS_C);

View File

@@ -1557,6 +1557,70 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) {
osSyncPrintf("item_get_setting=%d pt=%d z=%x\n", item, slot, gSaveContext.inventory.items[slot]);
osSyncPrintf(VT_RST);
if (item == ITEM_SINGLE_MAGIC) {
gSaveContext.magicAcquired = true;
gSaveContext.unk_13F6 = 0x30;
Magic_Fill(globalCtx);
return ITEM_NONE;
} else if (item == ITEM_DOUBLE_MAGIC) {
if (!gSaveContext.magicAcquired) {
gSaveContext.magicAcquired = true;
}
gSaveContext.doubleMagic = true;
gSaveContext.unk_13F6 = 0x60;
gSaveContext.magicLevel = 0;
Magic_Fill(globalCtx);
return ITEM_NONE;
}
if (item == ITEM_DOUBLE_DEFENSE) {
gSaveContext.doubleDefense = true;
gSaveContext.inventory.defenseHearts = 20;
gSaveContext.healthAccumulator = 0x140;
return ITEM_NONE;
}
if (item >= ITEM_BOTTLE_WITH_RED_POTION &&
item <= ITEM_BOTTLE_WITH_BIG_POE) {
temp = SLOT(ITEM_BOTTLE);
for (i = 0; i < 4; i++) {
if (gSaveContext.inventory.items[temp + i] == ITEM_NONE) {
switch (item) {
case ITEM_BOTTLE_WITH_RED_POTION:
item = ITEM_POTION_RED;
break;
case ITEM_BOTTLE_WITH_GREEN_POTION:
item = ITEM_POTION_GREEN;
break;
case ITEM_BOTTLE_WITH_BLUE_POTION:
item = ITEM_POTION_BLUE;
break;
case ITEM_BOTTLE_WITH_FAIRY:
item = ITEM_FAIRY;
break;
case ITEM_BOTTLE_WITH_FISH:
item = ITEM_FISH;
break;
case ITEM_BOTTLE_WITH_BLUE_FIRE:
item = ITEM_BLUE_FIRE;
break;
case ITEM_BOTTLE_WITH_BUGS:
item = ITEM_BUG;
break;
case ITEM_BOTTLE_WITH_POE:
item = ITEM_POE;
break;
case ITEM_BOTTLE_WITH_BIG_POE:
item = ITEM_BIG_POE;
break;
}
gSaveContext.inventory.items[temp + i] = item;
return ITEM_NONE;
}
}
}
if ((item >= ITEM_MEDALLION_FOREST) && (item <= ITEM_MEDALLION_LIGHT)) {
gSaveContext.inventory.questItems |= gBitFlags[item - ITEM_MEDALLION_FOREST + QUEST_MEDALLION_FOREST];
@@ -1637,9 +1701,41 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) {
gSaveContext.inventory.equipment |= (gBitFlags[item - ITEM_BOOTS_KOKIRI] << gEquipShifts[EQUIP_BOOTS]);
return ITEM_NONE;
} else if ((item == ITEM_KEY_BOSS) || (item == ITEM_COMPASS) || (item == ITEM_DUNGEON_MAP)) {
gSaveContext.inventory.dungeonItems[gSaveContext.mapIndex] |= gBitFlags[item - ITEM_KEY_BOSS];
// Boss Key, Compass, and Dungeon Map exceptions for rando.
if (gSaveContext.n64ddFlag) {
if (globalCtx->sceneNum == 13) { // ganon's castle -> ganon's tower
gSaveContext.inventory.dungeonItems[10] |= 1;
} else if (globalCtx->sceneNum == 92) { // Desert Colossus -> Spirit Temple.
gSaveContext.inventory.dungeonItems[6] |= gBitFlags[item - ITEM_KEY_BOSS];
} else {
gSaveContext.inventory.dungeonItems[gSaveContext.mapIndex] |= gBitFlags[item - ITEM_KEY_BOSS];
}
}
return ITEM_NONE;
} else if (item == ITEM_KEY_SMALL) {
// Small key exceptions for rando.
if (gSaveContext.n64ddFlag) {
if (globalCtx->sceneNum == 10) { // ganon's tower -> ganon's castle
if (gSaveContext.inventory.dungeonKeys[13] < 0) {
gSaveContext.inventory.dungeonKeys[13] = 1;
return ITEM_NONE;
} else {
gSaveContext.inventory.dungeonKeys[13]++;
return ITEM_NONE;
}
}
if (globalCtx->sceneNum == 92) { // Desert Colossus -> Spirit Temple.
if (gSaveContext.inventory.dungeonKeys[6] < 0) {
gSaveContext.inventory.dungeonKeys[6] = 1;
return ITEM_NONE;
} else {
gSaveContext.inventory.dungeonKeys[6]++;
return ITEM_NONE;
}
}
}
if (gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] < 0) {
gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] = 1;
return ITEM_NONE;
@@ -1712,9 +1808,15 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) {
return ITEM_NONE;
} else if (item == ITEM_WALLET_ADULT) {
Inventory_ChangeUpgrade(UPG_WALLET, 1);
if (gSaveContext.n64ddFlag && GetRandoSettingValue(RSK_FULL_WALLETS)) {
Rupees_ChangeBy(200);
}
return ITEM_NONE;
} else if (item == ITEM_WALLET_GIANT) {
Inventory_ChangeUpgrade(UPG_WALLET, 2);
if (gSaveContext.n64ddFlag && GetRandoSettingValue(RSK_FULL_WALLETS)) {
Rupees_ChangeBy(500);
}
return ITEM_NONE;
} else if (item == ITEM_STICK_UPGRADE_20) {
if (gSaveContext.inventory.items[slot] == ITEM_NONE) {
@@ -1746,12 +1848,30 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) {
return ITEM_NONE;
} else if (item == ITEM_LONGSHOT) {
INV_CONTENT(item) = item;
// always update "equips" as this is what is currently on the c-buttons
for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
if (gSaveContext.equips.buttonItems[i] == ITEM_HOOKSHOT) {
gSaveContext.equips.buttonItems[i] = ITEM_LONGSHOT;
Interface_LoadItemIcon1(globalCtx, i);
}
}
// update the adult/child equips when rando'd (accounting for equp swapped hookshot as child)
if (gSaveContext.n64ddFlag && LINK_IS_CHILD) {
for (i = 1; i < ARRAY_COUNT(gSaveContext.adultEquips.buttonItems); i++) {
if (gSaveContext.adultEquips.buttonItems[i] == ITEM_HOOKSHOT) {
gSaveContext.adultEquips.buttonItems[i] = ITEM_LONGSHOT;
Interface_LoadItemIcon1(globalCtx, i);
}
}
}
if (gSaveContext.n64ddFlag && LINK_IS_ADULT) {
for (i = 1; i < ARRAY_COUNT(gSaveContext.childEquips.buttonItems); i++) {
if (gSaveContext.childEquips.buttonItems[i] == ITEM_HOOKSHOT) {
gSaveContext.childEquips.buttonItems[i] = ITEM_LONGSHOT;
Interface_LoadItemIcon1(globalCtx, i);
}
}
}
return ITEM_NONE;
} else if (item == ITEM_STICK) {
if (gSaveContext.inventory.items[slot] == ITEM_NONE) {
@@ -1880,12 +2000,31 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) {
return ITEM_NONE;
} else if (item == ITEM_OCARINA_TIME) {
INV_CONTENT(ITEM_OCARINA_TIME) = ITEM_OCARINA_TIME;
// always update "equips" as this is what is currently on the c-buttons
for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
if (gSaveContext.equips.buttonItems[i] == ITEM_OCARINA_FAIRY) {
gSaveContext.equips.buttonItems[i] = ITEM_OCARINA_TIME;
Interface_LoadItemIcon1(globalCtx, i);
}
}
// update the adult/child equips when rando'd
if (gSaveContext.n64ddFlag && LINK_IS_CHILD) {
for (i = 1; i < ARRAY_COUNT(gSaveContext.adultEquips.buttonItems); i++) {
if (gSaveContext.adultEquips.buttonItems[i] == ITEM_OCARINA_FAIRY) {
gSaveContext.adultEquips.buttonItems[i] = ITEM_OCARINA_TIME;
Interface_LoadItemIcon1(globalCtx, i);
}
}
}
if (gSaveContext.n64ddFlag && LINK_IS_ADULT) {
for (i = 1; i < ARRAY_COUNT(gSaveContext.childEquips.buttonItems); i++) {
if (gSaveContext.childEquips.buttonItems[i] == ITEM_OCARINA_FAIRY) {
gSaveContext.childEquips.buttonItems[i] = ITEM_OCARINA_TIME;
Interface_LoadItemIcon1(globalCtx, i);
}
}
}
return ITEM_NONE;
} else if (item == ITEM_BEAN) {
if (gSaveContext.inventory.items[slot] == ITEM_NONE) {
@@ -2028,7 +2167,15 @@ u8 Item_CheckObtainability(u8 item) {
osSyncPrintf("item_get_non_setting=%d pt=%d z=%x\n", item, slot, gSaveContext.inventory.items[slot]);
osSyncPrintf(VT_RST);
if ((item >= ITEM_MEDALLION_FOREST) && (item <= ITEM_MEDALLION_LIGHT)) {
if (gSaveContext.n64ddFlag) {
if (item == ITEM_SINGLE_MAGIC || item == ITEM_DOUBLE_MAGIC || item == ITEM_DOUBLE_DEFENSE) {
return ITEM_NONE;
}
}
if ((item >= ITEM_SONG_MINUET) && (item <= ITEM_SONG_STORMS)) {
return ITEM_NONE;
} else if ((item >= ITEM_MEDALLION_FOREST) && (item <= ITEM_MEDALLION_LIGHT)) {
return ITEM_NONE;
} else if ((item >= ITEM_KOKIRI_EMERALD) && (item <= ITEM_SKULL_TOKEN)) {
return ITEM_NONE;
@@ -2037,25 +2184,25 @@ u8 Item_CheckObtainability(u8 item) {
return ITEM_NONE;
} else if ((gBitFlags[item - ITEM_SWORD_KOKIRI] << gEquipShifts[EQUIP_SWORD]) &
gSaveContext.inventory.equipment) {
return item;
return gSaveContext.n64ddFlag ? ITEM_NONE : item;
} else {
return ITEM_NONE;
}
} else if ((item >= ITEM_SHIELD_DEKU) && (item <= ITEM_SHIELD_MIRROR)) {
if ((gBitFlags[item - ITEM_SHIELD_DEKU] << gEquipShifts[EQUIP_SHIELD]) & gSaveContext.inventory.equipment) {
return item;
return gSaveContext.n64ddFlag ? ITEM_NONE : item;
} else {
return ITEM_NONE;
}
} else if ((item >= ITEM_TUNIC_KOKIRI) && (item <= ITEM_TUNIC_ZORA)) {
if ((gBitFlags[item - ITEM_TUNIC_KOKIRI] << gEquipShifts[EQUIP_TUNIC]) & gSaveContext.inventory.equipment) {
return item;
return gSaveContext.n64ddFlag ? ITEM_NONE : item;
} else {
return ITEM_NONE;
}
} else if ((item >= ITEM_BOOTS_KOKIRI) && (item <= ITEM_BOOTS_HOVER)) {
if ((gBitFlags[item - ITEM_BOOTS_KOKIRI] << gEquipShifts[EQUIP_BOOTS]) & gSaveContext.inventory.equipment) {
return item;
return gSaveContext.n64ddFlag ? ITEM_NONE : item;
} else {
return ITEM_NONE;
}
@@ -3326,6 +3473,7 @@ void Interface_DrawItemButtons(GlobalContext* globalCtx) {
if ((globalCtx->pauseCtx.state != 0) || (globalCtx->pauseCtx.debugState != 0)) {
// Start Button Texture, Color & Label
gDPPipeSync(OVERLAY_DISP++);
if (CVar_GetS32("gHudColors", 1) == 0) {
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 200, 0, 0, interfaceCtx->startAlpha);
} else if (CVar_GetS32("gHudColors", 1) == 1) {

View File

@@ -193,6 +193,70 @@ void Gameplay_Destroy(GameState* thisx) {
gGlobalCtx = NULL;
}
void GivePlayerRandoRewardSongOfTime(GlobalContext* globalCtx, RandomizerCheck check) {
Player* player = GET_PLAYER(globalCtx);
if (gSaveContext.entranceIndex == 0x050F && player != NULL && !Player_InBlockingCsMode(globalCtx, player) &&
!Flags_GetTreasure(globalCtx, 0x1F) && gSaveContext.nextTransition == 0xFF) {
GetItemID getItemId = GetRandomizedItemIdFromKnownCheck(check, GI_SONG_OF_TIME);
GiveItemWithoutActor(globalCtx, getItemId);
Flags_SetTreasure(globalCtx, 0x1F);
}
}
void GivePlayerRandoRewardNocturne(GlobalContext* globalCtx, RandomizerCheck check) {
Player* player = GET_PLAYER(globalCtx);
if ((gSaveContext.entranceIndex == 0x00DB ||
gSaveContext.entranceIndex == 0x0191 ||
gSaveContext.entranceIndex == 0x0195) && LINK_IS_ADULT && CHECK_QUEST_ITEM(QUEST_MEDALLION_FOREST) &&
CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE) && CHECK_QUEST_ITEM(QUEST_MEDALLION_WATER) && player != NULL &&
!Player_InBlockingCsMode(globalCtx, player) && !Flags_GetEventChkInf(0xAA)) {
GetItemID getItemId = GetRandomizedItemIdFromKnownCheck(check, GI_NOCTURNE_OF_SHADOW);
GiveItemWithoutActor(globalCtx, getItemId);
Flags_SetEventChkInf(0xAA);
}
}
void GivePlayerRandoRewardRequiem(GlobalContext* globalCtx, RandomizerCheck check) {
Player* player = GET_PLAYER(globalCtx);
if ((gSaveContext.gameMode == 0) && (gSaveContext.respawnFlag <= 0) && (gSaveContext.cutsceneIndex < 0xFFF0)) {
if ((gSaveContext.entranceIndex == 0x01E1) && !Flags_GetEventChkInf(0xAC) && player != NULL &&
!Player_InBlockingCsMode(globalCtx, player)) {
GetItemID getItemId = GetRandomizedItemIdFromKnownCheck(check, GI_SONG_OF_TIME);
GiveItemWithoutActor(globalCtx, getItemId);
Flags_SetEventChkInf(0xAC);
}
}
}
void GivePlayerRandoRewardZeldaLightArrowsGift(GlobalContext* globalCtx, RandomizerCheck check) {
Player* player = GET_PLAYER(globalCtx);
if (CHECK_QUEST_ITEM(QUEST_MEDALLION_SPIRIT) && CHECK_QUEST_ITEM(QUEST_MEDALLION_SHADOW) && LINK_IS_ADULT &&
(gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_TOKINOMA) &&
!Flags_GetTreasure(globalCtx, 0x1E) && player != NULL && !Player_InBlockingCsMode(globalCtx, player) &&
globalCtx->sceneLoadFlag == 0 && player->getItemId == GI_NONE) {
GetItemID getItemId = GetRandomizedItemIdFromKnownCheck(check, GI_ARROW_LIGHT);
GiveItemWithoutActor(globalCtx, getItemId);
Flags_SetTreasure(globalCtx, 0x1E);
}
}
void GivePlayerRandoRewardSariaGift(GlobalContext* globalCtx, RandomizerCheck check) {
Player* player = GET_PLAYER(globalCtx);
if (gSaveContext.entranceIndex == 0x05E0) {
GetItemID getItemId = GetRandomizedItemIdFromKnownCheck(check, GI_ZELDAS_LULLABY);
if ((!Flags_GetEventChkInf(0xC1) || (player->getItemId == getItemId && getItemId != GI_ICE_TRAP)) &&
player != NULL && !Player_InBlockingCsMode(globalCtx, player)) {
GiveItemWithoutActor(globalCtx, getItemId);
Flags_SetEventChkInf(0xC1);
}
}
}
void Gameplay_Init(GameState* thisx) {
GlobalContext* globalCtx = (GlobalContext*)thisx;
GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
@@ -207,6 +271,14 @@ void Gameplay_Init(GameState* thisx) {
u8 tempSetupIndex;
s32 pad[2];
if (gSaveContext.n64ddFlag && GetRandoSettingValue(RSK_SKIP_CHILD_STEALTH)) {
if (gSaveContext.entranceIndex == 0x7A) {
gSaveContext.entranceIndex = 0x400;
} else if (gSaveContext.entranceIndex == 0x296) {
gSaveContext.entranceIndex = 0x23D;
}
}
if (gSaveContext.entranceIndex == -1) {
gSaveContext.entranceIndex = 0;
globalCtx->state.running = false;
@@ -435,7 +507,7 @@ void Gameplay_Update(GlobalContext* globalCtx) {
input = globalCtx->state.input;
if ((SREG(1) < 0) || (DREG(0) != 0)) {
if ((SREG(1) < 0) || (DREG(0) != 0)) {
SREG(1) = 0;
ZeldaArena_Display();
}
@@ -1055,6 +1127,14 @@ skip:
Environment_Update(globalCtx, &globalCtx->envCtx, &globalCtx->lightCtx, &globalCtx->pauseCtx, &globalCtx->msgCtx,
&globalCtx->gameOverCtx, globalCtx->state.gfxCtx);
if (gSaveContext.n64ddFlag) {
GivePlayerRandoRewardSariaGift(globalCtx, RC_LW_GIFT_FROM_SARIA);
GivePlayerRandoRewardSongOfTime(globalCtx, RC_SONG_FROM_OCARINA_OF_TIME);
GivePlayerRandoRewardZeldaLightArrowsGift(globalCtx, RC_TOT_LIGHT_ARROWS_CUTSCENE);
GivePlayerRandoRewardNocturne(globalCtx, RC_SHEIK_IN_KAKARIKO);
GivePlayerRandoRewardRequiem(globalCtx, RC_SHEIK_AT_COLOSSUS);
}
}
void Gameplay_DrawOverlayElements(GlobalContext* globalCtx) {

View File

@@ -3,6 +3,9 @@
#include <string.h>
#define NUM_DUNGEONS 8
#define NUM_TRIALS 6
/**
* Initialize new save.
* This save has an empty inventory with 3 hearts and single magic.
@@ -24,6 +27,400 @@ void Sram_InitDebugSave(void) {
Save_InitFile(true);
}
// RANDOTODO replace most of these GiveLink functions with calls to
// Item_Give in z_parameter, we'll need to update Item_Give to ensure
// nothing breaks when calling it without a valid globalCtx first
void GiveLinkRupees(int numOfRupees) {
int maxRupeeCount;
if (CUR_UPG_VALUE(UPG_WALLET) == 0) {
maxRupeeCount = 99;
} else if (CUR_UPG_VALUE(UPG_WALLET) == 1) {
maxRupeeCount = 200;
} else if (CUR_UPG_VALUE(UPG_WALLET) == 2) {
maxRupeeCount = 500;
}
int newRupeeCount = gSaveContext.rupees;
newRupeeCount += numOfRupees;
if (newRupeeCount > maxRupeeCount) {
gSaveContext.rupees = maxRupeeCount;
} else {
gSaveContext.rupees = newRupeeCount;
}
}
void GiveLinkRupeesByGetItemId(GetItemID giid) {
if (giid == GI_RUPEE_GREEN) {
GiveLinkRupees(1);
} else if (giid == GI_RUPEE_BLUE) {
GiveLinkRupees(5);
} else if (giid == GI_RUPEE_RED) {
GiveLinkRupees(20);
} else if (giid == GI_RUPEE_PURPLE) {
GiveLinkRupees(50);
} else if (giid == GI_RUPEE_GOLD) {
GiveLinkRupees(100);
}
}
void GiveLinkBombchus(GetItemID giid) {
INV_CONTENT(ITEM_BOMBCHU) = ITEM_BOMBCHU;
if (giid == GI_BOMBCHUS_5) {
AMMO(ITEM_BOMBCHU) += 5;
} else if (giid == GI_BOMBCHUS_10) {
AMMO(ITEM_BOMBCHU) += 10;
} else if (giid == GI_BOMBCHUS_20) {
AMMO(ITEM_BOMBCHU) += 20;
}
}
void GiveLinkDekuSticks(int howManySticks) {
int maxStickCount;
if (CUR_UPG_VALUE(UPG_STICKS) == 0) {
INV_CONTENT(ITEM_STICK) = ITEM_STICK;
Inventory_ChangeUpgrade(UPG_STICKS, 1);
maxStickCount = 10;
} else if (CUR_UPG_VALUE(UPG_STICKS) == 1) {
maxStickCount = 10;
} else if (CUR_UPG_VALUE(UPG_STICKS) == 2) {
maxStickCount = 20;
} else if (CUR_UPG_VALUE(UPG_STICKS) == 3) {
maxStickCount = 30;
}
if ((AMMO(ITEM_STICK) + howManySticks) > maxStickCount) {
AMMO(ITEM_STICK) = maxStickCount;
} else {
AMMO(ITEM_STICK) += howManySticks;
}
}
void GiveLinkDekuSticksByGetItemId(GetItemID giid) {
if (giid == GI_STICKS_1) {
GiveLinkDekuSticks(1);
} else if (giid == GI_STICKS_5) {
GiveLinkDekuSticks(5);
} else if (giid == GI_STICKS_10) {
GiveLinkDekuSticks(10);
}
}
void GiveLinkDekuNuts(int howManyNuts) {
int maxNutCount;
if (CUR_UPG_VALUE(UPG_NUTS) == 0) {
INV_CONTENT(ITEM_NUT) = ITEM_NUT;
Inventory_ChangeUpgrade(UPG_NUTS, 1);
maxNutCount = 20;
} else if (CUR_UPG_VALUE(UPG_NUTS) == 1) {
maxNutCount = 20;
} else if (CUR_UPG_VALUE(UPG_NUTS) == 2) {
maxNutCount = 30;
} else if (CUR_UPG_VALUE(UPG_NUTS) == 3) {
maxNutCount = 40;
}
if ((AMMO(ITEM_NUT) + howManyNuts) > maxNutCount) {
AMMO(ITEM_NUT) = maxNutCount;
} else {
AMMO(ITEM_NUT) += howManyNuts;
}
}
void GiveLinkDekuNutsByGetItemId(GetItemID giid) {
if (giid == GI_NUTS_5) {
GiveLinkDekuNuts(5);
} else if (giid == GI_NUTS_10) {
GiveLinkDekuNuts(10);
}
}
void GiveLinkBeans() {
INV_CONTENT(ITEM_BEAN) = ITEM_BEAN;
AMMO(ITEM_BEAN)++;
}
void GiveLinkKokiriSword() {
uint32_t bitMask = 1 << 0;
gSaveContext.inventory.equipment |= bitMask;
}
void GiveLinkGiantsKnife() {
gSaveContext.bgsFlag = 0;
gSaveContext.swordHealth = 8;
uint32_t bitMask = 1 << 2;
gSaveContext.inventory.equipment |= bitMask;
}
void GiveLinkBiggoronSword() {
gSaveContext.bgsFlag = 1;
gSaveContext.swordHealth = 8;
uint32_t bitMask = 1 << 2;
gSaveContext.inventory.equipment |= bitMask;
}
void GiveLinkDekuShield() {
uint32_t bitMask = 1 << 4;
gSaveContext.inventory.equipment |= bitMask;
}
void GiveLinkHylianShield() {
uint32_t bitMask = 1 << 5;
gSaveContext.inventory.equipment |= bitMask;
}
void GiveLinkMirrorShield() {
uint32_t bitMask = 1 << 6;
gSaveContext.inventory.equipment |= bitMask;
}
void GiveLinkGoronTunic() {
uint32_t bitMask = 1 << 9;
gSaveContext.inventory.equipment |= bitMask;
}
void GiveLinkZoraTunic() {
uint32_t bitMask = 1 << 10;
gSaveContext.inventory.equipment |= bitMask;
}
void GiveLinkIronBoots() {
uint32_t bitMask = 1 << 13;
gSaveContext.inventory.equipment |= bitMask;
}
void GiveLinkHoverBoots() {
uint32_t bitMask = 1 << 14;
gSaveContext.inventory.equipment |= bitMask;
}
void GiveLinkStoneOfAgony() {
uint32_t bitMask = 1 << QUEST_STONE_OF_AGONY;
gSaveContext.inventory.questItems |= bitMask;
}
void GiveLinkGerudoCard() {
uint32_t bitMask = 1 << QUEST_GERUDO_CARD;
gSaveContext.inventory.questItems |= bitMask;
}
void GiveLinkPieceOfHeart() {
int32_t pohCount = (gSaveContext.inventory.questItems & 0xF0000000) >> 28;
pohCount++;
gSaveContext.inventory.questItems |= (pohCount << 28);
}
void GiveLinkHeartContainer() {
gSaveContext.healthCapacity += 16;
gSaveContext.health += 16;
}
void GiveLinkBulletBagUpgrade(GetItemID giid) {
if (giid == GI_SLINGSHOT) {
INV_CONTENT(ITEM_SLINGSHOT) = ITEM_SLINGSHOT;
AMMO(ITEM_SLINGSHOT) = 30;
Inventory_ChangeUpgrade(UPG_BULLET_BAG, 1);
} else if (giid == GI_BULLET_BAG_40) {
Inventory_ChangeUpgrade(UPG_BULLET_BAG, 2);
AMMO(ITEM_SLINGSHOT) = 40;
} else if (giid == GI_BULLET_BAG_50) {
Inventory_ChangeUpgrade(UPG_BULLET_BAG, 3);
AMMO(ITEM_SLINGSHOT) = 50;
}
}
void GiveLinkQuiverUpgrade(GetItemID giid) {
if (giid == GI_BOW) {
INV_CONTENT(ITEM_BOW) = ITEM_BOW;
Inventory_ChangeUpgrade(UPG_QUIVER, 1);
AMMO(ITEM_BOW) = 30;
} else if (giid == GI_QUIVER_40) {
Inventory_ChangeUpgrade(UPG_QUIVER, 2);
AMMO(ITEM_BOW) = 40;
} else if (giid == GI_QUIVER_50) {
Inventory_ChangeUpgrade(UPG_QUIVER, 3);
AMMO(ITEM_BOW) = 50;
}
}
void GiveLinkBombBagUpgrade(GetItemID giid) {
if (giid == GI_BOMB_BAG_20) {
INV_CONTENT(ITEM_BOMB) = ITEM_BOMB;
Inventory_ChangeUpgrade(UPG_BOMB_BAG, 1);
AMMO(ITEM_BOMB) = 20;
} else if (giid == GI_BOMB_BAG_30) {
Inventory_ChangeUpgrade(UPG_BOMB_BAG, 2);
AMMO(ITEM_BOMB) = 30;
} else if (giid == GI_BOMB_BAG_40) {
Inventory_ChangeUpgrade(UPG_BOMB_BAG, 3);
AMMO(ITEM_BOMB) = 40;
}
}
void GiveLinkStrengthUpgrade(GetItemID giid) {
if (giid == GI_BRACELET) {
Inventory_ChangeUpgrade(UPG_STRENGTH, 1);
} else if (giid == GI_GAUNTLETS_SILVER) {
Inventory_ChangeUpgrade(UPG_STRENGTH, 2);
} else if (giid == GI_GAUNTLETS_GOLD) {
Inventory_ChangeUpgrade(UPG_STRENGTH, 3);
}
}
void GiveLinkScaleUpgrade(GetItemID giid) {
if (giid == GI_SCALE_SILVER) {
Inventory_ChangeUpgrade(UPG_SCALE, 1);
} else if (giid == GI_SCALE_GOLD) {
Inventory_ChangeUpgrade(UPG_SCALE, 2);
}
}
void GiveLinkWalletUpgrade(GetItemID giid) {
if (giid == GI_WALLET_ADULT) {
Inventory_ChangeUpgrade(UPG_WALLET, 1);
} else if (giid == GI_WALLET_GIANT) {
Inventory_ChangeUpgrade(UPG_WALLET, 2);
}
}
void GiveLinkDekuStickUpgrade(GetItemID giid) {
if (giid == GI_STICK_UPGRADE_20) {
INV_CONTENT(ITEM_STICK) = ITEM_STICK;
Inventory_ChangeUpgrade(UPG_STICKS, 2);
AMMO(ITEM_STICK) = 20;
} else if (giid == GI_STICK_UPGRADE_30) {
Inventory_ChangeUpgrade(UPG_STICKS, 3);
AMMO(ITEM_STICK) = 30;
}
}
void GiveLinkDekuNutUpgrade(GetItemID giid) {
if (giid == GI_NUT_UPGRADE_30) {
INV_CONTENT(ITEM_NUT) = ITEM_NUT;
Inventory_ChangeUpgrade(UPG_NUTS, 2);
AMMO(ITEM_NUT) = 30;
} else if (giid == GI_NUT_UPGRADE_40) {
Inventory_ChangeUpgrade(UPG_NUTS, 3);
AMMO(ITEM_NUT) = 40;
}
}
void GiveLinkMagic(GetItemID giid) {
if (giid == GI_SINGLE_MAGIC) {
gSaveContext.magicLevel = 1;
gSaveContext.magicAcquired = true;
gSaveContext.doubleMagic = false;
} else if (giid == GI_DOUBLE_MAGIC) {
gSaveContext.magicLevel = 2;
gSaveContext.magicAcquired = true;
gSaveContext.doubleMagic = true;
}
}
void GiveLinkDoubleDefense() {
gSaveContext.doubleDefense = 1;
gSaveContext.inventory.defenseHearts = 20;
}
void GiveLinkSong(GetItemID getItemId) {
uint32_t bitMask;
switch (getItemId) {
case GI_ZELDAS_LULLABY:
bitMask = 1 << QUEST_SONG_LULLABY;
break;
case GI_SUNS_SONG:
bitMask = 1 << QUEST_SONG_SUN;
break;
case GI_EPONAS_SONG:
bitMask = 1 << QUEST_SONG_EPONA;
break;
case GI_SONG_OF_STORMS:
bitMask = 1 << QUEST_SONG_STORMS;
break;
case GI_SONG_OF_TIME:
bitMask = 1 << QUEST_SONG_TIME;
break;
case GI_SARIAS_SONG:
bitMask = 1 << QUEST_SONG_SARIA;
break;
case GI_MINUET_OF_FOREST:
bitMask = 1 << QUEST_SONG_MINUET;
break;
case GI_BOLERO_OF_FIRE:
bitMask = 1 << QUEST_SONG_BOLERO;
break;
case GI_SERENADE_OF_WATER:
bitMask = 1 << QUEST_SONG_SERENADE;
break;
case GI_NOCTURNE_OF_SHADOW:
bitMask = 1 << QUEST_SONG_NOCTURNE;
break;
case GI_REQUIEM_OF_SPIRIT:
bitMask = 1 << QUEST_SONG_REQUIEM;
break;
case GI_PRELUDE_OF_LIGHT:
bitMask = 1 << QUEST_SONG_PRELUDE;
break;
}
gSaveContext.inventory.questItems |= bitMask;
}
void GiveLinkDungeonReward(GetItemID getItemId) {
s16 item;
u8 medallion = 0;
switch (getItemId) {
case GI_MEDALLION_FOREST:
item = ITEM_MEDALLION_FOREST;
medallion = 1;
break;
case GI_MEDALLION_FIRE:
item = ITEM_MEDALLION_FIRE;
medallion = 1;
break;
case GI_MEDALLION_WATER:
item = ITEM_MEDALLION_WATER;
medallion = 1;
break;
case GI_MEDALLION_SHADOW:
item = ITEM_MEDALLION_SHADOW;
medallion = 1;
break;
case GI_MEDALLION_SPIRIT:
item = ITEM_MEDALLION_SPIRIT;
medallion = 1;
break;
case GI_MEDALLION_LIGHT:
item = ITEM_MEDALLION_LIGHT;
medallion = 1;
break;
case GI_STONE_KOKIRI:
item = ITEM_KOKIRI_EMERALD;
break;
case GI_STONE_GORON:
item = ITEM_GORON_RUBY;
break;
case GI_STONE_ZORA:
item = ITEM_ZORA_SAPPHIRE;
break;
}
if (medallion == 1) {
gSaveContext.inventory.questItems |= gBitFlags[item - ITEM_MEDALLION_FOREST + QUEST_MEDALLION_FOREST];
} else {
gSaveContext.inventory.questItems |= gBitFlags[item - ITEM_KOKIRI_EMERALD + QUEST_KOKIRI_EMERALD];
}
}
void GiveLinksPocketMedallion() {
GetItemID getItemId = GetRandomizedItemIdFromKnownCheck(RC_LINKS_POCKET, RG_NONE);
GiveLinkDungeonReward(getItemId);
}
/**
* Copy save currently on the buffer to Save Context and complete various tasks to open the save.
* This includes:
@@ -141,7 +538,7 @@ void Sram_OpenSave() {
}
// if zelda cutscene has been watched but lullaby was not obtained, restore cutscene and take away letter
if ((gSaveContext.eventChkInf[4] & 1) && !CHECK_QUEST_ITEM(QUEST_SONG_LULLABY)) {
if ((gSaveContext.eventChkInf[4] & 1) && !CHECK_QUEST_ITEM(QUEST_SONG_LULLABY) && !gSaveContext.n64ddFlag) {
i = gSaveContext.eventChkInf[4] & ~1;
gSaveContext.eventChkInf[4] = i;
@@ -202,6 +599,273 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
gSaveContext.playerName[offset] = Save_GetSaveMetaInfo(fileChooseCtx->buttonIndex)->playerName[offset];
}
if (CVar_GetS32("gRandomizer", 0) != 0 &&
strcmp(CVar_GetString("gSpoilerLog", ""), "") != 0) {
// Set N64DD Flags for save file
fileChooseCtx->n64ddFlags[fileChooseCtx->buttonIndex] = 1;
fileChooseCtx->n64ddFlag = 1;
gSaveContext.n64ddFlag = 1;
// Sets all the dungeons to incomplete when generating a rando save. Fixes https://github.com/briaguya-ai/rando-issue-tracker/issues/82
for (u8 i = 0; i < NUM_DUNGEONS; i++) {
gSaveContext.dungeonsDone[i] = 0;
}
// Sets all Ganon's Trials to incomplete when generating a rando save. Fixes https://github.com/briaguya-ai/rando-issue-tracker/issues/131
for (u8 i = 0; i < NUM_TRIALS; i++) {
gSaveContext.trialsDone[i] = 0;
}
// Set Cutscene flags to skip them
gSaveContext.eventChkInf[0xC] |= 0x10; // returned to tot with medallions
gSaveContext.eventChkInf[0xC] |= 0x20; //sheik at tot pedestal
gSaveContext.eventChkInf[4] |= 0x20; // master sword pulled
gSaveContext.eventChkInf[4] |= 0x8000; // entered master sword chamber
gSaveContext.infTable[0] |= 1;
// RANDTODO: Don't skip this scene if Don't Skip Glitch Useful Cutscenes is enabled.
gSaveContext.infTable[17] |= 0x400; // Darunia in Fire Temple
gSaveContext.cutsceneIndex = 0;
Flags_SetEventChkInf(5);
// Skip boss cutscenes
gSaveContext.eventChkInf[7] |= 1; // gohma
gSaveContext.eventChkInf[7] |= 2; // dodongo
gSaveContext.eventChkInf[7] |= 4; // phantom ganon
gSaveContext.eventChkInf[7] |= 8; // volvagia
gSaveContext.eventChkInf[7] |= 0x10; // morpha
gSaveContext.eventChkInf[7] |= 0x20; // twinrova
gSaveContext.eventChkInf[7] |= 0x40; // barinade
gSaveContext.eventChkInf[7] |= 0x80; // bongo bongo
// Skip cutscene before Nabooru fight
gSaveContext.eventChkInf[3] |= 0x800;
gSaveContext.eventChkInf[12] |= 1;
// Give Link's pocket item
GiveLinksPocketMedallion();
int openForest = GetRandoSettingValue(RSK_FOREST);
switch (openForest) {
case 0: // closed
break;
case 1: // open
Flags_SetEventChkInf(7);
gSaveContext.eventChkInf[0] |= 0x10;
break;
case 2: // closed deku
Flags_SetEventChkInf(7);
break;
}
int doorOfTime = GetRandoSettingValue(RSK_DOOR_OF_TIME);
switch (doorOfTime) {
case 0: // open
gSaveContext.eventChkInf[4] |= 0x800;
break;
}
int kakGate = GetRandoSettingValue(RSK_KAK_GATE);
switch (kakGate) {
case 1: // open
gSaveContext.infTable[7] |= 0x40;
break;
}
if(GetRandoSettingValue(RSK_STARTING_KOKIRI_SWORD)) GiveLinkKokiriSword();
if(GetRandoSettingValue(RSK_STARTING_DEKU_SHIELD)) GiveLinkDekuShield();
if(GetRandoSettingValue(RSK_STARTING_OCARINA)) {
INV_CONTENT(ITEM_OCARINA_FAIRY) = ITEM_OCARINA_FAIRY;
}
if(GetRandoSettingValue(RSK_STARTING_MAPS_COMPASSES)) {
uint32_t mapBitMask = 1 << 1;
uint32_t compassBitMask = 1 << 2;
uint32_t startingDungeonItemsBitMask = mapBitMask | compassBitMask;
for(int scene = 0; scene <= 9; scene++) {
gSaveContext.inventory.dungeonItems[scene] |= startingDungeonItemsBitMask;
}
}
if (GetRandoSettingValue(RSK_STARTING_CONSUMABLES)) {
GiveLinkDekuSticks(10);
GiveLinkDekuNuts(20);
}
if(GetRandoSettingValue(RSK_SKIP_CHILD_ZELDA)) {
s32 giid = GetRandomizedItemIdFromKnownCheck(RC_SONG_FROM_IMPA, GI_ZELDAS_LULLABY);
if(giid >= GI_ZELDAS_LULLABY && giid <= GI_PRELUDE_OF_LIGHT) {
GiveLinkSong(giid);
} else if (giid == GI_RUPEE_GREEN ||
giid == GI_RUPEE_BLUE ||
giid == GI_RUPEE_RED ||
giid == GI_RUPEE_PURPLE ||
giid == GI_RUPEE_GOLD) {
GiveLinkRupeesByGetItemId(giid);
} else if (giid == GI_BOMBCHUS_10 ||
giid == GI_BOMBCHUS_5 ||
giid == GI_BOMBCHUS_20) {
GiveLinkBombchus(giid);
} else if (giid == GI_STICKS_1 ||
giid == GI_STICKS_5 ||
giid == GI_STICKS_10) {
GiveLinkDekuSticksByGetItemId(giid);
} else if (giid == GI_NUTS_5 ||
giid == GI_NUTS_10) {
GiveLinkDekuNutsByGetItemId(giid);
} else if (giid == GI_BEAN) {
GiveLinkBeans();
} else if (giid >= GI_MEDALLION_LIGHT && giid <= GI_STONE_ZORA) {
GiveLinkDungeonReward(giid);
} else if (giid == GI_SWORD_KOKIRI) {
GiveLinkKokiriSword();
} else if (giid == GI_SWORD_BGS) {
GiveLinkBiggoronSword();
} else if (giid == GI_SWORD_KNIFE) {
GiveLinkGiantsKnife();
} else if (giid == GI_SHIELD_DEKU) {
GiveLinkDekuShield();
} else if (giid == GI_SHIELD_HYLIAN) {
GiveLinkHylianShield();
} else if (giid == GI_SHIELD_MIRROR) {
GiveLinkMirrorShield();
} else if (giid == GI_TUNIC_GORON) {
GiveLinkGoronTunic();
} else if (giid == GI_TUNIC_ZORA) {
GiveLinkZoraTunic();
} else if (giid == GI_BOOTS_IRON) {
GiveLinkIronBoots();
} else if (giid == GI_BOOTS_HOVER) {
GiveLinkHoverBoots();
} else if (giid == GI_SLINGSHOT ||
giid == GI_BULLET_BAG_40 ||
giid == GI_BULLET_BAG_50) {
GiveLinkBulletBagUpgrade(giid);
} else if (giid == GI_BOW ||
giid == GI_QUIVER_40 ||
giid == GI_QUIVER_50) {
GiveLinkQuiverUpgrade(giid);
} else if (giid == GI_BOMB_BAG_20 ||
giid == GI_BOMB_BAG_30 ||
giid == GI_BOMB_BAG_40) {
GiveLinkBombBagUpgrade(giid);
} else if (giid == GI_BRACELET ||
giid == GI_GAUNTLETS_SILVER ||
giid == GI_GAUNTLETS_GOLD) {
GiveLinkStrengthUpgrade(giid);
} else if (giid == GI_SCALE_SILVER ||
giid == GI_SCALE_GOLD) {
GiveLinkScaleUpgrade(giid);
} else if (giid == GI_WALLET_ADULT ||
giid == GI_WALLET_GIANT) {
GiveLinkWalletUpgrade(giid);
} else if (giid == GI_STONE_OF_AGONY) {
GiveLinkStoneOfAgony();
} else if (giid == GI_GERUDO_CARD) {
GiveLinkGerudoCard();
} else if (giid == GI_HEART_PIECE) {
GiveLinkPieceOfHeart();
} else if (giid == GI_HEART_CONTAINER) {
GiveLinkHeartContainer();
} else if (giid == GI_STICK_UPGRADE_20 ||
giid == GI_STICK_UPGRADE_30) {
GiveLinkDekuStickUpgrade(giid);
} else if (giid == GI_NUT_UPGRADE_30 ||
giid == GI_NUT_UPGRADE_40) {
GiveLinkDekuNutUpgrade(giid);
} else if (giid == GI_SINGLE_MAGIC ||
giid == GI_DOUBLE_MAGIC) {
GiveLinkMagic(giid);
} else if (giid == GI_DOUBLE_DEFENSE) {
GiveLinkDoubleDefense();
} else {
s32 iid = GetItemIDFromGetItemID(giid);
if (iid != -1) INV_CONTENT(iid) = iid;
}
// malon/talon back at ranch
gSaveContext.eventChkInf[1] |= (1 << 0);
gSaveContext.eventChkInf[1] |= (1 << 2);
gSaveContext.eventChkInf[1] |= (1 << 3);
gSaveContext.eventChkInf[1] |= (1 << 4);
// Got item from impa
gSaveContext.eventChkInf[5] |= 0x200;
// make sure saria is at SFM
gSaveContext.eventChkInf[4] |= (1 << 0);
// set this at the end to ensure we always start with the letter
// this is for the off chance we got the weird egg from impa (which should never happen)
INV_CONTENT(ITEM_LETTER_ZELDA) = ITEM_LETTER_ZELDA;
}
if (GetRandoSettingValue(RSK_FULL_WALLETS)) {
GiveLinkRupees(9001);
}
// For Ganon's boss key "Start With" is 0
if(GetRandoSettingValue(RSK_GANONS_BOSS_KEY) == 0) {
gSaveContext.inventory.dungeonItems[10] |= 1;
}
HIGH_SCORE(HS_POE_POINTS) = 1000 - (100 * GetRandoSettingValue(RSK_BIG_POE_COUNT));
if(GetRandoSettingValue(RSK_SKIP_EPONA_RACE)) {
gSaveContext.eventChkInf[1] |= (1 << 8);
}
// skip the z target talk instructions by the kokiri shop
gSaveContext.sceneFlags[85].swch |= (1 << 0x1F);
//Ruto already met in jabu and spawns down the hole immediately
gSaveContext.infTable[20] |= 2;
gSaveContext.infTable[20] |= 4;
// Go away ruto (water temple first cutscene)
gSaveContext.sceneFlags[05].swch |= (1 << 0x10);
// Skip intro cutscene when bombing mud wall in Dodongo's cavern
// this also makes the lower jaw render, and the eyes react to explosives
Flags_SetEventChkInf(0xB0);
// skip verbose lake owl, skip to "i'm on my way back to the castle"
gSaveContext.infTable[25] |= 0x20;
// fast gerudo fortress
if (GetRandoSettingValue(RSK_GERUDO_FORTRESS) == 1 || GetRandoSettingValue(RSK_GERUDO_FORTRESS) == 2) {
gSaveContext.eventChkInf[9] |= 2;
gSaveContext.eventChkInf[9] |= 4;
gSaveContext.eventChkInf[9] |= 8;
gSaveContext.sceneFlags[12].swch |= (1 << 0x02);
gSaveContext.sceneFlags[12].swch |= (1 << 0x03);
gSaveContext.sceneFlags[12].swch |= (1 << 0x04);
gSaveContext.sceneFlags[12].swch |= (1 << 0x06);
gSaveContext.sceneFlags[12].swch |= (1 << 0x07);
gSaveContext.sceneFlags[12].swch |= (1 << 0x08);
gSaveContext.sceneFlags[12].swch |= (1 << 0x10);
gSaveContext.sceneFlags[12].swch |= (1 << 0x12);
gSaveContext.sceneFlags[12].swch |= (1 << 0x13);
gSaveContext.sceneFlags[12].collect |= (1 << 0x0A);
gSaveContext.sceneFlags[12].collect |= (1 << 0x0E);
gSaveContext.sceneFlags[12].collect |= (1 << 0x0F);
}
// open gerudo fortress
if (GetRandoSettingValue(RSK_GERUDO_FORTRESS) == 2) {
gSaveContext.eventChkInf[9] |= 1;
gSaveContext.sceneFlags[12].swch |= (1 << 0x01);
gSaveContext.sceneFlags[12].swch |= (1 << 0x05);
gSaveContext.sceneFlags[12].swch |= (1 << 0x11);
gSaveContext.sceneFlags[12].collect |= (1 << 0x0C);
if (!GetRandoSettingValue(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)) {
GiveLinkGerudoCard();
}
}
}
Save_SaveFile();
}