Rtc implementation (#5)

added RTC and fixed time based evolutions
This commit is contained in:
cawtds
2024-05-05 14:20:30 +02:00
committed by GitHub
parent b4fddd348d
commit c2e0ab5d73
53 changed files with 3452 additions and 3475 deletions

View File

@@ -92,7 +92,7 @@ MID_BUILDDIR = $(OBJ_DIR)/$(MID_SUBDIR)
ASFLAGS := -mcpu=arm7tdmi --defsym $(GAME_VERSION)=1 --defsym REVISION=$(GAME_REVISION) --defsym $(GAME_LANGUAGE)=1 --defsym MODERN=$(MODERN)
LDFLAGS = -Map ../../$(MAP)
LDFLAGS = --print-memory-usage -Map ../../$(MAP)
LIB := $(LIBPATH) -lc -lgcc
ifneq ($(MODERN),0)
@@ -238,6 +238,8 @@ sound/songs/%.s: sound/songs/%.mid
$(MID) $< $@
ifeq ($(MODERN),0)
$(C_BUILDDIR)/siirtc.o: CFLAGS := -mthumb-interwork
$(C_BUILDDIR)/agb_flash.o: CFLAGS := -O -mthumb-interwork
$(C_BUILDDIR)/agb_flash_1m.o: CFLAGS := -O -mthumb-interwork
$(C_BUILDDIR)/agb_flash_mx.o: CFLAGS := -O -mthumb-interwork

3377
build.log

File diff suppressed because it is too large Load Diff

1
common_syms/rtc.txt Normal file
View File

@@ -0,0 +1 @@
gLocalTime

View File

@@ -98,6 +98,7 @@ ViridianCity_Mart_Items::
.2byte ITEM_STICKY_BARB
.2byte ITEM_ORAN_BERRY
.2byte ITEM_BEAST_BALL
.2byte ITEM_POMEG_BERRY
.2byte ITEM_NONE
release
end

View File

@@ -162,8 +162,8 @@ gSpecials::
def_special NullFieldSpecial @ Cable Car specials
def_special NullFieldSpecial
def_special Overworld_PlaySpecialMapMusic
def_special NullFieldSpecial @ Wall Clock specials
def_special NullFieldSpecial
def_special StartWallClock
def_special Special_ViewWallClock
def_special NullFieldSpecial
def_special StartOldManTutorialBattle
def_special ChangePokemonNickname
@@ -215,7 +215,7 @@ gSpecials::
def_special NullFieldSpecial
def_special EnterSafariMode
def_special ExitSafariMode
def_special NullFieldSpecial @ Misc Hoenn specials
def_special GetWeekCount
def_special NullFieldSpecial
def_special NullFieldSpecial
def_special NullFieldSpecial

View File

@@ -13,7 +13,7 @@ gText_PlayerSavedTheGame::
.string "{PLAYER} saved the game.$"
gText_SaveFailed2::
.string "セーブに しっぱい しました‥$"
.string "Save failed…$"
gText_DifferentGameFile::
.string "WARNING!\p"

View File

@@ -0,0 +1,7 @@
JASC-PAL
0100
4
0 0 0
255 0 0
74 74 74
0 0 0

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,19 @@
JASC-PAL
0100
16
65 65 90
222 230 238
213 213 222
205 205 213
197 197 205
255 197 255
255 156 255
255 115 255
255 82 255
74 180 189
255 230 49
90 90 123
123 123 172
65 65 90
255 255 255
0 0 0

BIN
graphics/wallclock/hand.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

View File

@@ -0,0 +1,19 @@
JASC-PAL
0100
16
65 65 90
222 230 238
213 213 222
205 205 213
197 197 205
164 180 255
115 139 255
74 98 255
32 65 255
74 180 189
255 230 49
90 90 123
123 123 172
65 65 90
255 255 255
0 0 0

View File

@@ -0,0 +1,7 @@
JASC-PAL
0100
4
0 0 0
74 180 189
255 255 255
0 0 0

8
include/clock.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef GUARD_CLOCK_H
#define GUARD_CLOCK_H
// TODO: time of day and seconds in a day defines
void DoTimeBasedEvents(void);
#endif // GUARD_CLOCK_H

View File

@@ -886,7 +886,7 @@
#define FLAG_0x359 0x359
#define FLAG_0x35A 0x35A
#define FLAG_0x35B 0x35B
#define FLAG_0x35C 0x35C
#define FLAG_SET_WALL_CLOCK 0x35C
#define FLAG_0x35D 0x35D
#define FLAG_0x35E 0x35E
#define FLAG_0x35F 0x35F
@@ -938,6 +938,9 @@
#define FLAG_0x38D 0x38D
#define FLAG_0x38E 0x38E
#define FLAG_0x38F 0x38F
#define DAILY_FLAGS_START (FLAG_0x38F + (8 - FLAG_0x38F % 8))
#define FLAG_0x390 0x390
#define FLAG_0x391 0x391
#define FLAG_0x392 0x392
@@ -1002,6 +1005,9 @@
#define FLAG_0x3CD 0x3CD
#define FLAG_0x3CE 0x3CE
#define FLAG_0x3CF 0x3CF
#define DAILY_FLAGS_END (FLAG_0x3CF + (7 - FLAG_0x3CF % 8))
#define FLAG_0x3D0 0x3D0
#define FLAG_0x3D1 0x3D1
#define FLAG_0x3D2 0x3D2
@@ -1394,7 +1400,7 @@
#define FLAG_SYS_SAW_HELP_SYSTEM_INTRO (SYS_FLAGS + 0x3C)
#define FLAG_0x83D (SYS_FLAGS + 0x3D)
#define FLAG_OPENED_START_MENU (SYS_FLAGS + 0x3E)
#define FLAG_0x83F (SYS_FLAGS + 0x3F)
#define FLAG_SYS_CLOCK_SET (SYS_FLAGS + 0x3F) // FLAG_0x83F
#define FLAG_SYS_NATIONAL_DEX (SYS_FLAGS + 0x40)
#define FLAG_SYS_PC_STORAGE_DISABLED (SYS_FLAGS + 0x41)
#define FLAG_SYS_INFORMED_OF_LOCAL_WIRELESS_PLAYER (SYS_FLAGS + 0x42)

View File

@@ -88,7 +88,7 @@
#define VAR_0x4029 0x4029
#define VAR_0x402A 0x402A
#define VAR_0x402B 0x402B
#define VAR_0x402C 0x402C
#define VAR_DAYS 0x402C // was VAR_RESET_RTC_ENABLE
#define VAR_0x402D 0x402D
#define VAR_0x402E 0x402E

View File

@@ -25,6 +25,7 @@ extern u16 gSpecialVar_PrevTextColor;
void InitEventData(void);
void ClearTempFieldEventData(void);
void ClearDailyFlags(void);
void ClearUpperFlags(void);
void DisableNationalPokedex(void);
void EnableNationalPokedex(void);

View File

@@ -2781,6 +2781,13 @@ extern const u8 gTeachyTvScreen_Tilemap[];
extern const u8 gTeachyTvTitle_Tilemap[];
extern const u32 gTeachyTv_Pal[];
// wall clock
extern const u32 gWallClock_Gfx[];
extern const u16 gWallClockMale_Pal[];
extern const u16 gWallClockFemale_Pal[];
extern const u32 gWallClockStart_Tilemap[];
extern const u32 gWallClockView_Tilemap[];
// berry_fix_program
extern const u8 gBerryFixGameboy_Gfx[];
extern const u8 gBerryFixGameboy_Tilemap[];

View File

@@ -5,6 +5,7 @@
#include "sprite.h"
#include "constants/items.h"
#include "constants/region_map_sections.h"
#include "constants/map_groups.h"
#include "constants/pokemon.h"
#define GET_BASE_SPECIES_ID(speciesId) (GetFormSpeciesId(speciesId, 0))
@@ -767,6 +768,7 @@ u16 GetMonEVCount(struct Pokemon *mon);
void RandomlyGivePartyPokerus(struct Pokemon *party);
u8 CheckPartyPokerus(struct Pokemon *party, u8 party_bm);
u8 CheckPartyHasHadPokerus(struct Pokemon *party, u8 selection);
void UpdatePartyPokerusTime(u16 days);
void PartySpreadPokerus(struct Pokemon *party);
bool8 TryIncrementMonLevel(struct Pokemon *mon);
u32 CanMonLearnTMHM(struct Pokemon *mon, u8 tm);

View File

@@ -0,0 +1,6 @@
#ifndef GUARD_RESET_RTC_SCREEN_H
#define GUARD_RESET_RTC_SCREEN_H
void CB2_InitResetRtcScreen(void);
#endif // GUARD_RESET_RTC_SCREEN_H

122
include/rtc.h Normal file
View File

@@ -0,0 +1,122 @@
#ifndef GUARD_RTC_UTIL_H
#define GUARD_RTC_UTIL_H
#include "siirtc.h"
#define RTC_INIT_ERROR 0x0001
#define RTC_INIT_WARNING 0x0002
#define RTC_ERR_12HOUR_CLOCK 0x0010
#define RTC_ERR_POWER_FAILURE 0x0020
#define RTC_ERR_INVALID_YEAR 0x0040
#define RTC_ERR_INVALID_MONTH 0x0080
#define RTC_ERR_INVALID_DAY 0x0100
#define RTC_ERR_INVALID_HOUR 0x0200
#define RTC_ERR_INVALID_MINUTE 0x0400
#define RTC_ERR_INVALID_SECOND 0x0800
#define RTC_ERR_FLAG_MASK 0x0FF0
//Morning and evening don't exist in Gen 3
#if OW_TIMES_OF_DAY == GEN_3
#define MORNING_HOUR_BEGIN 0
#define MORNING_HOUR_END 0
#define DAY_HOUR_BEGIN 12
#define DAY_HOUR_END HOURS_PER_DAY
#define EVENING_HOUR_BEGIN 0
#define EVENING_HOUR_END 0
#define NIGHT_HOUR_BEGIN 0
#define NIGHT_HOUR_END 12
//Evening doesn't exist in Gen 4
#elif OW_TIMES_OF_DAY == GEN_4
#define MORNING_HOUR_BEGIN 4
#define MORNING_HOUR_END 10
#define DAY_HOUR_BEGIN 10
#define DAY_HOUR_END 20
#define EVENING_HOUR_BEGIN 0
#define EVENING_HOUR_END 0
#define NIGHT_HOUR_BEGIN 20
#define NIGHT_HOUR_END 4
//Gen 5 currently not included as the seasons change the times of day
#elif OW_TIMES_OF_DAY <= GEN_6
#define MORNING_HOUR_BEGIN 4
#define MORNING_HOUR_END 11
#define DAY_HOUR_BEGIN 11
#define DAY_HOUR_END 18
#define EVENING_HOUR_BEGIN 18
#define EVENING_HOUR_END 21
#define NIGHT_HOUR_BEGIN 21
#define NIGHT_HOUR_END 4
//These are the Sun/Ultra Sun times
#elif OW_TIMES_OF_DAY == GEN_7
#define MORNING_HOUR_BEGIN 6
#define MORNING_HOUR_END 10
#define DAY_HOUR_BEGIN 10
#define DAY_HOUR_END 17
#define EVENING_HOUR_BEGIN 17
#define EVENING_HOUR_END 18
#define NIGHT_HOUR_BEGIN 18
#define NIGHT_HOUR_END 6
#elif OW_TIMES_OF_DAY >= GEN_8
#define MORNING_HOUR_BEGIN 6
#define MORNING_HOUR_END 10
#define DAY_HOUR_BEGIN 10
#define DAY_HOUR_END 19
#define EVENING_HOUR_BEGIN 19
#define EVENING_HOUR_END 20
#define NIGHT_HOUR_BEGIN 20
#define NIGHT_HOUR_END 6
#endif
#define TIME_MORNING 0
#define TIME_DAY 1
#define TIME_EVENING 2
#define TIME_NIGHT 3
extern struct Time gLocalTime;
void RtcDisableInterrupts(void);
void RtcRestoreInterrupts(void);
u32 ConvertBcdToBinary(u8 bcd);
bool8 IsLeapYear(u32 year);
u16 ConvertDateToDayCount(u8 year, u8 month, u8 day);
u16 RtcGetDayCount(struct SiiRtcInfo *rtc);
void RtcInit(void);
u16 RtcGetErrorStatus(void);
void RtcGetInfo(struct SiiRtcInfo *rtc);
void RtcGetDateTime(struct SiiRtcInfo *rtc);
void RtcGetStatus(struct SiiRtcInfo *rtc);
void RtcGetRawInfo(struct SiiRtcInfo *rtc);
u16 RtcCheckInfo(struct SiiRtcInfo *rtc);
void RtcReset(void);
void FormatDecimalTime(u8 *dest, s32 hour, s32 minute, s32 second);
void FormatHexTime(u8 *dest, s32 hour, s32 minute, s32 second);
void FormatHexRtcTime(u8 *dest);
void FormatDecimalDate(u8 *dest, s32 year, s32 month, s32 day);
void FormatHexDate(u8 *dest, s32 year, s32 month, s32 day);
void RtcCalcTimeDifference(struct SiiRtcInfo *rtc, struct Time *result, struct Time *t);
void RtcCalcLocalTime(void);
bool8 IsBetweenHours(s32 hours, s32 begin, s32 end);
u8 GetTimeOfDay(void);
void RtcInitLocalTimeOffset(s32 hour, s32 minute);
void RtcCalcLocalTimeOffset(s32 days, s32 hours, s32 minutes, s32 seconds);
void CalcTimeDifference(struct Time *result, struct Time *t1, struct Time *t2);
u32 RtcGetMinuteCount(void);
u32 RtcGetLocalDayCount(void);
#endif // GUARD_RTC_UTIL_H

54
include/siirtc.h Normal file
View File

@@ -0,0 +1,54 @@
#ifndef GUARD_RTC_H
#define GUARD_RTC_H
#include "gba/gba.h"
#define SIIRTCINFO_INTFE 0x01 // frequency interrupt enable
#define SIIRTCINFO_INTME 0x02 // per-minute interrupt enable
#define SIIRTCINFO_INTAE 0x04 // alarm interrupt enable
#define SIIRTCINFO_24HOUR 0x40 // 0: 12-hour mode, 1: 24-hour mode
#define SIIRTCINFO_POWER 0x80 // power on or power failure occurred
enum
{
MONTH_JAN = 1,
MONTH_FEB,
MONTH_MAR,
MONTH_APR,
MONTH_MAY,
MONTH_JUN,
MONTH_JUL,
MONTH_AUG,
MONTH_SEP,
MONTH_OCT,
MONTH_NOV,
MONTH_DEC
};
struct SiiRtcInfo
{
u8 year;
u8 month;
u8 day;
u8 dayOfWeek;
u8 hour;
u8 minute;
u8 second;
u8 status;
u8 alarmHour;
u8 alarmMinute;
};
void SiiRtcUnprotect(void);
void SiiRtcProtect(void);
u8 SiiRtcProbe(void);
bool8 SiiRtcReset(void);
bool8 SiiRtcGetStatus(struct SiiRtcInfo *rtc);
bool8 SiiRtcSetStatus(struct SiiRtcInfo *rtc);
bool8 SiiRtcGetDateTime(struct SiiRtcInfo *rtc);
bool8 SiiRtcSetDateTime(struct SiiRtcInfo *rtc);
bool8 SiiRtcGetTime(struct SiiRtcInfo *rtc);
bool8 SiiRtcSetTime(struct SiiRtcInfo *rtc);
bool8 SiiRtcSetAlarm(struct SiiRtcInfo *rtc);
#endif // GUARD_RTC_H

View File

@@ -506,6 +506,7 @@ extern const u8 gText_ABtnRegistrationCounter[];
extern const u8 gText_SaveFileCorrupted[];
extern const u8 gText_SaveFileHasBeenDeleted[];
extern const u8 gText_1MSubCircuitBoardNotInstalled[];
extern const u8 gText_BatteryRunDry[];
extern const u8 gText_NewGame[];
extern const u8 gText_Continue[];
extern const u8 gText_MysteryGift[];
@@ -520,6 +521,11 @@ extern const u8 gText_Badges[];
extern const u8 gTextJPDummy_Ko[];
extern const u8 gText_Register[];
// wallclock
extern const u8 gText_Confirm3[];
extern const u8 gText_Cancel4[];
extern const u8 gText_IsThisTheCorrectTime[];
// mystery_gift_menu
extern const u8 gText_PickOKExit[];
extern const u8 gText_PickOKCancel[];
@@ -625,6 +631,19 @@ extern const u8 gText_MessageWillBeLost[];
extern const u8 gText_BagIsFull[];
extern const u8 gText_MailReturnedToBagMessageErased[];
// reset rtc screen texts
extern const u8 gText_Day[];
extern const u8 gText_Colon3[];
extern const u8 gText_Confirm2[];
extern const u8 gText_PresentTime[];
extern const u8 gText_PreviousTime[];
extern const u8 gText_ResetRTCConfirmCancel[];
extern const u8 gText_NoSaveFileCantSetTime[];
extern const u8 gText_PleaseResetTime[];
extern const u8 gText_ClockHasBeenReset[];
extern const u8 gText_SaveCompleted[];
extern const u8 gText_SaveFailed[];
// start_menu
extern const u8 gText_MenuPokedex[];
extern const u8 gText_MenuBag[];

6
include/time_events.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef GUARD_TIME_EVENTS_H
#define GUARD_TIME_EVENTS_H
#endif // GUARD_TIME_EVENTS_H

7
include/wallclock.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef GUARD_WALLCLOCK_H
#define GUARD_WALLCLOCK_H
void CB2_StartWallClock(void);
void CB2_ViewWallClock(void);
#endif //GUARD_WALLCLOCK_H

View File

@@ -71,6 +71,7 @@ SECTIONS {
src/string_util.o(.text);
src/link.o(.text);
src/multiboot.o(.text);
src/rtc.o(.text);
src/main_menu.o(.text);
src/battle_controllers.o(.text);
src/decompress.o(.text);
@@ -114,6 +115,8 @@ SECTIONS {
src/event_data.o(.text);
src/coord_event_weather.o(.text);
src/field_tasks.o(.text);
src/clock.o(.text);
src/reset_rtc_screen.o(.text);
src/start_menu.o(.text);
src/tileset_anims.o(.text);
src/palette.o(.text);
@@ -197,10 +200,12 @@ SECTIONS {
src/region_map.o(.text);
src/image_processing_effects.o(.text);
src/battle_ai_script_commands.o(.text);
src/wallclock.o(.text);
src/fldeff_rocksmash.o(.text);
src/fldeff_dig.o(.text);
src/fldeff_flash.o(.text);
src/post_battle_event_funcs.o(.text);
src/time_events.o(.text);
src/prof_pc.o(.text);
src/hof_pc.o(.text);
src/field_specials.o(.text);
@@ -338,6 +343,7 @@ SECTIONS {
src/agb_flash_1m.o(.text);
src/agb_flash_mx.o(.text);
src/agb_flash_le.o(.text);
src/siirtc.o(.text);
src/librfu_stwi.o(.text);
src/librfu_intr.o(.text);
src/librfu_rfu.o(.text);
@@ -411,6 +417,8 @@ SECTIONS {
src/bg_regs.o(.rodata);
src/string_util.o(.rodata);
src/link.o(.rodata);
src/rtc.o(.rodata);
src/reset_rtc_screen.o(.rodata);
src/main_menu.o(.rodata);
src/data.o(.rodata);
src/battle_bg.o(.rodata);
@@ -506,7 +514,9 @@ SECTIONS {
src/region_map.o(.rodata);
src/image_processing_effects.o(.rodata);
src/battle_ai_script_commands.o(.rodata);
src/wallclock.o(.rodata);
src/fldeff_flash.o(.rodata);
src/time_events.o(.rodata);
src/field_specials.o(.rodata);
src/battle_records.o(.rodata);
src/evolution_scene.o(.rodata);
@@ -975,6 +985,7 @@ SECTIONS {
src/agb_flash_1m.o(.rodata);
src/agb_flash_mx.o(.rodata);
src/agb_flash_le.o(.rodata);
src/siirtc.o(.rodata);
src/librfu_rfu.o(.rodata);
src/librfu_sio32id.o(.rodata);
src/isagbprn.o(.rodata);

87
src/clock.c Normal file
View File

@@ -0,0 +1,87 @@
#include "global.h"
#include "event_data.h"
#include "rtc.h"
#include "time_events.h"
#include "field_specials.h"
// #include "lottery_corner.h"
// #include "dewford_trend.h"
// #include "tv.h"
#include "field_weather.h"
// #include "berry.h"
#include "main.h"
#include "overworld.h"
#include "wallclock.h"
static void UpdatePerDay(struct Time *localTime);
static void UpdatePerMinute(struct Time *localTime);
static void InitTimeBasedEvents(void)
{
FlagSet(FLAG_SYS_CLOCK_SET);
RtcCalcLocalTime();
gSaveBlock2Ptr->lastBerryTreeUpdate = gLocalTime;
VarSet(VAR_DAYS, gLocalTime.days);
}
void DoTimeBasedEvents(void)
{
// TODO: relevant?
if (FlagGet(FLAG_SYS_CLOCK_SET)) // && !InPokemonCenter()
{
RtcCalcLocalTime();
UpdatePerDay(&gLocalTime);
UpdatePerMinute(&gLocalTime);
}
}
static void UpdatePerDay(struct Time *localTime)
{
u16 *days = GetVarPointer(VAR_DAYS);
u16 daysSince;
if (*days != localTime->days && *days <= localTime->days)
{
daysSince = localTime->days - *days;
ClearDailyFlags();
// UpdateDewfordTrendPerDay(daysSince);
// UpdateTVShowsPerDay(daysSince);
// UpdateWeatherPerDay(daysSince);
UpdatePartyPokerusTime(daysSince);
// UpdateMirageRnd(daysSince);
// UpdateBirchState(daysSince);
// UpdateFrontierManiac(daysSince);
// UpdateFrontierGambler(daysSince);
// SetShoalItemFlag(daysSince);
// SetRandomLotteryNumber(daysSince);
*days = localTime->days;
}
}
static void UpdatePerMinute(struct Time *localTime)
{
struct Time difference;
int minutes;
CalcTimeDifference(&difference, &gSaveBlock2Ptr->lastBerryTreeUpdate, localTime);
minutes = 24 * 60 * difference.days + 60 * difference.hours + difference.minutes;
if (minutes != 0)
{
if (minutes >= 0)
{
// BerryTreeTimeUpdate(minutes);
gSaveBlock2Ptr->lastBerryTreeUpdate = *localTime;
}
}
}
static void ReturnFromStartWallClock(void)
{
InitTimeBasedEvents();
SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic);
}
void StartWallClock(void)
{
SetMainCallback2(CB2_StartWallClock);
gMain.savedCallback = ReturnFromStartWallClock;
}

View File

@@ -13632,9 +13632,9 @@ const struct SpeciesInfo gSpeciesInfoGen1[] =
{EVO_ITEM, ITEM_FIRE_STONE, SPECIES_FLAREON},
{EVO_FRIENDSHIP_DAY, 0, SPECIES_ESPEON},
{EVO_FRIENDSHIP_NIGHT, 0, SPECIES_UMBREON},
{EVO_SPECIFIC_MAP, MAPSEC_VIRIDIAN_FOREST, SPECIES_LEAFEON},
{EVO_SPECIFIC_MAP, MAP_VIRIDIAN_FOREST, SPECIES_LEAFEON},
{EVO_ITEM, ITEM_LEAF_STONE, SPECIES_LEAFEON},
{EVO_SPECIFIC_MAP, MAPSEC_SEAFOAM_ISLANDS, SPECIES_GLACEON},
{EVO_SPECIFIC_MAP, MAP_SEAFOAM_ISLANDS_B4F, SPECIES_GLACEON},
{EVO_ITEM, ITEM_ICE_STONE, SPECIES_GLACEON},
{EVO_FRIENDSHIP_MOVE_TYPE, TYPE_FAIRY, SPECIES_SYLVEON}),
},

View File

@@ -1126,7 +1126,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] =
FOOTPRINT(Crabrawler)
.levelUpLearnset = sCrabrawlerLevelUpLearnset,
.teachableLearnset = sCrabrawlerTeachableLearnset,
.evolutions = EVOLUTION({EVO_SPECIFIC_MAP, MAPSEC_SEAFOAM_ISLANDS, SPECIES_CRABOMINABLE},
.evolutions = EVOLUTION({EVO_SPECIFIC_MAP, MAP_SEAFOAM_ISLANDS_B4F, SPECIES_CRABOMINABLE},
{EVO_ITEM, ITEM_ICE_STONE, SPECIES_CRABOMINABLE}),
},

View File

@@ -8263,42 +8263,42 @@
{
"min_level": 3,
"max_level": 3,
"species": "SPECIES_DEOXYS"
"species": "SPECIES_EEVEE"
},
{
"min_level": 3,
"max_level": 3,
"species": "SPECIES_DEOXYS"
"species": "SPECIES_EEVEE"
},
{
"min_level": 3,
"max_level": 3,
"species": "SPECIES_DEOXYS_ATTACK"
"species": "SPECIES_EEVEE"
},
{
"min_level": 3,
"max_level": 3,
"species": "SPECIES_DEOXYS_ATTACK"
"species": "SPECIES_EEVEE"
},
{
"min_level": 2,
"max_level": 2,
"species": "SPECIES_DEOXYS_DEFENSE"
"species": "SPECIES_EEVEE"
},
{
"min_level": 2,
"max_level": 2,
"species": "SPECIES_DEOXYS_DEFENSE"
"species": "SPECIES_EEVEE"
},
{
"min_level": 3,
"max_level": 3,
"species": "SPECIES_DEOXYS_DEFENSE"
"species": "SPECIES_EEVEE"
},
{
"min_level": 3,
"max_level": 3,
"species": "SPECIES_MIMIKYU"
"species": "SPECIES_EEVEE"
},
{
"min_level": 4,

View File

@@ -35,6 +35,9 @@ EWRAM_DATA u16 gSpecialVar_PrevTextColor = 0;
EWRAM_DATA u16 gSpecialVar_0x8014 = 0;
EWRAM_DATA u8 sSpecialFlags[SPECIAL_FLAGS_SIZE] = {};
#define NUM_DAILY_FLAGS (DAILY_FLAGS_END - DAILY_FLAGS_START + 1)
#define DAILY_FLAGS_SIZE (NUM_DAILY_FLAGS / 8)
u16 gLastQuestLogStoredFlagOrVarIdx;
extern u16 *const gSpecialVars[];
@@ -57,6 +60,12 @@ void ClearTempFieldEventData(void)
FlagClear(FLAG_SYS_INFORMED_OF_LOCAL_WIRELESS_PLAYER);
}
void ClearDailyFlags(void)
{
memset(gSaveBlock1Ptr->flags + (DAILY_FLAGS_START / 8), 0, DAILY_FLAGS_SIZE);
}
// Unused
static void DisableNationalPokedex_RSE(void)
{
@@ -176,11 +185,12 @@ void EnableResetRTC(void)
bool32 CanResetRTC(void)
{
if (!FlagGet(FLAG_SYS_RESET_RTC_ENABLE))
return FALSE;
if (VarGet(VAR_RESET_RTC_ENABLE) != 0x0920)
return FALSE;
return TRUE;
// if (!FlagGet(FLAG_SYS_RESET_RTC_ENABLE))
// return FALSE;
// if (VarGet(VAR_RESET_RTC_ENABLE) != 0x0920)
// return FALSE;
// return TRUE;
}
u16 *GetVarPointer(u16 idx)

View File

@@ -31,6 +31,8 @@
#include "mystery_gift.h"
#include "naming_screen.h"
#include "party_menu.h"
#include "rtc.h"
#include "wallclock.h"
#include "dynamic_placeholder_text_util.h"
#include "new_menu_helpers.h"
#include "constants/songs.h"
@@ -94,6 +96,13 @@ void ShowDiploma(void)
LockPlayerFieldControls();
}
void Special_ViewWallClock(void)
{
gMain.savedCallback = CB2_ReturnToField;
SetMainCallback2(CB2_ViewWallClock);
LockPlayerFieldControls();
}
void ForcePlayerOntoBike(void)
{
if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_ON_FOOT)
@@ -160,6 +169,16 @@ void SetHiddenItemFlag(void)
FlagSet(gSpecialVar_0x8004);
}
u16 GetWeekCount(void)
{
u16 weekCount = gLocalTime.days / 7;
if (weekCount > 9999)
{
weekCount = 9999;
}
return weekCount;
}
u8 GetLeadMonFriendship(void)
{
struct Pokemon * pokemon = &gPlayerParty[GetLeadMonIndex()];

View File

@@ -1,6 +1,7 @@
#include "global.h"
#include "gflib.h"
#include "bike.h"
#include "clock.h"
#include "event_data.h"
#include "field_camera.h"
#include "field_effect_helpers.h"
@@ -69,18 +70,45 @@ static void Task_RunPerStepCallback(u8 taskId)
sPerStepCallbacks[idx](taskId);
}
// RTC functionality from RS was removed here.
#define tState data[0]
#define tAmbientCryState data[1]
#define tAmbientCryDelay data[2]
// RTC functionality from RS was removed here.
static void RunTimeBasedEvents(s16 *data)
{
switch (tState)
{
case 0:
if (*gMain.vblankCounter1 & 0x1000)
{
DoTimeBasedEvents();
tState++;
}
break;
case 1:
if (!(*gMain.vblankCounter1 & 0x1000))
{
tState--;
}
break;
}
}
static void Task_RunTimeBasedEvents(u8 taskId)
{
s16 *data = gTasks[taskId].data;
if (!ArePlayerFieldControlsLocked() && !QL_IS_PLAYBACK_STATE)
{
RunTimeBasedEvents(data);
UpdateAmbientCry(&tAmbientCryState, &tAmbientCryDelay);
}
}
#undef tState
void SetUpFieldTasks(void)
{
if (!FuncIsActiveTask(Task_RunPerStepCallback))

View File

@@ -1258,6 +1258,12 @@ const u16 gTilesetPalettes_General[][16] =
const u32 gTilesetTiles_General[] = INCBIN_U32("data/tilesets/primary/general/tiles.4bpp.lz");
const u16 gWallClockMale_Pal[] = INCBIN_U16("graphics/wallclock/male.gbapal");
const u16 gWallClockFemale_Pal[] = INCBIN_U16("graphics/wallclock/female.gbapal");
const u32 gWallClock_Gfx[] = INCBIN_U32("graphics/wallclock/clock.4bpp.lz");
const u32 gWallClockStart_Tilemap[] = INCBIN_U32("graphics/wallclock/clock_start.bin.lz");
const u32 gWallClockView_Tilemap[] = INCBIN_U32("graphics/wallclock/clock_view.bin.lz");
const u8 gBerryFixGameboy_Pal[] = INCBIN_U8("graphics/berry_fix/gba_small.gbapal");
const u8 gBerryFixGameboy_Gfx[] = INCBIN_U8("graphics/berry_fix/gba_small.4bpp.lz");
const u8 gBerryFixGameboy_Tilemap[] = INCBIN_U8("graphics/berry_fix/gba_small.bin.lz");

View File

@@ -14,6 +14,7 @@
#include "decompress.h"
#include "util.h"
#include "trig.h"
#include "load_save.h"
#include "constants/songs.h"
#include "constants/sound.h"
@@ -992,12 +993,15 @@ void CB2_InitCopyrightScreenAfterBootup(void)
{
if (!SetUpCopyrightScreen())
{
SeedRngAndSetTrainerId();
SetSaveBlocksPointers();
ResetMenuAndMonGlobals();
Save_ResetSaveCounters();
LoadGameSave(SAVE_NORMAL);
if (gSaveFileStatus == SAVE_STATUS_EMPTY || gSaveFileStatus == SAVE_STATUS_INVALID)
Sav2_ClearSetDefault();
SetPokemonCryStereo(gSaveBlock2Ptr->optionsSound);
InitHeap(gHeap, HEAP_SIZE);
}
}

View File

@@ -4,6 +4,7 @@
#include "link_rfu.h"
#include "load_save.h"
#include "m4a.h"
#include "rtc.h"
#include "random.h"
#include "gba/flash_internal.h"
#include "help_system.h"
@@ -130,6 +131,7 @@ void AgbMain()
m4aSoundInit();
EnableVCountIntrAtLine150();
InitRFU();
RtcInit();
CheckForFlashMemory();
InitMainCallbacks();
InitMapMusic();
@@ -463,6 +465,7 @@ void DoSoftReset(void)
DmaStop(1);
DmaStop(2);
DmaStop(3);
SiiRtcProtect();
SoftReset(RESET_ALL & ~RESET_SIO_REGS);
}

View File

@@ -5,6 +5,7 @@
#include "save.h"
#include "event_data.h"
#include "menu.h"
#include "rtc.h"
#include "link.h"
#include "oak_speech.h"
#include "overworld.h"
@@ -44,6 +45,8 @@ enum MainMenuWindow
static bool32 MainMenuGpuInit(u8 a0);
static void Task_SetWin0BldRegsAndCheckSaveFile(u8 taskId);
static void Task_MainMenuCheckBattery(u8);
static void Task_WaitForBatteryDryErrorWindow(u8);
static void PrintSaveErrorStatus(u8 taskId, const u8 *str);
static void Task_SaveErrorStatus_RunPrinterThenWaitButton(u8 taskId);
static void Task_SetWin0BldRegsNoSaveFileCheck(u8 taskId);
@@ -241,7 +244,8 @@ static void Task_SetWin0BldRegsAndCheckSaveFile(u8 taskId)
{
gTasks[taskId].tMenuType = MAIN_MENU_CONTINUE;
}
gTasks[taskId].func = Task_SetWin0BldRegsNoSaveFileCheck;
// gTasks[taskId].func = Task_SetWin0BldRegsNoSaveFileCheck;
gTasks[taskId].func = Task_MainMenuCheckBattery;
break;
case SAVE_STATUS_INVALID:
SetStdFrame0OnBg(0);
@@ -276,6 +280,67 @@ static void Task_SetWin0BldRegsAndCheckSaveFile(u8 taskId)
}
}
static void Task_MainMenuCheckBattery(u8 taskId)
{
if (!gPaletteFade.active)
{
SetGpuReg(REG_OFFSET_WIN0H, 0);
SetGpuReg(REG_OFFSET_WIN0V, 0);
SetGpuReg(REG_OFFSET_WININ, 0x0001);
SetGpuReg(REG_OFFSET_WINOUT, 0x0021);
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG0 | BLDCNT_TGT1_BG1 | BLDCNT_TGT1_BG2 | BLDCNT_TGT1_BG3 | BLDCNT_TGT1_OBJ | BLDCNT_TGT1_BD | BLDCNT_EFFECT_DARKEN);
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(0, 0));
SetGpuReg(REG_OFFSET_BLDY, 7);
if (!(RtcGetErrorStatus() & RTC_ERR_FLAG_MASK))
{
if(gTasks[taskId].tMenuType == MAIN_MENU_NEWGAME) {
LoadUserFrameToBg(0);
gTasks[taskId].tMenuType = MAIN_MENU_NEWGAME;
gTasks[taskId].func = Task_SetWin0BldRegsNoSaveFileCheck;
}
else {
gTasks[taskId].func = Task_SetWin0BldRegsNoSaveFileCheck;
}
}
else
{
SetStdFrame0OnBg(0);
PrintSaveErrorStatus(taskId, gText_BatteryRunDry);
gTasks[taskId].func = Task_WaitForBatteryDryErrorWindow;
}
}
}
static void Task_WaitForBatteryDryErrorWindow(u8 taskId)
{
if (!gPaletteFade.active)
{
RunTextPrinters();
if(gTasks[taskId].tUnused8 == 3)
{
if(!IsTextPrinterActive(MAIN_MENU_WINDOW_ERROR))
{
gTasks[taskId].func = Task_SetWin0BldRegsNoSaveFileCheck;
}
}
else
{
if (!IsTextPrinterActive(MAIN_MENU_WINDOW_ERROR) && JOY_NEW(A_BUTTON))
{
ClearWindowTilemap(MAIN_MENU_WINDOW_ERROR);
MainMenu_EraseWindow(&sWindowTemplate[MAIN_MENU_WINDOW_ERROR]);
LoadUserFrameToBg(0);
if (gTasks[taskId].tMenuType == MAIN_MENU_NEWGAME)
gTasks[taskId].func = Task_SetWin0BldRegsNoSaveFileCheck;
else
gTasks[taskId].func = Task_PrintMainMenuText;
}
}
}
}
static void PrintSaveErrorStatus(u8 taskId, const u8 *str)
{
PrintMessageOnWindow4(str);

View File

@@ -29,6 +29,8 @@
#include "berry_powder.h"
#include "pokemon_jump.h"
#include "event_scripts.h"
#include "save.h"
#include "rtc.h"
// this file's functions
static void ResetMiniGamesResults(void);
@@ -107,6 +109,9 @@ void ResetMenuAndMonGlobals(void)
void NewGameInitData(void)
{
u8 rivalName[PLAYER_NAME_LENGTH + 1];
if (gSaveFileStatus == SAVE_STATUS_EMPTY || gSaveFileStatus == SAVE_STATUS_INVALID)
RtcReset();
StringCopy(rivalName, gSaveBlock1Ptr->rivalName);
gDifferentSaveFile = TRUE;

View File

@@ -2,6 +2,7 @@
#include "gflib.h"
#include "bg_regs.h"
#include "cable_club.h"
#include "clock.h"
#include "credits.h"
#include "event_data.h"
#include "event_object_movement.h"
@@ -758,6 +759,7 @@ void LoadMapFromCameraTransition(u8 mapGroup, u8 mapNum)
ResetCyclingRoadChallengeData();
RestartWildEncounterImmunitySteps();
MapResetTrainerRematches(mapGroup, mapNum);
DoTimeBasedEvents();
SetSavedWeatherFromCurrMapHeader();
ChooseAmbientCrySpecies();
SetDefaultFlashLevel();
@@ -793,6 +795,7 @@ static void LoadMapFromWarp(bool32 unused)
ResetCyclingRoadChallengeData();
RestartWildEncounterImmunitySteps();
MapResetTrainerRematches(gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum);
DoTimeBasedEvents();
SetSavedWeatherFromCurrMapHeader();
ChooseAmbientCrySpecies();
if (isOutdoors)
@@ -815,6 +818,7 @@ static void QL_LoadMapNormal(void)
LoadObjEventTemplatesFromHeader();
isOutdoors = IsMapTypeOutdoors(gMapHeader.mapType);
TrySetMapSaveWarpStatus();
DoTimeBasedEvents();
SetSavedWeatherFromCurrMapHeader();
ChooseAmbientCrySpecies();
SetDefaultFlashLevel();
@@ -1684,6 +1688,7 @@ void CB2_ContinueSavedGame(void)
LoadSaveblockMapHeader();
LoadSaveblockObjEventScripts();
UnfreezeObjectEvents();
DoTimeBasedEvents();
Overworld_ResetStateOnContinue();
InitMapFromSavedGame();
PlayTimeCounter_Start();

View File

@@ -3,6 +3,7 @@
#include "global.h"
#include "gflib.h"
#include "random.h"
#include "rtc.h"
#include "text.h"
#include "data.h"
#include "battle.h"
@@ -4103,37 +4104,37 @@ u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 mode, u16 evolutionItem, s
targetSpecies = evolutions[i].targetSpecies;
break;
case EVO_FRIENDSHIP_DAY:
if (/*GetTimeOfDay() != TIME_NIGHT &&*/ friendship >= FRIENDSHIP_EVO_THRESHOLD)
if (GetTimeOfDay() != TIME_NIGHT && friendship >= FRIENDSHIP_EVO_THRESHOLD)
targetSpecies = evolutions[i].targetSpecies;
break;
case EVO_LEVEL_DAY:
if (/* GetTimeOfDay() != TIME_NIGHT && */ evolutions[i].param <= level)
if (GetTimeOfDay() != TIME_NIGHT && evolutions[i].param <= level)
targetSpecies = evolutions[i].targetSpecies;
break;
case EVO_FRIENDSHIP_NIGHT:
if (/* GetTimeOfDay() == TIME_NIGHT && */ friendship >= FRIENDSHIP_EVO_THRESHOLD)
if (GetTimeOfDay() == TIME_NIGHT && friendship >= FRIENDSHIP_EVO_THRESHOLD)
targetSpecies = evolutions[i].targetSpecies;
break;
case EVO_LEVEL_NIGHT:
if (/* GetTimeOfDay() == TIME_NIGHT && */ evolutions[i].param <= level)
if (GetTimeOfDay() == TIME_NIGHT && evolutions[i].param <= level)
targetSpecies = evolutions[i].targetSpecies;
break;
case EVO_ITEM_HOLD_NIGHT:
if (/* GetTimeOfDay() == TIME_NIGHT && */ heldItem == evolutions[i].param)
if (GetTimeOfDay() == TIME_NIGHT && heldItem == evolutions[i].param)
{
targetSpecies = evolutions[i].targetSpecies;
consumeItem = TRUE;
}
break;
case EVO_ITEM_HOLD_DAY:
if (/* GetTimeOfDay() != TIME_NIGHT && */ heldItem == evolutions[i].param)
if (GetTimeOfDay() != TIME_NIGHT && heldItem == evolutions[i].param)
{
targetSpecies = evolutions[i].targetSpecies;
consumeItem = TRUE;
}
break;
case EVO_LEVEL_DUSK:
if (/* GetTimeOfDay() == TIME_EVENING && */ evolutions[i].param <= level)
if (GetTimeOfDay() == TIME_EVENING && evolutions[i].param <= level)
targetSpecies = evolutions[i].targetSpecies;
break;
case EVO_LEVEL:
@@ -4374,11 +4375,11 @@ u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 mode, u16 evolutionItem, s
targetSpecies = evolutions[i].targetSpecies;
break;
case EVO_ITEM_NIGHT:
if (/* GetTimeOfDay() == TIME_NIGHT && */ evolutions[i].param == evolutionItem)
if (GetTimeOfDay() == TIME_NIGHT && evolutions[i].param == evolutionItem)
targetSpecies = evolutions[i].targetSpecies;
break;
case EVO_ITEM_DAY:
if (/* GetTimeOfDay() != TIME_NIGHT && */ evolutions[i].param == evolutionItem)
if (GetTimeOfDay() != TIME_NIGHT && evolutions[i].param == evolutionItem)
targetSpecies = evolutions[i].targetSpecies;
break;
}
@@ -4949,14 +4950,44 @@ u16 GetMonEVCount(struct Pokemon *mon)
return count;
}
// This function was stubbed from RS, but it is stubbed badly.
// This variable is likely the u8 passed to SetMonData in RSE.
// The pointer reference causes agbcc to reserve it on the stack before even checking
// whether it's used.
void RandomlyGivePartyPokerus(struct Pokemon *party)
{
u8 foo;
&foo;
u16 rnd = Random();
if (rnd == 0x4000 || rnd == 0x8000 || rnd == 0xC000)
{
struct Pokemon *mon;
do
{
do
{
rnd = Random() % PARTY_SIZE;
mon = &party[rnd];
}
while (!GetMonData(mon, MON_DATA_SPECIES, 0));
}
while (GetMonData(mon, MON_DATA_IS_EGG, 0));
if (!(CheckPartyHasHadPokerus(party, gBitTable[rnd])))
{
u8 rnd2;
do
{
rnd2 = Random();
}
while ((rnd2 & 0x7) == 0);
if (rnd2 & 0xF0)
rnd2 &= 0x7;
rnd2 |= (rnd2 << 4);
rnd2 &= 0xF3;
rnd2++;
SetMonData(&party[rnd], MON_DATA_POKERUS, &rnd2);
}
}
}
u8 CheckPartyPokerus(struct Pokemon *party, u8 selection)
@@ -5017,16 +5048,58 @@ u8 CheckPartyHasHadPokerus(struct Pokemon *party, u8 selection)
// These two functions are stubbed from RS, but they're stubbed badly.
// See note on RandomlyGivePartyPokerus above.
static void UpdatePartyPokerusTime(void)
void UpdatePartyPokerusTime(u16 days)
{
u8 foo;
&foo;
int i;
for (i = 0; i < PARTY_SIZE; i++)
{
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES, 0))
{
u8 pokerus = GetMonData(&gPlayerParty[i], MON_DATA_POKERUS, 0);
if (pokerus & 0xF)
{
if ((pokerus & 0xF) < days || days > 4)
pokerus &= 0xF0;
else
pokerus -= days;
if (pokerus == 0)
pokerus = 0x10;
SetMonData(&gPlayerParty[i], MON_DATA_POKERUS, &pokerus);
}
}
}
}
void PartySpreadPokerus(struct Pokemon *party)
{
u8 foo;
&foo;
if ((Random() % 3) == 0)
{
int i;
for (i = 0; i < PARTY_SIZE; i++)
{
if (GetMonData(&party[i], MON_DATA_SPECIES, 0))
{
u8 pokerus = GetMonData(&party[i], MON_DATA_POKERUS, 0);
u8 curPokerus = pokerus;
if (pokerus)
{
if (pokerus & 0xF)
{
// Spread to adjacent party members.
if (i != 0 && !(GetMonData(&party[i - 1], MON_DATA_POKERUS, 0) & 0xF0))
SetMonData(&party[i - 1], MON_DATA_POKERUS, &curPokerus);
if (i != (PARTY_SIZE - 1) && !(GetMonData(&party[i + 1], MON_DATA_POKERUS, 0) & 0xF0))
{
SetMonData(&party[i + 1], MON_DATA_POKERUS, &curPokerus);
i++;
}
}
}
}
}
}
}
static void SetMonExpWithMaxLevelCheck(struct Pokemon *mon, int species, u8 unused, u32 data)
@@ -5926,18 +5999,15 @@ u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *boxMon, u16 method, u32
case FORM_CHANGE_ITEM_USE:
if (arg == formChanges[i].param1)
{
// TODO: time
switch (formChanges[i].param2)
{
case DAY:
// if (GetTimeOfDay() != TIME_NIGHT)
// targetSpecies = formChanges[i].targetSpecies;
targetSpecies = SPECIES_NONE;
if (GetTimeOfDay() != TIME_NIGHT)
targetSpecies = formChanges[i].targetSpecies;
break;
case NIGHT:
// if (GetTimeOfDay() == TIME_NIGHT)
// targetSpecies = formChanges[i].targetSpecies;
targetSpecies = SPECIES_NONE;
if (GetTimeOfDay() == TIME_NIGHT)
targetSpecies = formChanges[i].targetSpecies;
break;
default:
targetSpecies = formChanges[i].targetSpecies;
@@ -5971,20 +6041,17 @@ u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *boxMon, u16 method, u32
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_TIME_OF_DAY:
// TODO: time
// switch (formChanges[i].param1)
// {
// case DAY:
// if (GetTimeOfDay() != TIME_NIGHT)
// targetSpecies = formChanges[i].targetSpecies;
// break;
// case NIGHT:
// if (GetTimeOfDay() == TIME_NIGHT)
// targetSpecies = formChanges[i].targetSpecies;
// break;
// }
// break;
targetSpecies = SPECIES_NONE;
switch (formChanges[i].param1)
{
case DAY:
if (GetTimeOfDay() != TIME_NIGHT)
targetSpecies = formChanges[i].targetSpecies;
break;
case NIGHT:
if (GetTimeOfDay() == TIME_NIGHT)
targetSpecies = formChanges[i].targetSpecies;
break;
}
break;
}
}

766
src/reset_rtc_screen.c Normal file
View File

@@ -0,0 +1,766 @@
#include "global.h"
#include "reset_rtc_screen.h"
#include "new_menu_helpers.h"
#include "event_data.h"
#include "main.h"
#include "menu.h"
#include "palette.h"
#include "rtc.h"
#include "save.h"
#include "sprite.h"
#include "constants/songs.h"
#include "sound.h"
#include "string_util.h"
#include "strings.h"
#include "task.h"
#include "text.h"
#include "text_window.h"
#include "scanline_effect.h"
#include "bg.h"
#include "window.h"
#include "gpu_regs.h"
#include "constants/rgb.h"
#define PALTAG_ARROW 0x1000
// Task data for the Task_ResetRtc_* series of tasks, when setting the time on the clock
// Data from these tasks is also used by the cursors and the main task (Task_ResetRtcScreen)
enum {
DATAIDX_DAYS = 3,
DATAIDX_HOURS,
DATAIDX_MINS,
DATAIDX_SECS,
DATAIDX_CONFIRM,
};
#define tFinished data[0]
#define tSetTime data[1]
#define tSelection data[2]
#define tDays data[DATAIDX_DAYS]
#define tHours data[DATAIDX_HOURS]
#define tMinutes data[DATAIDX_MINS]
#define tSeconds data[DATAIDX_SECS]
#define tConfirm data[DATAIDX_CONFIRM]
#define tWindowId data[8]
enum {
SELECTION_DAYS = 1,
SELECTION_HOURS,
SELECTION_MINS,
SELECTION_SECS,
SELECTION_CONFIRM,
SELECTION_NONE
};
enum {
WIN_TIME,
WIN_MSG,
};
struct ResetRtcInputMap
{
/*0x0*/ u8 dataIndex;
/*0x2*/ u16 minVal;
/*0x4*/ u16 maxVal;
/*0x6*/ u8 left;
/*0x7*/ u8 right;
/*0x8*/ u8 unk; // never read
};
static void CB2_ResetRtcScreen(void);
static void VBlankCB(void);
static void Task_ResetRtcScreen(u8 taskId);
static void InitResetRtcScreenBgAndWindows(void);
static const struct BgTemplate sBgTemplates[] =
{
{
.bg = 0,
.charBaseIndex = 0,
.mapBaseIndex = 31,
.screenSize = 0,
.paletteMode = 0,
.priority = 0,
.baseTile = 0
}
};
static const struct WindowTemplate sWindowTemplates[] =
{
[WIN_TIME] = {
.bg = 0,
.tilemapLeft = 1,
.tilemapTop = 1,
.width = 19,
.height = 9,
.paletteNum = 15,
.baseBlock = 0x155
},
[WIN_MSG] = {
.bg = 0,
.tilemapLeft = 2,
.tilemapTop = 15,
.width = 27,
.height = 4,
.paletteNum = 15,
.baseBlock = 0xE9
},
DUMMY_WIN_TEMPLATE
};
static const struct WindowTemplate sInputTimeWindow = {
.bg = 0,
.tilemapLeft = 4,
.tilemapTop = 9,
.width = 21,
.height = 2,
.paletteNum = 15,
.baseBlock = 0xBF
};
static const struct ResetRtcInputMap sInputMap[] =
{
[SELECTION_DAYS - 1] = {
.dataIndex = DATAIDX_DAYS,
.minVal = 1,
.maxVal = 9999,
.left = 0,
.right = 2,
.unk = 0,
},
[SELECTION_HOURS - 1] = {
.dataIndex = DATAIDX_HOURS,
.minVal = 0,
.maxVal = 23,
.left = 1,
.right = 3,
.unk = 0,
},
[SELECTION_MINS - 1] = {
.dataIndex = DATAIDX_MINS,
.minVal = 0,
.maxVal = 59,
.left = 2,
.right = 4,
.unk = 0,
},
[SELECTION_SECS - 1] = {
.dataIndex = DATAIDX_SECS,
.minVal = 0,
.maxVal = 59,
.left = 3,
.right = 5,
.unk = 0,
},
[SELECTION_CONFIRM - 1] = {
.dataIndex = DATAIDX_CONFIRM,
.minVal = 0,
.maxVal = 0,
.left = 4,
.right = 0,
.unk = 6,
},
};
static const struct OamData sOamData_Arrow =
{
.y = 0,
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_NORMAL,
.mosaic = FALSE,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(8x8),
.x = 0,
.matrixNum = 0,
.size = SPRITE_SIZE(8x8),
.tileNum = 0,
.priority = 0,
.paletteNum = 0,
.affineParam = 0,
};
static const u8 sResetRtcScreen_DownArrowGfx[] = INCBIN_U8("graphics/misc/reset_rtc_screen_downarrow.4bpp");
static const u8 sResetRtcScreen_RightArrowGfx[] = INCBIN_U8("graphics/misc/reset_rtc_screen_rightarrow.4bpp");
static const u16 sResetRtcScreen_ArrowPal[] = INCBIN_U16("graphics/misc/reset_rtc_screen_arrow.gbapal");
// static const u8 sArrowDown_Gfx[] = INCBIN_U8("graphics/reset_rtc_screen/arrow_down.4bpp");
// static const u8 sArrowRight_Gfx[] = INCBIN_U8("graphics/reset_rtc_screen/arrow_right.4bpp");
// static const u16 sArrow_Pal[] = INCBIN_U16("graphics/reset_rtc_screen/arrow.gbapal");
static const struct SpriteFrameImage sPicTable_Arrow[] =
{
obj_frame_tiles(sResetRtcScreen_DownArrowGfx),
obj_frame_tiles(sResetRtcScreen_RightArrowGfx)
};
const struct SpritePalette gSpritePalette_Arrow =
{
sResetRtcScreen_ArrowPal, PALTAG_ARROW
};
static const union AnimCmd sAnim_Arrow_Down[] =
{
ANIMCMD_FRAME(0, 30),
ANIMCMD_JUMP(0),
};
static const union AnimCmd sAnim_Arrow_Up[] =
{
ANIMCMD_FRAME(0, 30, .vFlip = TRUE),
ANIMCMD_JUMP(0),
};
static const union AnimCmd sAnim_Arrow_Right[] =
{
ANIMCMD_FRAME(1, 30),
ANIMCMD_JUMP(0),
};
enum {
ARROW_DOWN,
ARROW_UP,
ARROW_RIGHT,
};
static const union AnimCmd *const sAnims_Arrow[] =
{
[ARROW_DOWN] = sAnim_Arrow_Down,
[ARROW_UP] = sAnim_Arrow_Up,
[ARROW_RIGHT] = sAnim_Arrow_Right,
};
const struct SpriteTemplate gSpriteTemplate_Arrow =
{
.tileTag = TAG_NONE,
.paletteTag = PALTAG_ARROW,
.oam = &sOamData_Arrow,
.anims = sAnims_Arrow,
.images = sPicTable_Arrow,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCallbackDummy,
};
#define sTaskId data[0]
#define sState data[1]
static void SpriteCB_Cursor_UpOrRight(struct Sprite *sprite)
{
int state = gTasks[sprite->sTaskId].tSelection;
if (state != sprite->sState)
{
sprite->sState = state;
switch (state)
{
case SELECTION_DAYS:
sprite->invisible = FALSE;
sprite->animNum = ARROW_UP;
sprite->animDelayCounter = 0;
sprite->x = 53;
sprite->y = 68;
break;
case SELECTION_HOURS:
sprite->invisible = FALSE;
sprite->animNum = ARROW_UP;
sprite->animDelayCounter = 0;
sprite->x = 86;
sprite->y = 68;
break;
case SELECTION_MINS:
sprite->invisible = FALSE;
sprite->animNum = ARROW_UP;
sprite->animDelayCounter = 0;
sprite->x = 101;
sprite->y = 68;
break;
case SELECTION_SECS:
sprite->invisible = FALSE;
sprite->animNum = ARROW_UP;
sprite->animDelayCounter = 0;
sprite->x = 116;
sprite->y = 68;
break;
case SELECTION_CONFIRM:
sprite->invisible = FALSE;
sprite->animNum = ARROW_RIGHT;
sprite->animDelayCounter = 0;
sprite->x = 153;
sprite->y = 80;
break;
case SELECTION_NONE:
DestroySprite(sprite);
break;
}
}
}
static void SpriteCB_Cursor_Down(struct Sprite *sprite)
{
int state = gTasks[sprite->sTaskId].tSelection;
if (state != sprite->sState)
{
sprite->sState = state;
switch (state)
{
case SELECTION_DAYS:
sprite->invisible = FALSE;
sprite->animNum = ARROW_DOWN;
sprite->animDelayCounter = 0;
sprite->x = 53;
sprite->y = 92;
break;
case SELECTION_HOURS:
sprite->invisible = FALSE;
sprite->animNum = ARROW_DOWN;
sprite->animDelayCounter = 0;
sprite->x = 86;
sprite->y = 92;
break;
case SELECTION_MINS:
sprite->invisible = FALSE;
sprite->animNum = ARROW_DOWN;
sprite->animDelayCounter = 0;
sprite->x = 101;
sprite->y = 92;
break;
case SELECTION_SECS:
sprite->invisible = FALSE;
sprite->animNum = ARROW_DOWN;
sprite->animDelayCounter = 0;
sprite->x = 116;
sprite->y = 92;
break;
case SELECTION_CONFIRM:
// The up arrow is used as a right arrow when Confirm is selected
// Hide the down arrow
sprite->invisible = TRUE;
break;
case SELECTION_NONE:
DestroySprite(sprite);
break;
}
}
}
static void CreateCursor(u8 taskId)
{
u32 spriteId;
LoadSpritePalette(&gSpritePalette_Arrow);
spriteId = CreateSpriteAtEnd(&gSpriteTemplate_Arrow, 53, 68, 0);
gSprites[spriteId].callback = SpriteCB_Cursor_UpOrRight;
gSprites[spriteId].sTaskId = taskId;
gSprites[spriteId].sState = -1;
spriteId = CreateSpriteAtEnd(&gSpriteTemplate_Arrow, 53, 68, 0);
gSprites[spriteId].callback = SpriteCB_Cursor_Down;
gSprites[spriteId].sTaskId = taskId;
gSprites[spriteId].sState = -1;
}
static void FreeCursorPalette(void)
{
FreeSpritePaletteByTag(gSpritePalette_Arrow.tag);
}
static void HideChooseTimeWindow(u8 windowId)
{
ClearStdWindowAndFrameToTransparent(windowId, FALSE);
RemoveWindow(windowId);
ScheduleBgCopyTilemapToVram(0);
}
static void PrintTime(u8 windowId, u8 x, u8 y, u16 days, u8 hours, u8 minutes, u8 seconds)
{
u8 *dest = gStringVar4;
// Print days
ConvertIntToDecimalStringN(gStringVar1, days, STR_CONV_MODE_RIGHT_ALIGN, 4);
dest = StringCopy(dest, gStringVar1);
dest = StringCopy(dest, gText_Day);
// Print hours
ConvertIntToDecimalStringN(gStringVar1, hours, STR_CONV_MODE_RIGHT_ALIGN, 3);
dest = StringCopy(dest, gStringVar1);
dest = StringCopy(dest, gText_Colon3);
// Print minutes
ConvertIntToDecimalStringN(gStringVar1, minutes, STR_CONV_MODE_LEADING_ZEROS, 2);
dest = StringCopy(dest, gStringVar1);
dest = StringCopy(dest, gText_Colon3);
// Print seconds
ConvertIntToDecimalStringN(gStringVar1, seconds, STR_CONV_MODE_LEADING_ZEROS, 2);
dest = StringCopy(dest, gStringVar1);
AddTextPrinterParameterized(windowId, FONT_NORMAL, gStringVar4, x, y, TEXT_SKIP_DRAW, NULL);
}
static void ShowChooseTimeWindow(u8 windowId, u16 days, u8 hours, u8 minutes, u8 seconds)
{
DrawStdFrameWithCustomTileAndPalette(windowId, FALSE, 0x214, 0xE);
PrintTime(windowId, 0, 1, days, hours, minutes, seconds);
AddTextPrinterParameterized(windowId, FONT_NORMAL, gText_Confirm2, 126, 1, 0, NULL);
ScheduleBgCopyTilemapToVram(0);
}
static bool32 MoveTimeUpDown(s16 *val, int minVal, int maxVal, u16 keys)
{
if (keys & DPAD_DOWN)
{
*val -= 1;
if (*val < minVal)
*val = maxVal;
}
else if (keys & DPAD_UP)
{
*val += 1;
if (*val > maxVal)
*val = minVal;
}
else if (keys & DPAD_LEFT)
{
*val -= 10;
if (*val < minVal)
*val = maxVal;
}
else if (keys & DPAD_RIGHT)
{
*val += 10;
if (*val > maxVal)
*val = minVal;
}
else
{
return FALSE;
}
return TRUE;
}
static void Task_ResetRtc_SetFinished(u8 taskId)
{
gTasks[taskId].tFinished = TRUE;
}
static void Task_ResetRtc_Exit(u8 taskId)
{
s16 *data = gTasks[taskId].data;
HideChooseTimeWindow(tWindowId);
FreeCursorPalette();
gTasks[taskId].func = Task_ResetRtc_SetFinished;
}
static void Task_ResetRtc_HandleInput(u8 taskId)
{
s16 *data = gTasks[taskId].data;
u8 selection = tSelection;
const struct ResetRtcInputMap *selectionInfo = &sInputMap[selection - 1];
if (JOY_NEW(B_BUTTON))
{
gTasks[taskId].func = Task_ResetRtc_Exit;
tSetTime = FALSE;
tSelection = SELECTION_NONE;
PlaySE(SE_SELECT);
return;
}
if (JOY_NEW(DPAD_RIGHT))
{
if (selectionInfo->right)
{
tSelection = selectionInfo->right;
PlaySE(SE_SELECT);
return;
}
}
if (JOY_NEW(DPAD_LEFT))
{
if (selectionInfo->left)
{
tSelection = selectionInfo->left;
PlaySE(SE_SELECT);
return;
}
}
if (selection == SELECTION_CONFIRM)
{
if (JOY_NEW(A_BUTTON))
{
gLocalTime.days = tDays;
gLocalTime.hours = tHours;
gLocalTime.minutes = tMinutes;
gLocalTime.seconds = tSeconds;
PlaySE(SE_SELECT);
gTasks[taskId].func = Task_ResetRtc_Exit;
tSetTime = TRUE;
tSelection = SELECTION_NONE;
}
}
else if (MoveTimeUpDown(&data[selectionInfo->dataIndex], selectionInfo->minVal, selectionInfo->maxVal, JOY_REPT(DPAD_UP | DPAD_DOWN)))
{
PlaySE(SE_SELECT);
PrintTime(tWindowId, 0, 1, tDays, tHours, tMinutes, tSeconds);
CopyWindowToVram(tWindowId, COPYWIN_GFX);
}
}
static void Task_ResetRtc_Init(u8 taskId)
{
s16 *data = gTasks[taskId].data;
tFinished = FALSE;
tDays = gLocalTime.days;
tHours = gLocalTime.hours;
tMinutes = gLocalTime.minutes;
tSeconds = gLocalTime.seconds;
tWindowId = AddWindow(&sInputTimeWindow);
ShowChooseTimeWindow(tWindowId, tDays, tHours, tMinutes, tSeconds);
CreateCursor(taskId);
tSelection = SELECTION_HOURS;
gTasks[taskId].func = Task_ResetRtc_HandleInput;
}
void CB2_InitResetRtcScreen(void)
{
#ifdef FIRERED
FillPalette(RGB(30, 18, 11), 0, PLTT_SIZE);
#endif
#ifdef LEAFGREEN
FillPalette(RGB(23, 28, 11), 0, PLTT_SIZE);
#endif
BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, RGB_BLACK);
SetGpuReg(REG_OFFSET_DISPCNT, 0);
SetGpuReg(REG_OFFSET_BLDY, 0);
ResetBgsAndClearDma3BusyFlags(FALSE);
ChangeBgX(0, 0, 0);
ChangeBgY(0, 0, 0);
ChangeBgX(1, 0, 0);
ChangeBgY(1, 0, 0);
ChangeBgX(2, 0, 0);
ChangeBgY(2, 0, 0);
ChangeBgX(3, 0, 0);
ChangeBgY(3, 0, 0);
DeactivateAllTextPrinters();
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON);
ShowBg(0);
DmaClear16(3, PLTT, PLTT_SIZE);
DmaFillLarge16(3, 0, (u8 *)VRAM, VRAM_SIZE, 0x1000);
ResetOamRange(0, 128);
LoadOam();
ScanlineEffect_Stop();
ScanlineEffect_Clear();
ResetSpriteData();
ResetTasks();
ResetPaletteFade();
InitResetRtcScreenBgAndWindows();
SetVBlankCallback(VBlankCB);
SetMainCallback2(CB2_ResetRtcScreen);
CreateTask(Task_ResetRtcScreen, 80);
}
static void InitResetRtcScreenBgAndWindows(void)
{
ClearScheduledBgCopiesToVram();
ResetBgsAndClearDma3BusyFlags(0);
InitBgsFromTemplates(0, sBgTemplates, ARRAY_COUNT(sBgTemplates));
ScheduleBgCopyTilemapToVram(0);
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP);
ShowBg(0);
InitWindows(sWindowTemplates);
DeactivateAllTextPrinters();
LoadStdWindowFrameGfx();
}
static void CB2_ResetRtcScreen(void)
{
RunTasks();
AnimateSprites();
BuildOamBuffer();
DoScheduledBgTilemapCopiesToVram();
UpdatePaletteFade();
}
static void VBlankCB(void)
{
ProcessSpriteCopyRequests();
LoadOam();
TransferPlttBuffer();
}
static void ShowMessage(const u8 *str)
{
DrawDialogFrameWithCustomTileAndPalette(WIN_MSG, FALSE, 0x200, 0xF);
AddTextPrinterParameterized(WIN_MSG, FONT_NORMAL, str, 0, 1, 0, NULL);
ScheduleBgCopyTilemapToVram(0);
}
#define tState data[0]
static void Task_ShowResetRtcPrompt(u8 taskId)
{
s16 *data = gTasks[taskId].data;
switch (tState)
{
case 0:
DrawStdFrameWithCustomTileAndPalette(WIN_TIME, FALSE, 0x214, 0xE);
AddTextPrinterParameterized(WIN_TIME, FONT_NORMAL, gText_PresentTime, 0, 1, TEXT_SKIP_DRAW, 0);
PrintTime(
WIN_TIME,
0,
17,
gLocalTime.days,
gLocalTime.hours,
gLocalTime.minutes,
gLocalTime.seconds);
AddTextPrinterParameterized(WIN_TIME, FONT_NORMAL, gText_PreviousTime, 0, 33, TEXT_SKIP_DRAW, 0);
PrintTime(
WIN_TIME,
0,
49,
gSaveBlock2Ptr->lastBerryTreeUpdate.days,
gSaveBlock2Ptr->lastBerryTreeUpdate.hours,
gSaveBlock2Ptr->lastBerryTreeUpdate.minutes,
gSaveBlock2Ptr->lastBerryTreeUpdate.seconds);
ShowMessage(gText_ResetRTCConfirmCancel);
CopyWindowToVram(WIN_TIME, COPYWIN_GFX);
ScheduleBgCopyTilemapToVram(0);
tState++;
case 1:
if (JOY_NEW(B_BUTTON))
{
// Cancel, exit without resetting RTC
DestroyTask(taskId);
DoSoftReset();
}
else if (JOY_NEW(A_BUTTON))
{
// Confirm
PlaySE(SE_SELECT);
DestroyTask(taskId);
}
break;
}
}
#undef tState
// Task states for Task_ResetRtcScreen
enum {
MAINSTATE_FADE_IN,
MAINSTATE_CHECK_SAVE,
MAINSTATE_START_SET_TIME,
MAINSTATE_WAIT_SET_TIME,
MAINSTATE_SAVE,
MAINSTATE_WAIT_EXIT,
MAINSTATE_EXIT,
};
#define tState data[0]
#define tSubTaskId data[1]
static void Task_ResetRtcScreen(u8 taskId)
{
s16 *data = gTasks[taskId].data;
switch (tState)
{
case MAINSTATE_FADE_IN:
BeginNormalPaletteFade(PALETTES_ALL, 1, 0x10, 0, RGB_WHITEALPHA);
tState = MAINSTATE_CHECK_SAVE;
break;
case MAINSTATE_CHECK_SAVE:
if (!gPaletteFade.active)
{
if (gSaveFileStatus == SAVE_STATUS_EMPTY
|| gSaveFileStatus == SAVE_STATUS_INVALID)
{
ShowMessage(gText_NoSaveFileCantSetTime);
tState = MAINSTATE_WAIT_EXIT;
}
else
{
RtcCalcLocalTime();
tSubTaskId = CreateTask(Task_ShowResetRtcPrompt, 80);
tState = MAINSTATE_START_SET_TIME;
}
}
break;
case MAINSTATE_START_SET_TIME:
// Wait for A or B press on prompt first
if (gTasks[tSubTaskId].isActive != TRUE)
{
ClearStdWindowAndFrameToTransparent(WIN_TIME, FALSE);
ShowMessage(gText_PleaseResetTime);
gLocalTime = gSaveBlock2Ptr->lastBerryTreeUpdate;
tSubTaskId = CreateTask(Task_ResetRtc_Init, 80);
tState = MAINSTATE_WAIT_SET_TIME;
}
break;
case MAINSTATE_WAIT_SET_TIME:
if (gTasks[tSubTaskId].tFinished)
{
if (!gTasks[tSubTaskId].tSetTime)
{
// Exited without setting time, return to "Please reset time"
DestroyTask(tSubTaskId);
tState = MAINSTATE_START_SET_TIME;
}
else
{
// Time has been chosen, reset rtc and save
DestroyTask(tSubTaskId);
RtcReset();
RtcCalcLocalTimeOffset(
gLocalTime.days,
gLocalTime.hours,
gLocalTime.minutes,
gLocalTime.seconds);
gSaveBlock2Ptr->lastBerryTreeUpdate = gLocalTime;
VarSet(VAR_DAYS, gLocalTime.days);
DisableResetRTC();
ShowMessage(gText_ClockHasBeenReset);
tState = MAINSTATE_SAVE;
}
}
break;
case MAINSTATE_SAVE:
if (TrySavingData(SAVE_NORMAL) == SAVE_STATUS_OK)
{
ShowMessage(gText_SaveCompleted);
PlaySE(SE_DING_DONG);
}
else
{
ShowMessage(gText_SaveFailed);
PlaySE(SE_BOO);
}
tState = MAINSTATE_WAIT_EXIT;
// fallthrough
case MAINSTATE_WAIT_EXIT:
if (JOY_NEW(A_BUTTON))
{
BeginNormalPaletteFade(PALETTES_ALL, 1, 0, 0x10, RGB_WHITEALPHA);
tState = MAINSTATE_EXIT;
// fallthrough
}
else
{
break;
}
case MAINSTATE_EXIT:
if (!gPaletteFade.active)
{
DestroyTask(taskId);
FreeAllWindowBuffers();
DoSoftReset();
}
}
}

366
src/rtc.c Normal file
View File

@@ -0,0 +1,366 @@
#include "global.h"
#include "rtc.h"
#include "string_util.h"
#include "text.h"
// iwram bss
static u16 sErrorStatus;
static struct SiiRtcInfo sRtc;
static u8 sProbeResult;
static u16 sSavedIme;
// iwram common
struct Time gLocalTime;
// const rom
static const struct SiiRtcInfo sRtcDummy = {0, MONTH_JAN, 1}; // 2000 Jan 1
static const s32 sNumDaysInMonths[12] =
{
31,
28,
31,
30,
31,
30,
31,
31,
30,
31,
30,
31,
};
void RtcDisableInterrupts(void)
{
sSavedIme = REG_IME;
REG_IME = 0;
}
void RtcRestoreInterrupts(void)
{
REG_IME = sSavedIme;
}
u32 ConvertBcdToBinary(u8 bcd)
{
if (bcd > 0x9F)
return 0xFF;
if ((bcd & 0xF) <= 9)
return (10 * ((bcd >> 4) & 0xF)) + (bcd & 0xF);
else
return 0xFF;
}
bool8 IsLeapYear(u32 year)
{
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
return TRUE;
return FALSE;
}
u16 ConvertDateToDayCount(u8 year, u8 month, u8 day)
{
s32 i;
u16 dayCount = 0;
for (i = year - 1; i >= 0; i--)
{
dayCount += 365;
if (IsLeapYear(i) == TRUE)
dayCount++;
}
for (i = 0; i < month - 1; i++)
dayCount += sNumDaysInMonths[i];
if (month > MONTH_FEB && IsLeapYear(year) == TRUE)
dayCount++;
dayCount += day;
return dayCount;
}
u16 RtcGetDayCount(struct SiiRtcInfo *rtc)
{
u8 year = ConvertBcdToBinary(rtc->year);
u8 month = ConvertBcdToBinary(rtc->month);
u8 day = ConvertBcdToBinary(rtc->day);
return ConvertDateToDayCount(year, month, day);
}
void RtcInit(void)
{
sErrorStatus = 0;
RtcDisableInterrupts();
SiiRtcUnprotect();
sProbeResult = SiiRtcProbe();
RtcRestoreInterrupts();
if ((sProbeResult & 0xF) != 1)
{
sErrorStatus = RTC_INIT_ERROR;
return;
}
if (sProbeResult & 0xF0)
sErrorStatus = RTC_INIT_WARNING;
else
sErrorStatus = 0;
RtcGetRawInfo(&sRtc);
sErrorStatus = RtcCheckInfo(&sRtc);
}
u16 RtcGetErrorStatus(void)
{
return sErrorStatus;
}
void RtcGetInfo(struct SiiRtcInfo *rtc)
{
if (sErrorStatus & RTC_ERR_FLAG_MASK)
*rtc = sRtcDummy;
else
RtcGetRawInfo(rtc);
}
void RtcGetDateTime(struct SiiRtcInfo *rtc)
{
RtcDisableInterrupts();
SiiRtcGetDateTime(rtc);
RtcRestoreInterrupts();
}
void RtcGetStatus(struct SiiRtcInfo *rtc)
{
RtcDisableInterrupts();
SiiRtcGetStatus(rtc);
RtcRestoreInterrupts();
}
void RtcGetRawInfo(struct SiiRtcInfo *rtc)
{
RtcGetStatus(rtc);
RtcGetDateTime(rtc);
}
u16 RtcCheckInfo(struct SiiRtcInfo *rtc)
{
u16 errorFlags = 0;
s32 year;
s32 month;
s32 value;
if (rtc->status & SIIRTCINFO_POWER)
errorFlags |= RTC_ERR_POWER_FAILURE;
if (!(rtc->status & SIIRTCINFO_24HOUR))
errorFlags |= RTC_ERR_12HOUR_CLOCK;
year = ConvertBcdToBinary(rtc->year);
if (year == 0xFF)
errorFlags |= RTC_ERR_INVALID_YEAR;
month = ConvertBcdToBinary(rtc->month);
if (month == 0xFF || month == 0 || month > 12)
errorFlags |= RTC_ERR_INVALID_MONTH;
value = ConvertBcdToBinary(rtc->day);
if (value == 0xFF)
errorFlags |= RTC_ERR_INVALID_DAY;
if (month == MONTH_FEB)
{
if (value > IsLeapYear(year) + sNumDaysInMonths[month - 1])
errorFlags |= RTC_ERR_INVALID_DAY;
}
else
{
if (value > sNumDaysInMonths[month - 1])
errorFlags |= RTC_ERR_INVALID_DAY;
}
value = ConvertBcdToBinary(rtc->hour);
if (value > 24)
errorFlags |= RTC_ERR_INVALID_HOUR;
value = ConvertBcdToBinary(rtc->minute);
if (value > 60)
errorFlags |= RTC_ERR_INVALID_MINUTE;
value = ConvertBcdToBinary(rtc->second);
if (value > 60)
errorFlags |= RTC_ERR_INVALID_SECOND;
return errorFlags;
}
void RtcReset(void)
{
RtcDisableInterrupts();
SiiRtcReset();
RtcRestoreInterrupts();
}
void FormatDecimalTime(u8 *dest, s32 hour, s32 minute, s32 second)
{
dest = ConvertIntToDecimalStringN(dest, hour, STR_CONV_MODE_LEADING_ZEROS, 2);
*dest++ = CHAR_COLON;
dest = ConvertIntToDecimalStringN(dest, minute, STR_CONV_MODE_LEADING_ZEROS, 2);
*dest++ = CHAR_COLON;
dest = ConvertIntToDecimalStringN(dest, second, STR_CONV_MODE_LEADING_ZEROS, 2);
*dest = EOS;
}
void FormatHexTime(u8 *dest, s32 hour, s32 minute, s32 second)
{
dest = ConvertIntToHexStringN(dest, hour, STR_CONV_MODE_LEADING_ZEROS, 2);
*dest++ = CHAR_COLON;
dest = ConvertIntToHexStringN(dest, minute, STR_CONV_MODE_LEADING_ZEROS, 2);
*dest++ = CHAR_COLON;
dest = ConvertIntToHexStringN(dest, second, STR_CONV_MODE_LEADING_ZEROS, 2);
*dest = EOS;
}
void FormatHexRtcTime(u8 *dest)
{
FormatHexTime(dest, sRtc.hour, sRtc.minute, sRtc.second);
}
void FormatDecimalDate(u8 *dest, s32 year, s32 month, s32 day)
{
dest = ConvertIntToDecimalStringN(dest, year, STR_CONV_MODE_LEADING_ZEROS, 4);
*dest++ = CHAR_HYPHEN;
dest = ConvertIntToDecimalStringN(dest, month, STR_CONV_MODE_LEADING_ZEROS, 2);
*dest++ = CHAR_HYPHEN;
dest = ConvertIntToDecimalStringN(dest, day, STR_CONV_MODE_LEADING_ZEROS, 2);
*dest = EOS;
}
void FormatHexDate(u8 *dest, s32 year, s32 month, s32 day)
{
dest = ConvertIntToHexStringN(dest, year, STR_CONV_MODE_LEADING_ZEROS, 4);
*dest++ = CHAR_HYPHEN;
dest = ConvertIntToHexStringN(dest, month, STR_CONV_MODE_LEADING_ZEROS, 2);
*dest++ = CHAR_HYPHEN;
dest = ConvertIntToHexStringN(dest, day, STR_CONV_MODE_LEADING_ZEROS, 2);
*dest = EOS;
}
void RtcCalcTimeDifference(struct SiiRtcInfo *rtc, struct Time *result, struct Time *t)
{
u16 days = RtcGetDayCount(rtc);
result->seconds = ConvertBcdToBinary(rtc->second) - t->seconds;
result->minutes = ConvertBcdToBinary(rtc->minute) - t->minutes;
result->hours = ConvertBcdToBinary(rtc->hour) - t->hours;
result->days = days - t->days;
if (result->seconds < 0)
{
result->seconds += 60;
--result->minutes;
}
if (result->minutes < 0)
{
result->minutes += 60;
--result->hours;
}
if (result->hours < 0)
{
result->hours += 24;
--result->days;
}
}
bool8 IsBetweenHours(s32 hours, s32 begin, s32 end)
{
if (end < begin)
return hours >= begin || hours < end;
else
return hours >= begin && hours < end;
}
u8 GetTimeOfDay(void)
{
RtcCalcLocalTime();
if (IsBetweenHours(gLocalTime.hours, MORNING_HOUR_BEGIN, MORNING_HOUR_END))
return TIME_MORNING;
else if (IsBetweenHours(gLocalTime.hours, EVENING_HOUR_BEGIN, EVENING_HOUR_END))
return TIME_EVENING;
else if (IsBetweenHours(gLocalTime.hours, NIGHT_HOUR_BEGIN, NIGHT_HOUR_END))
return TIME_NIGHT;
return TIME_DAY;
}
void RtcCalcLocalTime(void)
{
RtcGetInfo(&sRtc);
RtcCalcTimeDifference(&sRtc, &gLocalTime, &gSaveBlock2Ptr->localTimeOffset);
}
void RtcInitLocalTimeOffset(s32 hour, s32 minute)
{
RtcCalcLocalTimeOffset(0, hour, minute, 0);
}
void RtcCalcLocalTimeOffset(s32 days, s32 hours, s32 minutes, s32 seconds)
{
gLocalTime.days = days;
gLocalTime.hours = hours;
gLocalTime.minutes = minutes;
gLocalTime.seconds = seconds;
RtcGetInfo(&sRtc);
RtcCalcTimeDifference(&sRtc, &gSaveBlock2Ptr->localTimeOffset, &gLocalTime);
}
void CalcTimeDifference(struct Time *result, struct Time *t1, struct Time *t2)
{
result->seconds = t2->seconds - t1->seconds;
result->minutes = t2->minutes - t1->minutes;
result->hours = t2->hours - t1->hours;
result->days = t2->days - t1->days;
if (result->seconds < 0)
{
result->seconds += 60;
--result->minutes;
}
if (result->minutes < 0)
{
result->minutes += 60;
--result->hours;
}
if (result->hours < 0)
{
result->hours += 24;
--result->days;
}
}
u32 RtcGetMinuteCount(void)
{
RtcGetInfo(&sRtc);
return (24 * 60) * RtcGetDayCount(&sRtc) + 60 * sRtc.hour + sRtc.minute;
}
u32 RtcGetLocalDayCount(void)
{
return RtcGetDayCount(&sRtc);
}

View File

@@ -1,5 +1,7 @@
#include "global.h"
#include "gflib.h"
#include "clock.h"
#include "rtc.h"
#include "script.h"
#include "mystery_event_script.h"
#include "event_data.h"
@@ -656,28 +658,25 @@ bool8 ScrCmd_delay(struct ScriptContext * ctx)
bool8 ScrCmd_initclock(struct ScriptContext * ctx)
{
// u8 hour = VarGet(ScriptReadHalfword(ctx));
// u8 minute = VarGet(ScriptReadHalfword(ctx));
//
// RtcInitLocalTimeOffset(hour, minute);
u8 hour = VarGet(ScriptReadHalfword(ctx));
u8 minute = VarGet(ScriptReadHalfword(ctx));
RtcInitLocalTimeOffset(hour, minute);
return FALSE;
}
bool8 ScrCmd_dotimebasedevents(struct ScriptContext * ctx)
{
// DoTimeBasedEvents();
DoTimeBasedEvents();
return FALSE;
}
bool8 ScrCmd_gettime(struct ScriptContext * ctx)
{
// RtcCalcLocalTime();
// gSpecialVar_0x8000 = gLocalTime.hours;
// gSpecialVar_0x8001 = gLocalTime.minutes;
// gSpecialVar_0x8002 = gLocalTime.seconds;
gSpecialVar_0x8000 = 0;
gSpecialVar_0x8001 = 0;
gSpecialVar_0x8002 = 0;
RtcCalcLocalTime();
gSpecialVar_0x8000 = gLocalTime.hours;
gSpecialVar_0x8001 = gLocalTime.minutes;
gSpecialVar_0x8002 = gLocalTime.seconds;
return FALSE;
}

445
src/siirtc.c Normal file
View File

@@ -0,0 +1,445 @@
// Ruby/Sapphire/Emerald cartridges contain a Seiko Instruments Inc. (SII)
// S-3511A real-time clock (RTC). This library ("SIIRTC_V001") is for
// communicating with the RTC.
#include "gba/gba.h"
#include "siirtc.h"
#define STATUS_INTFE 0x02 // frequency interrupt enable
#define STATUS_INTME 0x08 // per-minute interrupt enable
#define STATUS_INTAE 0x20 // alarm interrupt enable
#define STATUS_24HOUR 0x40 // 0: 12-hour mode, 1: 24-hour mode
#define STATUS_POWER 0x80 // power on or power failure occurred
#define TEST_MODE 0x80 // flag in the "second" byte
#define ALARM_AM 0x00
#define ALARM_PM 0x80
#define OFFSET_YEAR offsetof(struct SiiRtcInfo, year)
#define OFFSET_MONTH offsetof(struct SiiRtcInfo, month)
#define OFFSET_DAY offsetof(struct SiiRtcInfo, day)
#define OFFSET_DAY_OF_WEEK offsetof(struct SiiRtcInfo, dayOfWeek)
#define OFFSET_HOUR offsetof(struct SiiRtcInfo, hour)
#define OFFSET_MINUTE offsetof(struct SiiRtcInfo, minute)
#define OFFSET_SECOND offsetof(struct SiiRtcInfo, second)
#define OFFSET_STATUS offsetof(struct SiiRtcInfo, status)
#define OFFSET_ALARM_HOUR offsetof(struct SiiRtcInfo, alarmHour)
#define OFFSET_ALARM_MINUTE offsetof(struct SiiRtcInfo, alarmMinute)
#define INFO_BUF(info, index) (*((u8 *)(info) + (index)))
#define DATETIME_BUF(info, index) INFO_BUF(info, OFFSET_YEAR + index)
#define DATETIME_BUF_LEN (OFFSET_SECOND - OFFSET_YEAR + 1)
#define TIME_BUF(info, index) INFO_BUF(info, OFFSET_HOUR + index)
#define TIME_BUF_LEN (OFFSET_SECOND - OFFSET_HOUR + 1)
#define WR 0 // command for writing data
#define RD 1 // command for reading data
#define CMD(n) (0x60 | (n << 1))
#define CMD_RESET CMD(0)
#define CMD_STATUS CMD(1)
#define CMD_DATETIME CMD(2)
#define CMD_TIME CMD(3)
#define CMD_ALARM CMD(4)
#define SCK_HI 1
#define SIO_HI 2
#define CS_HI 4
#define DIR_0_IN 0
#define DIR_0_OUT 1
#define DIR_1_IN 0
#define DIR_1_OUT 2
#define DIR_2_IN 0
#define DIR_2_OUT 4
#define DIR_ALL_IN (DIR_0_IN | DIR_1_IN | DIR_2_IN)
#define DIR_ALL_OUT (DIR_0_OUT | DIR_1_OUT | DIR_2_OUT)
#define GPIO_PORT_DATA (*(vu16 *)0x80000C4)
#define GPIO_PORT_DIRECTION (*(vu16 *)0x80000C6)
#define GPIO_PORT_READ_ENABLE (*(vu16 *)0x80000C8)
extern vu16 GPIOPortDirection;
static u16 sDummy; // unused variable
static bool8 sLocked;
static int WriteCommand(u8 value);
static int WriteData(u8 value);
static u8 ReadData();
static void EnableGpioPortRead();
static void DisableGpioPortRead();
static const char AgbLibRtcVersion[] = "SIIRTC_V001";
void SiiRtcUnprotect(void)
{
EnableGpioPortRead();
sLocked = FALSE;
}
void SiiRtcProtect(void)
{
DisableGpioPortRead();
sLocked = TRUE;
}
u8 SiiRtcProbe(void)
{
u8 errorCode;
struct SiiRtcInfo rtc;
if (!SiiRtcGetStatus(&rtc))
return 0;
errorCode = 0;
if ((rtc.status & (SIIRTCINFO_POWER | SIIRTCINFO_24HOUR)) == SIIRTCINFO_POWER
|| (rtc.status & (SIIRTCINFO_POWER | SIIRTCINFO_24HOUR)) == 0)
{
// The RTC is in 12-hour mode. Reset it and switch to 24-hour mode.
// Note that the conditions are redundant and equivalent to simply
// "(rtc.status & SIIRTCINFO_24HOUR) == 0". It's possible that this
// was also intended to handle resetting the clock after power failure
// but a mistake was made.
if (!SiiRtcReset())
return 0;
errorCode++;
}
SiiRtcGetTime(&rtc);
if (rtc.second & TEST_MODE)
{
// The RTC is in test mode. Reset it to leave test mode.
if (!SiiRtcReset())
return (errorCode << 4) & 0xF0;
errorCode++;
}
return (errorCode << 4) | 1;
}
bool8 SiiRtcReset(void)
{
u8 result;
struct SiiRtcInfo rtc;
if (sLocked == TRUE)
return FALSE;
sLocked = TRUE;
GPIO_PORT_DATA = SCK_HI;
GPIO_PORT_DATA = SCK_HI | CS_HI;
GPIO_PORT_DIRECTION = DIR_ALL_OUT;
WriteCommand(CMD_RESET | WR);
GPIO_PORT_DATA = SCK_HI;
GPIO_PORT_DATA = SCK_HI;
sLocked = FALSE;
rtc.status = SIIRTCINFO_24HOUR;
result = SiiRtcSetStatus(&rtc);
return result;
}
bool8 SiiRtcGetStatus(struct SiiRtcInfo *rtc)
{
u8 statusData;
if (sLocked == TRUE)
return FALSE;
sLocked = TRUE;
GPIO_PORT_DATA = SCK_HI;
GPIO_PORT_DATA = SCK_HI | CS_HI;
GPIO_PORT_DIRECTION = DIR_ALL_OUT;
WriteCommand(CMD_STATUS | RD);
GPIO_PORT_DIRECTION = DIR_0_OUT | DIR_1_IN | DIR_2_OUT;
statusData = ReadData();
rtc->status = (statusData & (STATUS_POWER | STATUS_24HOUR))
| ((statusData & STATUS_INTAE) >> 3)
| ((statusData & STATUS_INTME) >> 2)
| ((statusData & STATUS_INTFE) >> 1);
GPIO_PORT_DATA = SCK_HI;
GPIO_PORT_DATA = SCK_HI;
sLocked = FALSE;
return TRUE;
}
bool8 SiiRtcSetStatus(struct SiiRtcInfo *rtc)
{
u8 statusData;
if (sLocked == TRUE)
return FALSE;
sLocked = TRUE;
GPIO_PORT_DATA = SCK_HI;
GPIO_PORT_DATA = SCK_HI | CS_HI;
statusData = STATUS_24HOUR
| ((rtc->status & SIIRTCINFO_INTAE) << 3)
| ((rtc->status & SIIRTCINFO_INTME) << 2)
| ((rtc->status & SIIRTCINFO_INTFE) << 1);
GPIO_PORT_DIRECTION = DIR_ALL_OUT;
WriteCommand(CMD_STATUS | WR);
WriteData(statusData);
GPIO_PORT_DATA = SCK_HI;
GPIO_PORT_DATA = SCK_HI;
sLocked = FALSE;
return TRUE;
}
bool8 SiiRtcGetDateTime(struct SiiRtcInfo *rtc)
{
u8 i;
if (sLocked == TRUE)
return FALSE;
sLocked = TRUE;
GPIO_PORT_DATA = SCK_HI;
GPIO_PORT_DATA = SCK_HI | CS_HI;
GPIO_PORT_DIRECTION = DIR_ALL_OUT;
WriteCommand(CMD_DATETIME | RD);
GPIO_PORT_DIRECTION = DIR_0_OUT | DIR_1_IN | DIR_2_OUT;
for (i = 0; i < DATETIME_BUF_LEN; i++)
DATETIME_BUF(rtc, i) = ReadData();
INFO_BUF(rtc, OFFSET_HOUR) &= 0x7F;
GPIO_PORT_DATA = SCK_HI;
GPIO_PORT_DATA = SCK_HI;
sLocked = FALSE;
return TRUE;
}
bool8 SiiRtcSetDateTime(struct SiiRtcInfo *rtc)
{
u8 i;
if (sLocked == TRUE)
return FALSE;
sLocked = TRUE;
GPIO_PORT_DATA = SCK_HI;
GPIO_PORT_DATA = SCK_HI | CS_HI;
GPIO_PORT_DIRECTION = DIR_ALL_OUT;
WriteCommand(CMD_DATETIME | WR);
for (i = 0; i < DATETIME_BUF_LEN; i++)
WriteData(DATETIME_BUF(rtc, i));
GPIO_PORT_DATA = SCK_HI;
GPIO_PORT_DATA = SCK_HI;
sLocked = FALSE;
return TRUE;
}
bool8 SiiRtcGetTime(struct SiiRtcInfo *rtc)
{
u8 i;
if (sLocked == TRUE)
return FALSE;
sLocked = TRUE;
GPIO_PORT_DATA = SCK_HI;
GPIO_PORT_DATA = SCK_HI | CS_HI;
GPIO_PORT_DIRECTION = DIR_ALL_OUT;
WriteCommand(CMD_TIME | RD);
GPIO_PORT_DIRECTION = DIR_0_OUT | DIR_1_IN | DIR_2_OUT;
for (i = 0; i < TIME_BUF_LEN; i++)
TIME_BUF(rtc, i) = ReadData();
INFO_BUF(rtc, OFFSET_HOUR) &= 0x7F;
GPIO_PORT_DATA = SCK_HI;
GPIO_PORT_DATA = SCK_HI;
sLocked = FALSE;
return TRUE;
}
bool8 SiiRtcSetTime(struct SiiRtcInfo *rtc)
{
u8 i;
if (sLocked == TRUE)
return FALSE;
sLocked = TRUE;
GPIO_PORT_DATA = SCK_HI;
GPIO_PORT_DATA = SCK_HI | CS_HI;
GPIO_PORT_DIRECTION = DIR_ALL_OUT;
WriteCommand(CMD_TIME | WR);
for (i = 0; i < TIME_BUF_LEN; i++)
WriteData(TIME_BUF(rtc, i));
GPIO_PORT_DATA = SCK_HI;
GPIO_PORT_DATA = SCK_HI;
sLocked = FALSE;
return TRUE;
}
bool8 SiiRtcSetAlarm(struct SiiRtcInfo *rtc)
{
u8 i;
u8 alarmData[2];
if (sLocked == TRUE)
return FALSE;
sLocked = TRUE;
// Decode BCD.
alarmData[0] = (rtc->alarmHour & 0xF) + 10 * ((rtc->alarmHour >> 4) & 0xF);
// The AM/PM flag must be set correctly even in 24-hour mode.
if (alarmData[0] < 12)
alarmData[0] = rtc->alarmHour | ALARM_AM;
else
alarmData[0] = rtc->alarmHour | ALARM_PM;
alarmData[1] = rtc->alarmMinute;
GPIO_PORT_DATA = SCK_HI;
GPIO_PORT_DATA = SCK_HI | CS_HI;
GPIOPortDirection = DIR_ALL_OUT; // Why is this the only instance that uses a symbol?
WriteCommand(CMD_ALARM | WR);
for (i = 0; i < 2; i++)
WriteData(alarmData[i]);
GPIO_PORT_DATA = SCK_HI;
GPIO_PORT_DATA = SCK_HI;
sLocked = FALSE;
return TRUE;
}
static int WriteCommand(u8 value)
{
u8 i;
u8 temp;
for (i = 0; i < 8; i++)
{
temp = ((value >> (7 - i)) & 1);
GPIO_PORT_DATA = (temp << 1) | CS_HI;
GPIO_PORT_DATA = (temp << 1) | CS_HI;
GPIO_PORT_DATA = (temp << 1) | CS_HI;
GPIO_PORT_DATA = (temp << 1) | SCK_HI | CS_HI;
}
// control reaches end of non-void function
}
static int WriteData(u8 value)
{
u8 i;
u8 temp;
for (i = 0; i < 8; i++)
{
temp = ((value >> i) & 1);
GPIO_PORT_DATA = (temp << 1) | CS_HI;
GPIO_PORT_DATA = (temp << 1) | CS_HI;
GPIO_PORT_DATA = (temp << 1) | CS_HI;
GPIO_PORT_DATA = (temp << 1) | SCK_HI | CS_HI;
}
// control reaches end of non-void function
}
static u8 ReadData()
{
u8 i;
u8 temp;
u8 value;
for (i = 0; i < 8; i++)
{
GPIO_PORT_DATA = CS_HI;
GPIO_PORT_DATA = CS_HI;
GPIO_PORT_DATA = CS_HI;
GPIO_PORT_DATA = CS_HI;
GPIO_PORT_DATA = CS_HI;
GPIO_PORT_DATA = SCK_HI | CS_HI;
temp = ((GPIO_PORT_DATA & SIO_HI) >> 1);
value = (value >> 1) | (temp << 7); // UB: accessing uninitialized var
}
return value;
}
static void EnableGpioPortRead()
{
GPIO_PORT_READ_ENABLE = 1;
}
static void DisableGpioPortRead()
{
GPIO_PORT_READ_ENABLE = 0;
}

View File

@@ -30,9 +30,9 @@ const u8 gText_FailedUpdateSwapBackup[] = _("レポ-トの こうしんは\nし
const u8 gText_SaveFileCorrupted[] = _("The save file is corrupted.\pThe previous save file will be\nloaded.");
const u8 gText_SaveFileHasBeenDeleted[] = _("The save file has been\ndeleted...");
const u8 gText_1MSubCircuitBoardNotInstalled[] = _("The 1M sub-circuit board is\nnot installed.");
const u8 gTextJP_InternalBatteryHasRunDry[] = _("でんちぎれの ために\nとけいが うごかなくなりました\pとけいに かんけいする できごとは おきませんが\nゲ-ムを つづけて あそぶことは できます");
const u8 gText_PlayerUnused[] = _("しゅじんこう");
const u8 gText_PokedexUnused[] = _("ポケモンずかん");
const u8 gText_BatteryRunDry[] = _("The internal battery has run dry.\nThe game can be played.\pHowever, clock-based events will\nno longer occur.");
const u8 gUnknown_8415CD9[] = _("しゅじんこう");
const u8 gUnknown_8415CE0[] = _("ポケモンずかん");
const u8 gText_MainMenuTime[] = _("TIME");
const u8 gText_BadgesUnused[] = _("もっているバッジ");
const u8 gText_AButton[] = _("Aボタン");
@@ -156,6 +156,16 @@ const u8 gText_SelectorArrow2[] = _("▶");
const u8 gText_YesNo[] = _("YES\nNO");
const u8 gText_GoBackToThePreviousMenu[] = _("Go back to the\nprevious menu.");
const u8 gText_WhatWouldYouLikeToDo[] = _("What would you like to do?");
const u8 gText_ResetRTCConfirmCancel[] = _("Reset RTC?\nA: Confirm, B: Cancel");
const u8 gText_PresentTime[] = _("Present time in game");
const u8 gText_PreviousTime[] = _("Previous time in game");
const u8 gText_PleaseResetTime[] = _("Please reset the time.");
const u8 gText_ClockHasBeenReset[] = _("The clock has been reset.\nData will be saved. Please wait.");
const u8 gText_SaveCompleted[] = _("Save completed.");
const u8 gText_NoSaveFileCantSetTime[] = _("There is no save file, so the time\ncan't be set.");
const u8 gText_InGameClockUsable[] = _("The in-game clock adjustment system\nis now useable.");
const u8 gText_MenuPokedex[] = _("POKéDEX");
const u8 gText_MenuBag[] = _("BAG");
const u8 gText_MenuPokenav[] = _("ポケナビ");
@@ -886,15 +896,7 @@ const u8 gText_ButtonTypeLEqualsA[] = _("L=A");
const u8 gText_ButtonTypeLR[] = _("LR");
const u8 gText_FrameType[] = _("TYPE");
const u8 gText_PickSwitchCancel[] = _("{DPAD_UPDOWN}PICK {DPAD_LEFTRIGHT}SWITCH {A_BUTTON}{B_BUTTON}CANCEL");
const u8 gText_ResetRTCConfirmCancel[] = _("RTCを リセットします\nAで けってい Bで キャンセル");
const u8 gText_PresentTime[] = _("げんざいの ゲ-ムない じかん");
const u8 gText_PreviousTime[] = _("ぜんかいの ゲ-ムない じかん");
const u8 gText_PleaseResetTime[] = _("じかんを さいせってい してください");
const u8 gText_ClockHasBeenReset[] = _("じかんを さいせってい しました!\nレポ-トを かいています おまちください");
const u8 gText_SaveCompleted[] = _("レポ-トを かきこみました!");
const u8 gText_SaveFailed[] = _("レポ-トの かきこみに\nしっぱい しました‥");
const u8 gText_NoSaveFileCantSetTime[] = _("レポ-トが ないので\nじかんの せっていは できません!");
const u8 gText_InGameClockUsable[] = _("ゲ-ムない じかんの しゅうせい システムが\nつかえる ように なりました!");
const u8 gText_SavingDontTurnOffThePower2[] = _("SAVING…\nDON'T TURN OFF THE POWER.");
// Start menu option descriptions
@@ -969,6 +971,9 @@ const u8 gText_Diploma_National[] = _("NATIONAL");
const u8 gText_Diploma_Kanto[] = _("KANTO");
const u8 gText_ClearAllSaveData[] = _("Clear all save data areas?");
const u8 gText_ClearingData[] = _("Clearing data‥\nPlease wait.");
const u8 gText_IsThisTheCorrectTime[] = _("Is this the correct time?");
const u8 gText_Confirm3[] = _("CONFIRM");
const u8 gText_Cancel4[] = _("CANCEL");
const u8 gText_Player[] = _("PLAYER");
const u8 gText_Time[] = _("TIME");
const u8 gText_Colon[] = _(":");
@@ -1175,6 +1180,9 @@ const u8 gText_BronzeCard[] = _("BRONZE");
const u8 gText_CopperCard[] = _("COPPER");
const u8 gText_SilverCard[] = _("SILVER");
const u8 gText_GoldCard[] = _("GOLD");
const u8 gText_Day[] = _("DAY");
const u8 gText_Colon3[] = _(":");
const u8 gText_Confirm2[] = _("CONFIRM");
const u8 gText_HelpSystemControls_A_Next[] = _("{A_BUTTON}NEXT");
const u8 gText_HelpSystemControls_PickOkEnd[] = _("{DPAD_UPDOWN}PICK {A_BUTTON}OK {B_BUTTON}END");
const u8 gText_HelpSystemControls_AorBtoCancel[] = _("{A_BUTTON}{B_BUTTON}CANCEL");

11
src/time_events.c Normal file
View File

@@ -0,0 +1,11 @@
#include "global.h"
#include "time_events.h"
#include "event_data.h"
#include "field_weather.h"
#include "pokemon.h"
#include "random.h"
#include "overworld.h"
#include "rtc.h"
#include "script.h"
#include "task.h"

View File

@@ -11,8 +11,10 @@
#include "new_game.h"
#include "random.h"
#include "save.h"
#include "event_data.h"
#include "main_menu.h"
#include "clear_save_data_screen.h"
#include "reset_rtc_screen.h"
#include "berry_fix_program.h"
#include "decompress.h"
#include "constants/songs.h"
@@ -55,6 +57,8 @@ static void UpdateScanlineEffectRegBuffer(s16 y);
static void ScheduleStopScanlineEffect(void);
static void LoadMainTitleScreenPalsAndResetBgs(void);
static void CB2_FadeOutTransitionToSaveClearScreen(void);
static void CB2_GoToResetRtcScreen(void);
static void CB2_FadeOutTransitionToResetRtcScreen(void);
static void CB2_FadeOutTransitionToBerryFix(void);
static void LoadSpriteGfxAndPals(void);
#if defined(FIRERED)
@@ -608,6 +612,7 @@ static void SetTitleScreenScene_FadeIn(s16 *data)
}
#define KEYSTROKE_DELSAVE (B_BUTTON | SELECT_BUTTON | DPAD_UP)
#define KEYSTROKE_RESET_RTC (B_BUTTON | SELECT_BUTTON | DPAD_LEFT)
#define KEYSTROKE_BERRY_FIX (B_BUTTON | SELECT_BUTTON)
static void SetTitleScreenScene_Run(s16 *data)
@@ -634,6 +639,12 @@ static void SetTitleScreenScene_Run(s16 *data)
DestroyTask(FindTaskIdByFunc(Task_TitleScreenMain));
SetMainCallback2(CB2_FadeOutTransitionToSaveClearScreen);
}
else if (JOY_HELD(KEYSTROKE_RESET_RTC) == KEYSTROKE_RESET_RTC && CanResetRTC() == TRUE)
{
DeactivateSlashSprite(tSlashSpriteId);
DestroyTask(FindTaskIdByFunc(Task_TitleScreenMain));
SetMainCallback2(CB2_FadeOutTransitionToResetRtcScreen);
}
else if (JOY_HELD(KEYSTROKE_BERRY_FIX) == KEYSTROKE_BERRY_FIX)
{
DeactivateSlashSprite(tSlashSpriteId);
@@ -652,6 +663,15 @@ static void SetTitleScreenScene_Run(s16 *data)
}
}
static void CB2_FadeOutTransitionToResetRtcScreen(void)
{
if (!UpdatePaletteFade())
{
m4aMPlayAllStop();
SetMainCallback2(CB2_InitResetRtcScreen);
}
}
static void SetGpuRegsForTitleScreenRun(void)
{
SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_OBJWIN_ON);
@@ -728,15 +748,20 @@ static void SetTitleScreenScene_Cry(s16 *data)
case 2:
if (!gPaletteFade.active)
{
SeedRngAndSetTrainerId();
SetSaveBlocksPointers();
ResetMenuAndMonGlobals();
Save_ResetSaveCounters();
LoadGameSave(SAVE_NORMAL);
if (gSaveFileStatus == SAVE_STATUS_EMPTY || gSaveFileStatus == SAVE_STATUS_INVALID)
Sav2_ClearSetDefault();
SetPokemonCryStereo(gSaveBlock2Ptr->optionsSound);
InitHeap(gHeap, HEAP_SIZE);
// These are commented out as they’ve been relocated to intro.c.
// This also allows RTC reset to work without file corruption.
// It also has the side effect of allowing you to run flags
// and functions as early as the intro.
// SeedRngAndSetTrainerId();
// SetSaveBlocksPointers();
// ResetMenuAndMonGlobals();
// Save_ResetSaveCounters();
// Save_LoadGameData(SAVE_NORMAL);
// if (gSaveFileStatus == SAVE_STATUS_EMPTY || gSaveFileStatus == SAVE_STATUS_INVALID)
// Sav2_ClearSetDefault();
// SetPokemonCryStereo(gSaveBlock2Ptr->optionsSound);
// InitHeap(gHeap, HEAP_SIZE);
SetMainCallback2(CB2_InitMainMenu);
DestroyTask(FindTaskIdByFunc(Task_TitleScreenMain));
}

1126
src/wallclock.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -30,6 +30,9 @@
.include "src/m4a_1.o"
.include "data/sound_data.o"
.include "src/agb_flash.o"
.include "src/siirtc.o"
.include "src/rtc.o"
.include "src/reset_rtc_screen.o"
.include "*libgcc.a:dp-bit.o"
.include "*libgcc.a:fp-bit.o"
.include "*libc.a:syscalls.o"

View File

@@ -1,4 +1,5 @@
.include "main.o"
.include "rtc.o"
.include "bg.o"
.include "text_printer.o"
.align 4