13 Commits
0.1 ... 0.6

Author SHA1 Message Date
Lesserkuma
cbe17ef7c5 0.6 2023-09-24 12:54:20 +02:00
Lesserkuma
8dc1d10a95 0.5 2023-08-17 17:57:35 +02:00
Lesserkuma
bcb9ae5d65 - 2023-08-01 12:47:35 +02:00
Lesserkuma
a33f0ed9db 0.3 2023-07-31 14:10:20 +02:00
Lesserkuma
34b1b4b8dc - 2023-07-28 16:29:42 +02:00
Lesserkuma
e21ad43d20 - 2023-07-28 13:52:49 +02:00
Lesserkuma
8f63cdb03f - 2023-07-27 19:40:18 +02:00
Lesserkuma
9499327b3b - 2023-07-27 19:21:22 +02:00
Lesserkuma
2c88286a66 - 2023-07-27 19:12:28 +02:00
Lesserkuma
ce1212d365 - 2023-07-26 18:01:49 +02:00
Lesserkuma
8cd4c1b953 - 2023-07-26 17:25:13 +02:00
Lesserkuma
d8df1ff28e - 2023-07-26 17:24:32 +02:00
Lesserkuma
b43c23db22 - 2023-07-26 17:11:16 +02:00
8 changed files with 121 additions and 55 deletions

BIN
.github/screen.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 KiB

View File

@@ -179,6 +179,7 @@ soundbank.bin soundbank.h : $(AUDIOFILES)
#replacement rule for gbafix #replacement rule for gbafix
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
$(shell touch $(CURDIR)/../$(SOURCES)/version.h)
%.gba: %.elf %.gba: %.elf
@$(OBJCOPY) -O binary $< $@ @$(OBJCOPY) -O binary $< $@
@gbafix $@ "-tLK MULTIMENU" "-cAGBJ" "-mLK" "-r0" @gbafix $@ "-tLK MULTIMENU" "-cAGBJ" "-mLK" "-r0"

View File

@@ -13,10 +13,10 @@ Open the config.json file in a text editor like Notepad.
The following section must be edited in order to specify the cartridge type to use and whether or not your cartridge has a battery installed: The following section must be edited in order to specify the cartridge type to use and whether or not your cartridge has a battery installed:
```json ```json
"cartridge": { "cartridge": {
"type": 2, "type": 2,
"battery_present": false "battery_present": false
}, },
``` ```
Set `type` to `1` or `2`: Set `type` to `1` or `2`:
- `1` = MSP55LV100S (e.g. The Legend of Zelda Collection - Classic Edition 7-in-1) - `1` = MSP55LV100S (e.g. The Legend of Zelda Collection - Classic Edition 7-in-1)
@@ -25,6 +25,16 @@ Set `type` to `1` or `2`:
Set `battery_present` to `true` or `false`. This will enable enhanced save data handling which will only be functional with a working battery. Set `battery_present` to `true` or `false`. This will enable enhanced save data handling which will only be functional with a working battery.
In the `games` section, you can edit the game-related stuff: In the `games` section, you can edit the game-related stuff:
```json
"games": [
{
"enabled": true,
"file": "wah7.gba",
"title": "Super WAHluigi Bros. 7",
"title_font": 1,
"save_slot": 1
},
```
- `enabled` can be set to `true` or `false`. If this option is set, the game entry will be skipped by the ROM Builder. - `enabled` can be set to `true` or `false`. If this option is set, the game entry will be skipped by the ROM Builder.
- `file` is the ROM's file name within the **roms** folder, including file extension. - `file` is the ROM's file name within the **roms** folder, including file extension.
- `title` is the unicode title that will be displayed in the menu. - `title` is the unicode title that will be displayed in the menu.
@@ -36,6 +46,7 @@ In the `games` section, you can edit the game-related stuff:
- `5` = Nintendo DSi IPL font (KOR) - `5` = Nintendo DSi IPL font (KOR)
- `6` = Pokémon Black & White condensed battle font - `6` = Pokémon Black & White condensed battle font
- `save_slot` defines which save slot your game uses. Set it to `null` for no saving or a number starting from `1`. Multiple games can share a save slot. - `save_slot` defines which save slot your game uses. Set it to `null` for no saving or a number starting from `1`. Multiple games can share a save slot.
- `map_256m`, if set to `true`, can serve as a workaround for a glitch with the cartridge mapper that causes games to freeze with screeching noises upon launch.
### ROM Builder Command Line Arguments ### ROM Builder Command Line Arguments
@@ -65,4 +76,11 @@ Tested repro cartridges:
- 100BS6600_48BALL_V4 with 6600M0U0BE - 100BS6600_48BALL_V4 with 6600M0U0BE
- 100SOP with MSP55LV100S - 100SOP with MSP55LV100S
ROM and save data can be written and read using a [GBxCart RW v1.4+](https://www.gbxcart.com/) device by insideGadgets and the [FlashGBX](https://github.com/lesserkuma/FlashGBX) software. The generated compilation ROM can be written and read using a [GBxCart RW v1.4+](https://www.gbxcart.com/) device by insideGadgets and the [FlashGBX](https://github.com/lesserkuma/FlashGBX) software.
## Thanks
Thanks to FraX, Ausar, liuyunx, BennVenn
## Screenshots
<img src="https://raw.githubusercontent.com/lesserkuma/GBA_MultiMenu/master/.github/screen.png" alt="" />

View File

@@ -5,7 +5,7 @@
import sys, os, glob, json, math, re, struct, hashlib, argparse, datetime import sys, os, glob, json, math, re, struct, hashlib, argparse, datetime
# Configuration # Configuration
app_version = "0.1" app_version = "0.6"
default_file = "LK_MULTIMENU_<CODE>.gba" default_file = "LK_MULTIMENU_<CODE>.gba"
################################ ################################
@@ -39,12 +39,14 @@ def logp(*args, **kwargs):
################################ ################################
cartridge_types = [ cartridge_types = [
{ # "MSP55LV100S {
"name":"MSP55LV100S",
"flash_size":0x4000000, "flash_size":0x4000000,
"sector_size":0x20000, "sector_size":0x20000,
"block_size":0x80000, "block_size":0x80000,
}, },
{ # 6600M0U0BE {
"name":"6600M0U0BE",
"flash_size":0x10000000, "flash_size":0x10000000,
"sector_size":0x40000, "sector_size":0x40000,
"block_size":0x80000, "block_size":0x80000,
@@ -64,11 +66,11 @@ parser.add_argument("--output", type=str, default=default_file, help="sets the f
args = parser.parse_args() args = parser.parse_args()
output_file = args.output output_file = args.output
if output_file == "lk_multimenu.gba": if output_file == "lk_multimenu.gba":
logp("Error: The file must not be named lk_multimenu.gba") logp("Error: The file must not be named lk_multimenu.gba")
if not args.no_wait: input("\nPress ENTER to exit.\n") if not args.no_wait: input("\nPress ENTER to exit.\n")
sys.exit(1) sys.exit(1)
if not os.path.exists("lk_multimenu.gba"): if not os.path.exists("lk_multimenu.gba"):
logp("Error: The Menu ROM is missing.\nPlease put it in the same directory that you are running this tool from.\nExpected file name: \"lk_multimenu.gba\"") logp("Error: The Menu ROM is missing.\nPlease put it in the same directory that you are running this tool from.\nExpected file name: lk_multimenu.gba")
if not args.no_wait: input("\nPress ENTER to exit.\n") if not args.no_wait: input("\nPress ENTER to exit.\n")
sys.exit() sys.exit()
@@ -82,13 +84,19 @@ if not os.path.exists(args.config):
cartridge_type = 1 cartridge_type = 1
battery_present = False battery_present = False
for file in files: for file in files:
games.append({ d = {
"enabled": True, "enabled": True,
"file": os.path.split(file)[1], "file": os.path.split(file)[1],
"title": os.path.splitext(os.path.split(file)[1])[0], "title": os.path.splitext(os.path.split(file)[1])[0],
"title_font": 1, "title_font": 1,
"save_slot": save_slot, "save_slot": save_slot,
}) }
with open(file, "rb") as f:
f.seek(0xAC)
code = f.read(0x4)
if code[:3] in (b"BPG", b"BPR"):
d["map_256m"] = True
games.append(d)
save_slot += 1 save_slot += 1
obj = { obj = {
"cartridge": { "cartridge": {
@@ -97,11 +105,22 @@ if not os.path.exists(args.config):
}, },
"games": games, "games": games,
} }
with open(args.config, "w", encoding="UTF-8-SIG") as f: if len(games) == 0:
f.write(json.dumps(obj=obj, indent=4, ensure_ascii=False)) logp("Error: No usable ROM files were found in the “roms” folder.")
else:
with open(args.config, "w", encoding="UTF-8-SIG") as f:
f.write(json.dumps(obj=obj, indent=4, ensure_ascii=False))
logp(f"A new configuration file ({args.config:s}) was created based on the files inside the “roms” folder.\nPlease edit the file to your liking in a text editor, then run this tool again.")
if not args.no_wait: input("\nPress ENTER to exit.\n")
sys.exit()
else: else:
with open(args.config, "r", encoding="UTF-8-SIG") as f: with open(args.config, "r", encoding="UTF-8-SIG") as f:
j = json.load(f) try:
j = json.load(f)
except json.decoder.JSONDecodeError as e:
logp(f"Error: The configuration file ({args.config:s}) is malformed and could not be loaded.\n" + str(e))
if not args.no_wait: input("\nPress ENTER to exit.\n")
sys.exit()
games = j["games"] games = j["games"]
cartridge_type = j["cartridge"]["type"] - 1 cartridge_type = j["cartridge"]["type"] - 1
battery_present = j["cartridge"]["battery_present"] battery_present = j["cartridge"]["battery_present"]
@@ -128,15 +147,16 @@ UpdateSectorMap(start=0, length=math.ceil(len(menu_rom) / sector_size), c="m")
item_list_offset = len(menu_rom) item_list_offset = len(menu_rom)
item_list_offset = 0x40000 - (item_list_offset % 0x40000) + item_list_offset item_list_offset = 0x40000 - (item_list_offset % 0x40000) + item_list_offset
item_list_offset = math.ceil(item_list_offset / sector_size) item_list_offset = math.ceil(item_list_offset / sector_size)
UpdateSectorMap(start=item_list_offset, length=1, c="i") UpdateSectorMap(start=item_list_offset, length=1, c="l")
status_offset = item_list_offset + 1 status_offset = item_list_offset + 1
UpdateSectorMap(start=status_offset, length=1, c="c") UpdateSectorMap(start=status_offset, length=1, c="c")
if battery_present: if battery_present:
status = bytearray([0x4B, 0x55, 0x4D, 0x41, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) status = bytearray([0x4B, 0x55, 0x4D, 0x41, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
else: else:
status = bytearray([0x4B, 0x55, 0x4D, 0x41, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) status = bytearray([0x4B, 0x55, 0x4D, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
compilation[status_offset * sector_size:status_offset * sector_size + len(status)] = status compilation[status_offset * sector_size:status_offset * sector_size + len(status)] = status
save_data_sector_offset = status_offset + 1 save_data_sector_offset = status_offset + 1
boot_logo_found = hashlib.sha1(compilation[0x04:0xA0]).digest() == bytearray([ 0x17, 0xDA, 0xA0, 0xFE, 0xC0, 0x2F, 0xC3, 0x3C, 0x0F, 0x6A, 0xBB, 0x54, 0x9A, 0x8B, 0x80, 0xB6, 0x61, 0x3B, 0x48, 0xEE ])
# Read game ROMs and import save data # Read game ROMs and import save data
saves_read = [] saves_read = []
@@ -152,6 +172,11 @@ for game in games:
x = 0x80000 x = 0x80000
while (x < size): x *= 2 while (x < size): x *= 2
size = x size = x
if size < 0x400000:
with open(f"roms/{game['file']}", "rb") as f:
buffer = f.read()
if b"Batteryless mod by Lesserkuma" in buffer:
size = 0x400000
game["index"] = index game["index"] = index
game["size"] = size game["size"] = size
if "title_font" in game: if "title_font" in game:
@@ -190,7 +215,7 @@ else:
games = [game for game in games if not ("missing" in game and game["missing"])] games = [game for game in games if not ("missing" in game and game["missing"])]
if len(games) == 0: if len(games) == 0:
logp("No ROMs found") logp(f"No ROMs found. Delete the “{args.config:s}” file to reset your configuration.")
sys.exit() sys.exit()
# Add index # Add index
@@ -201,19 +226,24 @@ for game in games:
# Read ROM data # Read ROM data
games.sort(key=lambda game: game["size"], reverse=True) games.sort(key=lambda game: game["size"], reverse=True)
boot_logo_found = False
c = 0 c = 0
for game in games: for game in games:
found = False found = False
for i in range(save_end_offset, len(sector_map)): for i in range(save_end_offset, len(sector_map)):
if i % game["sector_count"] == 0: sector_count_map = game["sector_count"]
if "map_256m" in game and game["map_256m"] == True:
# Map as 256M ROM, but don't waste space; some games may need this for unknown reasons
sector_count_map = (32 * 1024 * 1024) // sector_size
if i % sector_count_map == 0:
if sector_map[i:i + game["sector_count"]] == ["."] * game["sector_count"]: if sector_map[i:i + game["sector_count"]] == ["."] * game["sector_count"]:
UpdateSectorMap(i, game["sector_count"], "r") UpdateSectorMap(i, game["sector_count"], "r")
with open(f"roms/{game['file']}", "rb") as f: rom = f.read() with open(f"roms/{game['file']}", "rb") as f: rom = f.read()
compilation[i * sector_size:i * sector_size + len(rom)] = rom compilation[i * sector_size:i * sector_size + len(rom)] = rom
game["sector_offset"] = i game["sector_offset"] = i
game["block_offset"] = game["sector_offset"] * sector_size // block_size game["block_offset"] = game["sector_offset"] * sector_size // block_size
game["block_count"] = game["sector_count"] * sector_size // block_size game["block_count"] = sector_count_map * sector_size // block_size
found = True found = True
if not boot_logo_found and hashlib.sha1(rom[0x04:0xA0]).digest() == bytearray([ 0x17, 0xDA, 0xA0, 0xFE, 0xC0, 0x2F, 0xC3, 0x3C, 0x0F, 0x6A, 0xBB, 0x54, 0x9A, 0x8B, 0x80, 0xB6, 0x61, 0x3B, 0x48, 0xEE ]): if not boot_logo_found and hashlib.sha1(rom[0x04:0xA0]).digest() == bytearray([ 0x17, 0xDA, 0xA0, 0xFE, 0xC0, 0x2F, 0xC3, 0x3C, 0x0F, 0x6A, 0xBB, 0x54, 0x9A, 0x8B, 0x80, 0xB6, 0x61, 0x3B, 0x48, 0xEE ]):
@@ -240,10 +270,10 @@ logp("{:.2f}% ({:d} of {:d} sectors) used\n".format(sectors_used / sector_count
logp(f"Added {len(games)} ROM(s) to the compilation\n") logp(f"Added {len(games)} ROM(s) to the compilation\n")
if battery_present: if battery_present:
logp (" | Offset | Size | Save Slot | Title") logp (" | Offset | Map Size | Save Slot | Title")
toc_sep = "----+-----------+-----------+----------------+---------------------------------" toc_sep = "----+-----------+-----------+----------------+---------------------------------"
else: else:
logp (" | Offset | Size | Title") logp (" | Offset | Map Size | Title")
toc_sep = "----+-----------+-----------+--------------------------------------------------" toc_sep = "----+-----------+-----------+--------------------------------------------------"
item_list = bytearray() item_list = bytearray()
@@ -259,12 +289,11 @@ for game in games:
if game['save_type'] > 0: if game['save_type'] > 0:
table_line += f"{game['save_slot']+1:2d} (0x{(save_data_sector_offset + game['save_slot']) * sector_size:07X}) | " table_line += f"{game['save_slot']+1:2d} (0x{(save_data_sector_offset + game['save_slot']) * sector_size:07X}) | "
else: else:
table_line += "-------------- | " table_line += " | "
table_line += f"{title}" table_line += f"{title}"
if c % 8 == 0: logp(toc_sep) if c % 8 == 0: logp(toc_sep)
logp(table_line) logp(table_line)
c += 1 c += 1
#logp(f"0x{game['block_offset'] * block_size:07X} |")
title = title.ljust(0x30, "\0") title = title.ljust(0x30, "\0")
item_list += bytearray(struct.pack("B", game["title_font"])) item_list += bytearray(struct.pack("B", game["title_font"]))
@@ -275,6 +304,7 @@ for game in games:
item_list += bytearray(struct.pack("B", game["save_slot"])) item_list += bytearray(struct.pack("B", game["save_slot"]))
item_list += bytearray([0] * 8) item_list += bytearray([0] * 8)
item_list += bytearray(title.encode("UTF-16LE")) item_list += bytearray(title.encode("UTF-16LE"))
compilation[item_list_offset * sector_size:item_list_offset * sector_size + len(item_list)] = item_list compilation[item_list_offset * sector_size:item_list_offset * sector_size + len(item_list)] = item_list
rom_code = "L{:s}".format(hashlib.sha1(status + item_list).hexdigest()[:3]).upper() rom_code = "L{:s}".format(hashlib.sha1(status + item_list).hexdigest()[:3]).upper()
@@ -287,8 +317,13 @@ for i in range(0xA0, 0xBD):
checksum = (checksum - 0x19) & 0xFF checksum = (checksum - 0x19) & 0xFF
compilation[0xBD] = checksum compilation[0xBD] = checksum
logp("") logp("")
logp("Compilation ROM size: {:.2f} MiB".format(rom_size / 1024 / 1024)) logp("Menu ROM: 0x{:07X}0x{:07X}".format(0, len(menu_rom)))
logp("ROM code: {:s}".format(rom_code)) logp("Game List: 0x{:07X}0x{:07X}".format(item_list_offset * sector_size, item_list_offset * sector_size + len(item_list)))
logp("Status Area: 0x{:07X}0x{:07X}".format(status_offset * sector_size, status_offset * sector_size + 0x1000))
logp("")
logp("Cartridge Type: {:d} ({:s}) {:s}".format(cartridge_type + 1, cartridge_types[cartridge_type]["name"], "with battery" if battery_present else "without battery"))
logp("Output ROM Size: {:.2f} MiB".format(rom_size / 1024 / 1024))
logp("Output ROM Code: {:s}".format(rom_code))
output_file = output_file.replace("<CODE>", rom_code) output_file = output_file.replace("<CODE>", rom_code)
if args.split: if args.split:
for i in range(0, math.ceil(flash_size / 0x2000000)): for i in range(0, math.ceil(flash_size / 0x2000000)):
@@ -296,7 +331,7 @@ if args.split:
size = 0x2000000 size = 0x2000000
if pos > len(compilation[:rom_size]): break if pos > len(compilation[:rom_size]): break
if pos + size > rom_size: size = rom_size - pos if pos + size > rom_size: size = rom_size - pos
output_file_part = "{:s}_part{:d}{:s}".format(os.path.splitext(output_file)[0], i + 1, os.path.splitext(output_file)[1]) output_file_part = "{:s}_part{:d}{:s}".format(os.path.splitext(output_file)[0], i, os.path.splitext(output_file)[1])
with open(output_file_part, "wb") as f: f.write(compilation[pos:pos+size]) with open(output_file_part, "wb") as f: f.write(compilation[pos:pos+size])
else: else:
with open(output_file, "wb") as f: f.write(compilation[:rom_size]) with open(output_file, "wb") as f: f.write(compilation[:rom_size])
@@ -307,7 +342,3 @@ if not args.no_log:
log += "\n################################\n\n" log += "\n################################\n\n"
with open("log.txt", "ab") as f: f.write(log.encode("UTF-8-SIG")) with open("log.txt", "ab") as f: f.write(log.encode("UTF-8-SIG"))
if not args.no_wait: input("\nPress ENTER to exit.\n") if not args.no_wait: input("\nPress ENTER to exit.\n")
# Debug
#with open("output_menu.gba", "wb") as f: f.write(compilation[:save_data_sector_offset * sector_size])
#with open("output_menu+save.gba", "wb") as f: f.write(compilation[:save_end_offset * sector_size])

View File

@@ -215,7 +215,7 @@ IWRAM_CODE u8 BootGame(ItemConfig config, FlashStatus status)
if (_flash_type == 0) if (_flash_type == 0)
return 1; return 1;
// Temporarily store SRAM values at mapper registers // Temporarily store SRAM values located at mapper registers
sram_register_backup[0] = *(vu8 *)MAPPER_CONFIG1; sram_register_backup[0] = *(vu8 *)MAPPER_CONFIG1;
sram_register_backup[1] = *(vu8 *)MAPPER_CONFIG2; sram_register_backup[1] = *(vu8 *)MAPPER_CONFIG2;
sram_register_backup[2] = *(vu8 *)MAPPER_CONFIG3; sram_register_backup[2] = *(vu8 *)MAPPER_CONFIG3;
@@ -225,7 +225,8 @@ IWRAM_CODE u8 BootGame(ItemConfig config, FlashStatus status)
*(vu8 *)MAPPER_CONFIG4 = 1; *(vu8 *)MAPPER_CONFIG4 = 1;
// Write previous SRAM to flash // Write previous SRAM to flash
if (status.battery_present) { if (status.battery_present)
{
if (status.last_boot_save_type != SRAM_NONE) if (status.last_boot_save_type != SRAM_NONE)
{ {
for (int i = 0; i < SRAM_SIZE; i++) for (int i = 0; i < SRAM_SIZE; i++)
@@ -279,7 +280,7 @@ IWRAM_CODE u8 BootGame(ItemConfig config, FlashStatus status)
*(vu8 *)MAPPER_CONFIG3 = 0x40 - config.rom_size; // accessible ROM size (in 512 KB blocks) *(vu8 *)MAPPER_CONFIG3 = 0x40 - config.rom_size; // accessible ROM size (in 512 KB blocks)
// Wait until menu ROM is no longer visible // Wait until menu ROM is no longer visible
u16 timeout = 0xFFFF; u32 timeout = 0x2FFF;
while (((vu16 *)AGB_ROM)[0x58] == 0x4B4C) while (((vu16 *)AGB_ROM)[0x58] == 0x4B4C)
{ {
if (!timeout--) if (!timeout--)
@@ -294,16 +295,20 @@ IWRAM_CODE u8 BootGame(ItemConfig config, FlashStatus status)
// Lock mapper // Lock mapper
*(vu8 *)MAPPER_CONFIG2 |= 0x80; *(vu8 *)MAPPER_CONFIG2 |= 0x80;
// Restore SRAM values at mapper registers
*(vu8 *)MAPPER_CONFIG1 = sram_register_backup[0];
*(vu8 *)MAPPER_CONFIG2 = sram_register_backup[1];
*(vu8 *)MAPPER_CONFIG3 = sram_register_backup[2];
*(vu8 *)MAPPER_CONFIG4 = sram_register_backup[3];
// Write buffer to SRAM // Write buffer to SRAM
for (int i = 0; i < SRAM_SIZE; i++) if (config.save_type != SRAM_NONE)
{ {
((vu8 *)AGB_SRAM)[i] = data_buffer[i]; for (int i = 0; i < SRAM_SIZE; i++)
{
((vu8 *)AGB_SRAM)[i] = data_buffer[i];
}
}
else
{
*(vu8 *)MAPPER_CONFIG1 = sram_register_backup[0];
*(vu8 *)MAPPER_CONFIG2 = sram_register_backup[1];
*(vu8 *)MAPPER_CONFIG3 = sram_register_backup[2];
*(vu8 *)MAPPER_CONFIG4 = sram_register_backup[3];
} }
// Clear palette // Clear palette
@@ -313,7 +318,7 @@ IWRAM_CODE u8 BootGame(ItemConfig config, FlashStatus status)
} }
REG_BLDY = 0; REG_BLDY = 0;
// Soft Reset system call // Boot ROM
__asm("swi 0"); // Soft reset __asm("swi 0"); // Soft reset
return 3; return 3;

View File

@@ -15,7 +15,6 @@ Author: Lesserkuma (github.com/lesserkuma)
} }
#define MAGIC_FLASH_STATUS 0x414D554B #define MAGIC_FLASH_STATUS 0x414D554B
#define FLASH_STATUS_LOCATION 0xA0000
typedef struct __attribute__((packed)) FlashStatus_ typedef struct __attribute__((packed)) FlashStatus_
{ {

View File

@@ -14,6 +14,7 @@ Author: Lesserkuma (github.com/lesserkuma)
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "version.h"
#include "main.h" #include "main.h"
#include "font.h" #include "font.h"
#include "flash.h" #include "flash.h"
@@ -106,7 +107,7 @@ int main(void) {
page_total = (roms_total + 8.0 - 1) / 8.0; page_total = (roms_total + 8.0 - 1) / 8.0;
memcpy(&sFlashStatus, (void *)(AGB_ROM + flash_status_sector_offset * flash_sector_size), sizeof(sFlashStatus)); memcpy(&sFlashStatus, (void *)(AGB_ROM + flash_status_sector_offset * flash_sector_size), sizeof(sFlashStatus));
if ((sFlashStatus.magic != MAGIC_FLASH_STATUS) || (sFlashStatus.last_boot_menu_index > roms_total)) { if ((sFlashStatus.magic != MAGIC_FLASH_STATUS) || (sFlashStatus.last_boot_menu_index >= roms_total)) {
sFlashStatus.magic = MAGIC_FLASH_STATUS; sFlashStatus.magic = MAGIC_FLASH_STATUS;
sFlashStatus.version = 0; sFlashStatus.version = 0;
sFlashStatus.battery_present = 1; sFlashStatus.battery_present = 1;
@@ -186,14 +187,10 @@ int main(void) {
} }
} else if (show_credits) { } else if (show_credits) {
LoadFont(0); LoadFont(0);
#ifdef __TIMESTAMP_ISO__ memset(temp_unicode, 0, sizeof(temp_unicode));
memset(temp_unicode, 0, sizeof(temp_unicode)); snprintf(temp_ascii, 48, "Menu by LK - %s", BUILDTIME);
snprintf(temp_ascii, 48, "Menu by LK - %s", __TIMESTAMP_ISO__); AsciiToUnicode(temp_ascii, temp_unicode);
AsciiToUnicode(temp_ascii, temp_unicode); DrawText(6, SCREEN_HEIGHT - sFontSpecs.max_height - 3 - FontMarginBottom, ALIGN_LEFT, temp_unicode, 48, font, (void*)AGB_VRAM+0xA000, FALSE);
DrawText(6, SCREEN_HEIGHT - sFontSpecs.max_height - 3 - FontMarginBottom, ALIGN_LEFT, temp_unicode, 48, font, (void*)AGB_VRAM+0xA000, FALSE);
#else
DrawText(6, SCREEN_HEIGHT - sFontSpecs.max_height - 3 - FontMarginBottom, ALIGN_LEFT, u"Menu by LK", 48, font, (void*)AGB_VRAM+0xA000, FALSE);
#endif
} else if (show_debug) { } else if (show_debug) {
LoadFont(0); LoadFont(0);
u8 a = ((sItemConfig.rom_offset / 0x40) & 0xF) << 4; u8 a = ((sItemConfig.rom_offset / 0x40) & 0xF) << 4;

15
source/version.h Normal file
View File

@@ -0,0 +1,15 @@
/*
GBA Multi Game Menu
Author: Lesserkuma (github.com/lesserkuma)
*/
#ifndef VERSION_H_
#define VERSION_H_
#ifdef __TIMESTAMP_ISO__
#define BUILDTIME __TIMESTAMP_ISO__
#else
#define BUILDTIME __TIMESTAMP__
#endif
#endif