bcsfe 3.2.1__tar.gz → 3.3.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.
Files changed (187) hide show
  1. {bcsfe-3.2.1/src/bcsfe.egg-info → bcsfe-3.3.0}/PKG-INFO +1 -1
  2. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/__init__.py +1 -1
  3. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/cli/__init__.py +2 -0
  4. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/cli/dialog_creator.py +36 -14
  5. bcsfe-3.3.0/src/bcsfe/cli/edits/map.py +544 -0
  6. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/cli/feature_handler.py +1 -1
  7. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/cli/main.py +35 -3
  8. bcsfe-3.3.0/src/bcsfe/cli/recent_saves.py +141 -0
  9. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/cli/save_management.py +56 -13
  10. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/__init__.py +10 -1
  11. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/battle/battle_items.py +4 -1
  12. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/cat.py +3 -1
  13. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/login_bonuses.py +6 -5
  14. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/talent_orbs.py +31 -31
  15. bcsfe-3.3.0/src/bcsfe/core/game/catbase/unlock_popups.py +163 -0
  16. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/upgrade.py +8 -2
  17. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/gamoto/cat_shrine.py +25 -16
  18. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/map/__init__.py +2 -0
  19. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/map/chapters.py +15 -7
  20. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/map/enigma.py +1 -1
  21. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/map/event.py +91 -31
  22. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/map/gauntlets.py +19 -11
  23. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/map/legend_quest.py +18 -9
  24. bcsfe-3.3.0/src/bcsfe/core/game/map/map_names.py +112 -0
  25. bcsfe-3.3.0/src/bcsfe/core/game/map/map_option.py +79 -0
  26. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/map/story.py +2 -1
  27. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/map/tower.py +1 -1
  28. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/map/uncanny.py +3 -3
  29. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/map/zero_legends.py +14 -8
  30. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/io/config.py +15 -0
  31. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/io/save.py +19 -5
  32. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/server/game_data_getter.py +22 -2
  33. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/server/request.py +1 -1
  34. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/core/locale.properties +1 -1
  35. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/core/main.properties +1 -1
  36. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/core/save.properties +10 -3
  37. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/core/server.properties +7 -0
  38. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/core/theme.properties +1 -1
  39. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/edits/cats.properties +1 -0
  40. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/edits/gamototo.properties +6 -4
  41. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/edits/gold_pass.properties +1 -1
  42. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/edits/map.properties +39 -1
  43. {bcsfe-3.2.1 → bcsfe-3.3.0/src/bcsfe.egg-info}/PKG-INFO +1 -1
  44. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe.egg-info/SOURCES.txt +2 -0
  45. {bcsfe-3.2.1 → bcsfe-3.3.0}/tests/test_parse.py +3 -0
  46. bcsfe-3.2.1/src/bcsfe/cli/edits/map.py +0 -275
  47. bcsfe-3.2.1/src/bcsfe/core/game/catbase/unlock_popups.py +0 -71
  48. bcsfe-3.2.1/src/bcsfe/core/game/map/map_names.py +0 -138
  49. {bcsfe-3.2.1 → bcsfe-3.3.0}/LICENSE +0 -0
  50. {bcsfe-3.2.1 → bcsfe-3.3.0}/MANIFEST.in +0 -0
  51. {bcsfe-3.2.1 → bcsfe-3.3.0}/README.md +0 -0
  52. {bcsfe-3.2.1 → bcsfe-3.3.0}/pyproject.toml +0 -0
  53. {bcsfe-3.2.1 → bcsfe-3.3.0}/setup.cfg +0 -0
  54. {bcsfe-3.2.1 → bcsfe-3.3.0}/setup.py +0 -0
  55. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/__main__.py +0 -0
  56. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/cli/color.py +0 -0
  57. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/cli/edits/__init__.py +0 -0
  58. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/cli/edits/aku_realm.py +0 -0
  59. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/cli/edits/basic_items.py +0 -0
  60. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/cli/edits/cat_editor.py +0 -0
  61. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/cli/edits/clear_tutorial.py +0 -0
  62. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/cli/edits/enemy_editor.py +0 -0
  63. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/cli/edits/event_tickets.py +0 -0
  64. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/cli/edits/fixes.py +0 -0
  65. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/cli/edits/max_all.py +0 -0
  66. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/cli/edits/rare_ticket_trade.py +0 -0
  67. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/cli/edits/storage.py +0 -0
  68. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/cli/file_dialog.py +0 -0
  69. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/cli/server_cli.py +0 -0
  70. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/country_code.py +0 -0
  71. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/crypto.py +0 -0
  72. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/__init__.py +0 -0
  73. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/battle/__init__.py +0 -0
  74. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/battle/cleared_slots.py +0 -0
  75. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/battle/enemy.py +0 -0
  76. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/battle/slots.py +0 -0
  77. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/__init__.py +0 -0
  78. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/beacon_base.py +0 -0
  79. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/drop_chara.py +0 -0
  80. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/gambling.py +0 -0
  81. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/gatya.py +0 -0
  82. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/gatya_item.py +0 -0
  83. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/item_pack.py +0 -0
  84. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/matatabi.py +0 -0
  85. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/medals.py +0 -0
  86. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/mission.py +0 -0
  87. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/my_sale.py +0 -0
  88. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/nyanko_club.py +0 -0
  89. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/officer_pass.py +0 -0
  90. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/playtime.py +0 -0
  91. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/powerup.py +0 -0
  92. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/scheme_items.py +0 -0
  93. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/special_skill.py +0 -0
  94. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/stamp.py +0 -0
  95. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/catbase/user_rank_rewards.py +0 -0
  96. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/gamoto/__init__.py +0 -0
  97. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/gamoto/base_materials.py +0 -0
  98. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/gamoto/catamins.py +0 -0
  99. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/gamoto/gamatoto.py +0 -0
  100. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/gamoto/ototo.py +0 -0
  101. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/localizable.py +0 -0
  102. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/map/aku.py +0 -0
  103. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/map/challenge.py +0 -0
  104. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/map/dojo.py +0 -0
  105. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/map/ex_stage.py +0 -0
  106. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/map/item_reward_stage.py +0 -0
  107. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/map/map_reset.py +0 -0
  108. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/map/outbreaks.py +0 -0
  109. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game/map/timed_score.py +0 -0
  110. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/game_version.py +0 -0
  111. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/io/__init__.py +0 -0
  112. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/io/adb_handler.py +0 -0
  113. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/io/bc_csv.py +0 -0
  114. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/io/command.py +0 -0
  115. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/io/data.py +0 -0
  116. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/io/git_handler.py +0 -0
  117. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/io/json_file.py +0 -0
  118. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/io/path.py +0 -0
  119. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/io/root_handler.py +0 -0
  120. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/io/thread_helper.py +0 -0
  121. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/io/waydroid.py +0 -0
  122. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/io/yaml.py +0 -0
  123. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/locale_handler.py +0 -0
  124. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/log.py +0 -0
  125. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/max_value_helper.py +0 -0
  126. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/server/__init__.py +0 -0
  127. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/server/client_info.py +0 -0
  128. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/server/event_data.py +0 -0
  129. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/server/headers.py +0 -0
  130. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/server/managed_item.py +0 -0
  131. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/server/server_handler.py +0 -0
  132. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/server/updater.py +0 -0
  133. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/core/theme_handler.py +0 -0
  134. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/core/config.properties +0 -0
  135. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/core/files.properties +0 -0
  136. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/core/input.properties +0 -0
  137. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/core/updater.properties +0 -0
  138. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/edits/bannable_items.properties +0 -0
  139. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/edits/enemy.properties +0 -0
  140. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/edits/fixes.properties +0 -0
  141. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/edits/gambling.properties +0 -0
  142. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/edits/gatya.properties +0 -0
  143. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/edits/items.properties +0 -0
  144. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/edits/medals.properties +0 -0
  145. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/edits/missions.properties +0 -0
  146. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/edits/playtime.properties +0 -0
  147. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/edits/scheme_items.properties +0 -0
  148. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/edits/special_skills.properties +0 -0
  149. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/edits/talent_orbs.properties +0 -0
  150. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/edits/treasures.properties +0 -0
  151. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/en/edits/user_rank.properties +0 -0
  152. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/core/config.properties +0 -0
  153. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/core/files.properties +0 -0
  154. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/core/input.properties +0 -0
  155. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/core/locale.properties +0 -0
  156. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/core/main.properties +0 -0
  157. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/core/save.properties +0 -0
  158. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/core/server.properties +0 -0
  159. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/core/theme.properties +0 -0
  160. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/core/updater.properties +0 -0
  161. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/edits/bannable_items.properties +0 -0
  162. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/edits/cats.properties +0 -0
  163. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/edits/enemy.properties +0 -0
  164. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/edits/fixes.properties +0 -0
  165. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/edits/gambling.properties +0 -0
  166. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/edits/gamototo.properties +0 -0
  167. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/edits/gatya.properties +0 -0
  168. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/edits/gold_pass.properties +0 -0
  169. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/edits/items.properties +0 -0
  170. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/edits/map.properties +0 -0
  171. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/edits/medals.properties +0 -0
  172. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/edits/missions.properties +0 -0
  173. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/edits/playtime.properties +0 -0
  174. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/edits/scheme_items.properties +0 -0
  175. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/edits/special_skills.properties +0 -0
  176. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/edits/talent_orbs.properties +0 -0
  177. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/edits/treasures.properties +0 -0
  178. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/edits/user_rank.properties +0 -0
  179. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/locales/vi/metadata.json +0 -0
  180. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/max_values.json +0 -0
  181. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/themes/default.json +0 -0
  182. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/files/themes/discord.json +0 -0
  183. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe/py.typed +0 -0
  184. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe.egg-info/dependency_links.txt +0 -0
  185. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe.egg-info/entry_points.txt +0 -0
  186. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe.egg-info/requires.txt +0 -0
  187. {bcsfe-3.2.1 → bcsfe-3.3.0}/src/bcsfe.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bcsfe
3
- Version: 3.2.1
3
+ Version: 3.3.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
@@ -1,4 +1,4 @@
1
- __version__ = "3.2.1"
1
+ __version__ = "3.3.0"
2
2
 
3
3
  from bcsfe import core, cli
4
4
 
@@ -7,6 +7,7 @@ from bcsfe.cli import (
7
7
  save_management,
8
8
  server_cli,
9
9
  edits,
10
+ recent_saves,
10
11
  )
11
12
 
12
13
  __all__ = [
@@ -18,4 +19,5 @@ __all__ = [
18
19
  "save_management",
19
20
  "server_cli",
20
21
  "edits",
22
+ "recent_saves",
21
23
  ]
@@ -72,19 +72,29 @@ class IntInput:
72
72
  min: int = 0,
73
73
  default: int | None = None,
74
74
  signed: bool = True,
75
+ bit_count: int = 32,
76
+ ensure_max: bool = False,
75
77
  ):
76
78
  self.signed = signed
77
- self.max = self.get_max_value(max, signed)
79
+ self.bit_count = bit_count
80
+ self.max = self.get_max_value(max, signed, bit_count, ensure_max)
78
81
  self.min = min
79
82
  self.default = default
80
83
 
81
84
  @staticmethod
82
- def get_max_value(max: int | None, signed: bool = True) -> int:
83
- disable_maxes = core.core_data.config.get_bool(core.ConfigKey.DISABLE_MAXES)
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
+ )
84
95
  if signed:
85
- max_int = 2**31 - 1
86
- else:
87
- max_int = 2**32 - 1
96
+ bit_count -= 1
97
+ max_int = (2**bit_count) - 1
88
98
  if disable_maxes or max is None:
89
99
  return max_int
90
100
  return min(max, max_int)
@@ -272,9 +282,9 @@ class ChoiceInput:
272
282
  start_index=self.start_index,
273
283
  localize_elements=self.localize_options,
274
284
  ).display_locale(self.remove_alias)
275
- return IntInput(self.get_max_value(), self.get_min_value()).get_input_locale(
276
- self.dialog, self.perameters
277
- )
285
+ return IntInput(
286
+ self.get_max_value(), self.get_min_value(), ensure_max=True
287
+ ).get_input_locale(self.dialog, self.perameters)
278
288
 
279
289
  def get_input_while(self) -> int | None:
280
290
  if len(self.strings) == 0:
@@ -417,10 +427,12 @@ class MultiEditor:
417
427
  signed: bool = True,
418
428
  group_name_localized: bool = False,
419
429
  cumulative_max: bool = False,
430
+ bit_count: int = 32,
420
431
  ):
421
432
  self.items = items
422
433
  self.strings = strings
423
434
  self.ints = ints
435
+ self.bit_count = bit_count
424
436
  if self.ints is not None:
425
437
  total_ints = len(self.ints)
426
438
  else:
@@ -502,7 +514,9 @@ class MultiEditor:
502
514
  else:
503
515
  max_value = self.max_values[choice]
504
516
  if max_value is None:
505
- max_value = IntInput.get_max_value(max_value, self.signed)
517
+ max_value = IntInput.get_max_value(
518
+ max_value, self.signed, self.bit_count
519
+ )
506
520
  max_max_value = max(max_max_value, max_value)
507
521
  if self.cumulative_max:
508
522
  max_max_value = max_max_value // len(choices)
@@ -522,7 +536,7 @@ class MultiEditor:
522
536
  max_value = None
523
537
  else:
524
538
  max_value = self.max_values[choice]
525
- max_value = IntInput.get_max_value(max_value, self.signed)
539
+ max_value = IntInput.get_max_value(max_value, self.signed, self.bit_count)
526
540
  value = min(usr_input, max_value)
527
541
  ints[choice] = value
528
542
  if self.ints is not None:
@@ -543,7 +557,9 @@ class MultiEditor:
543
557
  else:
544
558
  max_value = self.max_values[choice]
545
559
  if max_value is None:
546
- max_value = IntInput.get_max_value(max_value, self.signed)
560
+ max_value = IntInput.get_max_value(
561
+ max_value, self.signed, self.bit_count
562
+ )
547
563
 
548
564
  if self.cumulative_max:
549
565
  max_value -= sum(ints) - ints[choice]
@@ -576,6 +592,7 @@ class SingleEditor:
576
592
  signed: bool = True,
577
593
  localized_item: bool = False,
578
594
  remove_alias: bool = False,
595
+ bit_count: int = 32,
579
596
  ):
580
597
  if localized_item:
581
598
  item = core.core_data.local_manager.get_key(item)
@@ -586,9 +603,10 @@ class SingleEditor:
586
603
  self.max_value = max_value
587
604
  self.min_value = min_value
588
605
  self.signed = signed
606
+ self.bit_count = bit_count
589
607
 
590
608
  def edit(self, escape_text: bool = True) -> int:
591
- max_value = IntInput.get_max_value(self.max_value, self.signed)
609
+ max_value = IntInput.get_max_value(self.max_value, self.signed, self.bit_count)
592
610
  if self.max_value is None:
593
611
  dialog = "input_non_max"
594
612
  elif self.min_value != 0:
@@ -596,7 +614,11 @@ class SingleEditor:
596
614
  else:
597
615
  dialog = "input"
598
616
  usr_input = IntInput(
599
- max_value, self.min_value, default=self.value, signed=self.signed
617
+ max_value,
618
+ self.min_value,
619
+ default=self.value,
620
+ signed=self.signed,
621
+ bit_count=self.bit_count,
600
622
  ).get_input_locale_while(
601
623
  dialog,
602
624
  {
@@ -0,0 +1,544 @@
1
+ from __future__ import annotations
2
+ from bcsfe import core
3
+ from bcsfe.cli import color, dialog_creator
4
+ from typing import Union
5
+
6
+ ChaptersType = Union[
7
+ "core.EventChapters",
8
+ "core.GauntletChapters",
9
+ "core.LegendQuestChapters",
10
+ "core.ZeroLegendsChapters",
11
+ "core.Chapters",
12
+ ]
13
+
14
+
15
+ def get_total_maps(chapters: ChaptersType) -> int:
16
+ if isinstance(chapters, core.EventChapters):
17
+ return chapters.get_lengths()[1]
18
+ return len(chapters.chapters)
19
+
20
+
21
+ def unclear_stage(
22
+ chapters: ChaptersType,
23
+ map: int,
24
+ star: int,
25
+ stage: int,
26
+ type: int | None = None,
27
+ ) -> bool:
28
+ if isinstance(chapters, core.EventChapters):
29
+ if type is None:
30
+ raise ValueError("Type must be specified for EventChapters!")
31
+ return chapters.unclear_stage(type, map, star, stage)
32
+ else:
33
+ return chapters.unclear_stage(map, star, stage)
34
+
35
+
36
+ def clear_stage(
37
+ chapters: ChaptersType,
38
+ map: int,
39
+ star: int,
40
+ stage: int,
41
+ clear_amount: int = 1,
42
+ overwrite_clear_progress: bool = False,
43
+ type: int | None = None,
44
+ ensure_cleared_only: bool = False,
45
+ ) -> bool:
46
+ if isinstance(chapters, core.EventChapters):
47
+ if type is None:
48
+ raise ValueError("Type must be specified for EventChapters!")
49
+
50
+ return chapters.clear_stage(
51
+ type, map, star, stage, clear_amount, overwrite_clear_progress
52
+ )
53
+ else:
54
+ return chapters.clear_stage(
55
+ map,
56
+ star,
57
+ stage,
58
+ clear_amount,
59
+ overwrite_clear_progress,
60
+ ensure_cleared_only=ensure_cleared_only,
61
+ )
62
+
63
+
64
+ def unclear_rest(
65
+ chapters: ChaptersType,
66
+ stages: list[int],
67
+ stars: int,
68
+ id: int,
69
+ type: int | None = None,
70
+ ):
71
+ if isinstance(chapters, core.EventChapters):
72
+ if type is None:
73
+ raise ValueError("Type must be specified for EventChapters!")
74
+ chapters.unclear_rest(stages, stars, id, type)
75
+ else:
76
+ chapters.unclear_rest(stages, stars, id)
77
+
78
+
79
+ def get_total_stars(
80
+ map_option: core.MapOption,
81
+ base_index: int,
82
+ chapters: ChaptersType,
83
+ id: int,
84
+ type: int | None = None,
85
+ ) -> int:
86
+
87
+ max_stars = get_max_stars(chapters, id, type)
88
+
89
+ map_option_stars = map_option.get_map(base_index + id)
90
+ if map_option_stars is not None:
91
+ return min(max_stars, map_option_stars.crown_count)
92
+ return max_stars
93
+
94
+
95
+ def get_max_max_stars(
96
+ map_option: core.MapOption,
97
+ base_index: int,
98
+ ids: list[int],
99
+ chapters: ChaptersType,
100
+ type: int | None = None,
101
+ ) -> int:
102
+ m = 0
103
+ for id in ids:
104
+ val = get_total_stars(map_option, base_index, chapters, id, type)
105
+ if val > m:
106
+ m = val
107
+
108
+ return m
109
+
110
+
111
+ def get_max_stars(
112
+ chapters: ChaptersType,
113
+ id: int,
114
+ type: int | None = None,
115
+ ) -> int:
116
+
117
+ if isinstance(chapters, core.EventChapters):
118
+ if type is None:
119
+ raise ValueError("Type must be specified for EventChapters!")
120
+ max_stars = chapters.get_total_stars(type, id)
121
+ else:
122
+ max_stars = chapters.get_total_stars(id)
123
+
124
+ return max_stars
125
+
126
+
127
+ def get_total_stages(
128
+ chapters: ChaptersType, id: int, star: int, type: int | None = None
129
+ ):
130
+ if isinstance(chapters, core.EventChapters):
131
+ if type is None:
132
+ raise ValueError("Type must be specified for EventChapters!")
133
+ total_stars = chapters.get_total_stages(type, id, star)
134
+ else:
135
+ total_stars = chapters.get_total_stages(id, star)
136
+
137
+ return total_stars
138
+
139
+
140
+ def select_maps(
141
+ save_file: core.SaveFile,
142
+ chapters: ChaptersType,
143
+ letter_code: str,
144
+ base_index: int,
145
+ no_r_prefix: bool = False,
146
+ ) -> list[int] | None:
147
+ map_names = core.MapNames(
148
+ save_file, letter_code, no_r_prefix=no_r_prefix, base_index=base_index
149
+ )
150
+ names: dict[int, str | None] = {}
151
+ for id, name in map_names.map_names.items():
152
+ if id >= get_total_maps(chapters):
153
+ continue
154
+ names[id] = name
155
+
156
+ return core.EventChapters.select_map_names(names)
157
+
158
+
159
+ def select_maps_stars(
160
+ save_file: core.SaveFile,
161
+ map_option: core.MapOption,
162
+ chapters: ChaptersType,
163
+ letter_code: str,
164
+ base_index: int,
165
+ type: int | None = None,
166
+ no_r_prefix: bool = False,
167
+ ) -> list[tuple[int, int]] | None:
168
+ map_names = core.MapNames(
169
+ save_file, letter_code, no_r_prefix=no_r_prefix, base_index=base_index
170
+ )
171
+ names: dict[int, str | None] = {}
172
+ for id, name in map_names.map_names.items():
173
+ if id >= get_total_maps(chapters):
174
+ continue
175
+
176
+ for star in range(get_total_stars(map_option, base_index, chapters, id, type)):
177
+ names[id * 10 + star] = core.localize(
178
+ "map_name_star", name=name, star=star + 1
179
+ )
180
+
181
+ ids = core.EventChapters.select_map_names(names)
182
+ if ids is None:
183
+ return None
184
+
185
+ new_ids: list[tuple[int, int]] = []
186
+
187
+ for id in ids:
188
+ map_id = id // 10
189
+ star_index = id % 10
190
+
191
+ new_ids.append((map_id, star_index))
192
+
193
+ return new_ids
194
+
195
+
196
+ def edit_chapters2_clear_count(
197
+ save_file: core.SaveFile,
198
+ chapters: ChaptersType,
199
+ letter_code: str,
200
+ base_index: int,
201
+ type: int | None = None,
202
+ no_r_prefix: bool = False,
203
+ ):
204
+
205
+ map_names = core.MapNames(
206
+ save_file, letter_code, no_r_prefix=no_r_prefix, base_index=base_index
207
+ )
208
+
209
+ map_option = core.MapOption.from_save(save_file)
210
+ if map_option is None:
211
+ return None
212
+
213
+ map_choices = select_maps_stars(
214
+ save_file, map_option, chapters, letter_code, base_index, type, no_r_prefix
215
+ )
216
+ if map_choices is None:
217
+ return None
218
+
219
+ clear_all = edit_all_or_handle_ind(len(map_choices))
220
+ if clear_all is None:
221
+ return None
222
+
223
+ if clear_all == 0:
224
+ clear_count = core.EventChapters.ask_clear_amount()
225
+ if clear_count is None:
226
+ return None
227
+
228
+ for local_map_id, star in map_choices:
229
+ total_stages = get_total_stages(chapters, local_map_id, star, type)
230
+ for stage in range(total_stages):
231
+ clear_stage(chapters, local_map_id, star, stage, clear_count, type=type)
232
+ else:
233
+ for local_map_id, star in map_choices:
234
+ print()
235
+ core.EventChapters.print_current_chapter(
236
+ core.localize(
237
+ "map_name_star",
238
+ star=star,
239
+ name=map_names.map_names.get(local_map_id),
240
+ ),
241
+ local_map_id,
242
+ )
243
+ clear_whole = dialog_creator.ChoiceInput.from_reduced(
244
+ ["edit_whole_chapter", "edit_specific_stages"], dialog="edit_chapter_q"
245
+ ).single_choice()
246
+ if clear_whole is None:
247
+ return None
248
+
249
+ clear_whole -= 1
250
+
251
+ if clear_whole == 0:
252
+ clear_count = core.EventChapters.ask_clear_amount()
253
+ if clear_count is None:
254
+ return None
255
+
256
+ for stage in range(
257
+ get_total_stages(chapters, local_map_id, star, type)
258
+ ):
259
+ clear_stage(
260
+ chapters, local_map_id, star, stage, clear_count, type=type
261
+ )
262
+ else:
263
+ stage_ids = core.EventChapters.ask_stages(map_names, local_map_id)
264
+
265
+ if stage_ids is None:
266
+ return None
267
+
268
+ all_selected_stages = dialog_creator.ChoiceInput.from_reduced(
269
+ ["each_stage_individually", "stage_all_at_once"],
270
+ dialog="set_clear_count_stage_q",
271
+ ).single_choice()
272
+ if all_selected_stages is None:
273
+ return None
274
+
275
+ all_selected_stages -= 1
276
+
277
+ stage_names = core.EventChapters.get_stage_names(
278
+ map_names, local_map_id
279
+ )
280
+ if stage_names is None:
281
+ stage_names = []
282
+ if all_selected_stages == 0:
283
+ for stage in stage_ids:
284
+ print()
285
+ if stage < len(stage_names):
286
+ stage_name = stage_names[stage]
287
+ else:
288
+ stage_name = None
289
+ core.EventChapters.print_current_stage(stage_name, stage)
290
+ clear_count = core.EventChapters.ask_clear_amount()
291
+ if clear_count is None:
292
+ return None
293
+ clear_stage(
294
+ chapters, local_map_id, star, stage, clear_count, type=type
295
+ )
296
+ else:
297
+ clear_count = core.EventChapters.ask_clear_amount()
298
+ if clear_count is None:
299
+ return None
300
+ for stage in stage_ids:
301
+ clear_stage(
302
+ chapters, local_map_id, star, stage, clear_count, type=type
303
+ )
304
+
305
+
306
+ def clear_all_or_handle_ind(map_choices_len: int) -> int | None:
307
+ if map_choices_len <= 1:
308
+ clear_all = 1
309
+ else:
310
+ clear_all = dialog_creator.ChoiceInput.from_reduced(
311
+ ["clear_all", "handle_individually"], dialog="clear_chapters_q"
312
+ ).single_choice()
313
+ if clear_all is None:
314
+ return None
315
+
316
+ clear_all -= 1
317
+
318
+ return clear_all
319
+
320
+
321
+ def unclear_all_or_handle_ind(map_choices_len: int) -> int | None:
322
+ if map_choices_len <= 1:
323
+ clear_all = 1
324
+ else:
325
+ clear_all = dialog_creator.ChoiceInput.from_reduced(
326
+ ["unclear_all", "handle_individually"], dialog="unclear_chapters_q"
327
+ ).single_choice()
328
+ if clear_all is None:
329
+ return None
330
+
331
+ clear_all -= 1
332
+
333
+ return clear_all
334
+
335
+
336
+ def edit_all_or_handle_ind(map_choices_len: int) -> int | None:
337
+ if map_choices_len <= 1:
338
+ clear_all = 1
339
+ else:
340
+ clear_all = dialog_creator.ChoiceInput.from_reduced(
341
+ ["edit_map_all", "handle_individually"], dialog="edit_chapters_q_all"
342
+ ).single_choice()
343
+ if clear_all is None:
344
+ return None
345
+
346
+ clear_all -= 1
347
+
348
+ return clear_all
349
+
350
+
351
+ def edit_chapters2_progress(
352
+ save_file: core.SaveFile,
353
+ chapters: ChaptersType,
354
+ letter_code: str,
355
+ base_index: int,
356
+ type: int | None = None,
357
+ no_r_prefix: bool = False,
358
+ allow_unclear: bool = False,
359
+ ):
360
+ map_names = core.MapNames(
361
+ save_file, letter_code, no_r_prefix=no_r_prefix, base_index=base_index
362
+ )
363
+
364
+ map_choices = select_maps(save_file, chapters, letter_code, base_index, no_r_prefix)
365
+ if map_choices is None:
366
+ return None
367
+
368
+ clear_all = clear_all_or_handle_ind(len(map_choices))
369
+ if clear_all is None:
370
+ return None
371
+
372
+ map_option = core.MapOption.from_save(save_file)
373
+ if map_option is None:
374
+ return None
375
+
376
+ if clear_all == 0:
377
+ max_stars = get_max_max_stars(
378
+ map_option, base_index, map_choices, chapters, type
379
+ )
380
+ if allow_unclear:
381
+ stars = core.EventChapters.ask_stars_unclear(max_stars, "max_stars")
382
+ else:
383
+ stars = core.EventChapters.ask_stars(max_stars, "max_stars")
384
+ if stars is None:
385
+ return None
386
+ for local_map_id in map_choices:
387
+ unclear_rest(
388
+ chapters,
389
+ [0],
390
+ max(0, stars - 1),
391
+ local_map_id,
392
+ type,
393
+ )
394
+ for star in range(stars):
395
+ total_stages = get_total_stages(chapters, local_map_id, star, type)
396
+ for stage in range(total_stages):
397
+ clear_stage(
398
+ chapters,
399
+ local_map_id,
400
+ star,
401
+ stage,
402
+ type=type,
403
+ ensure_cleared_only=True,
404
+ )
405
+
406
+ return map_choices
407
+
408
+ for local_map_id in map_choices:
409
+ name = map_names.map_names.get(local_map_id)
410
+ core.EventChapters.print_current_chapter(name, local_map_id)
411
+ clear_whole = dialog_creator.ChoiceInput.from_reduced(
412
+ ["clear_whole_chapter", "clear_to_specific_stage"], dialog="clear_whole_q"
413
+ ).single_choice()
414
+ if clear_whole is None:
415
+ return None
416
+
417
+ clear_whole -= 1
418
+
419
+ if clear_whole == 0:
420
+ max_stars = get_total_stars(
421
+ map_option, base_index, chapters, local_map_id, type
422
+ )
423
+ if allow_unclear:
424
+ stars = core.EventChapters.ask_stars_unclear(max_stars)
425
+ else:
426
+ stars = core.EventChapters.ask_stars(max_stars)
427
+ if stars is None:
428
+ return None
429
+
430
+ unclear_rest(
431
+ chapters,
432
+ [0],
433
+ max(stars - 1, 0),
434
+ local_map_id,
435
+ type,
436
+ )
437
+
438
+ for star in range(stars):
439
+ total_stages = get_total_stages(chapters, local_map_id, star, type)
440
+ for stage in range(total_stages):
441
+ clear_stage(
442
+ chapters,
443
+ local_map_id,
444
+ star,
445
+ stage,
446
+ type=type,
447
+ ensure_cleared_only=True,
448
+ )
449
+
450
+ else:
451
+ stage_names = map_names.stage_names.get(local_map_id)
452
+ stage_names = [
453
+ stage_name
454
+ for stage_name in stage_names or []
455
+ if stage_name and stage_name != "@"
456
+ ]
457
+ stage_id = core.EventChapters.ask_stages_stage_names_one(stage_names)
458
+ if stage_id is None:
459
+ return None
460
+
461
+ max_stars = get_total_stars(
462
+ map_option, base_index, chapters, local_map_id, type
463
+ )
464
+
465
+ if allow_unclear:
466
+ stars = core.EventChapters.ask_stars_unclear(max_stars)
467
+ else:
468
+ stars = core.EventChapters.ask_stars(max_stars)
469
+ if stars is None:
470
+ return None
471
+
472
+ unclear_rest(
473
+ chapters, list(range(stage_id)), max(stars - 1, 0), local_map_id, type
474
+ )
475
+
476
+ for star in range(stars - 1):
477
+ total_stages = get_total_stages(chapters, local_map_id, star, type)
478
+ for stage in range(total_stages):
479
+ clear_stage(
480
+ chapters,
481
+ local_map_id,
482
+ star,
483
+ stage,
484
+ type=type,
485
+ ensure_cleared_only=True,
486
+ )
487
+
488
+ for stage in range(stage_id + 1):
489
+ clear_stage(
490
+ chapters,
491
+ local_map_id,
492
+ stars - 1,
493
+ stage,
494
+ type=type,
495
+ ensure_cleared_only=True,
496
+ )
497
+
498
+
499
+ def edit_chapters(
500
+ save_file: core.SaveFile,
501
+ chapters: ChaptersType,
502
+ letter_code: str,
503
+ base_index: int,
504
+ type: int | None = None,
505
+ no_r_prefix: bool = False,
506
+ ) -> dict[int, bool] | None:
507
+ while True:
508
+ choice = dialog_creator.ChoiceInput.from_reduced(
509
+ [
510
+ "edit_progress_clear",
511
+ "edit_progress_unclear",
512
+ "edit_clear_counts",
513
+ "finish",
514
+ ],
515
+ dialog="edit_chapters_q",
516
+ ).single_choice()
517
+ if choice is None:
518
+ return None
519
+ choice -= 1
520
+
521
+ if choice == 0:
522
+ edit_chapters2_progress(
523
+ save_file, chapters, letter_code, base_index, type, no_r_prefix
524
+ )
525
+ elif choice == 1:
526
+ edit_chapters2_progress(
527
+ save_file,
528
+ chapters,
529
+ letter_code,
530
+ base_index,
531
+ type,
532
+ no_r_prefix,
533
+ allow_unclear=True,
534
+ )
535
+ elif choice == 2:
536
+ edit_chapters2_clear_count(
537
+ save_file, chapters, letter_code, base_index, type, no_r_prefix
538
+ )
539
+ else:
540
+ break
541
+ color.ColoredText.localize("map_chapters_edited")
542
+ color.ColoredText.localize("map_chapters_edited")
543
+
544
+ return None
@@ -206,7 +206,7 @@ class FeatureHandler:
206
206
  features.insert(0, "go_back")
207
207
  self.display_features(features)
208
208
  print()
209
- usr_input = color.ColoredInput().localize("select_features")
209
+ usr_input = color.ColoredInput().localize("select_features").strip()
210
210
  selected_features: list[str] = []
211
211
  if usr_input.isdigit():
212
212
  usr_input = int(usr_input)