541def parse_save(data, base_dir):
542 entries = parse_bnd4(data)
543 game = detect_game(data, entries)
545 version = save_format_version(data, entries, cfg, game)
546 patch = er_game_patch(data, entries)
if game ==
"er" else None
553 iddb = load_er_db(os.path.join(base_dir, cfg[
"db"]))
555 sys.exit(f
"No item database found in {os.path.join(base_dir, cfg['db'])}")
556 menu_entry = entries[cfg[
"menu"]]
558 data[menu_entry.offset : menu_entry.offset + menu_entry.size]
560 for i
in cfg[
"slots"]:
561 if i >= len(entries):
563 active, name, level = roster[i]
if i < len(roster)
else (
True,
None,
None)
566 slot = cfg[
"decrypt"](
567 data[entries[i].offset : entries[i].offset + entries[i].size]
571 ch = er_parse(slot, iddb, name, level)
573 attach_defeated_bosses(ch, base_dir)
574 attach_progress_totals(ch, base_dir)
575 characters.append((i, ch))
576 return SaveData(game, cfg, version, patch, characters, owner, folder)
582 menu_entry = entries[cfg[
"menu"]]
583 roster = cfg[
"decrypt"](
584 data[menu_entry.offset : menu_entry.offset + menu_entry.size]
586 names = nr_roster(roster)
if roster
is not None else [
None] * NR_SLOT_COUNT
587 for i
in cfg[
"slots"]:
588 if i >= len(entries):
590 slot = cfg[
"decrypt"](
591 data[entries[i].offset : entries[i].offset + entries[i].size]
593 if slot
is None or not nr_slot_used(slot):
595 characters.append((i, nr_parse(names[i]
if i < len(names)
else None)))
596 return SaveData(game, cfg, version, patch, characters, owner, folder)
601 db_dir = os.path.join(base_dir, cfg[
"db"])
602 iddb = load_sdt_db(db_dir)
603 if not any(iddb[
"names"].values()):
604 sys.exit(f
"No item database found in {db_dir}")
607 active = sdt_active_slots(data, entries, cfg[
"decrypt"])
608 for i
in cfg[
"slots"]:
609 if i >= len(entries)
or (active
is not None and i
not in active):
611 slot = cfg[
"decrypt"](
612 data[entries[i].offset : entries[i].offset + entries[i].size]
616 ch = sdt_parse(slot, iddb)
618 attach_defeated_bosses(ch, base_dir)
619 sdt_attach_flags(ch, slot, base_dir)
620 attach_progress_totals(ch, base_dir)
621 characters.append((i, ch))
622 return SaveData(game, cfg, version, patch, characters, owner, folder)
626 db_dir = os.path.join(base_dir, cfg[
"db"][0])
627 iddb = load_scan_db(db_dir, cfg[
"db"][1], ds3_item_cat)
629 sys.exit(f
"No item database found in {db_dir}")
630 menu_entry = entries[cfg[
"menu"]]
631 menu = cfg[
"decrypt"](
632 data[menu_entry.offset : menu_entry.offset + menu_entry.size]
634 names = dict(parse_roster(menu
or b
"", game))
if menu
is not None else {}
635 for i
in cfg[
"slots"]:
636 if i >= len(entries):
638 slot = cfg[
"decrypt"](
639 data[entries[i].offset : entries[i].offset + entries[i].size]
643 ch = ds3_parse(slot, iddb, names.get(i))
646 ch[
"play_time"] = ds3_playtime(menu, i)
647 flag_base = ds3_event_flag_base(slot)
648 ch[
"ng_plus"] = ds3_journey(slot, flag_base)
649 attach_defeated_bosses(ch, base_dir)
650 ds3_attach_ring_effects(ch, base_dir)
651 ds3_attach_flags(ch, slot, flag_base, base_dir)
652 attach_progress_totals(ch, base_dir)
653 characters.append((i, ch))
654 return SaveData(game, cfg, version, patch, characters, owner, folder)
657 db_dir = os.path.join(base_dir, cfg[
"db"][0])
658 item_db = load_item_db(db_dir, cfg[
"db"][1], cfg[
"db"][2])
660 sys.exit(f
"No item database found in {db_dir}")
664 active = cfg[
"active"](data, entries, cfg[
"slots"])
if "active" in cfg
else None
666 for i
in cfg[
"slots"]:
667 if i >= len(entries):
669 if active
is not None and i
not in active:
671 blob = data[entries[i].offset : entries[i].offset + entries[i].size]
672 game_data = cfg[
"decrypt"](blob)
673 if game_data
is None:
675 ch = cfg[
"parse"](game_data, item_db)
678 cfg[
"augment"](ch, data, entries, i, base_dir)
679 attach_defeated_bosses(ch, base_dir)
680 attach_progress_totals(ch, base_dir)
681 characters.append((i, ch))
682 return SaveData(game, cfg, version, patch, characters, owner, folder)