Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shuffle dungeon rewards #2034

Merged
merged 11 commits into from
May 25, 2024
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,857 changes: 1,442 additions & 1,415 deletions ASM/build/asm_symbols.txt

Large diffs are not rendered by default.

Binary file modified ASM/build/bundle.o
Binary file not shown.
1,222 changes: 626 additions & 596 deletions ASM/build/c_symbols.txt

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions ASM/c/actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ void Actor_StoreChestType(z64_actor_t* actor, z64_game_t* game);
z64_actor_t* Actor_SpawnEntry_Hack(void* actorCtx, ActorEntry* actorEntry, z64_game_t* globalCtx);
bool spawn_override_silver_rupee(ActorEntry* actorEntry, z64_game_t* globalCtx, bool* overridden);
void after_spawn_override_silver_rupee(z64_actor_t* actor, bool overridden);
extern ActorOverlay gActorOverlayTable[];
#endif
99 changes: 99 additions & 0 deletions ASM/c/blue_warp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#include <stdbool.h>

#include "blue_warp.h"
#include "save.h"
#include "z64.h"

#define TEXT_STATE_CLOSING 2

// Original function copied over
int32_t DoorWarp1_PlayerInRange(z64_actor_t* actor, z64_game_t* game) {
if (actor->xzdist_from_link < 60.0f) {
if ((z64_link.common.pos_world.y - 20.0f) < actor->pos_world.y) {
if (actor->pos_world.y < (z64_link.common.pos_world.y + 20.0f)) {
return true;
}
}
}
return false;
};

// Routine taken from Majora's Mask blue warps
int32_t DoorWarp1_PlayerInRange_Overwrite(z64_actor_t* actor, z64_game_t* game) {
// Check vanilla range
if (DoorWarp1_PlayerInRange(actor, game)) {

// Check if dungeon reward has already been collected
if (extended_savectx.collected_dungeon_rewards[game->scene_index - 0x0011]) {
return true;
}

// Null out blue warp parent if it is still the dungeon boss
if (z64_ActorHasParent(actor, game) && (actor->parent != &z64_link.common)) {
actor->parent = NULL;
}

// Link will attach as the parent actor once the GetItem is accepted. Until then, offer the dungeon reward for Link.
if (!z64_ActorHasParent(actor, game)) {
cjohnson57 marked this conversation as resolved.
Show resolved Hide resolved
// Put a dummy item value on the blue warp, which will be overwritten by the medallions
z64_ActorOfferGetItem(actor, game, 0x65, 60.0f, 20.0f);
return false;
}

// Wait until Link closes the textbox displaying the getItem reward
if (z64_MessageGetState(((uint8_t*)(&z64_game)) + 0x20D8) == TEXT_STATE_CLOSING) {
if ((game->scene_index != 0x17) && (game->scene_index != 0x18)) {
extended_savectx.collected_dungeon_rewards[game->scene_index - 0x0011] = true;
}
return true;
}
}


return false;
}

int32_t DoorWarp1_IsSpiritRewardObtained(void) {
return extended_savectx.collected_dungeon_rewards[6];
}

int32_t DoorWarp1_IsShadowRewardObtained(void) {
return extended_savectx.collected_dungeon_rewards[7];
}

void DoorWarp1_KokiriEmerald_Overwrite(void) {
z64_file.skybox_time = z64_file.day_time = 0x8000; // CLOCK_TIME(12, 00)
}

void DoorWarp1_GoronRuby_Overwrite(void) {
z64_file.skybox_time = z64_file.day_time = 0x8000; // CLOCK_TIME(12, 00)
}

void DoorWarp1_ZoraSapphire_Overwrite(void) {
z64_file.skybox_time = z64_file.day_time = 0x8000; // CLOCK_TIME(12, 00)
}

void DoorWarp1_ForestMedallion_Overwrite(void) {
z64_file.skybox_time = z64_file.day_time = 0x8000; // CLOCK_TIME(12, 00)
}

void DoorWarp1_FireMedallion_Overwrite(void) {
z64_file.skybox_time = z64_file.day_time = 0x8000; // CLOCK_TIME(12, 00)
z64_file.event_chk_inf[2] |= 1 << 15; // DMT cloud circle no longer fire
z64_file.timer_1_state = 0; // reset heat timer
}

void DoorWarp1_WaterMedallion_Overwrite(void) {
z64_file.skybox_time = z64_file.day_time = 0x4800; // CLOCK_TIME(6, 45)
z64_file.event_chk_inf[6] |= 1 << 9; // Lake Hylia water raised
}

void DoorWarp1_SpiritMedallion_Overwrite(void) {
extended_savectx.collected_dungeon_rewards[6] = true;
z64_file.skybox_time = z64_file.day_time = 0x8000; // CLOCK_TIME(12, 00)
}

void DoorWarp1_ShadowMedallion_Overwrite(void) {
extended_savectx.collected_dungeon_rewards[7] = true;
z64_file.skybox_time = z64_file.day_time = 0x8000; // CLOCK_TIME(12, 00)
}
Comment on lines +56 to +99
Copy link
Collaborator

Choose a reason for hiding this comment

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

These feel like they should all be a single function with a switch statement, but I'm not sure if that's easily doable within the context of the ASM functions that are being overwritten

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Just from looking at the asm, I don't think it's easily doable, since each of these functions are called from different locations. Maybe @engineer124 has an idea for how to do it?

20 changes: 20 additions & 0 deletions ASM/c/blue_warp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#ifndef DOOR_WARP1_H
#define DOOR_WARP1_H

#include "z64.h"

int32_t DoorWarp1_PlayerInRange_Overwrite(z64_actor_t* actor, z64_game_t* game);

int32_t DoorWarp1_IsSpiritRewardObtained(void);
int32_t DoorWarp1_IsShadowRewardObtained(void);

void DoorWarp1_KokiriEmerald_Overwrite(void);
void DoorWarp1_GoronRuby_Overwrite(void);
void DoorWarp1_ZoraSapphire_Overwrite(void);
void DoorWarp1_ForestMedallion_Overwrite(void);
void DoorWarp1_FireMedallion_Overwrite(void);
void DoorWarp1_WaterMedallion_Overwrite(void);
void DoorWarp1_SpiritMedallion_Overwrite(void);
void DoorWarp1_ShadowMedallion_Overwrite(void);

#endif
2 changes: 1 addition & 1 deletion ASM/c/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ void draw_debug_menu(z64_disp_buf_t *db) {
item_t *d = &(items_debug[current_menu_indexes.item_index]);
// Songs don't work somehow? So use the rando function instead.
if ((d->item_index >= ITEM_SONG_MINUET) && (d->item_index <= ITEM_SONG_STORMS)) {
give_song(&z64_file, d->item_index - 0x54, 0);
give_quest_item(&z64_file, d->item_index - 0x54, 0);
}
else {
if (d->item_index == Z64_ITEM_BIGGORON_SWORD) {
Expand Down
33 changes: 33 additions & 0 deletions ASM/c/demo_effect.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "z64.h"
#include "util.h"
#include "demo_effect.h"
#include "models.h"

extern void DemoEffect_DrawJewel(z64_actor_t* this, z64_game_t* globalCtx, void* func);
extern void* DemoEffect_DrawJewel_AfterHook;

extern override_key_t CFG_BIGOCTO_OVERRIDE_KEY;

// Overrides the item model for the dungeon reward shown before the Big Octo fight
void DemoEffect_DrawJewel_Hook(DemoEffect* this, z64_game_t* globalCtx) {
fenhl marked this conversation as resolved.
Show resolved Hide resolved
if (!this->override_initialized) {
if (globalCtx->scene_index == 0x02) {
if (CFG_BIGOCTO_OVERRIDE_KEY.all) {
this->override = lookup_override_by_key(CFG_BIGOCTO_OVERRIDE_KEY);
}
if (this->override.key.all) {
this->actor.rot_2.x = 0;
this->actor.scale = (z64_xyzf_t) { 0.02f, 0.02f, 0.02f };
}
}

this->override_initialized = true;
}
if (this->override.key.all) {
model_t model;
lookup_model_by_override(&model, this->override);
draw_model(model, &this->actor, globalCtx, 5.0);
} else {
DemoEffect_DrawJewel(this, globalCtx, resolve_overlay_addr(&DemoEffect_DrawJewel_AfterHook, 0x008B));
}
}
110 changes: 110 additions & 0 deletions ASM/c/demo_effect.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#ifndef _DEMO_EFFECT_H_
#define _DEMO_EFFECT_H_
#include "z64.h"
#include "get_items.h"

typedef struct {
/* 0x00 */ uint8_t timer;
} DemoEffectFireBall;

typedef struct {
/* 0x00 */ uint8_t alpha;
/* 0x01 */ uint8_t scale;
/* 0x02 */ uint8_t pad;
/* 0x04 */ int16_t rotation;
} DemoEffectBlueOrb;

typedef struct {
/* 0x00 */ uint8_t alpha;
/* 0x01 */ uint8_t scaleFlag;
/* 0x02 */ uint8_t flicker;
/* 0x04 */ int16_t rotation;
} DemoEffectLight;

typedef struct {
/* 0x00 */ uint8_t alpha;
} DemoEffectLgtShower;

typedef struct {
/* 0x00 */ uint8_t type;
/* 0x01 */ uint8_t lightRingSpawnDelay;
/* 0x02 */ uint8_t rotation;
/* 0x04 */ int16_t lightRingSpawnTimer;
} DemoEffectGodLgt;

typedef struct {
/* 0x00 */ uint8_t timerIncrement;
/* 0x01 */ uint8_t alpha;
/* 0x02 */ uint8_t pad;
/* 0x04 */ int16_t timer;
} DemoEffectLightRing;

typedef struct {
/* 0x00 */ uint8_t triforceSpotOpacity;
/* 0x01 */ uint8_t lightColumnOpacity;
/* 0x02 */ uint8_t crystalLightOpacity;
/* 0x04 */ int16_t rotation;
} DemoEffectTriforceSpot;

typedef struct {
/* 0x00 */ uint8_t isPositionInit;
/* 0x01 */ uint8_t isLoaded;
/* 0x02 */ uint8_t drawId;
/* 0x04 */ int16_t rotation;
} DemoEffectGetItem;

typedef struct {
/* 0x00 */ uint8_t pad;
/* 0x01 */ uint8_t pad2;
/* 0x02 */ uint8_t pad3;
/* 0x04 */ int16_t shrinkTimer;
} DemoEffectTimeWarp;

typedef struct {
/* 0x00 */ uint8_t type;
/* 0x01 */ uint8_t isPositionInit;
/* 0x02 */ uint8_t alpha;
/* 0x04 */ int16_t timer;
} DemoEffectJewel;

typedef struct {
/* 0x00 */ uint8_t timer;
} DemoEffectDust;

typedef void (*DemoEffectFunc)(struct DemoEffect*, z64_game_t*);

typedef struct DemoEffect {
/* 0x0000 */ z64_actor_t actor;
/* 0x013C */ uint8_t skelCurve[0x20]; // size = 0x20
/* 0x015C */ uint8_t requiredObjectSlot;
/* 0x0160 */ Gfx* jewelDisplayList;
/* 0x0164 */ Gfx* jewelHolderDisplayList;
/* 0x0168 */ uint8_t primXluColor[3];
/* 0x016B */ uint8_t envXluColor[3];
/* 0x016E */ uint8_t primOpaColor[3];
/* 0x0171 */ uint8_t envOpaColor[3];
/* 0x0174 */ union {
DemoEffectFireBall fireBall;
DemoEffectBlueOrb blueOrb;
DemoEffectLight light;
DemoEffectLgtShower lgtShower;
DemoEffectGodLgt godLgt;
DemoEffectLightRing lightRing;
DemoEffectTriforceSpot triforceSpot;
DemoEffectGetItem getItem;
DemoEffectTimeWarp timeWarp;
DemoEffectJewel jewel;
DemoEffectDust dust;
};
/* 0x017A */ int16_t effectFlags;
/* 0x017C */ int16_t cueChannel;
/* 0x017E */ z64_xyz_t jewelCsRotation;
/* 0x0184 */ DemoEffectFunc initUpdateFunc;
/* 0x0188 */ ActorFunc initDrawFunc;
/* 0x018C */ DemoEffectFunc updateFunc;
// original size = 0x0190
/* 0x0190 */ override_t override;
/* 0x0xxx*/ bool override_initialized;
} DemoEffect;

#endif
64 changes: 61 additions & 3 deletions ASM/c/dungeon_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,13 @@ extern uint32_t CFG_DUNGEON_INFO_REWARD_ENABLE;
extern uint32_t CFG_DUNGEON_INFO_REWARD_NEED_COMPASS;
extern uint32_t CFG_DUNGEON_INFO_REWARD_NEED_ALTAR;
extern uint32_t CFG_DUNGEON_INFO_REWARD_SUMMARY_ENABLE;
extern bool CFG_DUNGEON_INFO_REWARD_WORLDS_ENABLE;

extern uint8_t SHUFFLE_CHEST_GAME;

extern int8_t CFG_DUNGEON_REWARDS[14];
extern char CFG_DUNGEON_REWARD_AREAS[9][0x17];
extern uint8_t CFG_DUNGEON_REWARD_WORLDS[9];

extern uint8_t CFG_DUNGEON_INFO_SILVER_RUPEES;

Expand Down Expand Up @@ -320,7 +322,7 @@ void draw_dungeon_info(z64_disp_buf_t* db) {
if (total_keys < 0) total_keys = 0;
if (total_keys > 9) total_keys = 9;

char count[5] = "O(O)";
char count[5] = "O(O)"; // we use O instead of 0 because it's easier to distinguish from 8
if (current_keys > 0) count[0] = current_keys + '0';
if (total_keys > 0) count[2] = total_keys + '0';
int top = start_top + ((icon_size + padding) * i) + 1;
Expand Down Expand Up @@ -516,6 +518,9 @@ void draw_dungeon_info(z64_disp_buf_t* db) {
(1 * icon_size) +
(0x16 * font_sprite.tile_w) +
(3 * padding);
if (CFG_DUNGEON_INFO_REWARD_WORLDS_ENABLE) {
bg_width += 5 * font_sprite.tile_w;
}
int bg_height = (rows * icon_size) + ((rows + 1) * padding);
int bg_left = (Z64_SCREEN_WIDTH - bg_width) / 2;
int bg_top = (Z64_SCREEN_HEIGHT - bg_height) / 2;
Expand Down Expand Up @@ -552,7 +557,60 @@ void draw_dungeon_info(z64_disp_buf_t* db) {

left += icon_size + padding;

// Draw dungeon names
// Draw reward world numbers

if (CFG_DUNGEON_INFO_REWARD_WORLDS_ENABLE) {
for (int i = 0; i < 9; i++) {
uint8_t reward = reward_rows[i];
bool display_area = true;
switch (CFG_DUNGEON_INFO_REWARD_NEED_COMPASS) {
case 1:
for (int j = 0; j < 8; j++) {
uint8_t dungeon_idx = dungeons[j].index;
if (CFG_DUNGEON_REWARDS[dungeon_idx] == reward) {
if (!z64_file.dungeon_items[dungeon_idx].compass) {
display_area = false;
}
break;
}
}
break;
case 2:
if (i != 3) { // always display Light Medallion
dungeon_entry_t* d = &(dungeons[i - (i < 3 ? 0 : 1)]); // vanilla location of the reward
display_area = z64_file.dungeon_items[d->index].compass;
}
break;
}
if (!display_area) {
continue;
}
uint8_t world = CFG_DUNGEON_REWARD_WORLDS[i];
char world_text[5] = "WOOO"; // we use O instead of 0 because it's easier to distinguish from 8
fenhl marked this conversation as resolved.
Show resolved Hide resolved
if (world < 100) {
world_text[0] = ' ';
world_text[1] = 'W';
}
if (world < 10) {
world_text[1] = ' ';
world_text[2] = 'W';
}
if (world / 100) {
world_text[1] = world / 100 + '0';
}
if ((world % 100) / 10) {
world_text[2] = (world % 100) / 10 + '0';
}
if (world % 10) {
world_text[3] = world % 10 + '0';
}
int top = start_top + ((icon_size + padding) * i) + 1;
text_print(world_text, left, top);
}
left += 5 * font_sprite.tile_w;
}

// Draw reward locations

for (int i = 0; i < 9; i++) {
if (i < 3 ? show_stones : show_medals) {
Expand Down Expand Up @@ -640,7 +698,7 @@ void draw_dungeon_info(z64_disp_buf_t* db) {
if (total_keys < 0) total_keys = 0;
if (total_keys > 9) total_keys = 9;

char count[5] = "O(O)";
char count[5] = "O(O)"; // we use O instead of 0 because it's easier to distinguish from 8
if (current_keys > 0) count[0] = current_keys + '0';
if (total_keys > 0) count[2] = total_keys + '0';
int top = start_top + ((icon_size + padding) * i) + 1;
Expand Down
6 changes: 0 additions & 6 deletions ASM/c/ganon_boss_key.h

This file was deleted.

Loading
Loading