bcsfe 3.2.0b3__tar.gz → 3.2.1__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 (183) hide show
  1. {bcsfe-3.2.0b3/src/bcsfe.egg-info → bcsfe-3.2.1}/PKG-INFO +10 -9
  2. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/README.md +9 -8
  3. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/__init__.py +1 -1
  4. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/dialog_creator.py +5 -7
  5. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/edits/basic_items.py +7 -1
  6. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/edits/map.py +11 -1
  7. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/feature_handler.py +1 -0
  8. bcsfe-3.2.1/src/bcsfe/core/game/battle/battle_items.py +297 -0
  9. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/io/path.py +7 -3
  10. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/io/save.py +2 -36
  11. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/server/game_data_getter.py +7 -5
  12. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/edits/items.properties +9 -0
  13. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/core/input.properties +3 -1
  14. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/core/main.properties +0 -1
  15. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/core/save.properties +8 -1
  16. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/core/server.properties +4 -1
  17. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/edits/cats.properties +40 -28
  18. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/edits/map.properties +0 -41
  19. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/edits/treasures.properties +2 -2
  20. {bcsfe-3.2.0b3 → bcsfe-3.2.1/src/bcsfe.egg-info}/PKG-INFO +10 -9
  21. bcsfe-3.2.0b3/src/bcsfe/core/game/battle/battle_items.py +0 -127
  22. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/LICENSE +0 -0
  23. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/MANIFEST.in +0 -0
  24. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/pyproject.toml +0 -0
  25. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/setup.cfg +0 -0
  26. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/setup.py +0 -0
  27. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/__main__.py +0 -0
  28. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/__init__.py +0 -0
  29. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/color.py +0 -0
  30. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/edits/__init__.py +0 -0
  31. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/edits/aku_realm.py +0 -0
  32. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/edits/cat_editor.py +0 -0
  33. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/edits/clear_tutorial.py +0 -0
  34. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/edits/enemy_editor.py +0 -0
  35. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/edits/event_tickets.py +0 -0
  36. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/edits/fixes.py +0 -0
  37. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/edits/max_all.py +0 -0
  38. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/edits/rare_ticket_trade.py +0 -0
  39. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/edits/storage.py +0 -0
  40. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/file_dialog.py +0 -0
  41. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/main.py +0 -0
  42. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/save_management.py +0 -0
  43. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/cli/server_cli.py +0 -0
  44. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/__init__.py +0 -0
  45. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/country_code.py +0 -0
  46. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/crypto.py +0 -0
  47. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/__init__.py +0 -0
  48. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/battle/__init__.py +0 -0
  49. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/battle/cleared_slots.py +0 -0
  50. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/battle/enemy.py +0 -0
  51. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/battle/slots.py +0 -0
  52. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/__init__.py +0 -0
  53. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/beacon_base.py +0 -0
  54. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/cat.py +0 -0
  55. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/drop_chara.py +0 -0
  56. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/gambling.py +0 -0
  57. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/gatya.py +0 -0
  58. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/gatya_item.py +0 -0
  59. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/item_pack.py +0 -0
  60. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/login_bonuses.py +0 -0
  61. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/matatabi.py +0 -0
  62. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/medals.py +0 -0
  63. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/mission.py +0 -0
  64. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/my_sale.py +0 -0
  65. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/nyanko_club.py +0 -0
  66. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/officer_pass.py +0 -0
  67. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/playtime.py +0 -0
  68. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/powerup.py +0 -0
  69. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/scheme_items.py +0 -0
  70. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/special_skill.py +0 -0
  71. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/stamp.py +0 -0
  72. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/talent_orbs.py +0 -0
  73. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/unlock_popups.py +0 -0
  74. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/upgrade.py +0 -0
  75. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/catbase/user_rank_rewards.py +0 -0
  76. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/gamoto/__init__.py +0 -0
  77. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/gamoto/base_materials.py +0 -0
  78. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/gamoto/cat_shrine.py +0 -0
  79. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/gamoto/catamins.py +0 -0
  80. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/gamoto/gamatoto.py +0 -0
  81. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/gamoto/ototo.py +0 -0
  82. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/localizable.py +0 -0
  83. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/map/__init__.py +0 -0
  84. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/map/aku.py +0 -0
  85. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/map/challenge.py +0 -0
  86. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/map/chapters.py +0 -0
  87. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/map/dojo.py +0 -0
  88. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/map/enigma.py +0 -0
  89. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/map/event.py +0 -0
  90. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/map/ex_stage.py +0 -0
  91. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/map/gauntlets.py +0 -0
  92. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/map/item_reward_stage.py +0 -0
  93. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/map/legend_quest.py +0 -0
  94. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/map/map_names.py +0 -0
  95. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/map/map_reset.py +0 -0
  96. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/map/outbreaks.py +0 -0
  97. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/map/story.py +0 -0
  98. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/map/timed_score.py +0 -0
  99. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/map/tower.py +0 -0
  100. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/map/uncanny.py +0 -0
  101. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game/map/zero_legends.py +0 -0
  102. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/game_version.py +0 -0
  103. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/io/__init__.py +0 -0
  104. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/io/adb_handler.py +0 -0
  105. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/io/bc_csv.py +0 -0
  106. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/io/command.py +0 -0
  107. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/io/config.py +0 -0
  108. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/io/data.py +0 -0
  109. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/io/git_handler.py +0 -0
  110. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/io/json_file.py +0 -0
  111. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/io/root_handler.py +0 -0
  112. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/io/thread_helper.py +0 -0
  113. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/io/waydroid.py +0 -0
  114. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/io/yaml.py +0 -0
  115. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/locale_handler.py +0 -0
  116. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/log.py +0 -0
  117. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/max_value_helper.py +0 -0
  118. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/server/__init__.py +0 -0
  119. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/server/client_info.py +0 -0
  120. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/server/event_data.py +0 -0
  121. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/server/headers.py +0 -0
  122. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/server/managed_item.py +0 -0
  123. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/server/request.py +0 -0
  124. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/server/server_handler.py +0 -0
  125. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/server/updater.py +0 -0
  126. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/core/theme_handler.py +0 -0
  127. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/core/config.properties +0 -0
  128. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/core/files.properties +0 -0
  129. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/core/input.properties +0 -0
  130. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/core/locale.properties +0 -0
  131. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/core/main.properties +0 -0
  132. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/core/save.properties +0 -0
  133. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/core/server.properties +0 -0
  134. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/core/theme.properties +0 -0
  135. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/core/updater.properties +0 -0
  136. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/edits/bannable_items.properties +0 -0
  137. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/edits/cats.properties +0 -0
  138. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/edits/enemy.properties +0 -0
  139. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/edits/fixes.properties +0 -0
  140. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/edits/gambling.properties +0 -0
  141. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/edits/gamototo.properties +0 -0
  142. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/edits/gatya.properties +0 -0
  143. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/edits/gold_pass.properties +0 -0
  144. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/edits/map.properties +0 -0
  145. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/edits/medals.properties +0 -0
  146. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/edits/missions.properties +0 -0
  147. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/edits/playtime.properties +0 -0
  148. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/edits/scheme_items.properties +0 -0
  149. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/edits/special_skills.properties +0 -0
  150. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/edits/talent_orbs.properties +0 -0
  151. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/edits/treasures.properties +0 -0
  152. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/en/edits/user_rank.properties +0 -0
  153. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/core/config.properties +0 -0
  154. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/core/files.properties +0 -0
  155. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/core/locale.properties +0 -0
  156. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/core/theme.properties +0 -0
  157. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/core/updater.properties +0 -0
  158. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/edits/bannable_items.properties +0 -0
  159. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/edits/enemy.properties +0 -0
  160. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/edits/fixes.properties +0 -0
  161. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/edits/gambling.properties +0 -0
  162. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/edits/gamototo.properties +0 -0
  163. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/edits/gatya.properties +0 -0
  164. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/edits/gold_pass.properties +0 -0
  165. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/edits/items.properties +0 -0
  166. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/edits/medals.properties +0 -0
  167. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/edits/missions.properties +0 -0
  168. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/edits/playtime.properties +0 -0
  169. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/edits/scheme_items.properties +0 -0
  170. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/edits/special_skills.properties +0 -0
  171. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/edits/talent_orbs.properties +0 -0
  172. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/edits/user_rank.properties +0 -0
  173. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/locales/vi/metadata.json +0 -0
  174. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/max_values.json +0 -0
  175. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/themes/default.json +0 -0
  176. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/files/themes/discord.json +0 -0
  177. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe/py.typed +0 -0
  178. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe.egg-info/SOURCES.txt +0 -0
  179. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe.egg-info/dependency_links.txt +0 -0
  180. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe.egg-info/entry_points.txt +0 -0
  181. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe.egg-info/requires.txt +0 -0
  182. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/src/bcsfe.egg-info/top_level.txt +0 -0
  183. {bcsfe-3.2.0b3 → bcsfe-3.2.1}/tests/test_parse.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bcsfe
3
- Version: 3.2.0b3
3
+ Version: 3.2.1
4
4
  Summary: A save file editor for The Battle Cats
5
5
  Author: fieryhenry
6
6
  License-Expression: GPL-3.0-or-later
@@ -298,13 +298,16 @@ pip uninstall bcsfe
298
298
  ```
299
299
  ## Terms of Use
300
300
 
301
+ I don't like that I have to have Terms of use but these terms are designed to prevent scams and the
302
+ exploitation of users.
303
+
301
304
  By using the editor you agree to the following:
302
305
 
303
306
  If you are using the editor to run a paid service that profits off of the editor
304
307
  (e.g a service to provide people with hacked accounts, or a paid discord bot to edit people's accounts,
305
308
  etc) you must make it very clear that you are using this save editor.
306
309
 
307
- This should be done by linking this GitHub page, and explicitly stating that the tool you are
310
+ This should be done by linking this Codeberg page, and explicitly stating that the tool you are
308
311
  using is available for free and that they don't need to use your service to hack their account.
309
312
 
310
313
  This information needs to be visible and something the customer agrees to **before** any payment is made.
@@ -318,8 +321,6 @@ the editor under the hood as long as you abide by the [License](#license). Basic
318
321
  distributing a program which uses the editor, you need to license your own program under the GPL
319
322
  or a compatible license (basically make it open source / free software too).
320
323
 
321
- These terms are designed to prevent scams and the exploitation of users.
322
-
323
324
  Also if you **are** profiting from the editor, it would be greatly appreciated if you could
324
325
  give back something and support me.
325
326
 
@@ -429,13 +430,13 @@ You'll need to collect the catfood in-game after each clear though
429
430
 
430
431
  ### Install from source
431
432
 
432
- If you want the latest features then you can install the editor from the github.
433
+ If you want the latest features then you can install the editor from the git repo.
433
434
 
434
435
  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
436
+ - Windows: [Git](https://git-scm.com/downloads)
437
+ - Linux: (use package manager, e.g `sudo apt-get install git` or `sudo pacman -S git`)
438
+ - Android: Termux: `pkg install git`
439
+ - iOS: a-Shell should already include it
439
440
 
440
441
  2. Run the following commands: (You may have to replace `py` with `python` or `python3`)
441
442
 
@@ -269,13 +269,16 @@ pip uninstall bcsfe
269
269
  ```
270
270
  ## Terms of Use
271
271
 
272
+ I don't like that I have to have Terms of use but these terms are designed to prevent scams and the
273
+ exploitation of users.
274
+
272
275
  By using the editor you agree to the following:
273
276
 
274
277
  If you are using the editor to run a paid service that profits off of the editor
275
278
  (e.g a service to provide people with hacked accounts, or a paid discord bot to edit people's accounts,
276
279
  etc) you must make it very clear that you are using this save editor.
277
280
 
278
- This should be done by linking this GitHub page, and explicitly stating that the tool you are
281
+ This should be done by linking this Codeberg page, and explicitly stating that the tool you are
279
282
  using is available for free and that they don't need to use your service to hack their account.
280
283
 
281
284
  This information needs to be visible and something the customer agrees to **before** any payment is made.
@@ -289,8 +292,6 @@ the editor under the hood as long as you abide by the [License](#license). Basic
289
292
  distributing a program which uses the editor, you need to license your own program under the GPL
290
293
  or a compatible license (basically make it open source / free software too).
291
294
 
292
- These terms are designed to prevent scams and the exploitation of users.
293
-
294
295
  Also if you **are** profiting from the editor, it would be greatly appreciated if you could
295
296
  give back something and support me.
296
297
 
@@ -400,13 +401,13 @@ You'll need to collect the catfood in-game after each clear though
400
401
 
401
402
  ### Install from source
402
403
 
403
- If you want the latest features then you can install the editor from the github.
404
+ If you want the latest features then you can install the editor from the git repo.
404
405
 
405
406
  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
407
+ - Windows: [Git](https://git-scm.com/downloads)
408
+ - Linux: (use package manager, e.g `sudo apt-get install git` or `sudo pacman -S git`)
409
+ - Android: Termux: `pkg install git`
410
+ - iOS: a-Shell should already include it
410
411
 
411
412
  2. Run the following commands: (You may have to replace `py` with `python` or `python3`)
412
413
 
@@ -1,4 +1,4 @@
1
- __version__ = "3.2.0b3"
1
+ __version__ = "3.2.1"
2
2
 
3
3
  from bcsfe import core, cli
4
4
 
@@ -150,7 +150,7 @@ class ListOutput:
150
150
  def __init__(
151
151
  self,
152
152
  strings: list[str],
153
- ints: list[int],
153
+ ints: list[int] | list[str],
154
154
  dialog: str | None = None,
155
155
  perameters: dict[str, Any] | None = None,
156
156
  start_index: int = 1,
@@ -210,7 +210,7 @@ class ChoiceInput:
210
210
  self,
211
211
  items: list[str],
212
212
  strings: list[str],
213
- ints: list[int],
213
+ ints: list[int] | list[str],
214
214
  perameters: dict[str, int | str],
215
215
  dialog: str,
216
216
  single_choice: bool = False,
@@ -233,7 +233,7 @@ class ChoiceInput:
233
233
  @staticmethod
234
234
  def from_reduced(
235
235
  items: list[str],
236
- ints: list[int] | None = None,
236
+ ints: list[int] | list[str] | None = None,
237
237
  perameters: dict[str, int | str] | None = None,
238
238
  dialog: str | None = None,
239
239
  single_choice: bool = False,
@@ -482,7 +482,7 @@ class MultiEditor:
482
482
  choices, all_at_once = ChoiceInput(
483
483
  self.items,
484
484
  self.strings,
485
- self.ints or [],
485
+ self.ints or [], # type: ignore
486
486
  self.perameters,
487
487
  "select_edit",
488
488
  ).get()
@@ -588,9 +588,7 @@ class SingleEditor:
588
588
  self.signed = signed
589
589
 
590
590
  def edit(self, escape_text: bool = True) -> int:
591
- max_value = self.max_value
592
- if max_value is None:
593
- max_value = IntInput.get_max_value(max_value, self.signed)
591
+ max_value = IntInput.get_max_value(self.max_value, self.signed)
594
592
  if self.max_value is None:
595
593
  dialog = "input_non_max"
596
594
  elif self.min_value != 0:
@@ -165,6 +165,8 @@ class BasicItems:
165
165
  core.core_data.max_value_manager.get("platinum_tickets")
166
166
  - platinum_ticket_amount
167
167
  ) * 10 + 9
168
+
169
+ max_value = max(0, max_value)
168
170
  save_file.platinum_shards = dialog_creator.SingleEditor(
169
171
  BasicItems.get_name(name, "platinum_shards"),
170
172
  save_file.platinum_shards,
@@ -193,6 +195,10 @@ class BasicItems:
193
195
  def edit_battle_items(save_file: core.SaveFile):
194
196
  save_file.battle_items.edit(save_file)
195
197
 
198
+ @staticmethod
199
+ def edit_battle_items_endless(save_file: core.SaveFile):
200
+ save_file.battle_items.edit_endless_items(save_file)
201
+
196
202
  @staticmethod
197
203
  def edit_catamins(save_file: core.SaveFile):
198
204
  names_o = core.core_data.get_gatya_item_names(save_file)
@@ -249,7 +255,7 @@ class BasicItems:
249
255
  if items is None:
250
256
  return
251
257
  names: list[str] = []
252
- for item in items:
258
+ for item in items[: len(save_file.treasure_chests)]:
253
259
  name = names_o.get_name(item.id)
254
260
  if name is None:
255
261
  name = core.core_data.local_manager.get_key(
@@ -12,6 +12,12 @@ ChaptersType = Union[
12
12
  ]
13
13
 
14
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
+
15
21
  def unclear_stage(
16
22
  chapters: ChaptersType,
17
23
  map: int,
@@ -98,7 +104,11 @@ def edit_chapters(
98
104
  map_names = core.MapNames(
99
105
  save_file, letter_code, no_r_prefix=no_r_prefix, base_index=base_index
100
106
  )
101
- names = map_names.map_names
107
+ names: dict[int, str | None] = {}
108
+ for id, name in map_names.map_names.items():
109
+ if id >= get_total_maps(chapters):
110
+ continue
111
+ names[id] = name
102
112
 
103
113
  choice = dialog_creator.ChoiceInput.from_reduced(
104
114
  ["clear_stages", "unclear_stages"],
@@ -58,6 +58,7 @@ class FeatureHandler:
58
58
  "np": edits.basic_items.BasicItems.edit_np,
59
59
  "leadership": edits.basic_items.BasicItems.edit_leadership,
60
60
  "battle_items": edits.basic_items.BasicItems.edit_battle_items,
61
+ "battle_items_endless": edits.basic_items.BasicItems.edit_battle_items_endless,
61
62
  "catseyes": edits.basic_items.BasicItems.edit_catseyes,
62
63
  "catfruit": edits.basic_items.BasicItems.edit_catfruit,
63
64
  "talent_orbs": core.game.catbase.talent_orbs.SaveOrbs.edit_talent_orbs,
@@ -0,0 +1,297 @@
1
+ from __future__ import annotations
2
+
3
+ import datetime
4
+ from math import inf
5
+ from typing import Any
6
+ from bcsfe import core
7
+ from bcsfe.cli import dialog_creator, color
8
+
9
+
10
+ class EndlessItem:
11
+ def __init__(
12
+ self, active: bool, unknown: bool, amount: int, start: float, end: float
13
+ ):
14
+ self.active = active
15
+ self.unknown = unknown
16
+ self.amount = amount
17
+ self.start = start
18
+ self.end = end
19
+
20
+ @staticmethod
21
+ def init() -> EndlessItem:
22
+ return EndlessItem(False, False, 0, 0, 0)
23
+
24
+ @staticmethod
25
+ def read(stream: core.Data) -> EndlessItem:
26
+ return EndlessItem(
27
+ stream.read_bool(),
28
+ stream.read_bool(),
29
+ stream.read_byte(),
30
+ stream.read_double(),
31
+ stream.read_double(),
32
+ )
33
+
34
+ def write(self, stream: core.Data):
35
+ stream.write_bool(self.active)
36
+ stream.write_bool(self.unknown)
37
+ stream.write_byte(self.amount)
38
+ stream.write_double(self.start)
39
+ stream.write_double(self.end)
40
+
41
+ def serialize(self) -> dict[str, Any]:
42
+ return {
43
+ "active": self.active,
44
+ "unknown": self.unknown,
45
+ "amount": self.amount,
46
+ "start": self.start,
47
+ "end": self.end,
48
+ }
49
+
50
+ @staticmethod
51
+ def deserialize(data: dict[str, Any]) -> EndlessItem:
52
+ return EndlessItem(
53
+ data.get("active", False),
54
+ data.get("unknown", False),
55
+ data.get("amount", 0),
56
+ data.get("start", 0.0),
57
+ data.get("end", 0.0),
58
+ )
59
+
60
+ def get_endless_duration(self) -> datetime.timedelta | None:
61
+ if not self.active:
62
+ return datetime.timedelta()
63
+
64
+ if self.end == inf:
65
+ return None
66
+
67
+ return datetime.timedelta(
68
+ seconds=self.end - self.start + (self.amount * 3 * 60 * 60)
69
+ )
70
+
71
+ def get_endless_duration_formatted(self) -> str:
72
+ duration = self.get_endless_duration()
73
+
74
+ if duration is None:
75
+ return core.localize("infinity_duration")
76
+
77
+ days = duration.days
78
+ hours, rem = divmod(duration.seconds, 3600)
79
+ minutes, seconds = divmod(rem, 60)
80
+
81
+ return core.localize(
82
+ "duration", days=days, hours=hours, minutes=minutes, seconds=seconds
83
+ )
84
+
85
+ def set_duration_mins(self, mins: float, amount: int):
86
+ self.active = True
87
+ self.unknown = True
88
+ self.amount = amount
89
+ self.start = datetime.datetime.now(datetime.timezone.utc).timestamp()
90
+ self.end = self.start + mins * 60
91
+
92
+
93
+ class BattleItem:
94
+ def __init__(self, amount: int):
95
+ self.amount = amount
96
+ self.locked = False
97
+
98
+ self.endless_item = EndlessItem.init()
99
+
100
+ @staticmethod
101
+ def init() -> BattleItem:
102
+ return BattleItem(0)
103
+
104
+ @staticmethod
105
+ def read_amount(stream: core.Data) -> BattleItem:
106
+ return BattleItem(stream.read_int())
107
+
108
+ def write_amount(self, stream: core.Data):
109
+ stream.write_int(self.amount)
110
+
111
+ def read_locked(self, stream: core.Data):
112
+ self.locked = stream.read_bool()
113
+
114
+ def write_locked(self, stream: core.Data):
115
+ stream.write_bool(self.locked)
116
+
117
+ def read_endless_items(self, stream: core.Data):
118
+ self.endless_item = EndlessItem.read(stream)
119
+
120
+ def write_endless_items(self, stream: core.Data):
121
+ self.endless_item.write(stream)
122
+
123
+ def serialize(self) -> dict[str, Any]:
124
+ return {
125
+ "amount": self.amount,
126
+ "locked": self.locked,
127
+ "endless": self.endless_item.serialize(),
128
+ }
129
+
130
+ @staticmethod
131
+ def deserialize(data: dict[str, Any]) -> BattleItem:
132
+ battle_item = BattleItem(data.get("amount", 0))
133
+ battle_item.locked = data.get("locked", False)
134
+ battle_item.endless_item = EndlessItem.deserialize(data.get("endless", {}))
135
+ return battle_item
136
+
137
+ def __repr__(self):
138
+ try:
139
+ return f"BattleItem({self.amount}, {self.locked}, {self.endless_item})"
140
+ except AttributeError:
141
+ return f"BattleItem({self.amount}, {self.endless_item})"
142
+
143
+ def __str__(self):
144
+ return self.__repr__()
145
+
146
+
147
+ class BattleItems:
148
+ def __init__(self, items: list[BattleItem]):
149
+ self.items = items
150
+ self.lock_item = False
151
+
152
+ @staticmethod
153
+ def init() -> BattleItems:
154
+ return BattleItems([BattleItem.init() for _ in range(6)])
155
+
156
+ @staticmethod
157
+ def read_items(stream: core.Data) -> BattleItems:
158
+ total_items = 6
159
+ items = [BattleItem.read_amount(stream) for _ in range(total_items)]
160
+ return BattleItems(items)
161
+
162
+ def write_items(self, stream: core.Data):
163
+ for item in self.items:
164
+ item.write_amount(stream)
165
+
166
+ def read_locked_items(self, stream: core.Data):
167
+ self.lock_item = stream.read_bool()
168
+ for item in self.items:
169
+ item.read_locked(stream)
170
+
171
+ def write_locked_items(self, stream: core.Data):
172
+ stream.write_bool(self.lock_item)
173
+ for item in self.items:
174
+ item.write_locked(stream)
175
+
176
+ def read_endless_items(self, stream: core.Data):
177
+ for i in range(6):
178
+ if i >= len(self.items):
179
+ _ = EndlessItem.read(stream) # ensure we still read 6 items
180
+ else:
181
+ item = self.items[i]
182
+ item.read_endless_items(stream)
183
+
184
+ def write_endless_items(self, stream: core.Data):
185
+ for i in range(6):
186
+ if i >= len(self.items):
187
+ EndlessItem.init().write(stream) # ensure we still write 6 items
188
+ else:
189
+ item = self.items[i]
190
+ item.write_endless_items(stream)
191
+
192
+ def serialize(self) -> dict[str, Any]:
193
+ return {
194
+ "items": [item.serialize() for item in self.items],
195
+ "lock_item": self.lock_item,
196
+ }
197
+
198
+ @staticmethod
199
+ def deserialize(data: dict[str, Any]) -> BattleItems:
200
+ battle_items = BattleItems(
201
+ [BattleItem.deserialize(item) for item in data.get("items", [])]
202
+ )
203
+ battle_items.lock_item = data.get("lock_item", False)
204
+ return battle_items
205
+
206
+ def __repr__(self):
207
+ return f"BattleItems({self.items})"
208
+
209
+ def __str__(self):
210
+ return f"BattleItems({self.items})"
211
+
212
+ def get_names(self, save_file: core.SaveFile) -> list[str] | None:
213
+ names = core.core_data.get_gatya_item_names(save_file).names
214
+ if names is None:
215
+ return None
216
+ items = core.core_data.get_gatya_item_buy(save_file).get_by_category(3)
217
+ if items is None:
218
+ return None
219
+
220
+ names = [names[item.id] for item in items]
221
+ return names
222
+
223
+ def edit(self, save_file: core.SaveFile):
224
+ group_name = save_file.get_localizable().get("shop_category1")
225
+ if group_name is None:
226
+ group_name = core.core_data.local_manager.get_key("battle_items")
227
+ item_names = self.get_names(save_file)
228
+ if item_names is None:
229
+ return
230
+ current_values = [item.amount for item in self.items]
231
+ values = dialog_creator.MultiEditor.from_reduced(
232
+ group_name,
233
+ item_names,
234
+ current_values,
235
+ core.core_data.max_value_manager.get("battle_items"),
236
+ ).edit()
237
+ for i, value in enumerate(values):
238
+ self.items[i].amount = value
239
+
240
+ def edit_endless_items(self, save_file: core.SaveFile):
241
+ item_names = self.get_names(save_file)
242
+ if item_names is None:
243
+ return
244
+
245
+ current_values = [
246
+ item.endless_item.get_endless_duration_formatted() for item in self.items
247
+ ]
248
+
249
+ (options, all_at_once) = dialog_creator.ChoiceInput.from_reduced(
250
+ [core.localize("endless_item_item", item=item) for item in item_names],
251
+ current_values,
252
+ localize_options=False,
253
+ dialog="select_option",
254
+ ).multiple_choice(False)
255
+
256
+ if options is None:
257
+ return
258
+
259
+ infinity_str = core.localize("infinity")
260
+
261
+ if all_at_once:
262
+ val = dialog_creator.StringInput().get_input_locale_while(
263
+ "enter_duration_minutes", {}
264
+ )
265
+ if val is None:
266
+ return
267
+
268
+ if val.lower() == infinity_str.lower():
269
+ val = inf
270
+ else:
271
+ try:
272
+ val = float(val)
273
+ except ValueError:
274
+ return
275
+
276
+ for item in self.items:
277
+ item.endless_item.set_duration_mins(val, 0)
278
+ else:
279
+ for opt in options:
280
+ val = dialog_creator.StringInput().get_input_locale_while(
281
+ "enter_duration_minutes_item", {"item": item_names[opt]}
282
+ )
283
+ if val is None:
284
+ return
285
+
286
+ if val.lower() == infinity_str.lower():
287
+ val = inf
288
+ else:
289
+ try:
290
+ val = float(val)
291
+ except ValueError:
292
+ color.ColoredText.localize("invalid_minute_count")
293
+ continue
294
+
295
+ self.items[opt].endless_item.set_duration_mins(val, 0)
296
+
297
+ color.ColoredText.localize("endless_items_success")
@@ -2,7 +2,6 @@ from __future__ import annotations
2
2
  import glob
3
3
  import os
4
4
  import shutil
5
- import typing
6
5
 
7
6
  from bcsfe import core
8
7
  import re
@@ -88,12 +87,17 @@ class Path:
88
87
  path.generate_dirs()
89
88
  return path
90
89
 
90
+ def is_empty(self) -> bool:
91
+ return self.path == ""
92
+
91
93
  def generate_dirs(self: Path) -> Path:
94
+ if self.is_empty():
95
+ return self
92
96
  if not self.exists():
93
97
  try:
94
98
  self.__make_dirs()
95
- except OSError:
96
- pass
99
+ except OSError as e:
100
+ print(e, self)
97
101
  return self
98
102
 
99
103
  def create(self) -> Path:
@@ -794,15 +794,7 @@ class SaveFile:
794
794
  assert self.data.read_int() == 100100
795
795
 
796
796
  if self.game_version >= 100300:
797
- self.utl2: list[tuple[bool, bool, int, float, float]] = []
798
- length = 6
799
- for _ in range(length):
800
- b1 = self.data.read_bool()
801
- b2 = self.data.read_bool()
802
- i1 = self.data.read_byte()
803
- f1 = self.data.read_double()
804
- f2 = self.data.read_double()
805
- self.utl2.append((b1, b2, i1, f1, f2))
797
+ self.battle_items.read_endless_items(self.data)
806
798
 
807
799
  assert self.data.read_int() == 100300
808
800
 
@@ -1881,30 +1873,7 @@ class SaveFile:
1881
1873
  self.data.write_int(100100)
1882
1874
 
1883
1875
  if self.game_version >= 100300:
1884
- for i in range(6):
1885
- try:
1886
- item = self.utl2[i]
1887
- except IndexError:
1888
- item = (False, False, 0, 0.0, 0.0)
1889
-
1890
- tuple_len = len(item)
1891
- b1, b2, i1, f1, f2 = False, False, 0, 0.0, 0.0
1892
- if tuple_len >= 1:
1893
- b1 = item[0]
1894
- if tuple_len >= 2:
1895
- b2 = item[1]
1896
- if tuple_len >= 3:
1897
- i1 = item[2]
1898
- if tuple_len >= 4:
1899
- f1 = item[3]
1900
- if tuple_len >= 5:
1901
- f2 = item[4]
1902
-
1903
- self.data.write_bool(b1)
1904
- self.data.write_bool(b2)
1905
- self.data.write_byte(i1)
1906
- self.data.write_double(f1)
1907
- self.data.write_double(f2)
1876
+ self.battle_items.write_endless_items(self.data)
1908
1877
 
1909
1878
  self.data.write_int(100300)
1910
1879
 
@@ -2504,7 +2473,6 @@ class SaveFile:
2504
2473
  "ud8": self.ud8,
2505
2474
  "ud9": self.ud9,
2506
2475
  "date_int": self.date_int,
2507
- "utl2": self.utl2,
2508
2476
  "event_capsules_2": self.event_capsules_2,
2509
2477
  "two_battle_lines": self.two_battle_lines,
2510
2478
  "ud10": self.ud10,
@@ -2884,7 +2852,6 @@ class SaveFile:
2884
2852
  save_file.ud8 = data.get("ud8", 0.0)
2885
2853
  save_file.ud9 = data.get("ud9", 0.0)
2886
2854
  save_file.date_int = data.get("date_int", 0)
2887
- save_file.utl2 = data.get("utl2", [(False, False, 0, 0.0, 0.0)] * 6)
2888
2855
  save_file.event_capsules_2 = data.get("event_capsules_2", [])
2889
2856
  save_file.two_battle_lines = data.get("two_battle_lines", False)
2890
2857
  save_file.ud10 = data.get("ud10", 0.0)
@@ -3205,7 +3172,6 @@ class SaveFile:
3205
3172
  self.ushl6 = []
3206
3173
 
3207
3174
  self.utl1 = []
3208
- self.utl2 = [(False, False, 0, 0.0, 0.0)] * 6
3209
3175
  self.utl3 = []
3210
3176
  self.utl4 = []
3211
3177
 
@@ -141,6 +141,8 @@ class GameDataGetter:
141
141
 
142
142
  archive.extractall(outdir.path)
143
143
 
144
+ outdir.add("downloaded").write(core.Data())
145
+
144
146
  return True
145
147
 
146
148
  def get_version_path(self) -> core.Path | None:
@@ -150,11 +152,11 @@ class GameDataGetter:
150
152
  GameDataGetter.get_game_data_dir().add(self.cc.get_code()).add(self.version)
151
153
  ).generate_dirs()
152
154
 
153
- def is_missing(self) -> bool:
155
+ def has_downloaded(self) -> bool:
154
156
  path = self.get_version_path()
155
157
  if path is None:
156
158
  return False
157
- return len(path.add("DataLocal").get_files()) != 0
159
+ return path.add("downloaded").exists()
158
160
 
159
161
  def get_file(self, pack_name: str, file_name: str) -> core.Data | bool:
160
162
  path = self.get_file_path(pack_name, file_name)
@@ -164,7 +166,7 @@ class GameDataGetter:
164
166
  if path.exists():
165
167
  return path.read()
166
168
  else:
167
- if self.is_missing():
169
+ if self.has_downloaded():
168
170
  return True
169
171
  if self.download_version_data() is None:
170
172
  return False
@@ -175,7 +177,7 @@ class GameDataGetter:
175
177
 
176
178
  if path.exists():
177
179
  return path.read()
178
- return self.is_missing()
180
+ return self.has_downloaded()
179
181
 
180
182
  def save_file(self, pack_name: str, file_name: str) -> core.Data | bool:
181
183
  pack_name = self.get_packname(pack_name)
@@ -243,7 +245,7 @@ class GameDataGetter:
243
245
  self.print_no_file(pack_name, file_name)
244
246
  return None
245
247
 
246
- if display_text and not self.is_missing():
248
+ if display_text and not self.has_downloaded():
247
249
  color.ColoredText.localize(
248
250
  "downloading",
249
251
  file_name=file_name,
@@ -27,6 +27,15 @@ np=NP
27
27
  leadership=Leadership
28
28
  catseyes=Catseyes
29
29
  battle_items=Battle Items
30
+ duration=<@t>{days}</t> days, <@t>{hours}</t> hours, <@t>{minutes}</> minutes, <@t>{seconds}</> seconds
31
+ endless_item_item=<@s>{item}</> : <@s>{int}</>
32
+ endless_items_success=<@su>Successfully edited endless items</>
33
+ invalid_minute_count=<@e>Invalid minute amount</>
34
+ enter_duration_minutes=Enter the duration in minutes for the endless items to last for (if you enter <@t>infinity</> the items last forever):
35
+ infinity_duration=<@t>infinity</>
36
+ infinity=Infinity
37
+ enter_duration_minutes_item=Enter the duration in minutes for the endless <@t>{item}</> to last for (if you enter <@t>infinity</> the items last forever):
38
+ battle_items_endless=Endless Battle Items
30
39
  talent_orbs=Talent Orbs
31
40
  scheme_items=Scheme Items
32
41
  labyrinth_medals=Labyrinth Medals
@@ -27,4 +27,6 @@ select_features=
27
27
  >Đầu vào:
28
28
 
29
29
  individual=Cá nhân
30
- edit_all_at_once=Tất cả cùng lúc
30
+ edit_all_at_once=Tất cả cùng lúc
31
+ finish=Hoàn thành
32
+ select_option=Chọn tùy chọn: