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

Document Magic #1199

Merged
merged 39 commits into from
May 23, 2022
Merged

Document Magic #1199

merged 39 commits into from
May 23, 2022

Conversation

engineer124
Copy link
Contributor

This documents the different magic variables and functions in the game, primarily from z_parameter.

A few notes:

  • There are two variables to store the magicCapacity. One of them is always the true capacity, either 0, 0x30, or 0x60. The second one is the magicCapacity that's "drawn", which exists as a separate variable specifically for when you enter the first scene from a new load, and the magic bar grows from 0 width to the width of the current bar. I went with magicCapacity for the fixed value and magicCapacityDrawn as the drawn value. Other than that first scene load, they're always the same and are used interchangeably throughout the repo in terms of checking for magic capacity. Maybe another name could be magicCapacityTarget for the fixed values and magicCapacity for the drawn values
  • I'm not sure if the different types of border changes should be encapsulated in the enums or comments, since the enum names are getting long as is
  • I think the enum names for MagicBarChange could be improved, but I went with a more verbose name to start just to help reviewers understand how magic is working
  • Some of the comments for the magic bar enums are repeated both where the enum is defined and where the switch is, I wasn't sure which of the two the comments should be. So I put them in both for now

Copy link
Collaborator

@Dragorn421 Dragorn421 left a comment

Choose a reason for hiding this comment

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

Great job! 🪄 🎩 🐰

include/z64.h Outdated Show resolved Hide resolved
include/z64save.h Outdated Show resolved Hide resolved
src/code/z_parameter.c Outdated Show resolved Hide resolved
include/z64save.h Outdated Show resolved Hide resolved
include/z64save.h Outdated Show resolved Hide resolved
Comment on lines 24 to 28
/* 02 */ MAGIC_BAR_CONSUME_NOW_ALT, // Identical behaviour to MAGIC_BAR_CONSUME_NOW. Unused
/* 03 */ MAGIC_BAR_CONSUME_LENS, // Lens consumption
/* 04 */ MAGIC_BAR_CONSUME_WAIT_PREVIEW, // Sets consume target but waits to consume. Draws yellow magic to target consumption
/* 05 */ MAGIC_BAR_ADD // Sets a target to add magic
} MagicBarChange;
Copy link
Collaborator

Choose a reason for hiding this comment

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

would call the enum ChangeType instead of just "Change". may need to update variables to reflect that.
also normally we would have a common prefix for these values that all fit under the same umbrella, but its a bit weird with add being different from all the other consume types i guess

in general I think we can probably afford to make all the magic related enums just start with MAGIC_ and omit the bar? that goes for the enum above too.
Then we can do MAGIC_CHANGE_CONSUME_NOW and MAGIC_CHANGE_ADD etc, with MAGIC telling you its for the magic system, and CHANGE telling you its for the change type, followed by the actual type name

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For your first point:
I also had CHANGE_ in the enum earlier, but then decided to take it out because the names were getting quite long and it seems like some of the names had reduncency in them i.e.

typedef enum MagicBarChange {
    /* 00 */ MAGIC_BAR_CHANGE_CONSUME_NOW,
    /* 01 */ MAGIC_BAR_CHANGE_CONSUME_WAIT_NO_PREVIEW,
    /* 02 */ MAGIC_BAR_CHANGE_CONSUME_NOW_ALT,
    /* 03 */ MAGIC_BAR_CHANGE_CONSUME_LENS,
    /* 04 */ MAGIC_BAR_CHANGE_CONSUME_WAIT_PREVIEW,
    /* 05 */ MAGIC_BAR_CHANGE_ADD
} MagicBarChange;

The terms CHANGE_CONSUME and CHANGE_ADD feel redundant, and there's only one that's different than the others ADD (I'm fine with MagicBarChangeType though)

For your second point, I messed around a bit with magic vs. magicBar for many of these names and enums. The reason I leaned more towards MagicBar when I could is because magic felt a bit too general, like magic spell or magic amount, it's hard to articulate. I felt MagicBar was really clear in what it was referring to, does that make sense?

include/z64save.h Outdated Show resolved Hide resolved
@engineer124
Copy link
Contributor Author

Thoughts on consistently using the Magic_ prefix?
Interface_UpdateMagicBar -> Magic_UpdateBar
Interface_DrawMagicBar -> Magic_DrawBar
I know the magic bar itself is part of the interface system, but it's also part of the magic system.

Also, maybe Magic_ResetMagicBarAction could be simplified to Magic_ResetBar to keep it simple?

@engineer124
Copy link
Contributor Author

I've made the suggestions from the discord discussion, using the Magic_ prefix and dropping the bar everywhere. I've also changed ACTION -> STATE, and renamed lensMagicDepletionTimer to just magicConsuptionTimer. Other discussions are still open though

include/z64.h Outdated Show resolved Hide resolved
src/code/z_parameter.c Outdated Show resolved Hide resolved
src/code/z_parameter.c Outdated Show resolved Hide resolved
include/z64save.h Outdated Show resolved Hide resolved
include/z64save.h Outdated Show resolved Hide resolved
src/code/z_parameter.c Outdated Show resolved Hide resolved
src/code/z_parameter.c Outdated Show resolved Hide resolved
Copy link
Collaborator

@Dragorn421 Dragorn421 left a comment

Choose a reason for hiding this comment

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

minor things besides Magic_Reset

include/z64save.h Outdated Show resolved Hide resolved
include/z64save.h Outdated Show resolved Hide resolved
src/code/z_parameter.c Outdated Show resolved Hide resolved
src/code/z_parameter.c Outdated Show resolved Hide resolved
src/code/z_parameter.c Outdated Show resolved Hide resolved
src/code/z_parameter.c Outdated Show resolved Hide resolved
src/code/z_parameter.c Outdated Show resolved Hide resolved
Copy link
Collaborator

@Dragorn421 Dragorn421 left a comment

Choose a reason for hiding this comment

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

Great job on this! 🧙 🎈

I'm still not convinced by Magic_Reset but I don't have a strong suggestion

include/functions.h Outdated Show resolved Hide resolved
Copy link
Contributor

@EllipticEllipsis EllipticEllipsis left a comment

Choose a reason for hiding this comment

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

Nice job, this is actually comprehensible now. Couple of things.

Comment on lines +108 to +110
/* 0x003A */ u8 isMagicAcquired;
/* 0x003B */ char unk_3B[0x01];
/* 0x003C */ u8 doubleMagic;
/* 0x003C */ u8 isDoubleMagicAcquired;
Copy link
Contributor

Choose a reason for hiding this comment

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

I didn't realise this was used extensively in the repo, but now I'm wondering if we want to name variables like this interrogatively... does the is actually do anything here, that the plain past participle doesn't?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think in this specific instance, doubleMagicAcquired alone can be inferred to be a boolean-like value (it still uses the 0/1 in calculating magicCapacity so it's not a true bool), but as you mentioned, is is just a common and fast way to identify that something is boolean without thinking about it, at least that was my understanding of the convention

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also as a side note, not related to this comment but something I wanted to note:
doubleDefense -> isDoubleDefenseAcquired (or without the is) would be consistent with isDoubleMagicAcquired but I refrained from changing it for now

Copy link
Contributor

@EllipticEllipsis EllipticEllipsis May 14, 2022

Choose a reason for hiding this comment

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

If we were going by the game it should be "half damage" (or possibly "enhanced defence") anyway:

"I'm going to enhance your \n"
COLOR(LIGHTBLUE) "defensive power" COLOR(DEFAULT) "."
[...]
"Your " COLOR(LIGHTBLUE) "defensive power" COLOR(DEFAULT) " is enhanced!"
[...]
"Your defensive power has been \n"
"enhanced! Damage inflicted by \n"
"enemies will be " COLOR(RED) "reduced by half" COLOR(DEFAULT) "."

(I suppose we could say the same thing for magic, actually, it never explicitly says it doubles, although that's obvious from the bar size)

Copy link
Collaborator

Choose a reason for hiding this comment

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

imo this is a case where the common colloquial name makes more sense. no one says half damage or enhanced defense

Copy link
Contributor

@EllipticEllipsis EllipticEllipsis May 15, 2022

Choose a reason for hiding this comment

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

I had a look into this, since I was curious. I looked at 4 guidebooks (3 English, 1 the official one, 1 Japanese) and the first page of Google results for walkthroughs, including 4 GameFAQs guides. A large majority say one or more of

  • half damage
  • enhanced defense
  • doubled health

and only 2 (of about 20) say double/doubled defense. I was pretty surprised by this myself, since the tiny speedrunning corner of the world does seem to call always call it "double defense", probably because of the alliteration.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just to add a different perspective, I come from the randomizer community and never heard of any of those terms, it's only ever been "double defense" for me

Copy link
Collaborator

@Dragorn421 Dragorn421 May 16, 2022

Choose a reason for hiding this comment

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

Other related names in decomp: FAIRY_UPGRADE_HALF_DAMAGE (hi elliptic), gGreatFairyDoubleDefenceCs (hi louis)

I would be okay with normalizing all of that to "half damage", with a comment on the save context struct member like // double defense

"double defense" probably is so popular because it rolls so well off the tongue

src/code/z_parameter.c Outdated Show resolved Hide resolved
src/code/z_parameter.c Outdated Show resolved Hide resolved
src/code/z_parameter.c Outdated Show resolved Hide resolved
include/z64save.h Outdated Show resolved Hide resolved

switch (gSaveContext.magicState) {
case MAGIC_STATE_GROW_METER:
// Step magicCapacityDrawn to what is magicCapacity
Copy link
Contributor

Choose a reason for hiding this comment

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

As here: it's basically the same as MAGIC_STATE_FILL, but for the bar itself, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In a sense. The way this block is designed is that it just moves the bar drawn to where the true capacity is. In theory, it could be moved wider or smaller (i.e. it doesn't specifically have to grow), it's just that in practice it only grows based on how this case is used

Copy link
Contributor

Choose a reason for hiding this comment

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

So it could be UPDATE_WIDTH, even.

Copy link
Contributor Author

@engineer124 engineer124 May 16, 2022

Choose a reason for hiding this comment

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

WIDTH could apply to a lot of things so I think it'd be important to specify meter in there, but yeah I'd be fine with that. Could maybe even be SYNC_METER_WIDTH in the sense that it "sync"s the magicCapacityDrawn to the true magicCapacity just as an idea

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, something along those lines makes sense to me.

src/code/z_parameter.c Outdated Show resolved Hide resolved
@@ -1191,7 +1191,7 @@ void BossGanon_SetupTowerCutscene(BossGanon* this, GlobalContext* globalCtx) {
this->csTimer = 0;
this->csState = 100;
this->unk_198 = 1;
gSaveContext.magic = gSaveContext.unk_13F4;
gSaveContext.magic = gSaveContext.magicCapacityDrawn;
Copy link
Collaborator

Choose a reason for hiding this comment

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

magicCapacityDrawn seems misleading since it's used for things other than drawing (like here and in a few other places), and it seems to be closer to the "effective" capacity at a specific point in time (eg. in Magic_RequestChange).
So as you mentioned originally I think it would be better to name this one magicCapacity and the other one something like magicCapacityTarget or magicCapacityMax

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd be okay with either, but I have a slight preference to the way I have it now but it’s hard to articulate why.

But I interpret it as the point of magicCapacity being to store the “true” value in a sense while magicCapacityDrawn gives flexibility on how the capacity is drawn from 0 -> magicCapacity or the previous magicCapacity -> new magicCapacity. Most checks when comparing against magic capacity seems to be against magicCapacity instead of magicCapacityDrawn, but either work due to them being mostly the same. But I still has a sense that magicCapacity is the true value and calling that magicCapacityTarget or magicCapacityMax seems a bit funny to me.

Sure magicCapacityDrawn is used more to draw, but it also contains info on the magicCapacity which is what it’s used for, and is still in the name, so I don't find it misleading imo.

With the current names, you also get a meaningful distinction between the two variables instead of something like magicCapacityMax and magicCapacity which seems too similar.

There also doesn’t seemed to be a logic as to whether devs used magicCapacity vs magicCapacityDrawn (outside z_parameter) since they basically contain the same info 99.5% of the time and the devs names were awful so I’d understand if they mixed them up a little.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To note, I followed through on my suggestion of changing MAGIC_STATE_GROW_METER to MAGIC_STATE_SYNC_METER_WIDTH, but if these variables were to change, maybe it's be worth changing it to something like MAGIC_STATE_SYNC_CAPACITIES or something

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree they are both used as the capacity in different instances, but to me it's misleading to have magicCapacityDrawn if it gets used in actual game logic. Personally I would interpret that name as something that is used for drawing on the hud, which means I could change its value without affecting the rest of the game, but that would be a big mistake in this case.

Regarding the names I suggested, it's true that magicCapacity and magicCapacityMax/magicCapacityTarget are pretty similar, but I would argue there is no real way around that since they are used for similar purposes like you mentioned, and we can't fix that on our end unfortunately.

Also, looking at the code again, magicCapacityDrawn is actually used more than magicCapacity, even when only accounting for game logic purposes. Besides debug prints, magicCapacity is only read in one place for case MAGIC_STATE_FILL in Magic_Update, while magicCapacityDrawn is used everywhere else, including when adding magic through Magic_RequestChange. So imo it makes more sense to treat it as the "true" capacity in almost all cases (hence magicCapacity). And maybe we could have the other one as magicFillCapacity since that's only thing it's really used for?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, I see what you mean.

There's also the process of obtaining magic and double magic:
For obtaining normal magic,
gSaveContext.magicCapacity = MAGIC_NORMAL_METER;
Then in Interface_Update:

if (gSaveContext.isMagicAcquired && (gSaveContext.magicLevel == 0)) {
    gSaveContext.magicLevel = gSaveContext.isDoubleMagicAcquired + 1;
    gSaveContext.magicState = MAGIC_STATE_SYNC_METER_WIDTH;

Which is true because the magicLevel was 0 before, and this magicState is the one that steps magicCapacityDrawn -> magicCapacity (it happens when the hud is hidden so you don't actually visually see the magic bar grown).

And when obtaining double magic:

gSaveContext.magicCapacity = MAGIC_DOUBLE_METER;
gSaveContext.magicLevel = 0;

They explicitly set magicLevel to 0 so that the same code in Interface_Update runs i.e. (gSaveContext.magicLevel == 0) passes, and the state becomes MAGIC_STATE_SYNC_METER_WIDTH. to step magicCapacityDrawn -> magicCapacity

In both cases, magicCapacity is acting like a target, and magicCapacityDrawn does feel like the true magic capacity.

So I kinda like:
magicCapacity -> magicCapacityTarget
magicCapacityDrawn -> magicCapacity
as originally had. Then maybe:
MAGIC_STATE_SYNC_METER_WIDTH -> MAGIC_STATE_SYNC_CAPACITY

Thoughts?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Or maybe something like:
MAGIC_STATE_SYNC_METER_WIDTH ->
MAGIC_STATE_STEP_CAPACITY
OR
MAGIC_STATE_UPDATE_CAPACITY

src/code/z_parameter.c Outdated Show resolved Hide resolved
Copy link
Collaborator

@Dragorn421 Dragorn421 left a comment

Choose a reason for hiding this comment

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

yay figured it out for real this time
comments, mostly on comments

include/z64save.h Outdated Show resolved Hide resolved
include/z64save.h Outdated Show resolved Hide resolved
src/code/z_parameter.c Outdated Show resolved Hide resolved
src/code/z_parameter.c Outdated Show resolved Hide resolved
src/code/z_parameter.c Outdated Show resolved Hide resolved
src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.c Outdated Show resolved Hide resolved
src/overlays/gamestates/ovl_file_choose/z_file_choose.c Outdated Show resolved Hide resolved
src/overlays/gamestates/ovl_file_choose/z_file_choose.c Outdated Show resolved Hide resolved
src/overlays/gamestates/ovl_select/z_select.c Outdated Show resolved Hide resolved
@Roman971 Roman971 merged commit e68f321 into zeldaret:master May 23, 2022
@engineer124 engineer124 deleted the magic branch May 23, 2022 16:54
louist103 pushed a commit to louist103/oot that referenced this pull request Jan 3, 2023
* Magic docs WIP

* More docs, first round finished

* Better docs

* More renaming

* Simpler name

* Another small adjustment

* rm if(1)

* Better names again after in-game testing

* Change comments

* change comment

* Big rename based on all the suggestions

* Small touch-up

* More PR Suggestions

* RESTORE_IDLE -> RESET

* More docs

* Capitalization

* PR suggestions

* Make declaration consistent

* Health_ChangeBy (amount)

* PR Suggestions

* Missed one

* More PR Suggestions

* Change comment

* Add another clarity comment

* Discord discussions on `magicFillTarget`

* Comments

* grammar

* More comment clarity

* Another bad comment

* PR suggestions, improved comments

* One more comment

* one more thing

* bar -> meter
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants