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 Save.cutsceneIndex and adjacent data / code #2286

Open
wants to merge 29 commits into
base: main
Choose a base branch
from

Conversation

Feacur
Copy link
Contributor

@Feacur Feacur commented Nov 5, 2024

while studying the game logic flow, i saw there's a pattern between

  • Save.entranceIndex
  • Save.cutsceneIndex
  • SaveContext.sceneLayer

but values weren't yet described. so, it's time to cleanup my notes and shape them in a proper PR.
(UPD: not anymore) it's a WIP, but i'll start with a draft for visibility

P.S.:
the closest thing i see here is #1300, but

  • documented SaveContext.sceneLayer
  • it's merged already

so that it doesn't clutter previous commit. still, allowing `clangd LSP` to run format-on-save yields inconsistent results for me with the project's tooling, especially for header files
Comment on lines 377 to 379
CS_INDEX_SCRIPTED_D = 0xFFFD,
CS_INDEX_SCRIPTED_E = 0xFFFE,
CS_INDEX_SCRIPTED_F = 0xFFFF,
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
CS_INDEX_SCRIPTED_D = 0xFFFD,
CS_INDEX_SCRIPTED_E = 0xFFFE,
CS_INDEX_SCRIPTED_F = 0xFFFF,
CS_INDEX_SCRIPTED_D = 0xFFFD,

Values 0xFFF0-0xFFFC are directly tied to the scene layer system. These values are used to fetch scene layers 4-16, which are intended to contain scene command referencing a cutscene that will play immediately on scene load.

0xFFFD does not have the same behavior and thus should have a different name from the rest. It is intended to be used to trigger a scripted cutscene "manually" after scene load, and has no effect on the scene layer system. You can see this at Play_Init in z_play.c, line 332 or so, where the cutsceneIndex resets to 0 if it's 0xFFFD, before the sceneLayer is computed.

No scene has a layer count greater than 17, so values 0xFFFE/0xFFFF are never used and thus should not be enumerated.

Copy link
Contributor Author

@Feacur Feacur Nov 5, 2024

Choose a reason for hiding this comment

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

hmm, i do see this lines

if (gSaveContext.save.cutsceneIndex == CS_INDEX_SCRIPTED_D) {
    gSaveContext.save.cutsceneIndex = CS_INDEX_NONE;
}

and they look to me as

if (gSaveContext.save.cutsceneIndex == CS_INDEX_RESET) {
    gSaveContext.save.cutsceneIndex = CS_INDEX_NONE;
}

UPD 8cbdf80: preparing a commit, but did not apply the suggestion

Copy link
Contributor

Choose a reason for hiding this comment

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

The name needs to make sense in all parts of code, not just in the one code block. As I stated before, 0xFFFD triggers cutscenes after the scene has been loaded.

For example, z_bg_toki_sword is the Master Sword, and when you pull or drop the sword it will initiate a scripted cutscene by setting the cutscene script pointer and assigning gSaveContext.cutsceneTrigger to 1. This causes Cutscene_UpdateScripted to set the cutsceneIndex to 0xFFFD, which in turn starts the processing of the script.

The purpose of the block in Play_Init is to flush the cutsceneIndex state in the event that the PlayState is destroyed before the cutscene can complete normally. This can happen if e.g. the player falls out of bounds or dies mid-cutscene.

Copy link
Contributor Author

@Feacur Feacur Nov 5, 2024

Choose a reason for hiding this comment

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

ah, so CS_INDEX_TRIGGERED might do

// z_demo.c:2292
void Cutscene_SetupScripted(...)
    // if trigger flag set, isn't idling, and not in a cutscene
    if ((gSaveContext.cutsceneTrigger != 0) && (csCtx->state == CS_STATE_IDLE) && !Player_InCsMode(play))
        // then trigger
        gSaveContext.save.cutsceneIndex = CS_INDEX_TRIGGERED;

because it's a "state" not a "request"

UPD 32a2dd0

Copy link
Contributor

@cadmic cadmic Nov 27, 2024

Choose a reason for hiding this comment

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

Not sure I like "triggered". Don't values like 0xFFF0 also "trigger" a cutscene?

FWIW I'd prefer calling this CS_INDEX_D, and commenting that values above A do not correspond to any scene layer in the base game (i.e. only used for special cases) instead of trying to encode that in the name. I disagree that values above 0xFFFC are not "directly tied to the scene layer system", there's no check for this in the code, so if some scene did have a layer 19 for example everything would work fine.

This would also reduce the awkwardness with what is currently CS_INDEX_BARRIER if we call it CS_INDEX_F instead. Basically, I think all of the scripted cutscenes could be treated uniformly, and we should treat the uses of cutscene D for debug features and the Master Sword as hacks that use the magic value D. This does not seem so different than the fact that z_demo magically knows to use cutscene 1 for CS_DEST_GERUDO_VALLEY_DIN_PART_1, for example.

Copy link
Contributor Author

@Feacur Feacur Nov 29, 2024

Choose a reason for hiding this comment

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

i won't however add 0xFFFB, 0xFFFC, 0xFFFE, because no code even mentions them. additionally, i don't want to contradict #2286 (comment)

Copy link
Contributor Author

@Feacur Feacur Nov 30, 2024

Choose a reason for hiding this comment

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

ok, done: e9adab6, 67f0eef

oot/include/z64cutscene.h

Lines 347 to 381 in 67f0eef

// values `< 0xFFF0` indicate a "manual" cutscene; can be assigned to
// - `gSaveContext.save.cutsceneIndex`
// - `gSaveContext.nextCutsceneIndex`
// using them implies an intention to have `z_play.c` set `gSaveContext.sceneLayer` based on age and day time
// see enum values [`SCENE_LAYER_CHILD_DAY` .. `SCENE_LAYER_ADULT_NIGHT`]
#define CS_INDEX_DEFAULT 0x0000
#define CS_INDEX_UNK_8000 0x8000
// values `>= 0xFFF0` indicate a "scripted" cutscene; can be assigned to
// - `gSaveContext.save.cutsceneIndex`
// - `gSaveContext.nextCutsceneIndex`
// using them implies an intention to have `z_play.c` set `gSaveContext.sceneLayer` directly by index
// see `GET_CUTSCENE_LAYER(index)`
#define CS_INDEX_0 0xFFF0
#define CS_INDEX_1 0xFFF1
#define CS_INDEX_2 0xFFF2
#define CS_INDEX_3 0xFFF3
#define CS_INDEX_4 0xFFF4
#define CS_INDEX_5 0xFFF5
#define CS_INDEX_6 0xFFF6
#define CS_INDEX_7 0xFFF7
#define CS_INDEX_8 0xFFF8
#define CS_INDEX_9 0xFFF9
#define CS_INDEX_A 0xFFFA
// it's "out of range" even for the largest set of `entrance_table.h`
// but `z_demo.c` immediately sets `CS_STATE_STOP` state
#define CS_INDEX_UNK_FFFF 0xFFFF
// sentinel value used for `cutsceneIndex` to indicate that it should be reset to default
#define CS_INDEX_EMPTY 0xFFFD
// sentinel value used for `nextCutsceneIndex` to indicate that it is empty
// otherwise its value will be copied to `cutsceneIndex`
#define CS_INDEX_NEXT_EMPTY 0xFFEF

Copy link
Contributor

@cadmic cadmic Nov 30, 2024

Choose a reason for hiding this comment

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

Thanks, that is a bit better IMO. I still think that 0xFFFD and 0xFFFF should be named CS_INDEX_D and CS_INDEX_F like the other scripted cutscene indices though, sorry for disagreeing with mzxrules here. Commenting that 0xFFFC and above don't have any corresponding scene layers in the base game is good, but the scene layer bit is only one component of the "cutscene index" system here.

@mzxrules, any thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

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

To me, z_select uses the cutsceneIndex variable differently from the rest of the game, and thus should have separate definitions for values 0x0000 (Night) and 0x8000 (Day) that aren't defined as CS_INDEX values. Otherwise, you will never be able to provide useful names for their values.

0xFFFD is used when executing dozens of cutscenes, the Master Sword is only just one example. Pretty much every time cutsceneTrigger is set to 1 or 2 it starts such a scripted cutscene. I don't think it makes sense to name this CS_INDEX_EMPTY

0xFFFF seems like an anomaly to me. Idk if it actually represents anything meaningful since in the two instances it appears, the first case should override it with 0xFFFD if I understand the code correctly, and the second should terminate the cutscene.

I think it makes sense for values 0xFFF0-0xFFFA to have a distinction over 0xFFFD and 0xFFFF; values 0xFFF0-0xFFFA actually serve as index offsets for the sceneLayer system in all instances where they appear. 0xFFFD is not and cannot be used for such purposes. 0xFFFF could be, but is not actually being used for such (i.e. you could replace 0xFFFF with any value >= 0xFFF0 that isn't 0xFFFD and achieve the same effect).

Copy link
Contributor Author

@Feacur Feacur Dec 1, 2024

Choose a reason for hiding this comment

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

z_select

yeah, it's a special case as by me

I don't think it makes sense to name this CS_INDEX_EMPTY

what does? just CS_INDEX_D as suggested? looks too "magical", no much better than 0xFFFD; still, all right, let's

0xFFFF

it does. besides, z_demo.c sets CS_STATE_STOP for them right away (Ganon's tower barrier check after each of the beam cutscenes)

include/z64cutscene.h Outdated Show resolved Hide resolved
include/z64cutscene.h Outdated Show resolved Hide resolved
include/z64cutscene.h Outdated Show resolved Hide resolved
include/z64cutscene.h Outdated Show resolved Hide resolved
Feacur and others added 10 commits November 5, 2024 11:26
and some additional observations
reverified with
> `check_format.py ...`
> `make ...`

additionally:
- current clang-format lacks a rule for trailing commas
- compiler says about them `cfe: Warning 624`
zeldaret#2286 (comment)

reverified with
> `check_format.py ...`
> `make ...`
it gets assigned to the `nextCutsceneIndex`,
so `CS_INDEX_NONE` name was misleading
the purpose of `CS_INDEX_BARRIER` is not quite clear still
Copy link
Contributor

@cadmic cadmic left a comment

Choose a reason for hiding this comment

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

I made a few comments in the resolved threads, could you un-mark them as resolved? I don't have permission to unresolve them myself

include/z64cutscene.h Outdated Show resolved Hide resolved
include/z64cutscene.h Outdated Show resolved Hide resolved
src/overlays/gamestates/ovl_opening/z_opening.c Outdated Show resolved Hide resolved
src/code/z_scene.c Outdated Show resolved Hide resolved
src/code/z_horse.c Show resolved Hide resolved
include/z64cutscene.h Outdated Show resolved Hide resolved
include/z64cutscene.h Outdated Show resolved Hide resolved
Comment on lines 377 to 379
CS_INDEX_SCRIPTED_D = 0xFFFD,
CS_INDEX_SCRIPTED_E = 0xFFFE,
CS_INDEX_SCRIPTED_F = 0xFFFF,
Copy link
Contributor

@cadmic cadmic Nov 27, 2024

Choose a reason for hiding this comment

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

Not sure I like "triggered". Don't values like 0xFFF0 also "trigger" a cutscene?

FWIW I'd prefer calling this CS_INDEX_D, and commenting that values above A do not correspond to any scene layer in the base game (i.e. only used for special cases) instead of trying to encode that in the name. I disagree that values above 0xFFFC are not "directly tied to the scene layer system", there's no check for this in the code, so if some scene did have a layer 19 for example everything would work fine.

This would also reduce the awkwardness with what is currently CS_INDEX_BARRIER if we call it CS_INDEX_F instead. Basically, I think all of the scripted cutscenes could be treated uniformly, and we should treat the uses of cutscene D for debug features and the Master Sword as hacks that use the magic value D. This does not seem so different than the fact that z_demo magically knows to use cutscene 1 for CS_DEST_GERUDO_VALLEY_DIN_PART_1, for example.

@fig02
Copy link
Collaborator

fig02 commented Nov 27, 2024

(unresolved as needed)

@@ -350,7 +350,7 @@ void Scene_DrawConfigTempleOfTime(PlayState* play) {

CLOSE_DISPS(play->state.gfxCtx, "../z_scene_table.c", 5145);

if (gSaveContext.sceneLayer == 5) {
if (gSaveContext.sceneLayer == GET_CUTSCENE_LAYER(CS_INDEX_1)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if (gSaveContext.sceneLayer == GET_CUTSCENE_LAYER(CS_INDEX_1)) {
if (gSaveContext.sceneLayer == 5) {

I'd rather just have layers be defined on a per-scene basis than be a function of CS_INDEX

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oh, okay, so it was unnecessary for me to do? yeah, probably easier to read and compare with entrance_table.h when it's indexed the same way, from 0

i was thinking "hey, there's only two instances of gSaveContext.sceneLayer compared with values [0 .. 3]"

well, if it makes it more difficult, let's revert these line to the original state

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants