Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion code/src/actors/checkable_spot.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
void EnWonderTalk_rUpdate(Actor* thisx, GlobalContext* globalCtx) {
EnWonderTalk* this = (EnWonderTalk*)thisx;
if (this->actionFunc == (ActorFunc)GAME_ADDR(0x2065E0) && thisx->params == 0x0FFF) { // reading ToT altar
gExtSaveData.extInf[EXTINF_TOTALTAR_FLAGS] |= (1 << gSaveContext.linkAge);
gExtSaveData.extInf.totAltarFlags |= (1 << gSaveContext.linkAge);
}
EnWonderTalk_Update(thisx, globalCtx);
}
Expand Down
10 changes: 5 additions & 5 deletions code/src/actors/gorons.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
void EnGo2_rBiggoronSetTextId(EnGo2* self) {
Player* player = PLAYER;
if (player->exchangeItemId == EXCH_ITEM_CLAIM_CHECK) {
if (gExtSaveData.extInf[EXTINF_BIGGORONTRADES] & BIGGORON_TRADED_CLAIM_CHECK) {
if (gExtSaveData.extInf.biggoronTrades & BIGGORON_TRADED_CLAIM_CHECK) {
self->actor.textId = 0x3003; // "I giiiive thissss to yoooou forrr a souvenirrrrr."
} else {
self->actor.textId = 0x305E; // "Yourrrr sworrrrd is my finest worrrrk!"
Expand All @@ -36,7 +36,7 @@ u16 EnGo2_rGetTextIdGoronDmtBiggoron(GlobalContext* globalCtx, EnGo2* self) {
return 0x3058;
case ITEM_CLAIM_CHECK:
player->exchangeItemId = EXCH_ITEM_CLAIM_CHECK;
return (gExtSaveData.extInf[EXTINF_BIGGORONTRADES] & BIGGORON_TRADED_CLAIM_CHECK) ? 0x3053 : 0x305E;
return (gExtSaveData.extInf.biggoronTrades & BIGGORON_TRADED_CLAIM_CHECK) ? 0x3053 : 0x305E;
default:
player->exchangeItemId = EXCH_ITEM_NONE;
return 0x3053;
Expand All @@ -46,13 +46,13 @@ u16 EnGo2_rGetTextIdGoronDmtBiggoron(GlobalContext* globalCtx, EnGo2* self) {
void EnGo2_AfterGiveItem(EnGo2* self, GlobalContext* globaCtx) {
switch (self->getItemId) {
case GI_CLAIM_CHECK:
gExtSaveData.extInf[EXTINF_BIGGORONTRADES] |= BIGGORON_TRADED_EYEDROPS;
gExtSaveData.extInf.biggoronTrades |= BIGGORON_TRADED_EYEDROPS;
break;
case GI_SWORD_BGS:
gExtSaveData.extInf[EXTINF_BIGGORONTRADES] |= BIGGORON_TRADED_CLAIM_CHECK;
gExtSaveData.extInf.biggoronTrades |= BIGGORON_TRADED_CLAIM_CHECK;
break;
case GI_PERSCRIPTION:
gExtSaveData.extInf[EXTINF_BIGGORONTRADES] |= BIGGORON_TRADED_BROKEN_SWORD;
gExtSaveData.extInf.biggoronTrades |= BIGGORON_TRADED_BROKEN_SWORD;
break;
}
self->actionFunc = EnGo2_SetGetItem;
Expand Down
4 changes: 2 additions & 2 deletions code/src/enemy_souls.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,14 @@ u8 EnemySouls_GetSoulFlag(EnemySoulId soulId) {
if (soulId == SOUL_NONE) {
return 1;
}
return gExtSaveData.extInf[EXTINF_ENEMYSOULSFLAGS_START + (soulId >> 3)] & (1 << (soulId & 0b111));
return gExtSaveData.extInf.enemySouls[(soulId >> 3)] & (1 << (soulId & 0b111));
}

void EnemySouls_SetSoulFlag(EnemySoulId soulId) {
if (soulId == SOUL_NONE) {
return;
}
gExtSaveData.extInf[EXTINF_ENEMYSOULSFLAGS_START + (soulId >> 3)] |= (1 << (soulId & 0b111));
gExtSaveData.extInf.enemySouls[(soulId >> 3)] |= (1 << (soulId & 0b111));
}

u8 EnemySouls_CheckSoulForActor(Actor* actor) {
Expand Down
2 changes: 1 addition & 1 deletion code/src/item_effect.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ void ItemEffect_IceTrap(SaveContext* saveCtx, s16 arg1, s16 arg2) {
}

void ItemEffect_GiveMasterSword(SaveContext* saveCtx, s16 arg1, s16 arg2) {
gExtSaveData.extInf[EXTINF_MASTERSWORDFLAGS] |= 1;
gExtSaveData.extInf.masterSwordFlags |= 1;
}

void ItemEffect_EquipMasterSword(void) {
Expand Down
8 changes: 4 additions & 4 deletions code/src/master_sword_pedestal.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include "savefile.h"

u8 ShouldSkipMasterSwordCutscene() {
return gExtSaveData.extInf[EXTINF_HASTIMETRAVELED] || gSettingsContext.openDoorOfTime == OPENDOOROFTIME_OPEN;
return gExtSaveData.hasTimeTraveled || gSettingsContext.openDoorOfTime == OPENDOOROFTIME_OPEN;
}

void TimeTravelAdvanceCutsceneTimer() {
Expand All @@ -18,12 +18,12 @@ void TimeTravelAdvanceCutsceneTimer() {
}

void SetTimeTraveled() {
gExtSaveData.extInf[EXTINF_HASTIMETRAVELED] = 1;
gExtSaveData.hasTimeTraveled = 1;
}

void Pedestal_PickUpMasterSword(void) {
// Push pedestal item
if (gSettingsContext.shuffleMasterSword && !(gExtSaveData.extInf[EXTINF_MASTERSWORDFLAGS] & 2)) {
if (gSettingsContext.shuffleMasterSword && !(gExtSaveData.extInf.masterSwordFlags & 2)) {
ItemOverride_PushDelayedOverride(0x00);
}

Expand All @@ -33,5 +33,5 @@ void Pedestal_PickUpMasterSword(void) {
}

// Mark pedestal item collected
gExtSaveData.extInf[EXTINF_MASTERSWORDFLAGS] |= 2;
gExtSaveData.extInf.masterSwordFlags |= 2;
}
4 changes: 2 additions & 2 deletions code/src/menus.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,11 @@ u16 GearMenu_GetRewardHint(void) {

if (gGearMenuSelectedSlot >= GEARSLOT_KOKIRI_EMERALD && gGearMenuSelectedSlot <= GEARSLOT_ZORA_SAPPHIRE) {
rewardId = gGearMenuSelectedSlot - GEARSLOT_KOKIRI_EMERALD;
checkedAltar = gExtSaveData.extInf[EXTINF_TOTALTAR_FLAGS] & (1 << AGE_CHILD);
checkedAltar = gExtSaveData.extInf.totAltarFlags & (1 << AGE_CHILD);
} else if (gGearMenuSelectedSlot >= GEARSLOT_FOREST_MEDALLION &&
gGearMenuSelectedSlot <= GEARSLOT_LIGHT_MEDALLION) {
rewardId = gGearMenuSelectedSlot - GEARSLOT_FOREST_MEDALLION + 3;
checkedAltar = gExtSaveData.extInf[EXTINF_TOTALTAR_FLAGS] & (1 << AGE_ADULT);
checkedAltar = gExtSaveData.extInf.totAltarFlags & (1 << AGE_ADULT);
} else {
return 0;
}
Expand Down
22 changes: 10 additions & 12 deletions code/src/multiplayer.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ static void Multiplayer_Overwrite_mSaveContext(void) {
mSaveContext.magicMeterSize = gSaveContext.magicMeterSize;
// ExtData
for (size_t i = 0; i < EXTINF_SIZE; i++) {
mSaveContext.extInf[i] = gExtSaveData.extInf[i];
mSaveContext.extInf[i] = gExtSaveData.extInfArray[i];
}
for (size_t i = 0; i < SAVEFILE_SCENES_DISCOVERED_IDX_COUNT; i++) {
mSaveContext.scenesDiscovered[i] = gExtSaveData.scenesDiscovered[i];
Expand Down Expand Up @@ -198,7 +198,7 @@ static void Multiplayer_Overwrite_gSaveContext(void) {
gSaveContext.magicMeterSize = mSaveContext.magicMeterSize;
// ExtData
for (size_t i = 0; i < EXTINF_SIZE; i++) {
gExtSaveData.extInf[i] = mSaveContext.extInf[i];
gExtSaveData.extInfArray[i] = mSaveContext.extInf[i];
}
for (size_t i = 0; i < SAVEFILE_SCENES_DISCOVERED_IDX_COUNT; i++) {
gExtSaveData.scenesDiscovered[i] = mSaveContext.scenesDiscovered[i];
Expand Down Expand Up @@ -525,7 +525,7 @@ static void Multiplayer_Sync_Init(void) {

// Extra Info Table
for (size_t i = 0; i < EXTINF_SIZE; i++) {
prevExtInf[i] = gExtSaveData.extInf[i];
prevExtInf[i] = gExtSaveData.extInfArray[i];
}

// Triforce Pieces
Expand Down Expand Up @@ -854,24 +854,22 @@ static void Multiplayer_Sync_SharedProgress(void) {
prevAdultTrade = gSaveContext.sceneFlags[0x60].unk;

// Extra Info Table
for (size_t index = 0; index < ARRAY_SIZE(gExtSaveData.extInf); index++) {
// Don't send this to allow all current players to watch the cutscene
if (index == EXTINF_HASTIMETRAVELED) {
continue;
}
if (prevExtInf[index] != gExtSaveData.extInf[index]) {
for (size_t bit = 0; bit < BIT_COUNT(gExtSaveData.extInf[index]); bit++) {
s8 result = BitCompare(gExtSaveData.extInf[index], prevExtInf[index], bit);
for (size_t index = 0; index < ARRAY_SIZE(gExtSaveData.extInfArray); index++) {
if (prevExtInf[index] != gExtSaveData.extInfArray[index]) {
for (size_t bit = 0; bit < BIT_COUNT(gExtSaveData.extInfArray[index]); bit++) {
s8 result = BitCompare(gExtSaveData.extInfArray[index], prevExtInf[index], bit);
if (result > 0) {
Multiplayer_Send_ExtInfBit(index, bit, 1);
} else if (result < 0) {
Multiplayer_Send_ExtInfBit(index, bit, 0);
}
}
}
prevExtInf[index] = gExtSaveData.extInf[index];
prevExtInf[index] = gExtSaveData.extInfArray[index];
}

// `hasTimeTraveled` is not synced to allow all current players to watch the cutscene

// Triforce Pieces
if (prevTriforcePieces != gExtSaveData.triforcePieces) {
Multiplayer_Send_TriforcePieces(gExtSaveData.triforcePieces - prevTriforcePieces);
Expand Down
5 changes: 2 additions & 3 deletions code/src/ocarina_notes.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,11 @@ void OcarinaNotes_Init(void) {
}

s32 OcarinaNotes_IsButtonOwned(OcarinaNoteButton button) {
return (gSettingsContext.shuffleOcarinaButtons == OFF) ||
(gExtSaveData.extInf[EXTINF_OCARINA_BUTTONS] & (1 << button));
return (gSettingsContext.shuffleOcarinaButtons == OFF) || (gExtSaveData.extInf.ocarinaButtons & (1 << button));
}

void OcarinaNotes_RegisterButtonOwned(OcarinaNoteButton button) {
gExtSaveData.extInf[EXTINF_OCARINA_BUTTONS] |= (1 << button);
gExtSaveData.extInf.ocarinaButtons |= (1 << button);
}

void OcarinaNotes_MoveButtons(void* spriteStruct, Vec2f* posOffset, u32 unk, u32 spriteIndex) {
Expand Down
12 changes: 6 additions & 6 deletions code/src/savefile.c
Original file line number Diff line number Diff line change
Expand Up @@ -541,11 +541,11 @@ void SaveFile_SetStartingInventory(void) {
}

// Set owned ocarina buttons. If the shuffle option is disabled, this value will be ignored.
gExtSaveData.extInf[EXTINF_OCARINA_BUTTONS] = gSettingsContext.startingOcarinaButtons;
gExtSaveData.extInf.ocarinaButtons = gSettingsContext.startingOcarinaButtons;

// Set owned enemy souls. If the shuffle option is disabled, these values will be ignored.
for (u32 i = 0; i < sizeof(gSettingsContext.startingEnemySouls); i++) {
gExtSaveData.extInf[EXTINF_ENEMYSOULSFLAGS_START + i] = gSettingsContext.startingEnemySouls[i];
gExtSaveData.extInf.enemySouls[i] = gSettingsContext.startingEnemySouls[i];
}
}

Expand Down Expand Up @@ -718,7 +718,7 @@ void SaveFile_InitExtSaveData(u32 saveNumber, u8 fromSaveCreation) {
memset(&gExtSaveData, 0, sizeof(gExtSaveData));

gExtSaveData.version = EXTSAVEDATA_VERSION; // Do not change this line
gExtSaveData.extInf[EXTINF_MASTERSWORDFLAGS] =
gExtSaveData.extInf.masterSwordFlags =
(gSettingsContext.shuffleMasterSword && !(gSettingsContext.startingEquipment & 0x2)) ? 0 : 1;
gExtSaveData.permadeath = fromSaveCreation ? gSettingsContext.permadeath : 0;
// Ingame Options
Expand Down Expand Up @@ -803,7 +803,7 @@ void SaveFile_EnforceHealthLimit(void) {
}

u8 SaveFile_SwordlessPatchesEnabled(void) {
return gSettingsContext.shuffleMasterSword && !(gExtSaveData.extInf[EXTINF_MASTERSWORDFLAGS] & 1);
return gSettingsContext.shuffleMasterSword && !(gExtSaveData.extInf.masterSwordFlags & 1);
}

u8 SaveFile_BecomeAdult(void) {
Expand Down Expand Up @@ -835,12 +835,12 @@ u8 SaveFile_BecomeAdult(void) {
void SaveFile_LoadFileSwordless(void) {
if (gSaveContext.linkAge == 0) {
// Push pedestal item if adult and haven't received yet
if (gSettingsContext.shuffleMasterSword && !(gExtSaveData.extInf[EXTINF_MASTERSWORDFLAGS] & 2)) {
if (gSettingsContext.shuffleMasterSword && !(gExtSaveData.extInf.masterSwordFlags & 2)) {
ItemOverride_PushDelayedOverride(0x00);
}

// Mark pedestal item collected
gExtSaveData.extInf[EXTINF_MASTERSWORDFLAGS] |= 2;
gExtSaveData.extInf.masterSwordFlags |= 2;
}
}

Expand Down
27 changes: 15 additions & 12 deletions code/src/savefile.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,24 @@ void SaveFile_EnforceHealthLimit(void);
u8 SaveFile_SwordlessPatchesEnabled(void);

// Increment the version number whenever the ExtSaveData structure is changed
#define EXTSAVEDATA_VERSION 16
#define EXTSAVEDATA_VERSION 17

typedef enum {
EXTINF_BIGGORONTRADES,
EXTINF_HASTIMETRAVELED,
EXTINF_MASTERSWORDFLAGS,
EXTINF_TOTALTAR_FLAGS,
EXTINF_ENEMYSOULSFLAGS_START, // 64 bits (at least one for each EnemySoulId)
EXTINF_ENEMYSOULSFLAGS_END = EXTINF_ENEMYSOULSFLAGS_START + 7,
EXTINF_OCARINA_BUTTONS,
EXTINF_SIZE,
typedef struct ExtInf {
u8 biggoronTrades;
u8 masterSwordFlags;
u8 totAltarFlags;
u8 enemySouls[8];
u8 ocarinaButtons;
} ExtInf;

#define EXTINF_SIZE sizeof(ExtInf)

typedef struct {
u32 version; // Needs to always be the first field of the structure
u8 extInf[EXTINF_SIZE]; // Used for various bit flags that should also be synced in multiplayer
u32 version; // Needs to always be the first field of the structure
union {
ExtInf extInf; // Used for various bit flags that should also be synced in multiplayer with shared progress
u8 extInfArray[EXTINF_SIZE]; // Used only by multiplayer code for easier management of bit flags
};
struct {
Vec3i pos;
s32 yaw;
Expand All @@ -61,6 +63,7 @@ typedef struct {
u32 playtimeSeconds;
u32 scenesDiscovered[SAVEFILE_SCENES_DISCOVERED_IDX_COUNT];
u32 entrancesDiscovered[SAVEFILE_ENTRANCES_DISCOVERED_IDX_COUNT];
u8 hasTimeTraveled;
u8 permadeath;
u8 gloomedHeart;
u8 triforcePieces;
Expand Down
4 changes: 2 additions & 2 deletions code/src/spoiler_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ u8 SpoilerData_ScrubCheck(SpoilerItemLocation* itemLoc) {
}

u8 SpoilerData_BiggoronCheck(u8 mask) {
return (gExtSaveData.extInf[EXTINF_BIGGORONTRADES] & mask) != 0;
return (gExtSaveData.extInf.biggoronTrades & mask) != 0;
}

u8 SpoilerData_GerudoTokenCheck() {
Expand Down Expand Up @@ -110,7 +110,7 @@ u8 SpoilerData_MagicBeansCheck(SpoilerItemLocation* itemLoc) {
}

u8 SpoilerData_MasterSwordCheck() {
return (gExtSaveData.extInf[EXTINF_MASTERSWORDFLAGS] & 2) != 0;
return (gExtSaveData.extInf.masterSwordFlags & 2) != 0;
}

u8 SpoilerData_GetIsItemLocationCollected(u16 itemIndex) {
Expand Down