tuipet 0.5.330__tar.gz → 0.5.332__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 (356) hide show
  1. {tuipet-0.5.330/src/tuipet.egg-info → tuipet-0.5.332}/PKG-INFO +1 -1
  2. {tuipet-0.5.330 → tuipet-0.5.332}/pyproject.toml +1 -1
  3. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/app.py +1 -1
  4. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/petbase.py +11 -2
  5. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/petbody.py +39 -19
  6. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/petcare.py +7 -4
  7. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/shop.py +4 -2
  8. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/statusbox.py +22 -0
  9. {tuipet-0.5.330 → tuipet-0.5.332/src/tuipet.egg-info}/PKG-INFO +1 -1
  10. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_canon_discipline.py +15 -11
  11. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_filth_system.py +89 -6
  12. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_shop_dossier_audit.py +6 -1
  13. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_status_box.py +38 -0
  14. {tuipet-0.5.330 → tuipet-0.5.332}/LICENSE +0 -0
  15. {tuipet-0.5.330 → tuipet-0.5.332}/README.md +0 -0
  16. {tuipet-0.5.330 → tuipet-0.5.332}/setup.cfg +0 -0
  17. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/__init__.py +0 -0
  18. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/__main__.py +0 -0
  19. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/accountscreen.py +0 -0
  20. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/adventure.py +0 -0
  21. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/adventurescreen.py +0 -0
  22. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/albumscreen.py +0 -0
  23. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/anim.py +0 -0
  24. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/appactions.py +0 -0
  25. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/appboot.py +0 -0
  26. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/arena.py +0 -0
  27. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/arenafx.py +0 -0
  28. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/assistscreen.py +0 -0
  29. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/backgrounds.py +0 -0
  30. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/backgroundscreen.py +0 -0
  31. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/battle.py +0 -0
  32. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/battlescreen.py +0 -0
  33. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/bugscreen.py +0 -0
  34. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/cloudsync.py +0 -0
  35. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/attr_icons.json +0 -0
  36. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/backgrounds.json.gz +0 -0
  37. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/battle_fx.json.gz +0 -0
  38. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/battle_overlays.json +0 -0
  39. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/careEffect.csv +0 -0
  40. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/deviceAttacks.csv +0 -0
  41. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/digicoreMenuConfig.csv +0 -0
  42. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/digimon.csv +0 -0
  43. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/dropRate.csv +0 -0
  44. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/effects.json.gz +0 -0
  45. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/eggUnlock.csv +0 -0
  46. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/eggs.json.gz +0 -0
  47. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/elementAffinity.csv +0 -0
  48. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/enemies.csv +0 -0
  49. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/evolutions.csv +0 -0
  50. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/fieldAffinity.csv +0 -0
  51. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/foods.csv +0 -0
  52. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/hp_dummies.json +0 -0
  53. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/icons.json.gz +0 -0
  54. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/items.csv +0 -0
  55. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/jogress_overlays.json +0 -0
  56. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/lines.csv +0 -0
  57. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/lootTable.csv +0 -0
  58. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/maps.csv +0 -0
  59. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/orbs.json.gz +0 -0
  60. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/shopConsumable.csv +0 -0
  61. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/alarm.wav +0 -0
  62. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/angry.wav +0 -0
  63. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/attack.wav +0 -0
  64. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/attackHit.wav +0 -0
  65. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/battle.wav +0 -0
  66. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/boot.wav +0 -0
  67. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/cancel.wav +0 -0
  68. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/champion.wav +0 -0
  69. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/click.wav +0 -0
  70. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/compatible.wav +0 -0
  71. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/confirm.wav +0 -0
  72. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/death.wav +0 -0
  73. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/eat.wav +0 -0
  74. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/error.wav +0 -0
  75. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/evolve.wav +0 -0
  76. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/happy.wav +0 -0
  77. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/hatch.wav +0 -0
  78. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/jogress.wav +0 -0
  79. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/largePoop.wav +0 -0
  80. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/lastBite.wav +0 -0
  81. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/lose.wav +0 -0
  82. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/menu.wav +0 -0
  83. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/mischief.wav +0 -0
  84. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/poop.wav +0 -0
  85. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/refuse.wav +0 -0
  86. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/reward.wav +0 -0
  87. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/scroll.wav +0 -0
  88. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/select.wav +0 -0
  89. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/smallPoop.wav +0 -0
  90. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/startBattle.wav +0 -0
  91. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/strongAttack.wav +0 -0
  92. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/strongHit.wav +0 -0
  93. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/trainhit.wav +0 -0
  94. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/wash.wav +0 -0
  95. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sounds/win.wav +0 -0
  96. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/sprites.json.gz +0 -0
  97. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/titles.csv +0 -0
  98. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/tournies.csv +0 -0
  99. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/towns.csv +0 -0
  100. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/train_wall.json +0 -0
  101. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/vitems.json +0 -0
  102. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data/zones.csv +0 -0
  103. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data.py +0 -0
  104. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data_core.py +0 -0
  105. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data_meta.py +0 -0
  106. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data_shop.py +0 -0
  107. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/data_world.py +0 -0
  108. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/deathscreen.py +0 -0
  109. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/digicore.py +0 -0
  110. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/digicorescreen.py +0 -0
  111. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/disciplinescreen.py +0 -0
  112. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/dnascreen.py +0 -0
  113. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/egg.py +0 -0
  114. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/eggguidescreen.py +0 -0
  115. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/eggmigrate.py +0 -0
  116. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/eggselectscreen.py +0 -0
  117. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/evolution.py +0 -0
  118. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/feedscreen.py +0 -0
  119. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/grid.py +0 -0
  120. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/hallscreen.py +0 -0
  121. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/helpscreen.py +0 -0
  122. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/hostinfo.py +0 -0
  123. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/itemfx.py +0 -0
  124. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/jogress.py +0 -0
  125. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/jogressscreen.py +0 -0
  126. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/lines.py +0 -0
  127. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/lobbybout.py +0 -0
  128. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/lobbychat.py +0 -0
  129. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/lobbyscreen.py +0 -0
  130. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/menu.py +0 -0
  131. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/net.py +0 -0
  132. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/optionsscreen.py +0 -0
  133. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/persistence.py +0 -0
  134. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/persistio.py +0 -0
  135. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/pet.py +0 -0
  136. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/petbattle.py +0 -0
  137. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/petdna.py +0 -0
  138. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/placeholder.py +0 -0
  139. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/raidscreen.py +0 -0
  140. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/render.py +0 -0
  141. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/rival.py +0 -0
  142. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/shopscreen.py +0 -0
  143. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/sound.py +0 -0
  144. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/strikefx.py +0 -0
  145. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/theme.py +0 -0
  146. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/themescreen.py +0 -0
  147. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/titlescreen.py +0 -0
  148. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/tournament.py +0 -0
  149. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/tournamentscreen.py +0 -0
  150. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/towneggscreen.py +0 -0
  151. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/townscreen.py +0 -0
  152. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/training.py +0 -0
  153. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet/update.py +0 -0
  154. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet.egg-info/SOURCES.txt +0 -0
  155. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet.egg-info/dependency_links.txt +0 -0
  156. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet.egg-info/entry_points.txt +0 -0
  157. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet.egg-info/requires.txt +0 -0
  158. {tuipet-0.5.330 → tuipet-0.5.332}/src/tuipet.egg-info/top_level.txt +0 -0
  159. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_audit.py +0 -0
  160. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_boss.py +0 -0
  161. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_conditions.py +0 -0
  162. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_drain.py +0 -0
  163. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_encounters.py +0 -0
  164. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_finds.py +0 -0
  165. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_foundation.py +0 -0
  166. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_geography.py +0 -0
  167. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_hazards.py +0 -0
  168. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_holiday.py +0 -0
  169. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_march.py +0 -0
  170. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_placement.py +0 -0
  171. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_progression.py +0 -0
  172. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_replay.py +0 -0
  173. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_rewards.py +0 -0
  174. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_score.py +0 -0
  175. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_shop.py +0 -0
  176. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_streak.py +0 -0
  177. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_summary.py +0 -0
  178. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_towns.py +0 -0
  179. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_adventure_transport.py +0 -0
  180. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_album_completable.py +0 -0
  181. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_album_dex.py +0 -0
  182. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_album_screen.py +0 -0
  183. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_anim_canon.py +0 -0
  184. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_anim_hardening.py +0 -0
  185. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_anim_timing.py +0 -0
  186. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_announce.py +0 -0
  187. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_armor_canon.py +0 -0
  188. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_audit_fixes.py +0 -0
  189. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_auto_care.py +0 -0
  190. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_auto_update.py +0 -0
  191. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_away_flag.py +0 -0
  192. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_background_audit.py +0 -0
  193. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_backgrounds.py +0 -0
  194. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_battle_audit.py +0 -0
  195. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_battle_race.py +0 -0
  196. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_bedtime.py +0 -0
  197. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_birthday.py +0 -0
  198. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_body_math.py +0 -0
  199. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_body_tells.py +0 -0
  200. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_bugreport.py +0 -0
  201. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_call_cadence.py +0 -0
  202. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_canon_injury.py +0 -0
  203. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_card_runoffs.py +0 -0
  204. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_care_asleep.py +0 -0
  205. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_care_audit.py +0 -0
  206. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_care_bonus.py +0 -0
  207. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_catalog_categories.py +0 -0
  208. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_catalog_record.py +0 -0
  209. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_catalog_touches.py +0 -0
  210. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_clock_units.py +0 -0
  211. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_completeness_sweep.py +0 -0
  212. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_constant_shadowing.py +0 -0
  213. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_cup_audit.py +0 -0
  214. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_cup_cadence.py +0 -0
  215. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_cup_festival_eggs.py +0 -0
  216. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_cup_theater.py +0 -0
  217. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_dark_room_fx.py +0 -0
  218. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_data.py +0 -0
  219. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_data_facade.py +0 -0
  220. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_dead_gate.py +0 -0
  221. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_death.py +0 -0
  222. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_device_lines.py +0 -0
  223. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_digicore.py +0 -0
  224. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_digimemory.py +0 -0
  225. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_digimental_gates.py +0 -0
  226. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_distribution.py +0 -0
  227. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_divergence.py +0 -0
  228. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_dmx_level.py +0 -0
  229. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_dna_audit.py +0 -0
  230. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_dna_charge.py +0 -0
  231. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_dna_slim.py +0 -0
  232. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_effects_integrity.py +0 -0
  233. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_egg_audit.py +0 -0
  234. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_egg_dominance.py +0 -0
  235. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_egg_economy.py +0 -0
  236. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_egg_guide.py +0 -0
  237. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_egg_guide_audit.py +0 -0
  238. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_egg_unlock.py +0 -0
  239. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_egg_unlock_math.py +0 -0
  240. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_encoding.py +0 -0
  241. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_energy_system.py +0 -0
  242. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_evolution.py +0 -0
  243. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_evolution_audit.py +0 -0
  244. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_evolution_math.py +0 -0
  245. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_evolution_system.py +0 -0
  246. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_feed.py +0 -0
  247. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_feeding_math.py +0 -0
  248. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_festival_gifts.py +0 -0
  249. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_filth_sick_rate.py +0 -0
  250. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_food_audit.py +0 -0
  251. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_fusion_mode_canon.py +0 -0
  252. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_fx.py +0 -0
  253. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_gift_birthday_math.py +0 -0
  254. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_hall.py +0 -0
  255. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_hardening_0712.py +0 -0
  256. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_help.py +0 -0
  257. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_hint_strips.py +0 -0
  258. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_holiday_decor.py +0 -0
  259. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_home_battle.py +0 -0
  260. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_honors.py +0 -0
  261. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_hud.py +0 -0
  262. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_humulos_eggs.py +0 -0
  263. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_hunger.py +0 -0
  264. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_ios_support.py +0 -0
  265. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_item_expansion.py +0 -0
  266. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_item_heal.py +0 -0
  267. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_itemfx.py +0 -0
  268. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_items_p5.py +0 -0
  269. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_items_p6.py +0 -0
  270. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_items_sweep.py +0 -0
  271. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_jogress.py +0 -0
  272. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_jogress_canon.py +0 -0
  273. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_jogress_math.py +0 -0
  274. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_jogress_wire.py +0 -0
  275. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_ko6_gate.py +0 -0
  276. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_ko6_reachable.py +0 -0
  277. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_line_anchoring.py +0 -0
  278. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_line_curation.py +0 -0
  279. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_lines.py +0 -0
  280. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_liveplay_audit.py +0 -0
  281. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_lobby.py +0 -0
  282. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_lobby_admin.py +0 -0
  283. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_lobby_audit.py +0 -0
  284. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_lobby_chat_polish.py +0 -0
  285. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_lobby_screens.py +0 -0
  286. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_menu_bounds.py +0 -0
  287. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_menu_runoffs.py +0 -0
  288. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_messages.py +0 -0
  289. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_mortality_math.py +0 -0
  290. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_msg_strip.py +0 -0
  291. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_nav_quit.py +0 -0
  292. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_night_palette.py +0 -0
  293. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_note_marquee.py +0 -0
  294. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_options.py +0 -0
  295. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_orb_integrity.py +0 -0
  296. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_panel_smoke.py +0 -0
  297. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_performance.py +0 -0
  298. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_persistence.py +0 -0
  299. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_persistence_audit.py +0 -0
  300. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_pet_effect.py +0 -0
  301. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_poop_audit.py +0 -0
  302. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_poop_model.py +0 -0
  303. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_poop_placement.py +0 -0
  304. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_poop_report.py +0 -0
  305. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_pvp_duel.py +0 -0
  306. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_qol_polish.py +0 -0
  307. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_raid.py +0 -0
  308. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_rank_system.py +0 -0
  309. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_render_budgets.py +0 -0
  310. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_rival.py +0 -0
  311. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_road_presents.py +0 -0
  312. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_robustness.py +0 -0
  313. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_rooms.py +0 -0
  314. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_save_integrity.py +0 -0
  315. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_scene_actors.py +0 -0
  316. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_scene_picker.py +0 -0
  317. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_screen_sweep.py +0 -0
  318. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_sfx_scroll.py +0 -0
  319. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_shop_clone.py +0 -0
  320. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_shops_audit.py +0 -0
  321. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_sickness_clone.py +0 -0
  322. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_silent_failures.py +0 -0
  323. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_sleep.py +0 -0
  324. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_sleep_audit.py +0 -0
  325. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_sleep_system.py +0 -0
  326. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_sound.py +0 -0
  327. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_sound_ios.py +0 -0
  328. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_special_idles.py +0 -0
  329. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_stage_arrival.py +0 -0
  330. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_status_box_sweep.py +0 -0
  331. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_status_icons.py +0 -0
  332. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_sync.py +0 -0
  333. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_theme.py +0 -0
  334. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_theme_contrast.py +0 -0
  335. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_tier1_robustness.py +0 -0
  336. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_tier2_onboarding.py +0 -0
  337. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_tier3_moments.py +0 -0
  338. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_timing_honesty.py +0 -0
  339. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_tournament.py +0 -0
  340. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_town_cup.py +0 -0
  341. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_town_egg_market.py +0 -0
  342. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_town_shop_economy.py +0 -0
  343. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_training_audit.py +0 -0
  344. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_training_clone.py +0 -0
  345. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_training_hp.py +0 -0
  346. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_training_system.py +0 -0
  347. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_ui_stats.py +0 -0
  348. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_update.py +0 -0
  349. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_update_install.py +0 -0
  350. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_verx.py +0 -0
  351. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_visual_audit.py +0 -0
  352. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_visual_polish.py +0 -0
  353. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_weight_system.py +0 -0
  354. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_whats_new.py +0 -0
  355. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_wild_memory.py +0 -0
  356. {tuipet-0.5.330 → tuipet-0.5.332}/tests/test_win_eggs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tuipet
3
- Version: 0.5.330
3
+ Version: 0.5.332
4
4
  Summary: A terminal virtual pet (Digimon V-Pet style) rendered with halfblock sprites, built on data from the real devices.
5
5
  Author-email: Joel Taylor <joeltaylor734@gmail.com>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tuipet"
3
- version = "0.5.330"
3
+ version = "0.5.332"
4
4
  description = "A terminal virtual pet (Digimon V-Pet style) rendered with halfblock sprites, built on data from the real devices."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -150,7 +150,7 @@ class TuiPetApp(ActionsMixin, App):
150
150
  """
151
151
  # the release-news line (title-screen msg box, first launch per build) --
152
152
  # UPDATE THIS WITH EVERY RELEASE that ships something player-visible
153
- WHATS_NEW = ("A CARE MISTAKE NOW TELLS YOU WHAT YOU MISSED: the counter used to just tick up on the card with no explanation, which is a rough way to learn about the one thing that can kill a Mega. Every slip names itself as it happens — 'left hungry too long', 'the lights left on', 'acting up, not scolded', 'empty effort gauge'. And to settle it: POOP HAS NEVER COST YOU A CARE MISTAKE, not at one pile and not at four. A dirty room makes your pet sick and makes it act up; it is not a missed call, and the counter does not move for it.")
153
+ WHATS_NEW = ("THAT LITTLE SPRITE IN THE CORNER IS A FESTIVAL, NOT A STUCK PIXEL: on four days a year a decoration appears in your arena — the Crest of Courage on Odaiba Memorial Day, a present at Christmas, candy at Halloween, cake at New Year — and until now nothing on the home screen said so. The card names the day above your vitals whenever one is on, on the egg screen too. It was only ever labelled on the adventure card before.")
154
154
 
155
155
  BINDINGS = [
156
156
  # jogress is LOBBY-ONLY (fusion needs a real partner from the
@@ -679,8 +679,17 @@ LIGHTS_MISTAKE_POSTPONE = -60.0 # AfterMistakeMinutesPostponed: the NEXT
679
679
  LIGHTS_MISTAKE_OBED = -1 # LightsOnMistakeObedienceChange (once per night)
680
680
  HUNGER_MISTAKE_OBED = 1 # HungerMistakeObedienceChange (canon: +1!)
681
681
  HUNGER_MISTAKE_OBED_GLUTTON = -1 # ...ChangeGlutton
682
- LIGHTS_MISTAKE_SEC = 60.0 # MinutesToMistakeLights(60) as ~12% of the sleep,
683
- # scaled to tuipet's ~6-min night -- one mistake/night
682
+ LIGHTS_MISTAKE_SEC = 60.0 # MinutesToMistakeLights(60): the FIRST lit mistake
683
+ # lands 60 game-min into the sleep, then every 120
684
+ # (LIGHTS_MISTAKE_POSTPONE). ⚠ THE OLD TAIL HERE
685
+ # CLAIMED "~6-min night -- one mistake/night" AND IT
686
+ # WAS WRONG BOTH WAYS: measured on a live Mega the
687
+ # night runs ~600 game-min, so a fully lit one books
688
+ # FIVE (canon's own ~8h night gives 4 -- _tick_asleep
689
+ # has always said so). The number is canon and stays;
690
+ # only this comment lied. Diagnosed 2026-07-31 when
691
+ # Joel asked what was eating his care mistakes: it was
692
+ # this, 5 of his 6 a day.
684
693
  MORNING_MOOD_CHANCE = 5 # MorningMoodChance: 1/5 bad, 1/5 terrible-if-happy, 1/5 good
685
694
  BAD_MORNING_MOOD = {"Happy": -150, "Neutral": -100, "Unhappy": -10, "Depressed": -10}
686
695
  GOOD_MORNING_MOOD = {"Happy": 50, "Neutral": 100, "Unhappy": 150, "Depressed": 150}
@@ -128,15 +128,30 @@ class BodyMixin:
128
128
  anyone else loses 50 -- then the counters tick (care-mistake audit
129
129
  2026-07-05: the counters ticked silently).
130
130
 
131
+ ⭐⭐THE THREE CALLS, AND ONLY THE THREE (2026-08-01, Joel: "canonize
132
+ all care mistakes"). ⛔DO NOT ADD A FOURTH CALLER TO THIS METHOD.
133
+ THE BANDAI DEVICE RECORD IS THE AUTHORITY on what a care mistake IS:
134
+ a MISSED CALL, and the device makes exactly three calls --
135
+ 1. hunger empty (petbody, the hunger call)
136
+ 2. strength empty (petbody, the effort call)
137
+ 3. tired / wants sleep (petbody, the lights call)
138
+ The manual also names things that are explicitly NOT care mistakes:
139
+ overfeeding, injury, and waking a sleeper. Two impostors were cut on
140
+ that ruling -- the ignored TANTRUM (`_tick_mortality`; the device has
141
+ no scold mechanic at all, so ignoring one cannot cost a mistake) and
142
+ the CHEESEBURGER (`petcare._junk`; that is overfeeding, named in the
143
+ manual as not-a-mistake). Both keep their own penalties in tuipet's
144
+ own currencies -- obedience and weight.
145
+ FILTH books nothing either, and never did: `_open_scold` raises only
146
+ `scold_window`, never `discipline_call`, so the timeout cannot reach
147
+ it. Measured 2026-07-31: 4.2 game-days pegged at poop 4 with the
148
+ calls answered books ZERO.
149
+
131
150
  ⭐`reason` NAMES THE SLIP (bug report 2026-07-31, Joel: "mon is getting
132
- a care mistake after 4 poops, not 1... correct?"). It is not the poop
133
- -- filth books NO mistake, by the LINES_SPEC §5 / Pen20 ruling above
134
- `_open_scold`, and measured: 4.2 game-days pegged at poop 4 with the
135
- other calls answered books ZERO. But he could not know that, because a
136
- care mistake was SILENT: the counter moved on the card and nothing ever
137
- said which of the four calls went unanswered -- for a Mega, where five
138
- of them turn lethal. The app reads this on the tick edge and flashes
139
- it (an unheard verdict is a silent failure)."""
151
+ a care mistake after 4 poops, not 1... correct?"). A care mistake was
152
+ SILENT: the counter moved on the card and nothing ever said which call
153
+ went unanswered -- on a Mega, where five turn lethal. The app reads
154
+ this on the tick edge and flashes it."""
140
155
  self.care_mistakes += 1
141
156
  self.mistake_reason = reason
142
157
  self.mistake_day += 1 # MistakeIncMissedDayChange
@@ -676,23 +691,28 @@ class BodyMixin:
676
691
  self._obed_t -= _lapse
677
692
  self._set_obedience(self.obedience + OBEDIENCE_LAPSE_DEC * -1 # noqa: F405
678
693
  + OBEDIENCE_FILTH_SCALE * self.poop) # noqa: F405
679
- # THE TANTRUM (canon restoration B, 2026-07-23 -- adapted
680
- # checkDisciplineCall): an awake pet AT HOME acts up about once
681
- # per 5400 game-min (~90 REAL minutes of play -- the label used to
682
- # read "90 game-min", the P0b mislabel); SCOLD inside the window
683
- # pays obedience +25, IGNORING it past the window costs a care
684
- # mistake and -5 (canon: ignored calls cost). Never on the road,
685
- # never asleep.
694
+ # THE TANTRUM: an awake pet AT HOME acts up about once per 5400
695
+ # game-min (~90 REAL minutes of play); SCOLD inside the window pays
696
+ # obedience +25, IGNORING it past the window costs obedience -5.
697
+ # Never on the road, never asleep.
698
+ #
699
+ # ⭐IT IS NOT A CARE MISTAKE (2026-08-01, Joel: "not scolding an acting
700
+ # out mon is canonically a care mistake?" -> "canon is bandai"). THE
701
+ # BANDAI DEVICE RECORD IS THE AUTHORITY, and it is unambiguous: a care
702
+ # mistake is a MISSED CALL, and the device has exactly three calls --
703
+ # hunger empty, strength empty, and tired/wants-sleep (the lights).
704
+ # The manual carries no praise, no scold, no acting-up mechanic at all,
705
+ # so ignoring one cannot cost a mistake there. The line that stood
706
+ # here booked one anyway under a citation it never had.
707
+ # The TANTRUM ITSELF stays: it is tuipet's own system, so it pays in
708
+ # tuipet's own currency (obedience), and it no longer touches the
709
+ # Bandai-defined counter that gates evolution and kills at 20.
686
710
  if (not self.asleep and not getattr(self, "away", False)
687
711
  and self.stage not in ("Egg", "Fresh")):
688
712
  if self.discipline_call:
689
713
  if self.world_seconds > getattr(self, "scold_window", 0.0):
690
714
  self.discipline_call = False
691
715
  self.scold_window = 0.0
692
- # through the front door: the bare += here skipped the
693
- # mood sting + the birthday mistake_day tally every
694
- # other mistake pays (incMistake; audit 2026-07-25)
695
- self._inc_mistake("acting up, not scolded")
696
716
  self._set_obedience(self.obedience - 5)
697
717
  else:
698
718
  # canon checkDisciplineCall: a check every DisciplineCallMin
@@ -798,12 +798,15 @@ class CareMixin:
798
798
  return "...it was DELICIOUS. And fatal."
799
799
 
800
800
  def _junk(self):
801
+ # ⭐NOT A CARE MISTAKE (2026-08-01, Joel: "canonize all care mistakes").
802
+ # THE BANDAI DEVICE RECORD IS THE AUTHORITY and it is explicit on this
803
+ # one: a care mistake is a MISSED CALL, and OVERFEEDING is called out
804
+ # by name as something that is NOT one. The burger is junk food -- it
805
+ # fills the belly and it makes the pet fat, which is the whole penalty.
806
+ # It has no business touching the counter that gates evolution and
807
+ # kills at 20.
801
808
  self.hunger = FULL_HUNGER
802
809
  self._set_weight(self.weight + 4)
803
- # the real mistake pipeline: the bare counter bumped care_mistakes
804
- # without the mood sting or mistake_day, so the burger slip was
805
- # invisible to the birthday judgment
806
- self._inc_mistake("that cheeseburger")
807
810
  return "Delicious. Regrettable."
808
811
 
809
812
  def _premium_meat(self):
@@ -75,7 +75,7 @@ _AUTHORED = {
75
75
  "vegetable": ("Vegetable", "f:3", 150, "Feed", "hunger +1 · weight -1", "crunchy diet fare"),
76
76
  "tuna": ("Tuna", "f:14", 400, "Feed", "hunger +2 · energy +1", "a hearty catch"),
77
77
  "cake": ("Cake", "f:6", 300, "Feed", "hunger +1 · energy +2 · weight +2", "a celebration slice"),
78
- "cheese_burger": ("Cheese burger", "f:57", 50, "Feed", "fills belly · weight +4 · a care mistake", "greasy, regrettable"),
78
+ "cheese_burger": ("Cheese burger", "f:57", 50, "Feed", "fills the belly · weight +4", "greasy, regrettable"),
79
79
  "giga_meal": ("Giga Meal", "f:28", 800, "Feed", "fills belly · energy +4 · weight +6", "a feast fit for a Mega"),
80
80
  "steak": ("Steak", "f:8", 2000, "Feed", "fills belly · 12h satiety", "the premium table"),
81
81
  "poison_mushroom": ("Poison Mushroom", "f:13", 200, "Feed", "DO NOT FEED", "it does look delicious"),
@@ -249,7 +249,9 @@ _TOUCHES = {
249
249
  "cupcake": ("hunger", "energy"),
250
250
  "cookie": ("hunger", "energy"),
251
251
  "candy": ("hunger", "energy"),
252
- "cheese_burger": ("hunger", "weight", "care_mistakes"),
252
+ # (care_mistakes dropped 2026-08-01, "canonize all care mistakes": the
253
+ # Bandai record names OVERFEEDING as explicitly NOT a care mistake)
254
+ "cheese_burger": ("hunger", "weight"),
253
255
  "giga_meal": ("hunger", "energy", "weight"),
254
256
  "steak": ("hunger", "full_until"),
255
257
  "poison_mushroom": ("dead",), # _die(): the one lethal entry
@@ -198,6 +198,21 @@ def adventure_line(pet):
198
198
  return f"Quest {count}[dim]▸ {_frontier_name(pet, 16 - len(count))}[/]"
199
199
 
200
200
 
201
+ def festival_line():
202
+ """TODAY's festival, named -- or None on an ordinary day.
203
+
204
+ ⭐Bug report 2026-08-01 (Joel): "whyyyy is there a sun pixel sprite stuck
205
+ on the lcd screen?" It was the Crest of Courage, the Odaiba Memorial Day
206
+ decoration (arenafx.HOLIDAY_DECOR) -- a prop that quietly appears in the
207
+ arena's corner on four dates a year. The festival was named NOWHERE on
208
+ the home screen, so the only thing a player could conclude was that a
209
+ pixel had got stuck. A prop with no label is a glitch; a prop with a
210
+ label is a holiday. (The road card has always named it -- statusbox.road
211
+ -- and that is the only place it was ever said.)"""
212
+ from . import tournament
213
+ return tournament.holiday()
214
+
215
+
201
216
  def home_lines(pet):
202
217
  from . import lines as _lines # DMX level: exp vs canon thresholds
203
218
  T = theme
@@ -206,9 +221,11 @@ def home_lines(pet):
206
221
  age = age_compact(pet.age_seconds)
207
222
  xm = f" [b {T.ACCENT}]X[/]" if pet.x_antibody != "None" else ""
208
223
  lvl = _lines._pet_level(pet)
224
+ fest = festival_line()
209
225
  return [
210
226
  f"[b]{pet.name[:22]}[/]{xm}",
211
227
  f"[dim]{pet.stage}{(' · ' + pet.attribute) if pet.attribute else ''}[/]",
228
+ ] + ([f"[{T.COIN}]★ {fest[:24]}[/]"] if fest else []) + [
212
229
  DIV,
213
230
  f"Hunger {hearts(pet.hunger)}",
214
231
  f"Effort {hearts(pet.strength)}",
@@ -252,9 +269,14 @@ def home_lines(pet):
252
269
 
253
270
  def egg_lines(pet):
254
271
  mins, secs = divmod(int(pet.age_seconds), 60)
272
+ # the festival prop draws over an EGG's arena too (arenafx._effect_overlay
273
+ # blits it before the `pet.num == -1` return), so the egg card names the
274
+ # day for the same reason the home card does -- 12 rows, room to spare
275
+ fest = festival_line()
255
276
  return [
256
277
  "[b]Digitama[/] [dim]· egg[/]",
257
278
  DIV,
279
+ ] + ([f"[{theme.COIN}]★ {fest[:24]}[/]", ""] if fest else []) + [
258
280
  "[dim]a new life is warming[/]",
259
281
  "",
260
282
  "Destined to hatch",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tuipet
3
- Version: 0.5.330
3
+ Version: 0.5.332
4
4
  Summary: A terminal virtual pet (Digimon V-Pet style) rendered with halfblock sprites, built on data from the real devices.
5
5
  Author-email: Joel Taylor <joeltaylor734@gmail.com>
6
6
  License-Expression: MIT
@@ -48,15 +48,20 @@ def test_the_tantrum_never_fires_on_the_road_or_asleep(monkeypatch):
48
48
  assert not road.discipline_call
49
49
 
50
50
 
51
- def test_an_ignored_tantrum_costs(monkeypatch):
51
+ def test_an_ignored_tantrum_costs_manners_not_a_care_mistake(monkeypatch):
52
+ """⭐2026-08-01, Joel: "canonize all care mistakes". The BANDAI device
53
+ record defines a care mistake as a MISSED CALL and the device makes three
54
+ -- hunger, strength, tired/sleep. It has no scold mechanic at all, so
55
+ ignoring a tantrum cannot be one. The tantrum is TUIPET'S OWN system, so
56
+ it keeps paying in tuipet's own currency: obedience."""
52
57
  p = _pet(discipline_call=True)
53
58
  p.scold_window = p.world_seconds - 1.0 # the window has passed
54
59
  monkeypatch.setattr(petbody.random, "random", lambda: 0.99)
55
60
  m0, o0 = p.care_mistakes, p.obedience
56
61
  p.tick(1.0)
57
- assert not p.discipline_call
58
- assert p.care_mistakes == m0 + 1 # canon: ignored calls cost
59
- assert p.obedience == o0 - 5
62
+ assert not p.discipline_call # the window closed
63
+ assert p.obedience == o0 - 5 # manners, yes
64
+ assert p.care_mistakes == m0 # the counter, NO
60
65
 
61
66
 
62
67
  def test_scold_answers_the_call_and_wrong_scold_lands_nothing():
@@ -359,15 +364,14 @@ def test_a_new_pet_is_not_born_disobedient():
359
364
  assert p.manners_refusal("feed") is False
360
365
 
361
366
 
362
- def test_an_ignored_tantrum_pays_the_full_mistake(monkeypatch):
363
- """The ignored-call path bumped the bare counter, skipping incMistake --
364
- whose one LIVE side effect is the birthday mistake_day tally (the mood
365
- sting is an inert citation; _set_mood is a no-op). Every other mistake
366
- pays the tally; this one didn't (claims audit 2026-07-25)."""
367
+ def test_an_ignored_tantrum_touches_neither_counter(monkeypatch):
368
+ """It used to route through incMistake, which pays BOTH the care-mistake
369
+ counter and the birthday mistake_day tally. Canonized 2026-08-01: the
370
+ device has no scold mechanic, so an ignored tantrum feeds neither."""
367
371
  p = _pet(discipline_call=True)
368
372
  p.scold_window = p.world_seconds - 1.0
369
373
  monkeypatch.setattr(petbody.random, "random", lambda: 0.99)
370
374
  d0, m0 = p.mistake_day, p.care_mistakes
371
375
  p.tick(1.0)
372
- assert p.care_mistakes == m0 + 1
373
- assert p.mistake_day == d0 + 1 # the birthday tally
376
+ assert p.care_mistakes == m0
377
+ assert p.mistake_day == d0 # nor the birthday tally
@@ -147,11 +147,16 @@ def test_filth_never_books_a_care_mistake():
147
147
  f"filth booked {p.care_mistakes} care mistakes -- it must book none")
148
148
 
149
149
 
150
- def test_every_care_mistake_names_itself():
151
- """The real defect behind that report: a care mistake was SILENT. The
152
- counter moved on the card, the mood took its sting, and nothing said WHICH
153
- call was missed -- on a Mega, where the fifth slip turns lethal. Every
154
- source stamps a reason, and each fits the 40-cell HUD line."""
150
+ def test_a_care_mistake_is_a_missed_call_and_nothing_else():
151
+ """⭐THE THREE CALLS (2026-08-01, Joel: "canonize all care mistakes").
152
+ The BANDAI device record defines a care mistake as a MISSED CALL, and the
153
+ device makes exactly three: hunger empty, strength empty, tired/wants
154
+ sleep. It also names what is NOT one -- overfeeding, injury, waking a
155
+ sleeper. Two impostors were cut on that ruling: the ignored TANTRUM (the
156
+ device has no scold mechanic at all) and the CHEESEBURGER (overfeeding).
157
+ ⛔THIS PIN IS A FENCE: a fourth `_inc_mistake` caller fails it.
158
+
159
+ Each source also NAMES itself, and each fits the 40-cell HUD line."""
155
160
  import inspect
156
161
  import os
157
162
  import re
@@ -164,7 +169,10 @@ def test_every_care_mistake_names_itself():
164
169
  from tuipet.pet import Pet
165
170
  src = inspect.getsource(petbody) + inspect.getsource(petcare)
166
171
  calls = re.findall(r"_inc_mistake\((.*?)\)", src)
167
- assert len(calls) >= 5, calls
172
+ reasons = [a.strip('"') for a in calls if not a.startswith("self")]
173
+ assert sorted(reasons) == sorted([
174
+ "left hungry too long", "empty effort gauge", "the lights left on",
175
+ ]), f"the three calls, and only the three -- got {reasons}"
168
176
  for arg in calls:
169
177
  if arg.startswith("self"): # the definition's own signature
170
178
  continue
@@ -194,3 +202,78 @@ def test_the_first_slip_of_a_session_still_flashes():
194
202
  assert src.index("cm0 = self.pet.care_mistakes") < src.index("self.pet.tick(1.0)")
195
203
  assert src.index("self.pet.tick(1.0)") < src.index("if p.care_mistakes > cm0")
196
204
  assert not re.search(r"_cm_seen\s*=", src) # no lazy latch, ever again
205
+
206
+
207
+ def test_a_lit_night_is_the_dominant_mistake_source():
208
+ """Diagnosed 2026-07-31 (Joel: "ok so what's actually causing my care
209
+ mistakes then"). His cloud save carried lights=True; measured on his own
210
+ numbers, one game-day costs FIVE lights mistakes and one ignored tantrum,
211
+ against ONE with the lights off. Canon: the first lit mistake lands 60
212
+ game-min in, then every 120 (LIGHTS_MISTAKE_POSTPONE = -60). The number
213
+ is canon and stays -- this pins the SHAPE so the constants block's old
214
+ "one mistake/night" claim can never quietly come back."""
215
+ import os
216
+ import random
217
+ import tempfile
218
+ os.environ.setdefault("TUIPET_SAVE_DIR", tempfile.mkdtemp())
219
+ from tuipet.pet import Pet
220
+
221
+ def day(lights):
222
+ random.seed(12)
223
+ p = Pet(num=399, name="Omni", stage="Mega", attribute="Vaccine",
224
+ obedience=111)
225
+ p.hunger, p.strength = 4, 4
226
+ p.sleep_limit, p.world_seconds = 840.0, 12607.0
227
+ p.max_energy = 38
228
+ p._set_energy(26)
229
+ p.lights = lights
230
+ seen = []
231
+ real = type(p)._inc_mistake
232
+ type(p)._inc_mistake = lambda s, reason="": (seen.append(reason),
233
+ real(s, reason))[1]
234
+ try:
235
+ for _ in range(1440):
236
+ p.tick(1.0)
237
+ finally:
238
+ type(p)._inc_mistake = real
239
+ return seen
240
+
241
+ lit = day(True)
242
+ dark = day(False)
243
+ assert lit.count("the lights left on") >= 4, lit
244
+ assert "the lights left on" not in dark, dark
245
+ assert len(lit) > len(dark), (lit, dark)
246
+
247
+
248
+ def test_the_two_cut_impostors_keep_their_own_penalties():
249
+ """Canonizing the counter must not quietly delete the SYSTEMS. An ignored
250
+ tantrum still costs obedience (tuipet's own currency), and the burger
251
+ still packs on weight -- they just no longer touch the Bandai-defined
252
+ counter that gates evolution and kills at 20."""
253
+ import os
254
+ import tempfile
255
+ os.environ.setdefault("TUIPET_SAVE_DIR", tempfile.mkdtemp())
256
+ from tuipet.pet import Pet
257
+
258
+ # the ignored tantrum: obedience yes, care mistake no
259
+ p = Pet(num=399, name="Omni", stage="Mega", attribute="Vaccine",
260
+ obedience=111)
261
+ p.hunger, p.strength = 4, 4
262
+ p.world_seconds = 12607.0
263
+ p.discipline_call = True
264
+ p.scold_window = p.world_seconds - 1.0 # already expired
265
+ obed0, cm0 = p.obedience, p.care_mistakes
266
+ p._tick_mortality(1.0)
267
+ assert p.discipline_call is False # the window closed
268
+ assert p.obedience == obed0 - 5 # it still stings manners
269
+ assert p.care_mistakes == cm0 # ...and NOT the counter
270
+
271
+ # the cheeseburger: weight yes, care mistake no
272
+ q = Pet(num=399, name="Omni", stage="Mega", attribute="Vaccine")
273
+ q.world_seconds = 600.0
274
+ q.hunger = 1
275
+ q.add_item("cheese_burger")
276
+ w0, cm0 = q.weight, q.care_mistakes
277
+ q.use_item("cheese_burger")
278
+ assert q.weight > w0 and q.hunger == 4 # fat and fed
279
+ assert q.care_mistakes == cm0 # overfeeding is not a slip
@@ -37,8 +37,13 @@ def test_food_dials_match_their_blurbs():
37
37
 
38
38
  def test_the_big_meals_and_the_mushroom():
39
39
  p = _pet()
40
+ w0 = p.weight
40
41
  _use(p, "cheese_burger")
41
- assert p.hunger == FULL_HUNGER and p.care_mistakes == 1 # "a care mistake"
42
+ # "fills the belly · weight +4" -- and NOT a care mistake since the
43
+ # canonization (2026-08-01): the Bandai record names overfeeding as
44
+ # explicitly not one, so the blurb no longer promises it either
45
+ assert p.hunger == FULL_HUNGER and p.weight - w0 == 4
46
+ assert p.care_mistakes == 0
42
47
  p = _pet()
43
48
  w0, e0 = p.weight, p.energy
44
49
  _use(p, "giga_meal")
@@ -192,3 +192,41 @@ def test_battle_card_wraps_the_result_note():
192
192
  statusbox.battle(app)
193
193
  _fits(app.stats_w, "battle")
194
194
  _no_words_lost(app.stats_w, "battle", _M.hud_note)
195
+
196
+
197
+ def test_the_home_and_egg_cards_name_the_festival():
198
+ """⭐Bug report 2026-08-01 (Joel): "whyyyy is there a sun pixel sprite
199
+ stuck on the lcd screen?" It was the Crest of Courage — the Odaiba
200
+ Memorial Day decoration (arenafx.HOLIDAY_DECOR), a prop that appears in
201
+ the arena corner on four dates a year and was named NOWHERE on the home
202
+ screen. A prop with no label reads as a stuck pixel.
203
+
204
+ ⛔THIS ALSO FENCES THE ROW BUDGET. The festival banner is the 16th row of
205
+ a 16-row card, so a future 17th row would break the home card on four days
206
+ a year and pass every other day. Forcing a festival here turns that
207
+ landmine into an always-on gate."""
208
+ import datetime
209
+ from tuipet import statusbox, tournament
210
+ from tuipet.arenafx import HOLIDAY_DECOR
211
+ fake = _FakeStats()
212
+ p = _pet()
213
+ e = Pet(num=-1, name="", stage="Egg")
214
+ e.world_seconds = 600.0
215
+ for name, (m, d) in {"Odaiba Memorial Day": (8, 1),
216
+ "Christmas Festival": (12, 25),
217
+ "Halloween Festival": (10, 31),
218
+ "New Year Festival": (1, 1)}.items():
219
+ tournament._today = (lambda mm, dd: (lambda: datetime.date(2026, mm, dd)))(m, d)
220
+ assert name in HOLIDAY_DECOR, f"{name} draws a prop with no decor entry"
221
+ for lines, tag in ((statusbox.home_lines(p), "home"),
222
+ (statusbox.egg_lines(e), "egg")):
223
+ fake.txt = "\n".join(lines)
224
+ _fits(fake, f"{tag} on {name}")
225
+ assert name in fake.txt, f"{tag} card never names {name}"
226
+ # ...and an ordinary day carries no banner at all
227
+ tournament._today = lambda: datetime.date(2026, 6, 17)
228
+ fake.txt = "\n".join(statusbox.home_lines(p))
229
+ _fits(fake, "home, ordinary day")
230
+ # (not a bare "★" check -- the Battle row wears ★{trophies} every day)
231
+ for name in ("Odaiba", "Christmas", "Halloween", "New Year"):
232
+ assert name not in fake.txt
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes