bcsfe 3.2.2__tar.gz → 3.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bcsfe-3.2.2/src/bcsfe.egg-info → bcsfe-3.4.0}/PKG-INFO +6 -4
- {bcsfe-3.2.2 → bcsfe-3.4.0}/README.md +5 -3
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/__init__.py +1 -1
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/__main__.py +16 -2
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/__init__.py +2 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/dialog_creator.py +15 -6
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/edits/cat_editor.py +6 -4
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/edits/storage.py +31 -2
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/feature_handler.py +36 -40
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/main.py +37 -7
- bcsfe-3.4.0/src/bcsfe/cli/recent_saves.py +144 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/save_management.py +50 -14
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/server_cli.py +7 -1
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/__init__.py +20 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/cat.py +3 -1
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/gatya.py +1 -1
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/login_bonuses.py +6 -5
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/talent_orbs.py +31 -31
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/gamoto/cat_shrine.py +3 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/io/config.py +2 -2
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/io/git_handler.py +2 -4
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/io/path.py +47 -7
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/io/root_handler.py +1 -1
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/io/save.py +24 -3
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/locale_handler.py +1 -1
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/log.py +11 -18
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/server/game_data_getter.py +22 -4
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/server/request.py +1 -1
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/server/server_handler.py +8 -6
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/theme_handler.py +3 -11
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/core/save.properties +13 -5
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/core/server.properties +2 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/cats.properties +2 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/gamototo.properties +3 -3
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/special_skills.properties +1 -1
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/core/config.properties +95 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/core/files.properties +9 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/core/input.properties +31 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/core/locale.properties +33 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/core/main.properties +111 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/core/save.properties +117 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/core/server.properties +58 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/core/theme.properties +24 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/core/updater.properties +19 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/bannable_items.properties +30 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/cats.properties +160 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/enemy.properties +17 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/fixes.properties +13 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/gambling.properties +3 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/gamototo.properties +56 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/gatya.properties +8 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/gold_pass.properties +6 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/items.properties +64 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/map.properties +178 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/medals.properties +8 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/missions.properties +7 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/playtime.properties +7 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/scheme_items.properties +6 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/special_skills.properties +10 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/talent_orbs.properties +26 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/treasures.properties +24 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/user_rank.properties +9 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/tw/metadata.json +4 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/core/config.properties +95 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/vi/core/files.properties +1 -1
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/core/input.properties +33 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/core/locale.properties +118 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/core/main.properties +75 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/core/save.properties +84 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/core/server.properties +31 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/core/theme.properties +24 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/core/updater.properties +20 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/bannable_items.properties +31 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/cats.properties +154 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/enemy.properties +18 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/fixes.properties +13 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/vi/edits/gambling.properties +4 -3
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/gamototo.properties +56 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/gatya.properties +9 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/gold_pass.properties +7 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/items.properties +65 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/map.properties +177 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/medals.properties +9 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/missions.properties +8 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/playtime.properties +8 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/vi/edits/scheme_items.properties +1 -1
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/vi/edits/special_skills.properties +3 -3
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/talent_orbs.properties +24 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/treasures.properties +25 -0
- bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/user_rank.properties +10 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0/src/bcsfe.egg-info}/PKG-INFO +6 -4
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe.egg-info/SOURCES.txt +29 -0
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/core/config.properties +0 -97
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/core/input.properties +0 -32
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/core/locale.properties +0 -33
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/core/main.properties +0 -113
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/core/save.properties +0 -107
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/core/server.properties +0 -51
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/core/theme.properties +0 -25
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/core/updater.properties +0 -20
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/edits/bannable_items.properties +0 -31
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/edits/cats.properties +0 -166
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/edits/enemy.properties +0 -18
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/edits/fixes.properties +0 -14
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/edits/gamototo.properties +0 -55
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/edits/gatya.properties +0 -9
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/edits/gold_pass.properties +0 -7
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/edits/items.properties +0 -56
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/edits/map.properties +0 -158
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/edits/medals.properties +0 -9
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/edits/missions.properties +0 -8
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/edits/playtime.properties +0 -8
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/edits/talent_orbs.properties +0 -25
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/edits/treasures.properties +0 -25
- bcsfe-3.2.2/src/bcsfe/files/locales/vi/edits/user_rank.properties +0 -10
- {bcsfe-3.2.2 → bcsfe-3.4.0}/LICENSE +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/MANIFEST.in +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/pyproject.toml +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/setup.cfg +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/setup.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/color.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/edits/__init__.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/edits/aku_realm.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/edits/basic_items.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/edits/clear_tutorial.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/edits/enemy_editor.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/edits/event_tickets.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/edits/fixes.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/edits/map.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/edits/max_all.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/edits/rare_ticket_trade.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/cli/file_dialog.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/country_code.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/crypto.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/__init__.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/battle/__init__.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/battle/battle_items.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/battle/cleared_slots.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/battle/enemy.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/battle/slots.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/__init__.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/beacon_base.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/drop_chara.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/gambling.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/gatya_item.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/item_pack.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/matatabi.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/medals.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/mission.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/my_sale.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/nyanko_club.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/officer_pass.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/playtime.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/powerup.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/scheme_items.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/special_skill.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/stamp.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/unlock_popups.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/upgrade.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/user_rank_rewards.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/gamoto/__init__.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/gamoto/base_materials.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/gamoto/catamins.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/gamoto/gamatoto.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/gamoto/ototo.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/localizable.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/__init__.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/aku.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/challenge.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/chapters.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/dojo.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/enigma.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/event.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/ex_stage.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/gauntlets.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/item_reward_stage.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/legend_quest.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/map_names.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/map_option.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/map_reset.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/outbreaks.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/story.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/timed_score.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/tower.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/uncanny.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game/map/zero_legends.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/game_version.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/io/__init__.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/io/adb_handler.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/io/bc_csv.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/io/command.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/io/data.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/io/json_file.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/io/thread_helper.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/io/waydroid.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/io/yaml.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/max_value_helper.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/server/__init__.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/server/client_info.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/server/event_data.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/server/headers.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/server/managed_item.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/core/server/updater.py +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/core/config.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/core/files.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/core/input.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/core/locale.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/core/main.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/core/theme.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/core/updater.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/bannable_items.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/enemy.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/fixes.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/gambling.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/gatya.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/gold_pass.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/items.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/map.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/medals.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/missions.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/playtime.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/scheme_items.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/talent_orbs.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/treasures.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/user_rank.properties +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/locales/vi/metadata.json +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/max_values.json +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/themes/default.json +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/files/themes/discord.json +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe/py.typed +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe.egg-info/dependency_links.txt +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe.egg-info/entry_points.txt +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe.egg-info/requires.txt +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/src/bcsfe.egg-info/top_level.txt +0 -0
- {bcsfe-3.2.2 → bcsfe-3.4.0}/tests/test_parse.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bcsfe
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.4.0
|
|
4
4
|
Summary: A save file editor for The Battle Cats
|
|
5
5
|
Author: fieryhenry
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -56,6 +56,8 @@ test/develop new features
|
|
|
56
56
|
|
|
57
57
|
- HungJoesifer for Vietnamese localization
|
|
58
58
|
|
|
59
|
+
- LinYuAn for Traditional Chinese localization
|
|
60
|
+
|
|
59
61
|
### Themes
|
|
60
62
|
|
|
61
63
|
- HungJoesifer for the `discord` inspired theme
|
|
@@ -330,7 +332,7 @@ Once you have installed and ran the editor, you can now begin to edit your save
|
|
|
330
332
|
|
|
331
333
|
1. In `The Battle Cats` enter the `Change Account / Device` menu in the `Settings` on the main menu.
|
|
332
334
|
|
|
333
|
-
2. Then enter the `
|
|
335
|
+
2. Then enter the `Change Device` -> `Retrieve Data from Old Device` menu.
|
|
334
336
|
|
|
335
337
|
3. Then click / tap `Save Data to Server`, this should give you a transfer code and a confirmation
|
|
336
338
|
code.
|
|
@@ -359,8 +361,8 @@ may also fail, if it does then try again.
|
|
|
359
361
|
11. Back in-game, tap the `Close Game` button, then tap `Cancel Data Transfer` (and also possibly
|
|
360
362
|
`Start Game From Beginning`)
|
|
361
363
|
|
|
362
|
-
12. Go back into the `Change Account / Device` menu and then go into the `Resume Data Transfer`
|
|
363
|
-
menu
|
|
364
|
+
12. Go back into the `Change Account / Device` menu and then go into the `Resume Data Transfer` ->
|
|
365
|
+
`Transfer Data to New Device` menu
|
|
364
366
|
|
|
365
367
|
13. Enter the new codes, and tap `Resume Transfer`
|
|
366
368
|
|
|
@@ -27,6 +27,8 @@ test/develop new features
|
|
|
27
27
|
|
|
28
28
|
- HungJoesifer for Vietnamese localization
|
|
29
29
|
|
|
30
|
+
- LinYuAn for Traditional Chinese localization
|
|
31
|
+
|
|
30
32
|
### Themes
|
|
31
33
|
|
|
32
34
|
- HungJoesifer for the `discord` inspired theme
|
|
@@ -301,7 +303,7 @@ Once you have installed and ran the editor, you can now begin to edit your save
|
|
|
301
303
|
|
|
302
304
|
1. In `The Battle Cats` enter the `Change Account / Device` menu in the `Settings` on the main menu.
|
|
303
305
|
|
|
304
|
-
2. Then enter the `
|
|
306
|
+
2. Then enter the `Change Device` -> `Retrieve Data from Old Device` menu.
|
|
305
307
|
|
|
306
308
|
3. Then click / tap `Save Data to Server`, this should give you a transfer code and a confirmation
|
|
307
309
|
code.
|
|
@@ -330,8 +332,8 @@ may also fail, if it does then try again.
|
|
|
330
332
|
11. Back in-game, tap the `Close Game` button, then tap `Cancel Data Transfer` (and also possibly
|
|
331
333
|
`Start Game From Beginning`)
|
|
332
334
|
|
|
333
|
-
12. Go back into the `Change Account / Device` menu and then go into the `Resume Data Transfer`
|
|
334
|
-
menu
|
|
335
|
+
12. Go back into the `Change Account / Device` menu and then go into the `Resume Data Transfer` ->
|
|
336
|
+
`Transfer Data to New Device` menu
|
|
335
337
|
|
|
336
338
|
13. Enter the new codes, and tap `Resume Transfer`
|
|
337
339
|
|
|
@@ -18,19 +18,27 @@ def main():
|
|
|
18
18
|
parser.add_argument(
|
|
19
19
|
"--input-path", "-i", type=str, help="input path to save file to edit"
|
|
20
20
|
)
|
|
21
|
+
parser.add_argument(
|
|
22
|
+
"--game-data-dir", "-g", type=str, help="path to store the game data to"
|
|
23
|
+
)
|
|
24
|
+
parser.add_argument(
|
|
25
|
+
"--transfer-backup-path",
|
|
26
|
+
type=str,
|
|
27
|
+
help="path to save the backup SAVE_DATA after transfering to",
|
|
28
|
+
)
|
|
21
29
|
parser.add_argument(
|
|
22
30
|
"--config-path",
|
|
23
31
|
"-c",
|
|
24
32
|
type=str,
|
|
25
33
|
default=None,
|
|
26
|
-
help="path to the config file. If unspecified defaults to
|
|
34
|
+
help=f"path to the config file. If unspecified defaults to {core.Config.get_config_path()}",
|
|
27
35
|
)
|
|
28
36
|
parser.add_argument(
|
|
29
37
|
"--log-path",
|
|
30
38
|
"-l",
|
|
31
39
|
type=str,
|
|
32
40
|
default=None,
|
|
33
|
-
help="path to the log file. If unspecified defaults to
|
|
41
|
+
help=f"path to the log file. If unspecified defaults to {core.Logger.get_log_path()}",
|
|
34
42
|
)
|
|
35
43
|
|
|
36
44
|
args = parser.parse_args()
|
|
@@ -44,6 +52,12 @@ def main():
|
|
|
44
52
|
if args.log_path is not None:
|
|
45
53
|
core.set_log_path(core.Path(args.log_path))
|
|
46
54
|
|
|
55
|
+
if args.transfer_backup_path is not None:
|
|
56
|
+
core.set_transfer_backup_path(core.Path(args.transfer_backup_path))
|
|
57
|
+
|
|
58
|
+
if args.game_data_dir is not None:
|
|
59
|
+
core.set_game_data_path(core.Path(args.game_data_dir))
|
|
60
|
+
|
|
47
61
|
core.core_data.init_data()
|
|
48
62
|
|
|
49
63
|
try:
|
|
@@ -73,16 +73,25 @@ class IntInput:
|
|
|
73
73
|
default: int | None = None,
|
|
74
74
|
signed: bool = True,
|
|
75
75
|
bit_count: int = 32,
|
|
76
|
+
ensure_max: bool = False,
|
|
76
77
|
):
|
|
77
78
|
self.signed = signed
|
|
78
79
|
self.bit_count = bit_count
|
|
79
|
-
self.max = self.get_max_value(max, signed, bit_count)
|
|
80
|
+
self.max = self.get_max_value(max, signed, bit_count, ensure_max)
|
|
80
81
|
self.min = min
|
|
81
82
|
self.default = default
|
|
82
83
|
|
|
83
84
|
@staticmethod
|
|
84
|
-
def get_max_value(
|
|
85
|
-
|
|
85
|
+
def get_max_value(
|
|
86
|
+
max: int | None,
|
|
87
|
+
signed: bool = True,
|
|
88
|
+
bit_count: int = 32,
|
|
89
|
+
ensure_max: bool = False,
|
|
90
|
+
) -> int:
|
|
91
|
+
disable_maxes = (
|
|
92
|
+
core.core_data.config.get_bool(core.ConfigKey.DISABLE_MAXES)
|
|
93
|
+
and not ensure_max
|
|
94
|
+
)
|
|
86
95
|
if signed:
|
|
87
96
|
bit_count -= 1
|
|
88
97
|
max_int = (2**bit_count) - 1
|
|
@@ -273,9 +282,9 @@ class ChoiceInput:
|
|
|
273
282
|
start_index=self.start_index,
|
|
274
283
|
localize_elements=self.localize_options,
|
|
275
284
|
).display_locale(self.remove_alias)
|
|
276
|
-
return IntInput(
|
|
277
|
-
self.
|
|
278
|
-
)
|
|
285
|
+
return IntInput(
|
|
286
|
+
self.get_max_value(), self.get_min_value(), ensure_max=True
|
|
287
|
+
).get_input_locale(self.dialog, self.perameters)
|
|
279
288
|
|
|
280
289
|
def get_input_while(self) -> int | None:
|
|
281
290
|
if len(self.strings) == 0:
|
|
@@ -413,8 +413,9 @@ class CatEditor:
|
|
|
413
413
|
if should_exit:
|
|
414
414
|
return
|
|
415
415
|
if upgrade is not None:
|
|
416
|
-
|
|
417
|
-
|
|
416
|
+
if upgrade.base != -1:
|
|
417
|
+
power_up.reset_upgrade()
|
|
418
|
+
power_up.upgrade_by(upgrade.base)
|
|
418
419
|
cat.set_upgrade(self.save_file, upgrade, True)
|
|
419
420
|
color.ColoredText.localize(
|
|
420
421
|
"selected_cat_upgraded",
|
|
@@ -435,8 +436,9 @@ class CatEditor:
|
|
|
435
436
|
success = True
|
|
436
437
|
for cat in cats:
|
|
437
438
|
power_up = core.PowerUpHelper(cat, self.save_file)
|
|
438
|
-
|
|
439
|
-
|
|
439
|
+
if upgrade.base != -1:
|
|
440
|
+
power_up.reset_upgrade()
|
|
441
|
+
power_up.upgrade_by(upgrade.base)
|
|
440
442
|
cat.set_upgrade(self.save_file, upgrade, True)
|
|
441
443
|
if success:
|
|
442
444
|
color.ColoredText.localize("upgrade_success")
|
|
@@ -128,6 +128,23 @@ def edit_loop(save_file: core.SaveFile) -> bool:
|
|
|
128
128
|
if editor is None:
|
|
129
129
|
return False
|
|
130
130
|
|
|
131
|
+
new_cats: list[core.Cat] = []
|
|
132
|
+
for cat in cats:
|
|
133
|
+
names = cat.get_names_cls(save_file)
|
|
134
|
+
if names is None or not names:
|
|
135
|
+
name = core.localize("unknown")
|
|
136
|
+
else:
|
|
137
|
+
name = names[0]
|
|
138
|
+
quantity, _ = dialog_creator.IntInput(default=1).get_input_locale(
|
|
139
|
+
"cat_quantity", {"name": name, "id": cat.id}
|
|
140
|
+
)
|
|
141
|
+
if quantity is None:
|
|
142
|
+
return False
|
|
143
|
+
for _ in range(quantity):
|
|
144
|
+
new_cats.append(cat)
|
|
145
|
+
|
|
146
|
+
cats = new_cats
|
|
147
|
+
|
|
131
148
|
space = get_storage_space(storage)
|
|
132
149
|
if len(cats) > len(storage):
|
|
133
150
|
color.ColoredText.localize(
|
|
@@ -164,6 +181,19 @@ def edit_loop(save_file: core.SaveFile) -> bool:
|
|
|
164
181
|
if options is None:
|
|
165
182
|
return False
|
|
166
183
|
|
|
184
|
+
items: list[core.StorageItem] = []
|
|
185
|
+
|
|
186
|
+
for id in options:
|
|
187
|
+
item = core.StorageItem.from_special_skill(id)
|
|
188
|
+
|
|
189
|
+
quantity, _ = dialog_creator.IntInput(default=1).get_input_locale(
|
|
190
|
+
"skill_quantity", {"name": skill_names[id]}
|
|
191
|
+
)
|
|
192
|
+
if quantity is None:
|
|
193
|
+
return False
|
|
194
|
+
for _ in range(quantity):
|
|
195
|
+
items.append(item)
|
|
196
|
+
|
|
167
197
|
space = get_storage_space(storage)
|
|
168
198
|
if len(options) > len(storage):
|
|
169
199
|
color.ColoredText.localize(
|
|
@@ -177,8 +207,7 @@ def edit_loop(save_file: core.SaveFile) -> bool:
|
|
|
177
207
|
return False
|
|
178
208
|
|
|
179
209
|
color.ColoredText.localize("added_special_skills")
|
|
180
|
-
for
|
|
181
|
-
item = core.StorageItem.from_special_skill(choice)
|
|
210
|
+
for item in items:
|
|
182
211
|
add_item(storage, item)
|
|
183
212
|
display_item(item, save_file)
|
|
184
213
|
|
|
@@ -8,7 +8,7 @@ class FeatureHandler:
|
|
|
8
8
|
def __init__(self, save_file: core.SaveFile):
|
|
9
9
|
self.save_file = save_file
|
|
10
10
|
|
|
11
|
-
def get_features(self):
|
|
11
|
+
def get_features(self) -> dict[str, Any]:
|
|
12
12
|
cat_features = {"cats": edits.cat_editor.CatEditor.edit_cats}
|
|
13
13
|
if core.core_data.config.get_bool(core.ConfigKey.SEPARATE_CAT_EDIT_OPTIONS):
|
|
14
14
|
cat_features = {
|
|
@@ -33,7 +33,9 @@ class FeatureHandler:
|
|
|
33
33
|
"save_save": save_management.SaveManagement.save_save,
|
|
34
34
|
"save_upload": save_management.SaveManagement.save_upload,
|
|
35
35
|
"save_save_file": save_management.SaveManagement.save_save_dialog,
|
|
36
|
-
|
|
36
|
+
core.localize(
|
|
37
|
+
"save_save_documents", path=core.SaveFile.get_save_path()
|
|
38
|
+
): save_management.SaveManagement.save_save_data_dir,
|
|
37
39
|
"waydroid_push": save_management.SaveManagement.waydroid_push,
|
|
38
40
|
"waydroid_push_rerun": save_management.SaveManagement.waydroid_push_rerun,
|
|
39
41
|
"adb_push": save_management.SaveManagement.adb_push,
|
|
@@ -142,8 +144,7 @@ class FeatureHandler:
|
|
|
142
144
|
}
|
|
143
145
|
return features
|
|
144
146
|
|
|
145
|
-
def get_feature(self,
|
|
146
|
-
feature_path = feature_name.split(".")
|
|
147
|
+
def get_feature(self, feature_path: list[str]):
|
|
147
148
|
feature_dict = self.get_features()
|
|
148
149
|
feature = feature_dict
|
|
149
150
|
for path in feature_path:
|
|
@@ -154,10 +155,10 @@ class FeatureHandler:
|
|
|
154
155
|
def search_features(
|
|
155
156
|
self,
|
|
156
157
|
name: str,
|
|
157
|
-
|
|
158
|
+
current_path: list[str],
|
|
158
159
|
features: dict[str, Any] | None = None,
|
|
159
|
-
found_features: dict[str, int] | None = None,
|
|
160
|
-
) -> dict[str, int]:
|
|
160
|
+
found_features: dict[tuple[str, ...], int] | None = None,
|
|
161
|
+
) -> dict[tuple[str, ...], int]:
|
|
161
162
|
name = name.lower()
|
|
162
163
|
if features is None:
|
|
163
164
|
features = self.get_features()
|
|
@@ -166,9 +167,8 @@ class FeatureHandler:
|
|
|
166
167
|
|
|
167
168
|
for feature_name_key, feature in features.items():
|
|
168
169
|
feature_name = core.core_data.local_manager.get_key(feature_name_key)
|
|
169
|
-
path = (
|
|
170
|
-
|
|
171
|
-
)
|
|
170
|
+
path = current_path.copy()
|
|
171
|
+
path.append(feature_name_key)
|
|
172
172
|
if isinstance(feature, dict):
|
|
173
173
|
found_features.update(
|
|
174
174
|
self.search_features(
|
|
@@ -180,34 +180,36 @@ class FeatureHandler:
|
|
|
180
180
|
)
|
|
181
181
|
for alias in core.LocalManager.get_all_aliases(feature_name):
|
|
182
182
|
if not name:
|
|
183
|
-
found_features[path] = 100
|
|
183
|
+
found_features[*path] = 100
|
|
184
184
|
break
|
|
185
185
|
alias = alias.lower()
|
|
186
186
|
|
|
187
187
|
name = name.replace(" ", "")
|
|
188
188
|
alias = alias.replace(" ", "")
|
|
189
189
|
if alias in name or name in alias:
|
|
190
|
-
found_features[path] = 100
|
|
190
|
+
found_features[*path] = 100
|
|
191
191
|
break
|
|
192
192
|
|
|
193
193
|
return found_features
|
|
194
194
|
|
|
195
|
-
def display_features(self, features: list[str]):
|
|
195
|
+
def display_features(self, features: list[list[str]]):
|
|
196
196
|
feature_names: list[str] = []
|
|
197
197
|
for feature_name in features:
|
|
198
|
-
feature_names.append(feature_name
|
|
198
|
+
feature_names.append(feature_name[-1])
|
|
199
199
|
print()
|
|
200
200
|
dialog_creator.ListOutput(feature_names, [], "features", {}).display_locale(
|
|
201
201
|
remove_alias=True
|
|
202
202
|
)
|
|
203
203
|
|
|
204
|
-
def select_features(
|
|
204
|
+
def select_features(
|
|
205
|
+
self, features: list[list[str]], current_path: list[str]
|
|
206
|
+
) -> list[list[str]]:
|
|
205
207
|
if features != list(self.get_features().keys()):
|
|
206
|
-
features.insert(0, "go_back")
|
|
208
|
+
features.insert(0, ["go_back"])
|
|
207
209
|
self.display_features(features)
|
|
208
210
|
print()
|
|
209
211
|
usr_input = color.ColoredInput().localize("select_features").strip()
|
|
210
|
-
selected_features: list[str] = []
|
|
212
|
+
selected_features: list[list[str]] = []
|
|
211
213
|
if usr_input.isdigit():
|
|
212
214
|
usr_input = int(usr_input)
|
|
213
215
|
if usr_input > len(features):
|
|
@@ -216,59 +218,53 @@ class FeatureHandler:
|
|
|
216
218
|
color.ColoredText.localize("invalid_input")
|
|
217
219
|
else:
|
|
218
220
|
feature_name_top = features[usr_input - 1]
|
|
219
|
-
if feature_name_top == "go_back":
|
|
220
|
-
return
|
|
221
|
+
if feature_name_top == ["go_back"]:
|
|
222
|
+
return [[k] for k in self.get_features().keys()]
|
|
221
223
|
feature = self.get_feature(feature_name_top)
|
|
222
224
|
if isinstance(feature, dict):
|
|
223
225
|
for feature_name in feature.keys(): # type: ignore
|
|
224
|
-
feature_path = (
|
|
225
|
-
|
|
226
|
-
if parent_path
|
|
227
|
-
else f"{feature_name_top}.{feature_name}"
|
|
228
|
-
)
|
|
226
|
+
feature_path: list[str] = current_path.copy()
|
|
227
|
+
feature_path.extend(feature_name_top + [feature_name])
|
|
229
228
|
selected_features.append(feature_path)
|
|
230
229
|
|
|
231
230
|
else:
|
|
232
|
-
feature_path = (
|
|
233
|
-
|
|
234
|
-
if parent_path
|
|
235
|
-
else feature_name_top
|
|
236
|
-
)
|
|
231
|
+
feature_path = current_path.copy()
|
|
232
|
+
feature_path.extend(feature_name_top)
|
|
237
233
|
selected_features.append(feature_path)
|
|
238
234
|
|
|
239
235
|
else:
|
|
240
|
-
feats = self.search_features(usr_input)
|
|
236
|
+
feats = self.search_features(usr_input, [])
|
|
241
237
|
if not feats:
|
|
242
238
|
color.ColoredText.localize("no_feature_with_name", name=usr_input)
|
|
243
239
|
kv_map = list(feats.items())
|
|
244
240
|
kv_map.sort(key=lambda v: v[1], reverse=True)
|
|
245
|
-
selected_features = [v[0] for v in kv_map]
|
|
241
|
+
selected_features = [list(v[0]) for v in kv_map]
|
|
246
242
|
|
|
247
243
|
return selected_features
|
|
248
244
|
|
|
249
245
|
def select_features_run(self):
|
|
250
|
-
|
|
251
|
-
features =
|
|
246
|
+
features_dict = self.get_features()
|
|
247
|
+
features: list[list[str]] = [[k] for k in features_dict.keys()]
|
|
252
248
|
self.save_file.to_file_thread(self.save_file.get_temp_path())
|
|
253
249
|
edits.clear_tutorial.clear_tutorial(self.save_file, False)
|
|
254
250
|
self.save_file.show_ban_message = False
|
|
255
251
|
|
|
256
252
|
while True:
|
|
257
|
-
features = self.select_features(features)
|
|
253
|
+
features = self.select_features(features, [])
|
|
258
254
|
|
|
259
|
-
new_features: list[str] = []
|
|
255
|
+
new_features: list[list[str]] = []
|
|
260
256
|
found_strs: list[str] = []
|
|
261
257
|
for feature_ in features:
|
|
262
|
-
if feature_
|
|
258
|
+
if feature_[-1] in found_strs:
|
|
263
259
|
continue
|
|
264
|
-
found_strs.append(feature_
|
|
260
|
+
found_strs.append(feature_[-1])
|
|
265
261
|
new_features.append(feature_)
|
|
266
262
|
|
|
267
263
|
features = new_features
|
|
268
264
|
feature = None
|
|
269
265
|
if len(features) == 1:
|
|
270
266
|
feature = features[0]
|
|
271
|
-
if len(features) == 2 and features[0] == "go_back":
|
|
267
|
+
if len(features) == 2 and features[0] == ["go_back"]:
|
|
272
268
|
feature = features[1]
|
|
273
269
|
|
|
274
270
|
if not feature:
|
|
@@ -283,8 +279,8 @@ class FeatureHandler:
|
|
|
283
279
|
|
|
284
280
|
self.save_file.to_file_thread(self.save_file.get_temp_path())
|
|
285
281
|
|
|
286
|
-
|
|
287
|
-
features =
|
|
282
|
+
features_dict = self.get_features()
|
|
283
|
+
features = [[k] for k in features_dict.keys()]
|
|
288
284
|
|
|
289
285
|
core.core_data.game_data_getter = None # reset game data getter so that if an old version is removed, it will download the new version
|
|
290
286
|
|
|
@@ -40,6 +40,26 @@ class Main:
|
|
|
40
40
|
if stop:
|
|
41
41
|
break
|
|
42
42
|
|
|
43
|
+
def version_check(self, v1: str, v2: str) -> bool:
|
|
44
|
+
v1_p = v1.split(".")
|
|
45
|
+
v2_p = v2.split(".")
|
|
46
|
+
|
|
47
|
+
for p1, p2 in zip(v1_p, v2_p):
|
|
48
|
+
if p1.isdigit():
|
|
49
|
+
p1 = int(p1)
|
|
50
|
+
else:
|
|
51
|
+
continue
|
|
52
|
+
if p2.isdigit():
|
|
53
|
+
p2 = int(p2)
|
|
54
|
+
else:
|
|
55
|
+
continue
|
|
56
|
+
if p1 > p2:
|
|
57
|
+
return True
|
|
58
|
+
if p1 < p2:
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
return len(v1_p) > len(v2_p)
|
|
62
|
+
|
|
43
63
|
def check_update(self):
|
|
44
64
|
"""Check for updates."""
|
|
45
65
|
|
|
@@ -64,16 +84,19 @@ class Main:
|
|
|
64
84
|
local_no_beta = local_version.split("b")[0]
|
|
65
85
|
latest_no_beta = latest_version.split("b")[0]
|
|
66
86
|
|
|
67
|
-
if latest_no_beta
|
|
87
|
+
if self.version_check(latest_no_beta, local_no_beta):
|
|
68
88
|
update_needed = True
|
|
69
|
-
elif latest_no_beta
|
|
89
|
+
elif self.version_check(local_no_beta, latest_no_beta):
|
|
70
90
|
update_needed = False
|
|
71
91
|
else:
|
|
72
92
|
if latest_version == local_version:
|
|
73
93
|
update_needed = False
|
|
74
94
|
else:
|
|
75
95
|
if is_local_beta and is_latest_beta:
|
|
76
|
-
update_needed =
|
|
96
|
+
update_needed = self.version_check(
|
|
97
|
+
latest_version.replace("b", "."),
|
|
98
|
+
local_version.replace("b", "."),
|
|
99
|
+
)
|
|
77
100
|
elif is_local_beta:
|
|
78
101
|
update_needed = True
|
|
79
102
|
else:
|
|
@@ -168,6 +191,15 @@ class Main:
|
|
|
168
191
|
return stop
|
|
169
192
|
self.save_file = save_file
|
|
170
193
|
|
|
194
|
+
color.ColoredText.localize(
|
|
195
|
+
"current_save",
|
|
196
|
+
inquiry_code=save_file.inquiry_code[:4]
|
|
197
|
+
+ "***"
|
|
198
|
+
+ save_file.inquiry_code[-2:],
|
|
199
|
+
gv=save_file.game_version,
|
|
200
|
+
cc=save_file.cc,
|
|
201
|
+
)
|
|
202
|
+
|
|
171
203
|
self.feature_handler()
|
|
172
204
|
return False
|
|
173
205
|
|
|
@@ -259,10 +291,8 @@ class Main:
|
|
|
259
291
|
return None
|
|
260
292
|
try:
|
|
261
293
|
json_data = core.JsonFile.from_data(path.read()).to_object()
|
|
262
|
-
except core.JSONDecodeError:
|
|
263
|
-
color.ColoredText.localize(
|
|
264
|
-
"load_json_fail", error=core.core_data.logger.get_traceback()
|
|
265
|
-
)
|
|
294
|
+
except (core.JSONDecodeError, UnicodeDecodeError):
|
|
295
|
+
color.ColoredText.localize("parse_json_fail")
|
|
266
296
|
return None
|
|
267
297
|
try:
|
|
268
298
|
save_file = core.SaveFile.from_dict(json_data)
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from bcsfe import core
|
|
5
|
+
import datetime
|
|
6
|
+
import json
|
|
7
|
+
from bcsfe.cli import color, dialog_creator
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RecentSave:
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
path: core.Path,
|
|
14
|
+
cc: core.CountryCode,
|
|
15
|
+
gv: core.GameVersion,
|
|
16
|
+
inquiry: str,
|
|
17
|
+
time: datetime.datetime,
|
|
18
|
+
name: core.Path,
|
|
19
|
+
):
|
|
20
|
+
self.path = path
|
|
21
|
+
self.cc = cc
|
|
22
|
+
self.gv = gv
|
|
23
|
+
self.inquiry = inquiry
|
|
24
|
+
self.time = time
|
|
25
|
+
self.name = name
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def from_dict(data: dict[str, Any]) -> RecentSave | None:
|
|
29
|
+
path = data.get("path")
|
|
30
|
+
cc = data.get("cc")
|
|
31
|
+
gv = data.get("gv")
|
|
32
|
+
inquiry = data.get("inquiry")
|
|
33
|
+
time_stamp = data.get("timestamp")
|
|
34
|
+
name = data.get("name")
|
|
35
|
+
if (
|
|
36
|
+
path is None
|
|
37
|
+
or cc is None
|
|
38
|
+
or gv is None
|
|
39
|
+
or inquiry is None
|
|
40
|
+
or time_stamp is None
|
|
41
|
+
or name is None
|
|
42
|
+
):
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
return RecentSave(
|
|
46
|
+
core.Path(path),
|
|
47
|
+
core.CountryCode(cc),
|
|
48
|
+
core.GameVersion.from_string(gv),
|
|
49
|
+
inquiry,
|
|
50
|
+
datetime.datetime.fromtimestamp(time_stamp),
|
|
51
|
+
core.Path(name),
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def to_dict(self) -> dict[str, Any]:
|
|
55
|
+
return {
|
|
56
|
+
"path": self.path.to_str(),
|
|
57
|
+
"cc": self.cc.get_code(),
|
|
58
|
+
"gv": self.gv.to_string(),
|
|
59
|
+
"inquiry": self.inquiry,
|
|
60
|
+
"timestamp": self.time.timestamp(),
|
|
61
|
+
"name": self.name.to_str(),
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class RecentSaves:
|
|
66
|
+
def __init__(self, saves: list[RecentSave]):
|
|
67
|
+
self.saves = saves
|
|
68
|
+
|
|
69
|
+
@staticmethod
|
|
70
|
+
def from_json(data: list[dict[str, Any]]) -> RecentSaves:
|
|
71
|
+
res: list[RecentSave] = []
|
|
72
|
+
|
|
73
|
+
for item in data:
|
|
74
|
+
save = RecentSave.from_dict(item)
|
|
75
|
+
if save is not None:
|
|
76
|
+
res.append(save)
|
|
77
|
+
|
|
78
|
+
return RecentSaves(res)
|
|
79
|
+
|
|
80
|
+
def to_json(self) -> list[dict[str, Any]]:
|
|
81
|
+
return [save.to_dict() for save in self.saves][-10:] # only store 10
|
|
82
|
+
|
|
83
|
+
@staticmethod
|
|
84
|
+
def from_path(path: core.Path) -> RecentSaves | None:
|
|
85
|
+
json_data = json.loads(path.read().to_str())
|
|
86
|
+
|
|
87
|
+
return RecentSaves.from_json(json_data)
|
|
88
|
+
|
|
89
|
+
def to_path(self, path: core.Path):
|
|
90
|
+
data = json.dumps(self.to_json(), indent=4)
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
path.write(core.Data(data))
|
|
94
|
+
except Exception as e:
|
|
95
|
+
print(e)
|
|
96
|
+
|
|
97
|
+
@staticmethod
|
|
98
|
+
def read_default() -> RecentSaves:
|
|
99
|
+
path = RecentSaves.get_path()
|
|
100
|
+
if path.exists():
|
|
101
|
+
return RecentSaves.from_path(path) or RecentSaves([])
|
|
102
|
+
return RecentSaves([])
|
|
103
|
+
|
|
104
|
+
@staticmethod
|
|
105
|
+
def get_path() -> core.Path:
|
|
106
|
+
return core.Path.get_data_folder().add("recent_saves.json")
|
|
107
|
+
|
|
108
|
+
def save_default(self):
|
|
109
|
+
path = RecentSaves.get_path()
|
|
110
|
+
self.to_path(path)
|
|
111
|
+
|
|
112
|
+
def select(self) -> RecentSave | None:
|
|
113
|
+
if not self.saves:
|
|
114
|
+
color.ColoredText.localize("no_recent_saves")
|
|
115
|
+
return None
|
|
116
|
+
items: list[str] = []
|
|
117
|
+
for save in self.saves:
|
|
118
|
+
items.append(
|
|
119
|
+
core.localize(
|
|
120
|
+
"recent_save",
|
|
121
|
+
path=save.path,
|
|
122
|
+
cc=save.cc,
|
|
123
|
+
gv=save.gv,
|
|
124
|
+
inquiry_code=save.inquiry,
|
|
125
|
+
year=save.time.year,
|
|
126
|
+
month=str(save.time.month).zfill(2),
|
|
127
|
+
day=str(save.time.day).zfill(2),
|
|
128
|
+
hour=str(save.time.hour).zfill(2),
|
|
129
|
+
minute=str(save.time.minute).zfill(2),
|
|
130
|
+
second=str(save.time.second).zfill(2),
|
|
131
|
+
name=save.name,
|
|
132
|
+
)
|
|
133
|
+
)
|
|
134
|
+
items.reverse()
|
|
135
|
+
|
|
136
|
+
resp = dialog_creator.ChoiceInput.from_reduced(
|
|
137
|
+
items, localize_options=False, dialog="select_recent"
|
|
138
|
+
).single_choice()
|
|
139
|
+
if resp is None:
|
|
140
|
+
return None
|
|
141
|
+
|
|
142
|
+
resp = len(self.saves) - resp
|
|
143
|
+
|
|
144
|
+
return self.saves[resp]
|