Skip to content

Conversation

@mckinlee
Copy link
Contributor

@mckinlee mckinlee commented Sep 20, 2025

Turns the 3-day cycle into collectible items that you need to find before accessing different time periods.

How it works:

  • Each half-day (Day 1, Night 1, Day 2, Night 2, Day 3, Night 3) becomes a randomized item
  • You can only visit time periods you've collected
  • If you try to access a locked time period, you'll be redirected to the earliest one you own
  • If you don't own any half-days, you'll be sent to the start of the final hours

Settings:

  • Random: Half-days are shuffled randomly
  • Ascending: Unlock in order (Day 1 → Night 1 → Day 2, etc.)
  • Descending: Unlock in reverse order (Night 3 → Day 3 → Night 2, etc.)

Must Have

  • Logic, I think is fully implemented, but could use a few passes
  • Logic needed for pots, crates, snowballs, you name it.
  • Needs a thorough review and testing

Nice to Have

  • Animated clock item (Cal will work on this, thank you!)
  • Make all "remaining hours" calculation based on obtained clock items
  • Add daytelops (This is complete on my local machine, gonna test more before pushing)
  • Configurable final hours length (Default is 6 hours before moon crash)
  • SoDT textbox to state the correct half-day
  • BetterSoDT feedback

Needs Fixing

  • SkipSoTCutscenes conflicts causing wierd cascading miscalculated overcorrection
  • "Queue Randomizer Item Gives" section of save editor should not be conditional on RO_CLOCK_SHUFFLE
  • On file load, should not correct for owl saves
  • Deku hopping during a correction causes infinite loop of sinking
  • seed generation issues for french vanilla and glitchless when clock shuffle is disabled
  • SkipSoTCutscene still conflicts on N3 and reverts back to start of N3

Build Artifacts

@balloondude2 balloondude2 added the help wanted Extra attention is needed label Sep 20, 2025
Copy link
Contributor

@Eblo Eblo left a comment

Choose a reason for hiding this comment

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

First wave of feedback with plenty of questions. I think you know this already, but it looks like there is strangely a crash in CollisionCheck_SetAC for the clocks. This only seems to happen for the Zora-rangable ones, which call that function. I'm not sure what that's about. Maybe the weirdness with how the animated drawfunc is handled causes it to mess with its collider?

BetterSoDT feedback.. might leave this for a potential v2.. can't come up with a good solution atm

Current behavior is to load the time you selected, then abort and load the next available time if that isn't one. Not great. I think the most painless route is to just check if the selected time is actually available, and if not, tell the player as much instead of charging ahead.

All that aside, while I didn't do a full run, the bits I did were a fairly interesting way of challenging my understanding of this schedule-driven game. I think this will be a fun shuffle for sure.

@Eblo Eblo mentioned this pull request Nov 11, 2025
31 tasks
Copy link
Contributor

@Eblo Eblo left a comment

Choose a reason for hiding this comment

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

With enemy drops now being merged, this will now need to account for enemies that are exclusive to certain times. My review on that PR should have you covered for a primer: https://github.com/HarbourMasters/2ship2harkinian/pull/1282/files#diff-69c6aa4d2342ae40aead6a9a0efd7dee2c7ed6788bf2f998c60e36fb769f1e7f

This will also need rebased on the latest develop.

@Eblo
Copy link
Contributor

Eblo commented Nov 21, 2025

Quick thought that just occurred to me is that the scarecrow is another way in the game to advance time. I just tried it in a seed where I had Night 2 and Night 3. Tried it on Night 2, which advanced to Day 3, which then panicked and moon crashed. I left the clock tower to see Dawn of the First Day, which then loaded Night 2.

I wouldn't want to lose the scarecrow behavior, so maybe this can be patched to just advance to the next chunk, or imitate vanilla Night 3 behavior if you're already on your latest chunk.

And now that I think about it, granny's stories are another thing to test.

Edit: Upon testing, granny seems fine at least.

Copy link
Contributor

@Eblo Eblo left a comment

Choose a reason for hiding this comment

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

Small feedback update. One last thing is that my recent enemy drops v2 PR changes how enemy drops are defined. I went ahead and commented any sort of time window logic for your convenience. I'll want to do a more thorough review of this after that enemy drops PR is merged and incorporated into this one, but I found no issues after the scarecrow fix. Clock Shuffle (name pending?) is looking to be in pretty good shape.

Comment on lines 216 to 218
#define CAN_USE_DAY2_RAIN_BEAN \
(HAS_ITEM(ITEM_MAGIC_BEANS) && (CLOCK_DAY2() || CAN_PLAY_SONG(STORMS) || \
(HAS_BOTTLE && (CAN_ACCESS(SPRING_WATER) || CAN_ACCESS(HOT_SPRING_WATER)))))
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably simpler to define this as CAN_GROW_BEAN_PLANT or day 2 and bean:

Suggested change
#define CAN_USE_DAY2_RAIN_BEAN \
(HAS_ITEM(ITEM_MAGIC_BEANS) && (CLOCK_DAY2() || CAN_PLAY_SONG(STORMS) || \
(HAS_BOTTLE && (CAN_ACCESS(SPRING_WATER) || CAN_ACCESS(HOT_SPRING_WATER)))))
#define CAN_USE_DAY2_RAIN_BEAN (CAN_GROW_BEAN_PLANT || (HAS_ITEM(ITEM_MAGIC_BEANS) && CLOCK_DAY2()))

@mckinlee
Copy link
Contributor Author

mckinlee commented Dec 8, 2025

Small feedback update. One last thing is that my recent enemy drops v2 PR changes how enemy drops are defined. I went ahead and commented any sort of time window logic for your convenience. I'll want to do a more thorough review of this after that enemy drops PR is merged and incorporated into this one, but I found no issues after the scarecrow fix. Clock Shuffle (name pending?) is looking to be in pretty good shape.

When that happens, I'll go back and rebrand to "Shuffle Time" as discussed in discord.

@Eblo
Copy link
Contributor

Eblo commented Dec 13, 2025

With recent merges, this will need to do the following with a rebase:

Copy link
Contributor

@Eblo Eblo left a comment

Choose a reason for hiding this comment

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

Top notch job on this so far. In practice in gameplay, this whole thing seems to work splendidly and is just plain fun. My feedback is almost entirely concerned with how things are under the hood, with plenty of questions.

I think that a number of my comments from prior reviews got lost in the mix, as they have not been addressed while others have. I'd like you to carefully go through the entire PR files themselves for review comments. Certain views on GitHub might be only showing so much.

Again, bang up job here. This was no small feat.

Comment on lines 272 to 273
CHECK(RC_ENEMY_DROP_TEKTITE, CanKillEnemy(ACTOR_OBJ_SNOWBALL) && CanKillEnemy(ACTOR_EN_TITE) && (IS_DAY1() || IS_DAY3())), // Day 1 and 3 only
CHECK(RC_ENEMY_DROP_WOLFOS, CanKillEnemy(ACTOR_OBJ_SNOWBALL) && CanKillEnemy(ACTOR_EN_WF) && IS_DAY2()), // Day 2 only
Copy link
Contributor

Choose a reason for hiding this comment

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

My comments may have been ambiguous. These enemies appear at night also, e.g. Day+Night 2 for the Wolfos:

Suggested change
CHECK(RC_ENEMY_DROP_TEKTITE, CanKillEnemy(ACTOR_OBJ_SNOWBALL) && CanKillEnemy(ACTOR_EN_TITE) && (IS_DAY1() || IS_DAY3())), // Day 1 and 3 only
CHECK(RC_ENEMY_DROP_WOLFOS, CanKillEnemy(ACTOR_OBJ_SNOWBALL) && CanKillEnemy(ACTOR_EN_WF) && IS_DAY2()), // Day 2 only
CHECK(RC_ENEMY_DROP_TEKTITE, CanKillEnemy(ACTOR_OBJ_SNOWBALL) && CanKillEnemy(ACTOR_EN_TITE) && (FIRST_DAY() || THIRD_DAY())), // Day 1 and 3 only
CHECK(RC_ENEMY_DROP_WOLFOS, CanKillEnemy(ACTOR_OBJ_SNOWBALL) && CanKillEnemy(ACTOR_EN_WF) && SECOND_DAY()), // Day 2 only

Comment on lines 398 to 399
CHECK(RC_ENEMY_DROP_WOLFOS, CanKillEnemy(ACTOR_OBJ_SNOWBALL) && CanKillEnemy(ACTOR_EN_WF) && IS_DAY2()), // Day 2 only
CHECK(RC_ENEMY_DROP_SNAPPER, CanKillEnemy(ACTOR_OBJ_SNOWBALL) && CanKillEnemy(ACTOR_EN_KAME) && IS_DAY3()), // Day 3 only
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
CHECK(RC_ENEMY_DROP_WOLFOS, CanKillEnemy(ACTOR_OBJ_SNOWBALL) && CanKillEnemy(ACTOR_EN_WF) && IS_DAY2()), // Day 2 only
CHECK(RC_ENEMY_DROP_SNAPPER, CanKillEnemy(ACTOR_OBJ_SNOWBALL) && CanKillEnemy(ACTOR_EN_KAME) && IS_DAY3()), // Day 3 only
CHECK(RC_ENEMY_DROP_WOLFOS, CanKillEnemy(ACTOR_OBJ_SNOWBALL) && CanKillEnemy(ACTOR_EN_WF) && SECOND_DAY()), // Day 2 only
CHECK(RC_ENEMY_DROP_SNAPPER, CanKillEnemy(ACTOR_OBJ_SNOWBALL) && CanKillEnemy(ACTOR_EN_KAME) && THIRD_DAY()), // Day 3 only

Comment on lines 419 to 420
CHECK(RC_ENEMY_DROP_WOLFOS, CanKillEnemy(ACTOR_OBJ_SNOWBALL) && CanKillEnemy(ACTOR_EN_WF) && IS_DAY2()), // Day 2 only
CHECK(RC_ENEMY_DROP_SNAPPER, CanKillEnemy(ACTOR_OBJ_SNOWBALL) && CanKillEnemy(ACTOR_EN_KAME) && IS_DAY3()), // Day 3 only
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
CHECK(RC_ENEMY_DROP_WOLFOS, CanKillEnemy(ACTOR_OBJ_SNOWBALL) && CanKillEnemy(ACTOR_EN_WF) && IS_DAY2()), // Day 2 only
CHECK(RC_ENEMY_DROP_SNAPPER, CanKillEnemy(ACTOR_OBJ_SNOWBALL) && CanKillEnemy(ACTOR_EN_KAME) && IS_DAY3()), // Day 3 only
CHECK(RC_ENEMY_DROP_WOLFOS, CanKillEnemy(ACTOR_OBJ_SNOWBALL) && CanKillEnemy(ACTOR_EN_WF) && SECOND_DAY()), // Day 2 only
CHECK(RC_ENEMY_DROP_SNAPPER, CanKillEnemy(ACTOR_OBJ_SNOWBALL) && CanKillEnemy(ACTOR_EN_KAME) && THIRD_DAY()), // Day 3 only

Comment on lines 576 to 577
CHECK(RC_WOODS_OF_MYSTERY_GRASS_22, true),
CHECK(RC_WOODS_OF_MYSTERY_GRASS_23, true),
Copy link
Contributor

Choose a reason for hiding this comment

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

Wrong grass checks got marked:

Suggested change
CHECK(RC_WOODS_OF_MYSTERY_GRASS_22, FINAL_DAY()),
CHECK(RC_WOODS_OF_MYSTERY_GRASS_23, FINAL_DAY()),

Comment on lines 563 to 564
CHECK(RC_WOODS_OF_MYSTERY_GRASS_09, FINAL_DAY()),
CHECK(RC_WOODS_OF_MYSTERY_GRASS_10, FINAL_DAY()),
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
CHECK(RC_WOODS_OF_MYSTERY_GRASS_09, true),
CHECK(RC_WOODS_OF_MYSTERY_GRASS_10, true),

}

// Add remaining (non-starting) time items to pool
// Only works in random mode - progressive mode items are added elsewhere
Copy link
Contributor

Choose a reason for hiding this comment

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

Clarify where that is here, so that anybody working with this knows where to look.

Comment on lines 2470 to 2476
RI_CLOCK_DAY_1,
RI_CLOCK_NIGHT_1,
RI_CLOCK_DAY_2,
RI_CLOCK_NIGHT_2,
RI_CLOCK_DAY_3,
RI_CLOCK_NIGHT_3,
RI_CLOCK_PROGRESSIVE,
Copy link
Contributor

Choose a reason for hiding this comment

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

This list is in alphabetical order for the most part, so these RIs don't belong here.

On another note, the RI names are partially user-facing at least due to the save editor. Should these be renamed to RI_TIME_*?

CHECK(RC_GORMAN_MILK_PURCHASE, CAN_AFFORD(RC_GORMAN_MILK_PURCHASE)),
CHECK(RC_GORMAN_TRACK_GARO_MASK, CAN_PLAY_SONG(EPONA)),
CHECK(RC_GORMAN_MILK_PURCHASE, CAN_AFFORD(RC_GORMAN_MILK_PURCHASE) && IS_DAY()),
CHECK(RC_GORMAN_TRACK_GARO_MASK, CAN_PLAY_SONG(EPONA) && CAN_AFFORD(RC_GORMAN_TRACK_GARO_MASK) && IS_DAY()),
Copy link
Contributor

Choose a reason for hiding this comment

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

While the Gorman race does cost money, it's a flat 10 Rupee fee and not tied into a shop check with a price. It's not gated by wallet size.

Suggested change
CHECK(RC_GORMAN_TRACK_GARO_MASK, CAN_PLAY_SONG(EPONA) && CAN_AFFORD(RC_GORMAN_TRACK_GARO_MASK) && IS_DAY()),
CHECK(RC_GORMAN_TRACK_GARO_MASK, CAN_PLAY_SONG(EPONA) && IS_DAY()),

EVENT(RE_ACCESS_FISH, true),
EVENT(RE_ACCESS_BUGS, true),
EVENT(RE_SETUP_MEET_ANJU, HAS_ITEM(ITEM_MASK_KAFEIS_MASK) && BETWEEN(TIME_DAY1_PM_01_45, TIME_NIGHT1_PM_09_00)),
EVENT(RE_MEET_ANJU, RANDO_EVENTS[RE_SETUP_MEET_ANJU] && BETWEEN(TIME_NIGHT1_AM_12_00, TIME_DAY2_AM_06_00) && (Flags_GetRandoInf(RANDO_INF_OBTAINED_ROOM_KEY) || CAN_BE_DEKU)),
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems to be for the midnight meeting, which makes the event name confusing. Maybe just RE_ANJU_MIDNIGHT_MEETING?

Copy link
Contributor

@Eblo Eblo left a comment

Choose a reason for hiding this comment

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

One miscellaneous thing is that my comment regarding CheckTrackerDrawLogicalList is still not addressed. That, and there are conflicts with the Central.cpp logic file.

This is really close. This review is trivial things. I'm pretty happy with this overall.

Comment on lines 2473 to 2479
RI_TIME_DAY_1,
RI_TIME_NIGHT_1,
RI_TIME_DAY_2,
RI_TIME_NIGHT_2,
RI_TIME_DAY_3,
RI_TIME_NIGHT_3,
RI_TIME_PROGRESSIVE,
Copy link
Contributor

Choose a reason for hiding this comment

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

What do you think of naming the time RIs like so, to keep them both alphabetical and also the same order as what you have? I'm not 100% sure myself:

Suggested change
RI_TIME_DAY_1,
RI_TIME_NIGHT_1,
RI_TIME_DAY_2,
RI_TIME_NIGHT_2,
RI_TIME_DAY_3,
RI_TIME_NIGHT_3,
RI_TIME_PROGRESSIVE,
RI_TIME_1_DAY,
RI_TIME_1_NIGHT,
RI_TIME_2_DAY,
RI_TIME_2_NIGHT,
RI_TIME_3_DAY,
RI_TIME_3_NIGHT,
RI_TIME_PROGRESSIVE,

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'm indifferent, but I left it as is for now. Just let me know how ya wanna proceed. The other feedback is addressed though.

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

Labels

help wanted Extra attention is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants