bcsfe 3.2.0b2__tar.gz → 3.2.0b3__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 (182) hide show
  1. {bcsfe-3.2.0b2/src/bcsfe.egg-info → bcsfe-3.2.0b3}/PKG-INFO +93 -8
  2. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/README.md +92 -7
  3. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/__init__.py +1 -1
  4. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/cli/edits/__init__.py +2 -0
  5. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/cli/edits/cat_editor.py +91 -15
  6. bcsfe-3.2.0b3/src/bcsfe/cli/edits/storage.py +214 -0
  7. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/cli/feature_handler.py +3 -1
  8. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/__init__.py +4 -0
  9. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/cat.py +12 -0
  10. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/server/game_data_getter.py +40 -14
  11. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/core/input.properties +2 -0
  12. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/edits/cats.properties +36 -0
  13. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3/src/bcsfe.egg-info}/PKG-INFO +93 -8
  14. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe.egg-info/SOURCES.txt +1 -0
  15. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/LICENSE +0 -0
  16. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/MANIFEST.in +0 -0
  17. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/pyproject.toml +0 -0
  18. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/setup.cfg +0 -0
  19. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/setup.py +0 -0
  20. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/__main__.py +0 -0
  21. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/cli/__init__.py +0 -0
  22. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/cli/color.py +0 -0
  23. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/cli/dialog_creator.py +0 -0
  24. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/cli/edits/aku_realm.py +0 -0
  25. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/cli/edits/basic_items.py +0 -0
  26. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/cli/edits/clear_tutorial.py +0 -0
  27. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/cli/edits/enemy_editor.py +0 -0
  28. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/cli/edits/event_tickets.py +0 -0
  29. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/cli/edits/fixes.py +0 -0
  30. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/cli/edits/map.py +0 -0
  31. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/cli/edits/max_all.py +0 -0
  32. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/cli/edits/rare_ticket_trade.py +0 -0
  33. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/cli/file_dialog.py +0 -0
  34. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/cli/main.py +0 -0
  35. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/cli/save_management.py +0 -0
  36. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/cli/server_cli.py +0 -0
  37. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/country_code.py +0 -0
  38. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/crypto.py +0 -0
  39. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/__init__.py +0 -0
  40. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/battle/__init__.py +0 -0
  41. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/battle/battle_items.py +0 -0
  42. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/battle/cleared_slots.py +0 -0
  43. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/battle/enemy.py +0 -0
  44. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/battle/slots.py +0 -0
  45. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/__init__.py +0 -0
  46. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/beacon_base.py +0 -0
  47. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/drop_chara.py +0 -0
  48. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/gambling.py +0 -0
  49. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/gatya.py +0 -0
  50. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/gatya_item.py +0 -0
  51. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/item_pack.py +0 -0
  52. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/login_bonuses.py +0 -0
  53. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/matatabi.py +0 -0
  54. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/medals.py +0 -0
  55. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/mission.py +0 -0
  56. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/my_sale.py +0 -0
  57. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/nyanko_club.py +0 -0
  58. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/officer_pass.py +0 -0
  59. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/playtime.py +0 -0
  60. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/powerup.py +0 -0
  61. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/scheme_items.py +0 -0
  62. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/special_skill.py +0 -0
  63. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/stamp.py +0 -0
  64. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/talent_orbs.py +0 -0
  65. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/unlock_popups.py +0 -0
  66. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/upgrade.py +0 -0
  67. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/catbase/user_rank_rewards.py +0 -0
  68. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/gamoto/__init__.py +0 -0
  69. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/gamoto/base_materials.py +0 -0
  70. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/gamoto/cat_shrine.py +0 -0
  71. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/gamoto/catamins.py +0 -0
  72. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/gamoto/gamatoto.py +0 -0
  73. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/gamoto/ototo.py +0 -0
  74. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/localizable.py +0 -0
  75. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/map/__init__.py +0 -0
  76. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/map/aku.py +0 -0
  77. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/map/challenge.py +0 -0
  78. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/map/chapters.py +0 -0
  79. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/map/dojo.py +0 -0
  80. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/map/enigma.py +0 -0
  81. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/map/event.py +0 -0
  82. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/map/ex_stage.py +0 -0
  83. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/map/gauntlets.py +0 -0
  84. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/map/item_reward_stage.py +0 -0
  85. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/map/legend_quest.py +0 -0
  86. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/map/map_names.py +0 -0
  87. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/map/map_reset.py +0 -0
  88. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/map/outbreaks.py +0 -0
  89. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/map/story.py +0 -0
  90. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/map/timed_score.py +0 -0
  91. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/map/tower.py +0 -0
  92. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/map/uncanny.py +0 -0
  93. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game/map/zero_legends.py +0 -0
  94. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/game_version.py +0 -0
  95. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/io/__init__.py +0 -0
  96. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/io/adb_handler.py +0 -0
  97. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/io/bc_csv.py +0 -0
  98. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/io/command.py +0 -0
  99. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/io/config.py +0 -0
  100. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/io/data.py +0 -0
  101. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/io/git_handler.py +0 -0
  102. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/io/json_file.py +0 -0
  103. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/io/path.py +0 -0
  104. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/io/root_handler.py +0 -0
  105. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/io/save.py +0 -0
  106. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/io/thread_helper.py +0 -0
  107. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/io/waydroid.py +0 -0
  108. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/io/yaml.py +0 -0
  109. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/locale_handler.py +0 -0
  110. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/log.py +0 -0
  111. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/max_value_helper.py +0 -0
  112. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/server/__init__.py +0 -0
  113. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/server/client_info.py +0 -0
  114. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/server/event_data.py +0 -0
  115. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/server/headers.py +0 -0
  116. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/server/managed_item.py +0 -0
  117. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/server/request.py +0 -0
  118. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/server/server_handler.py +0 -0
  119. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/server/updater.py +0 -0
  120. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/core/theme_handler.py +0 -0
  121. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/core/config.properties +0 -0
  122. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/core/files.properties +0 -0
  123. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/core/locale.properties +0 -0
  124. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/core/main.properties +0 -0
  125. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/core/save.properties +0 -0
  126. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/core/server.properties +0 -0
  127. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/core/theme.properties +0 -0
  128. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/core/updater.properties +0 -0
  129. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/edits/bannable_items.properties +0 -0
  130. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/edits/enemy.properties +0 -0
  131. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/edits/fixes.properties +0 -0
  132. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/edits/gambling.properties +0 -0
  133. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/edits/gamototo.properties +0 -0
  134. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/edits/gatya.properties +0 -0
  135. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/edits/gold_pass.properties +0 -0
  136. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/edits/items.properties +0 -0
  137. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/edits/map.properties +0 -0
  138. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/edits/medals.properties +0 -0
  139. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/edits/missions.properties +0 -0
  140. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/edits/playtime.properties +0 -0
  141. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/edits/scheme_items.properties +0 -0
  142. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/edits/special_skills.properties +0 -0
  143. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/edits/talent_orbs.properties +0 -0
  144. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/edits/treasures.properties +0 -0
  145. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/en/edits/user_rank.properties +0 -0
  146. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/core/config.properties +0 -0
  147. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/core/files.properties +0 -0
  148. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/core/input.properties +0 -0
  149. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/core/locale.properties +0 -0
  150. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/core/main.properties +0 -0
  151. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/core/save.properties +0 -0
  152. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/core/server.properties +0 -0
  153. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/core/theme.properties +0 -0
  154. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/core/updater.properties +0 -0
  155. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/edits/bannable_items.properties +0 -0
  156. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/edits/cats.properties +0 -0
  157. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/edits/enemy.properties +0 -0
  158. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/edits/fixes.properties +0 -0
  159. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/edits/gambling.properties +0 -0
  160. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/edits/gamototo.properties +0 -0
  161. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/edits/gatya.properties +0 -0
  162. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/edits/gold_pass.properties +0 -0
  163. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/edits/items.properties +0 -0
  164. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/edits/map.properties +0 -0
  165. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/edits/medals.properties +0 -0
  166. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/edits/missions.properties +0 -0
  167. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/edits/playtime.properties +0 -0
  168. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/edits/scheme_items.properties +0 -0
  169. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/edits/special_skills.properties +0 -0
  170. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/edits/talent_orbs.properties +0 -0
  171. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/edits/treasures.properties +0 -0
  172. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/edits/user_rank.properties +0 -0
  173. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/locales/vi/metadata.json +0 -0
  174. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/max_values.json +0 -0
  175. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/themes/default.json +0 -0
  176. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/files/themes/discord.json +0 -0
  177. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe/py.typed +0 -0
  178. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe.egg-info/dependency_links.txt +0 -0
  179. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe.egg-info/entry_points.txt +0 -0
  180. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe.egg-info/requires.txt +0 -0
  181. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/src/bcsfe.egg-info/top_level.txt +0 -0
  182. {bcsfe-3.2.0b2 → bcsfe-3.2.0b3}/tests/test_parse.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bcsfe
3
- Version: 3.2.0b2
3
+ Version: 3.2.0b3
4
4
  Summary: A save file editor for The Battle Cats
5
5
  Author: fieryhenry
6
6
  License-Expression: GPL-3.0-or-later
@@ -98,7 +98,8 @@ python3 -m pip install bcsfe
98
98
  py -m ensurepip --upgrade
99
99
  ```
100
100
 
101
- Again change `py` for `python` or `python3` if needed
101
+ Again change `py` for `python` or `python3` if needed. I won't mention this again, so just remember
102
+ the one which works at keep using that.
102
103
 
103
104
  5. To run the editor, as long as Python is in your PATH, you should be able to run:
104
105
 
@@ -112,10 +113,20 @@ bcsfe
112
113
  py -m bcsfe
113
114
  ```
114
115
 
115
- Again change `py` for `python` or `python3` if needed.
116
-
117
116
  If you are using Windows and you are still struggling, try watching this video [here](https://codeberg.org/fieryhenry/videos/media/branch/main/bcsfe_windows_help.webm).
118
117
 
118
+ 7. To update the editor run:
119
+
120
+ ```powershell
121
+ py -m pip install -U bcsfe
122
+ ```
123
+
124
+ 8. To uninstall the editor run:
125
+
126
+ ```powershell
127
+ py -m pip uninstall bcsfe
128
+ ```
129
+
119
130
  ### Linux
120
131
 
121
132
  1. Install Python 3.9 or later using your system's package manager if you don't already have it
@@ -145,6 +156,18 @@ bcsfe
145
156
  6. You may also need to install `tk` with your system package manager to open the
146
157
  file selection dialog. This package may be called `tk` or `python-tk` or `python3-tk`.
147
158
 
159
+ 7. To update the editor if you are using pipx run:
160
+
161
+ ```sh
162
+ pipx upgrade bcsfe
163
+ ```
164
+
165
+ 8. To uninstall the editor if you are using pipx run:
166
+
167
+ ```sh
168
+ pipx uninstall bcsfe
169
+ ```
170
+
148
171
  If anyone wants to put the editor on the AUR or another package repo, feel free, I'll be happy to
149
172
  help if needed.
150
173
 
@@ -207,14 +230,72 @@ selection dialog, you just have to type the file path manually.
207
230
  For example to save your save file to your downloads directory, the path might look something like
208
231
  `/storage/emulated/0/Download/SAVE_DATA` or `/sdcard/Download/SAVE_DATA`
209
232
 
233
+ 5. To update the editor run:
234
+
235
+ ```sh
236
+ pip install -U bcsfe
237
+ ```
238
+
239
+ Or
240
+
241
+ ```sh
242
+ python -m pip install -U bcsfe
243
+ ```
244
+
245
+
246
+ 5. To uninstall the editor run:
247
+
248
+ ```sh
249
+ pip uninstall bcsfe
250
+ ```
251
+
252
+ Or
253
+
254
+ ```sh
255
+ python -m pip uninstall bcsfe
256
+ ```
210
257
 
211
258
  ### iOS
212
259
 
213
- I do not have an iOS device, so there is no text tutorial, but Viarules has made a video
214
- tutorial [here](https://www.youtube.com/watch?v=xw-uOqQRYJ8). The video uses iSH which is
215
- apparently quite slow, and other people recommend using a-Shell instead.
260
+ I do not have an iOS device, so there is no tutorial. The video that was recommended is now outdated.
261
+ But for a general overview of what you need to do:
262
+
263
+ 1. Download a-Shell from the App Store
264
+ 2. Install the editor with:
265
+
266
+ ```sh
267
+ pip install bcsfe
268
+ ```
216
269
 
270
+ 3. Run the editor with:
217
271
 
272
+ ```sh
273
+ bcsfe
274
+ ```
275
+
276
+ Or if that doesn't work try:
277
+
278
+ ```sh
279
+ python -m bcsfe
280
+ ```
281
+
282
+ Or
283
+
284
+ ```sh
285
+ python3 -m bcsfe
286
+ ```
287
+
288
+ 4. To update the editor run:
289
+
290
+ ```sh
291
+ pip install -U bcsfe
292
+ ```
293
+
294
+ 5. To uninstall the editor run:
295
+
296
+ ```sh
297
+ pip uninstall bcsfe
298
+ ```
218
299
  ## Terms of Use
219
300
 
220
301
  By using the editor you agree to the following:
@@ -350,7 +431,11 @@ You'll need to collect the catfood in-game after each clear though
350
431
 
351
432
  If you want the latest features then you can install the editor from the github.
352
433
 
353
- 1. Download [Git](https://git-scm.com/downloads)
434
+ 1. Download git:
435
+ 1. Windows: [Git](https://git-scm.com/downloads)
436
+ 2. Linux: (use package manager, e.g `sudo apt-get install git` or `sudo pacman -S git`)
437
+ 3. Android: Termux: `pkg install git`
438
+ 4. iOS: a-Shell should already include it
354
439
 
355
440
  2. Run the following commands: (You may have to replace `py` with `python` or `python3`)
356
441
 
@@ -69,7 +69,8 @@ python3 -m pip install bcsfe
69
69
  py -m ensurepip --upgrade
70
70
  ```
71
71
 
72
- Again change `py` for `python` or `python3` if needed
72
+ Again change `py` for `python` or `python3` if needed. I won't mention this again, so just remember
73
+ the one which works at keep using that.
73
74
 
74
75
  5. To run the editor, as long as Python is in your PATH, you should be able to run:
75
76
 
@@ -83,10 +84,20 @@ bcsfe
83
84
  py -m bcsfe
84
85
  ```
85
86
 
86
- Again change `py` for `python` or `python3` if needed.
87
-
88
87
  If you are using Windows and you are still struggling, try watching this video [here](https://codeberg.org/fieryhenry/videos/media/branch/main/bcsfe_windows_help.webm).
89
88
 
89
+ 7. To update the editor run:
90
+
91
+ ```powershell
92
+ py -m pip install -U bcsfe
93
+ ```
94
+
95
+ 8. To uninstall the editor run:
96
+
97
+ ```powershell
98
+ py -m pip uninstall bcsfe
99
+ ```
100
+
90
101
  ### Linux
91
102
 
92
103
  1. Install Python 3.9 or later using your system's package manager if you don't already have it
@@ -116,6 +127,18 @@ bcsfe
116
127
  6. You may also need to install `tk` with your system package manager to open the
117
128
  file selection dialog. This package may be called `tk` or `python-tk` or `python3-tk`.
118
129
 
130
+ 7. To update the editor if you are using pipx run:
131
+
132
+ ```sh
133
+ pipx upgrade bcsfe
134
+ ```
135
+
136
+ 8. To uninstall the editor if you are using pipx run:
137
+
138
+ ```sh
139
+ pipx uninstall bcsfe
140
+ ```
141
+
119
142
  If anyone wants to put the editor on the AUR or another package repo, feel free, I'll be happy to
120
143
  help if needed.
121
144
 
@@ -178,14 +201,72 @@ selection dialog, you just have to type the file path manually.
178
201
  For example to save your save file to your downloads directory, the path might look something like
179
202
  `/storage/emulated/0/Download/SAVE_DATA` or `/sdcard/Download/SAVE_DATA`
180
203
 
204
+ 5. To update the editor run:
205
+
206
+ ```sh
207
+ pip install -U bcsfe
208
+ ```
209
+
210
+ Or
211
+
212
+ ```sh
213
+ python -m pip install -U bcsfe
214
+ ```
215
+
216
+
217
+ 5. To uninstall the editor run:
218
+
219
+ ```sh
220
+ pip uninstall bcsfe
221
+ ```
222
+
223
+ Or
224
+
225
+ ```sh
226
+ python -m pip uninstall bcsfe
227
+ ```
181
228
 
182
229
  ### iOS
183
230
 
184
- I do not have an iOS device, so there is no text tutorial, but Viarules has made a video
185
- tutorial [here](https://www.youtube.com/watch?v=xw-uOqQRYJ8). The video uses iSH which is
186
- apparently quite slow, and other people recommend using a-Shell instead.
231
+ I do not have an iOS device, so there is no tutorial. The video that was recommended is now outdated.
232
+ But for a general overview of what you need to do:
233
+
234
+ 1. Download a-Shell from the App Store
235
+ 2. Install the editor with:
236
+
237
+ ```sh
238
+ pip install bcsfe
239
+ ```
187
240
 
241
+ 3. Run the editor with:
188
242
 
243
+ ```sh
244
+ bcsfe
245
+ ```
246
+
247
+ Or if that doesn't work try:
248
+
249
+ ```sh
250
+ python -m bcsfe
251
+ ```
252
+
253
+ Or
254
+
255
+ ```sh
256
+ python3 -m bcsfe
257
+ ```
258
+
259
+ 4. To update the editor run:
260
+
261
+ ```sh
262
+ pip install -U bcsfe
263
+ ```
264
+
265
+ 5. To uninstall the editor run:
266
+
267
+ ```sh
268
+ pip uninstall bcsfe
269
+ ```
189
270
  ## Terms of Use
190
271
 
191
272
  By using the editor you agree to the following:
@@ -321,7 +402,11 @@ You'll need to collect the catfood in-game after each clear though
321
402
 
322
403
  If you want the latest features then you can install the editor from the github.
323
404
 
324
- 1. Download [Git](https://git-scm.com/downloads)
405
+ 1. Download git:
406
+ 1. Windows: [Git](https://git-scm.com/downloads)
407
+ 2. Linux: (use package manager, e.g `sudo apt-get install git` or `sudo pacman -S git`)
408
+ 3. Android: Termux: `pkg install git`
409
+ 4. iOS: a-Shell should already include it
325
410
 
326
411
  2. Run the following commands: (You may have to replace `py` with `python` or `python3`)
327
412
 
@@ -1,4 +1,4 @@
1
- __version__ = "3.2.0b2"
1
+ __version__ = "3.2.0b3"
2
2
 
3
3
  from bcsfe import core, cli
4
4
 
@@ -9,6 +9,7 @@ from bcsfe.cli.edits import (
9
9
  map,
10
10
  event_tickets,
11
11
  max_all,
12
+ storage,
12
13
  )
13
14
 
14
15
  __all__ = [
@@ -22,4 +23,5 @@ __all__ = [
22
23
  "map",
23
24
  "event_tickets",
24
25
  "max_all",
26
+ "storage",
25
27
  ]
@@ -55,9 +55,8 @@ class CatEditor:
55
55
  color.ColoredText.localize("selected_cat", id=cat.id, name=names[0])
56
56
 
57
57
  def select(
58
- self,
59
- current_cats: list[core.Cat] | None = None,
60
- ) -> list[core.Cat] | None:
58
+ self, current_cats: list[core.Cat] | None = None, finish_option: bool = True
59
+ ) -> tuple[list[core.Cat], bool]:
61
60
  if current_cats is None:
62
61
  current_cats = []
63
62
  options: dict[str, Callable[[], Any]] = {
@@ -71,19 +70,25 @@ class CatEditor:
71
70
  "select_cats_not_unlocked": self.get_non_unlocked_cats,
72
71
  "select_cats_not_obtainable": self.get_cats_unobtainable,
73
72
  "select_cats_non_gatya": self.get_non_gacha_cats,
73
+ "select_cats_game_version": self.select_cats_game_version,
74
74
  }
75
+ if finish_option:
76
+ options["finish"] = lambda: None
75
77
  option_id = dialog_creator.ChoiceInput(
76
78
  list(options), list(options), [], {}, "select_cats", True
77
79
  ).single_choice()
78
80
  if option_id is None:
79
- return current_cats
81
+ return current_cats, False
80
82
  option_id -= 1
81
83
 
84
+ if option_id == len(options) - 1 and finish_option:
85
+ return current_cats, True
86
+
82
87
  func = options[list(options)[option_id]]
83
88
  new_cats = func()
84
89
 
85
90
  if new_cats is None:
86
- return None
91
+ return current_cats, False
87
92
 
88
93
  if current_cats:
89
94
  mode_id = dialog_creator.IntInput().get_basic_input_locale("and_mode_q", {})
@@ -101,12 +106,12 @@ class CatEditor:
101
106
  mode = SelectMode.OR
102
107
 
103
108
  if mode == SelectMode.AND:
104
- return list(set(current_cats) & set(new_cats))
109
+ return list(set(current_cats) & set(new_cats)), False
105
110
  if mode == SelectMode.OR:
106
- return list(set(current_cats) | set(new_cats))
111
+ return list(set(current_cats) | set(new_cats)), False
107
112
  if mode == SelectMode.REPLACE:
108
- return new_cats
109
- return new_cats
113
+ return new_cats, False
114
+ return new_cats, False
110
115
 
111
116
  def select_id(self) -> list[core.Cat] | None:
112
117
  cat_ids = dialog_creator.RangeInput(
@@ -116,6 +121,78 @@ class CatEditor:
116
121
  return None
117
122
  return self.save_file.cats.get_cats_by_ids(cat_ids)
118
123
 
124
+ def select_cats_game_version(self) -> list[core.Cat] | None:
125
+ unitbuy = core.UnitBuy(self.save_file)
126
+ if unitbuy.unit_buy is None:
127
+ return None
128
+
129
+ versions_set: set[int] = set()
130
+ for cat in unitbuy.unit_buy:
131
+ if cat.game_version == -1:
132
+ continue
133
+ versions_set.add(cat.game_version)
134
+
135
+ if not versions_set:
136
+ return None
137
+
138
+ versions = list(versions_set)
139
+ versions.sort()
140
+
141
+ color.ColoredText.localize("possible_gvs")
142
+
143
+ cur_major_v = -1
144
+ for version in versions:
145
+ gv = core.GameVersion(version)
146
+ major_v = gv.get_parts()[0]
147
+ if major_v != cur_major_v:
148
+ if cur_major_v != -1:
149
+ print()
150
+ cur_major_v = major_v
151
+ else:
152
+ color.ColoredText(", ", end="")
153
+ color.ColoredText(f"<@t>{gv.format()}</>", end="")
154
+
155
+ print()
156
+
157
+ usr_input = dialog_creator.StringInput().get_input_locale("select_gv")
158
+ if usr_input is None:
159
+ return None
160
+ chunks = usr_input.split(" ")
161
+
162
+ versions_selected: list[int] = []
163
+ for chunk in chunks:
164
+ parts = chunk.split("-")
165
+ if len(parts) == 2:
166
+ min = parts[0]
167
+ max = parts[1]
168
+
169
+ v1 = core.GameVersion.from_string(min)
170
+ v2 = core.GameVersion.from_string(max)
171
+
172
+ for v in range(v1.game_version, v2.game_version + 1):
173
+ versions_selected.append(v)
174
+ else:
175
+ v = core.GameVersion.from_string(chunk)
176
+ versions_selected.append(v.game_version)
177
+
178
+ valid_versions: set[int] = set()
179
+ for version in versions_selected:
180
+ if version in versions_set:
181
+ valid_versions.add(version)
182
+
183
+ if not valid_versions:
184
+ color.ColoredText.localize("no_valid_gvs_entered")
185
+
186
+ cats: list[core.Cat] = []
187
+ for cat in self.save_file.cats.cats:
188
+ row = unitbuy.get_unit_buy(cat.id)
189
+ if row is None:
190
+ continue
191
+ if row.game_version in valid_versions:
192
+ cats.append(cat)
193
+
194
+ return cats
195
+
119
196
  def select_rarity(self) -> list[core.Cat] | None:
120
197
  rarity_names = self.save_file.cats.get_rarity_names(self.save_file)
121
198
  rarity_ids, _ = dialog_creator.ChoiceInput(
@@ -638,11 +715,12 @@ class CatEditor:
638
715
  stop = False
639
716
  cats = []
640
717
  while not stop:
641
- current_cats = cat_editor.select(cats)
642
- if current_cats is None:
643
- return None, []
718
+ current_cats, finished = cat_editor.select(cats)
644
719
  cats = current_cats
645
720
  cat_editor.print_selected_cats(cats)
721
+ if finished:
722
+ stop = True
723
+ continue
646
724
  finished = dialog_creator.YesNoInput().get_input_once(
647
725
  "finished_cats_selection"
648
726
  )
@@ -681,9 +759,7 @@ class CatEditor:
681
759
  return False, cats
682
760
  option_id -= 1
683
761
  if option_id == 0:
684
- cats_ = self.select(cats)
685
- if cats_ is None:
686
- return False, cats
762
+ cats_, _ = self.select(cats, False)
687
763
  cats = cats_
688
764
  elif option_id == 1:
689
765
  self.unlock_remove_cats_run(self.save_file, cats, self)
@@ -0,0 +1,214 @@
1
+ from __future__ import annotations
2
+ from bcsfe import core
3
+ from bcsfe.cli import color, dialog_creator
4
+ from bcsfe.cli.edits import cat_editor
5
+
6
+
7
+ def display_storage(save_file: core.SaveFile, storage: list[core.StorageItem]):
8
+ color.ColoredText.localize("current_storage_items")
9
+ index = 0
10
+ for item in storage:
11
+ if item.item_type == 0:
12
+ continue
13
+
14
+ index += 1
15
+ color.ColoredText(f"{index}. ", end="")
16
+ display_item(item, save_file)
17
+
18
+ if index == 0:
19
+ color.ColoredText.localize("storage_is_empty")
20
+
21
+ available_slots = len(storage) - index
22
+
23
+ color.ColoredText.localize("available_storage", slots=available_slots)
24
+
25
+
26
+ def display_item(item: core.StorageItem, save_file: core.SaveFile):
27
+ color.ColoredText(get_item_str(item, save_file))
28
+
29
+
30
+ def get_item_str(item: core.StorageItem, save_file: core.SaveFile) -> str:
31
+ if item.item_type == 1:
32
+ cat_id = item.item_id
33
+ names = core.Cat.get_names(cat_id, save_file)
34
+
35
+ if not names:
36
+ names = [str(cat_id)]
37
+
38
+ return core.localize("cat", name=names[0], id=cat_id)
39
+ elif item.item_type == 2:
40
+ skill_id = item.item_id
41
+
42
+ skill_names = (
43
+ core.core_data.get_gatya_item_buy(save_file).get_names_by_category(
44
+ core.GatyaItemCategory.SPECIAL_SKILLS
45
+ )
46
+ or []
47
+ )
48
+
49
+ if skill_id >= len(skill_names) or skill_id < 0:
50
+ name = str(skill_id)
51
+ else:
52
+ name = skill_names[skill_id][1]
53
+
54
+ return core.localize("special_skill", name=name, id=skill_id)
55
+ elif item.item_type == 3:
56
+ item_id = item.item_id
57
+
58
+ name = core.core_data.get_gatya_item_names(save_file).get_name(item_id)
59
+ if name is None:
60
+ name = str(item_id)
61
+
62
+ return core.localize("item", name=name, id=item_id)
63
+ else:
64
+ return core.localize(
65
+ "unrecognised_storage_item", item_type=item.item_type, id=item.item_id
66
+ )
67
+
68
+
69
+ def clear_storage(storage: list[core.StorageItem]):
70
+ for item in storage:
71
+ item.item_id = 0
72
+ item.item_type = 0
73
+
74
+
75
+ def add_item(storage: list[core.StorageItem], item: core.StorageItem) -> bool:
76
+ for citem in storage:
77
+ if citem.item_type == 0:
78
+ citem.item_type = item.item_type
79
+ citem.item_id = item.item_id
80
+ return True
81
+ return False
82
+
83
+
84
+ def get_storage_space(storage: list[core.StorageItem]) -> int:
85
+ space = 0
86
+
87
+ for item in storage:
88
+ if item.item_type == 0:
89
+ space += 1
90
+ return space
91
+
92
+
93
+ def edit_storage(save_file: core.SaveFile):
94
+ display_storage(save_file, save_file.cats.storage_items)
95
+ exit = False
96
+ while not exit:
97
+ exit = edit_loop(save_file)
98
+
99
+ color.ColoredText.localize("storage_success")
100
+
101
+
102
+ def edit_loop(save_file: core.SaveFile) -> bool:
103
+ storage = save_file.cats.storage_items
104
+
105
+ options = [
106
+ "display_storage",
107
+ "clear_storage",
108
+ "add_cats",
109
+ "add_special_skills",
110
+ "remove_items",
111
+ "finish",
112
+ ]
113
+
114
+ choice = dialog_creator.ChoiceInput.from_reduced(
115
+ options, dialog="select_option"
116
+ ).single_choice()
117
+ if choice is None:
118
+ return False
119
+
120
+ choice -= 1
121
+
122
+ if choice == 0:
123
+ display_storage(save_file, storage)
124
+ if choice == 1:
125
+ clear_storage(storage)
126
+ elif choice == 2:
127
+ editor, cats = cat_editor.CatEditor.from_save_file(save_file)
128
+ if editor is None:
129
+ return False
130
+
131
+ space = get_storage_space(storage)
132
+ if len(cats) > len(storage):
133
+ color.ColoredText.localize(
134
+ "too_many_cats_selected", max=len(storage), current=len(cats)
135
+ )
136
+ return False
137
+
138
+ needs = len(cats) - space
139
+ if needs > 0:
140
+ color.ColoredText.localize("need_x_more_space", needs=needs)
141
+ return False
142
+
143
+ color.ColoredText.localize("added_cats")
144
+ for cat in cats:
145
+ item = core.StorageItem.from_cat(cat.id)
146
+ add_item(storage, item)
147
+ display_item(item, save_file)
148
+ elif choice == 3:
149
+
150
+ skill_names: list[str] = list(
151
+ map(
152
+ lambda sk: sk[1] or str(sk[0].id),
153
+ core.core_data.get_gatya_item_buy(save_file).get_names_by_category(
154
+ core.GatyaItemCategory.SPECIAL_SKILLS
155
+ )
156
+ or [],
157
+ )
158
+ )
159
+
160
+ options, _ = dialog_creator.ChoiceInput.from_reduced(
161
+ skill_names, localize_options=False, dialog="select_special_skills"
162
+ ).multiple_choice(False)
163
+
164
+ if options is None:
165
+ return False
166
+
167
+ space = get_storage_space(storage)
168
+ if len(options) > len(storage):
169
+ color.ColoredText.localize(
170
+ "too_many_skills_selected", max=len(storage), current=len(options)
171
+ )
172
+ return False
173
+
174
+ needs = len(options) - space
175
+ if needs > 0:
176
+ color.ColoredText.localize("need_x_more_space", needs=needs)
177
+ return False
178
+
179
+ color.ColoredText.localize("added_special_skills")
180
+ for choice in options:
181
+ item = core.StorageItem.from_special_skill(choice)
182
+ add_item(storage, item)
183
+ display_item(item, save_file)
184
+
185
+ elif choice == 4:
186
+ options2: list[str] = []
187
+ for item in storage:
188
+ if item.item_type == 0:
189
+ continue
190
+ options2.append(get_item_str(item, save_file))
191
+
192
+ choices, _ = dialog_creator.ChoiceInput.from_reduced(
193
+ options2, localize_options=False
194
+ ).multiple_choice(False)
195
+ if choices is None:
196
+ return False
197
+
198
+ color.ColoredText.localize("removed_items")
199
+ index = 0
200
+ for item in storage:
201
+ if item.item_type == 0:
202
+ continue
203
+
204
+ if index in choices:
205
+ display_item(item, save_file)
206
+ item.item_type = 0
207
+ item.item_id = 0
208
+
209
+ index += 1
210
+
211
+ elif choice == 5:
212
+ return True
213
+
214
+ return False
@@ -26,6 +26,8 @@ class FeatureHandler:
26
26
  edits.basic_items.BasicItems.edit_special_skills
27
27
  )
28
28
 
29
+ cat_features["cat_storage"] = edits.storage.edit_storage
30
+
29
31
  features: dict[str, Any] = {
30
32
  "save_management": {
31
33
  "save_save": save_management.SaveManagement.save_save,
@@ -217,7 +219,7 @@ class FeatureHandler:
217
219
  return list(self.get_features().keys())
218
220
  feature = self.get_feature(feature_name_top)
219
221
  if isinstance(feature, dict):
220
- for feature_name in feature.keys():
222
+ for feature_name in feature.keys(): # type: ignore
221
223
  feature_path = (
222
224
  f"{parent_path}.{feature_name_top}.{feature_name}"
223
225
  if parent_path