Pokémon Crystal - On general RTC manipulation ------ 0. Introduction RTC (Real-Time Clock) is an hardware clock that runs whenever the console is alimented (ON or OFF). It features several memory addresses that track frames, seconds, minutes, hours, days. Some games use this available data for different in-game purposes, such as Pokémon Crystal, which allows with RTC usage to update days of the week for example. It appears to also have an impact on RNG (randomness in the game). -- 1. Software variables Pokémon Crystal uses different timers for different uses. Here are some : > IGT (In-Game Time) : used to display player's progression time through the Trainer Card / save menu / Hall of Fame > RTC (Real Time Clock) : stored in the RAM of the game for some uses. The game only stores some RTC values from the seconds : the number of RTC frames is not stored, which decreases the execution accuracy in current RTC manipulation attempts. Some useful values are split in the game between the WRAM and the HRAM as follows. 1.1 WRAM variables In WRAM1, you can find values initialized during the ingame clock setup when confirming the number of minutes : > StartDay [0xD4B6] > StartHour [0xD4B7] > StartMinute [0xD4B8] > StartSecond [0xD4B9] You can easily manipulate these values by waiting a certain amount of time from the Hard Reset. Note that having a savefile breaks any manipulation of these values 1.2 HRAM variables In HRAM, you can find values that act like an actual RTC clock. They are nearly always displaying the RTC values provided by the hardware (the whole game introduction freezes them) > hRTCHours [0xFF8F] > hRTCMinutes [0xFF90] > hRTCSeconds [0xFF91] -- 2. Code behaviour linked with RTC _InitTime is a function called twice after New Game is selected. 1) When confirming the ingame clock minute during the game introduction, the function sets StartSecond, StartMinute, StartHour & StartDay. 2) When confirming the ingame day during Mom's speech, the function sets StartHour and StartDay. This lets StartSecond and StartMinute unchanged from the 1st _InitTime call. The reason behind manipulating the RTC in order to lead to RNG manipulation comes from the funtion FixTime, called every frame (source code in Postface). This function takes hRTCSeconds and adds it to StartSecond (and does the same for hRTCMinutes and StartMinute, etc.). By doing so, the game "fixes" the ingame time by aligning the start of the game clock with the running RTC. In case these sums overflow (>=60 for seconds and minutes, >= 24 for hours), the code will execute an extra instruction. Since hRTCSeconds is updated once per second, this sum will overflow at some point and execute this instruction for every following hRTCSeconds until it reaches 0 again. This behaviour also applies to the sum hRTCMinutes + StartMinute, etc. By setting StartSecond and StartMinute to 0, the previously described sums will never overflow and thus the extra instructions will never be executed. -- 3. Current RTC manipulations Current RTC setup sets both StartSecond and StartMinute to 0 (refered from now as "RTC0"), and is performed as follows : 0) If any save was done, clear it (doing the LID setup doesn't interfere with RTC0 setup). 1) Hard Reset and start a timer set at 63.30s for BGB and 65.30s for GameBoy Player. 2) Set ingame clock to 6:01PM. 2) Confirm ingame minute ("YES" textbox) when the timer reaches 0. This setup sets Start variables like so : > StartDay = 0x00 > StartHour = 0x12 > StartMinute = 0x00 > StartSecond = 0x00 Runners are currently investigating how this setup affects RNG through potential RNG manipulation attempts. -- 4. Postface > FixTime source code FixTime:: ; 61d ; add ingame time (set at newgame) to current time ; day hr min sec ; store time in CurDay, hHours, hMinutes, hSeconds ; second ld a, [hRTCSeconds] ; S ld c, a ld a, [StartSecond] add c sub 60 jr nc, .updatesec add 60 .updatesec ld [hSeconds], a ; minute ccf ; carry is set, so turn it off ld a, [hRTCMinutes] ; M ld c, a ld a, [StartMinute] adc c sub 60 jr nc, .updatemin add 60 .updatemin ld [hMinutes], a ; hour ccf ; carry is set, so turn it off ld a, [hRTCHours] ; H ld c, a ld a, [StartHour] adc c sub 24 jr nc, .updatehr add 24 .updatehr ld [hHours], a ; day ccf ; carry is set, so turn it off ld a, [hRTCDayLo] ; DL ld c, a ld a, [StartDay] adc c ld [CurDay], a ret ; 658