tuipet 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. tuipet-0.1.0/LICENSE +30 -0
  2. tuipet-0.1.0/PKG-INFO +235 -0
  3. tuipet-0.1.0/README.md +210 -0
  4. tuipet-0.1.0/pyproject.toml +45 -0
  5. tuipet-0.1.0/setup.cfg +4 -0
  6. tuipet-0.1.0/src/tuipet/__init__.py +0 -0
  7. tuipet-0.1.0/src/tuipet/adventure.py +230 -0
  8. tuipet-0.1.0/src/tuipet/adventurescreen.py +92 -0
  9. tuipet-0.1.0/src/tuipet/anim.py +112 -0
  10. tuipet-0.1.0/src/tuipet/app.py +1464 -0
  11. tuipet-0.1.0/src/tuipet/battle.py +220 -0
  12. tuipet-0.1.0/src/tuipet/battlefx.py +193 -0
  13. tuipet-0.1.0/src/tuipet/battlescreen.py +341 -0
  14. tuipet-0.1.0/src/tuipet/data/backgrounds.json.gz +0 -0
  15. tuipet-0.1.0/src/tuipet/data/battle_overlays.json +1 -0
  16. tuipet-0.1.0/src/tuipet/data/careEffect.csv +2 -0
  17. tuipet-0.1.0/src/tuipet/data/digicoreMenuConfig.csv +85 -0
  18. tuipet-0.1.0/src/tuipet/data/digimon.csv +1575 -0
  19. tuipet-0.1.0/src/tuipet/data/dropRate.csv +43 -0
  20. tuipet-0.1.0/src/tuipet/data/effects.json.gz +0 -0
  21. tuipet-0.1.0/src/tuipet/data/eggUnlock.csv +48 -0
  22. tuipet-0.1.0/src/tuipet/data/eggs.json.gz +0 -0
  23. tuipet-0.1.0/src/tuipet/data/elementAffinity.csv +12 -0
  24. tuipet-0.1.0/src/tuipet/data/enemies.csv +463 -0
  25. tuipet-0.1.0/src/tuipet/data/evolutions.csv +1401 -0
  26. tuipet-0.1.0/src/tuipet/data/fieldAffinity.csv +11 -0
  27. tuipet-0.1.0/src/tuipet/data/foods.csv +60 -0
  28. tuipet-0.1.0/src/tuipet/data/habitats.csv +17 -0
  29. tuipet-0.1.0/src/tuipet/data/icons.json.gz +0 -0
  30. tuipet-0.1.0/src/tuipet/data/items.csv +85 -0
  31. tuipet-0.1.0/src/tuipet/data/lootTable.csv +42 -0
  32. tuipet-0.1.0/src/tuipet/data/maps.csv +7 -0
  33. tuipet-0.1.0/src/tuipet/data/orbs.json.gz +0 -0
  34. tuipet-0.1.0/src/tuipet/data/shopConsumable.csv +23 -0
  35. tuipet-0.1.0/src/tuipet/data/sounds/alarm.wav +0 -0
  36. tuipet-0.1.0/src/tuipet/data/sounds/angry.wav +0 -0
  37. tuipet-0.1.0/src/tuipet/data/sounds/attack.wav +0 -0
  38. tuipet-0.1.0/src/tuipet/data/sounds/attackHit.wav +0 -0
  39. tuipet-0.1.0/src/tuipet/data/sounds/battle.wav +0 -0
  40. tuipet-0.1.0/src/tuipet/data/sounds/click.wav +0 -0
  41. tuipet-0.1.0/src/tuipet/data/sounds/compatible.wav +0 -0
  42. tuipet-0.1.0/src/tuipet/data/sounds/death.wav +0 -0
  43. tuipet-0.1.0/src/tuipet/data/sounds/eat.wav +0 -0
  44. tuipet-0.1.0/src/tuipet/data/sounds/error.wav +0 -0
  45. tuipet-0.1.0/src/tuipet/data/sounds/evolve.wav +0 -0
  46. tuipet-0.1.0/src/tuipet/data/sounds/happy.wav +0 -0
  47. tuipet-0.1.0/src/tuipet/data/sounds/hatch.wav +0 -0
  48. tuipet-0.1.0/src/tuipet/data/sounds/jogress.wav +0 -0
  49. tuipet-0.1.0/src/tuipet/data/sounds/largePoop.wav +0 -0
  50. tuipet-0.1.0/src/tuipet/data/sounds/lastBite.wav +0 -0
  51. tuipet-0.1.0/src/tuipet/data/sounds/lose.wav +0 -0
  52. tuipet-0.1.0/src/tuipet/data/sounds/menu.wav +0 -0
  53. tuipet-0.1.0/src/tuipet/data/sounds/mischief.wav +0 -0
  54. tuipet-0.1.0/src/tuipet/data/sounds/poop.wav +0 -0
  55. tuipet-0.1.0/src/tuipet/data/sounds/rain.wav +0 -0
  56. tuipet-0.1.0/src/tuipet/data/sounds/refuse.wav +0 -0
  57. tuipet-0.1.0/src/tuipet/data/sounds/select.wav +0 -0
  58. tuipet-0.1.0/src/tuipet/data/sounds/smallPoop.wav +0 -0
  59. tuipet-0.1.0/src/tuipet/data/sounds/startBattle.wav +0 -0
  60. tuipet-0.1.0/src/tuipet/data/sounds/strongAttack.wav +0 -0
  61. tuipet-0.1.0/src/tuipet/data/sounds/strongHit.wav +0 -0
  62. tuipet-0.1.0/src/tuipet/data/sounds/thunder.wav +0 -0
  63. tuipet-0.1.0/src/tuipet/data/sounds/thunder2.wav +0 -0
  64. tuipet-0.1.0/src/tuipet/data/sounds/thunder3.wav +0 -0
  65. tuipet-0.1.0/src/tuipet/data/sounds/wash.wav +0 -0
  66. tuipet-0.1.0/src/tuipet/data/sounds/win.wav +0 -0
  67. tuipet-0.1.0/src/tuipet/data/sounds/wind.wav +0 -0
  68. tuipet-0.1.0/src/tuipet/data/sprites.json.gz +0 -0
  69. tuipet-0.1.0/src/tuipet/data/tournies.csv +326 -0
  70. tuipet-0.1.0/src/tuipet/data/towns.csv +27 -0
  71. tuipet-0.1.0/src/tuipet/data/zones.csv +27 -0
  72. tuipet-0.1.0/src/tuipet/data.py +1072 -0
  73. tuipet-0.1.0/src/tuipet/deathscreen.py +44 -0
  74. tuipet-0.1.0/src/tuipet/digicorescreen.py +111 -0
  75. tuipet-0.1.0/src/tuipet/dnascreen.py +293 -0
  76. tuipet-0.1.0/src/tuipet/egg.py +249 -0
  77. tuipet-0.1.0/src/tuipet/eggselectscreen.py +154 -0
  78. tuipet-0.1.0/src/tuipet/evolution.py +354 -0
  79. tuipet-0.1.0/src/tuipet/habitatscreen.py +78 -0
  80. tuipet-0.1.0/src/tuipet/jogress.py +104 -0
  81. tuipet-0.1.0/src/tuipet/jogressscreen.py +123 -0
  82. tuipet-0.1.0/src/tuipet/lobbyscreen.py +541 -0
  83. tuipet-0.1.0/src/tuipet/loot.py +23 -0
  84. tuipet-0.1.0/src/tuipet/menu.py +59 -0
  85. tuipet-0.1.0/src/tuipet/net.py +119 -0
  86. tuipet-0.1.0/src/tuipet/persistence.py +269 -0
  87. tuipet-0.1.0/src/tuipet/pet.py +1871 -0
  88. tuipet-0.1.0/src/tuipet/placeholder.py +22 -0
  89. tuipet-0.1.0/src/tuipet/render.py +173 -0
  90. tuipet-0.1.0/src/tuipet/shop.py +31 -0
  91. tuipet-0.1.0/src/tuipet/shopscreen.py +206 -0
  92. tuipet-0.1.0/src/tuipet/sound.py +48 -0
  93. tuipet-0.1.0/src/tuipet/theme.py +165 -0
  94. tuipet-0.1.0/src/tuipet/themescreen.py +61 -0
  95. tuipet-0.1.0/src/tuipet/titlescreen.py +93 -0
  96. tuipet-0.1.0/src/tuipet/tournament.py +125 -0
  97. tuipet-0.1.0/src/tuipet/tournamentscreen.py +127 -0
  98. tuipet-0.1.0/src/tuipet/training.py +347 -0
  99. tuipet-0.1.0/src/tuipet/transportscreen.py +77 -0
  100. tuipet-0.1.0/src/tuipet/weather.py +110 -0
  101. tuipet-0.1.0/src/tuipet.egg-info/PKG-INFO +235 -0
  102. tuipet-0.1.0/src/tuipet.egg-info/SOURCES.txt +123 -0
  103. tuipet-0.1.0/src/tuipet.egg-info/dependency_links.txt +1 -0
  104. tuipet-0.1.0/src/tuipet.egg-info/entry_points.txt +2 -0
  105. tuipet-0.1.0/src/tuipet.egg-info/requires.txt +3 -0
  106. tuipet-0.1.0/src/tuipet.egg-info/top_level.txt +1 -0
  107. tuipet-0.1.0/tests/test_announce.py +89 -0
  108. tuipet-0.1.0/tests/test_battle.py +133 -0
  109. tuipet-0.1.0/tests/test_data.py +74 -0
  110. tuipet-0.1.0/tests/test_death.py +85 -0
  111. tuipet-0.1.0/tests/test_egg_unlock.py +182 -0
  112. tuipet-0.1.0/tests/test_evolution.py +116 -0
  113. tuipet-0.1.0/tests/test_fx.py +77 -0
  114. tuipet-0.1.0/tests/test_hud.py +43 -0
  115. tuipet-0.1.0/tests/test_item_effects.py +59 -0
  116. tuipet-0.1.0/tests/test_item_heal.py +29 -0
  117. tuipet-0.1.0/tests/test_msg_strip.py +43 -0
  118. tuipet-0.1.0/tests/test_performance.py +37 -0
  119. tuipet-0.1.0/tests/test_persistence.py +129 -0
  120. tuipet-0.1.0/tests/test_pet_effect.py +117 -0
  121. tuipet-0.1.0/tests/test_robustness.py +134 -0
  122. tuipet-0.1.0/tests/test_theme.py +73 -0
  123. tuipet-0.1.0/tests/test_tournament.py +143 -0
  124. tuipet-0.1.0/tests/test_training.py +96 -0
  125. tuipet-0.1.0/tests/test_ui_stats.py +128 -0
tuipet-0.1.0/LICENSE ADDED
@@ -0,0 +1,30 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Joel Taylor
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ ----
24
+
25
+ NOTE: This license covers the tuipet source code only. tuipet does not include
26
+ any game assets. The game data and sprites it reads at runtime are derived from
27
+ DVPet (https://theundersigned.itch.io/dvpet), a Digimon fan game, and from the
28
+ Digimon franchise (© Bandai). Those assets are the property of their respective
29
+ owners and are not licensed here. See the README for how to regenerate them from
30
+ your own copy of DVPet.
tuipet-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,235 @@
1
+ Metadata-Version: 2.4
2
+ Name: tuipet
3
+ Version: 0.1.0
4
+ Summary: A terminal virtual pet (Digimon V-Pet style) rendered with halfblock sprites, built on data extracted from DVPet.
5
+ Author-email: Joel Taylor <joeltaylor734@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/joeltco/tuipet
8
+ Project-URL: Repository, https://github.com/joeltco/tuipet
9
+ Project-URL: Issues, https://github.com/joeltco/tuipet/issues
10
+ Keywords: terminal,tui,virtual-pet,digimon,vpet,textual,game
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: End Users/Desktop
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Games/Entertainment
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Operating System :: Android
18
+ Requires-Python: >=3.10
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: textual>=0.50
22
+ Requires-Dist: rich>=13
23
+ Requires-Dist: websockets>=12
24
+ Dynamic: license-file
25
+
26
+ # tuipet
27
+
28
+ A terminal virtual pet — Digimon V-Pet style — rendered with halfblock Unicode
29
+ sprites and animated in the terminal. Built on data mined from the free
30
+ [DVPet](https://theundersigned.itch.io/dvpet) fan game.
31
+
32
+ ## What's inside
33
+
34
+ - **1511 creatures**, 11 animation frames each, extracted from the game's sprite
35
+ atlases as 1-bit bitmaps (`src/tuipet/data/sprites.json.gz`, ~330 KB).
36
+ - Real **evolution graph** and **food** tables parsed from the game CSVs.
37
+ - A `rich`/`textual` UI: an LCD screen with an animated pet, stat bars, and care
38
+ actions (feed, train, play, clean, heal, sleep), plus time-based evolution.
39
+
40
+ ## Install
41
+
42
+ **One command** (Termux on Android, or any Linux):
43
+
44
+ ```sh
45
+ curl -fsSL https://raw.githubusercontent.com/joeltco/tuipet/main/install.sh | bash
46
+ tuipet
47
+ ```
48
+
49
+ That installs Python + tuipet with every sprite, sound, and CSV bundled — nothing
50
+ else to download. On **Termux** it also pulls `termux-api`; to actually hear the
51
+ LCD beeps you additionally need the **Termux:API** app from F-Droid/Play (the
52
+ package alone isn't enough). Over SSH, sound stays silent on purpose.
53
+
54
+ Prefer pip directly:
55
+
56
+ ```sh
57
+ pip install git+https://github.com/joeltco/tuipet
58
+ ```
59
+
60
+ ## Run from source
61
+
62
+ ```sh
63
+ python -m venv .venv && . .venv/bin/activate
64
+ pip install -e .
65
+ tuipet # or: PYTHONPATH=src python -m tuipet.app
66
+ ```
67
+
68
+ Start from an **egg** — one of 11 real DVPet egg designs (from armorEggs.png) — it wobbles, cracks, and hatches into a random Fresh baby.
69
+
70
+ Keys: **f** feed · **t** train (minigame) · **p** play · **c** clean · **h** heal ·
71
+ **s** sleep · **n** new egg · **q** quit.
72
+
73
+ **Training** is a timing minigame: strike **SPACE** when the marker hits the green
74
+ target zone. Three reps raise effort and the pet's attribute power (Vaccine/Data/Virus).
75
+
76
+ ## Asset pipeline
77
+
78
+ Raw game files live under `_extract/` (gitignored). Re-extract with:
79
+
80
+ ```sh
81
+ python tools/extract_sprites.py # rebuilds data/sprites.json.gz
82
+ python tools/preview.py Agumon # preview a creature as halfblocks
83
+ python tools/allframes.py Agumon # see all 11 frames
84
+ ```
85
+
86
+ The atlases are 672×672, an 11×11 grid: each **column** is one creature, each of
87
+ the 11 **rows** is an animation frame. Creatures are authored at 3× scale on a
88
+ cyan LCD background; the extractor box-downsamples 3× (recovering native ~20px
89
+ sprites and dropping the dev-build column labels) and thresholds to 1-bit.
90
+
91
+ ## Sprite frame convention
92
+
93
+ Each creature's 11-frame strip uses a fixed pose order, reverse-engineered from
94
+ the game's own `View/SpriteAnim.class` (cfr-decompiled). Animations in
95
+ `src/tuipet/data.py::ROLES` mirror the game's `cheer`/`jeer`/`eat`/`idleSleep`/etc.
96
+
97
+ | idx | pose | used by |
98
+ |-----|-------------------------------|----------------------------------|
99
+ | 0 | idle / walk A | idle bob (0,1), walk |
100
+ | 1 | idle / walk B | idle bob, play, tantrum |
101
+ | 2 | sleep / rest A | `idleSleep` (2,3), wake stretch |
102
+ | 3 | sleep / rest B | `idleSleep` |
103
+ | 4 | angry / refuse / attack | jeer, refuse head-shake, battle |
104
+ | 5 | happy / cheer-up | cheer (good), play |
105
+ | 6 | sad / unhappy | jeer (bad), tantrum, attack |
106
+ | 7 | eat-closed (chew) / cheer-down| eat (8↔7), heal, cheer |
107
+ | 8 | eat-open (mouth) / neutral | eat, heal, default expression |
108
+ | 9 | tired / sick / disliked / old | fatigue idle, geriatric, dislike |
109
+ | 10 | exhausted (very tired) | deep-fatigue idle |
110
+
111
+ `refuse` is drawn as a left/right mirror flip on alternating frames (head-shake).
112
+
113
+ ## Evolution (care-quality based)
114
+
115
+ Evolution is a faithful port of DVPet's `Model/Evolution.checkEvolReq` + selection.
116
+ Each form's row in `digimon.csv` defines gates (comparison `Key` + `Value`):
117
+ care **mistakes**, **overfeed**, **sleep disturbances**, **sickness**, **injuries**,
118
+ **weight** class (Over/Healthy/Under, ±50% of base), **mood**, **attribute power**
119
+ (Vaccine/Data/Virus), **battles/wins**, plus a probability roll.
120
+
121
+ When a stage's minimum time elapses, the engine gathers the current form's
122
+ evolution targets, keeps those whose every gate passes, then picks the one with
123
+ the highest **fulfilledReq** score (priority + per-gate rates), breaking ties by
124
+ the smallest **deviation** (closest stat match) — exactly as the game does.
125
+
126
+ Per-stage counters (mistakes, overfeed, disturbances, sickness, injuries) **reset
127
+ on evolution**; **attribute power, battles and wins carry over** for life — matching
128
+ DVPet's `resetEvolVar`.
129
+
130
+ Verified against the game data and online guides:
131
+
132
+ | Care during Koromon (In-Training) | Evolves to |
133
+ |-----------------------------------|------------|
134
+ | good care + Vaccine training | Agumon |
135
+ | good care + Data training | Gabumon |
136
+ | good care + Virus training | Goburimon |
137
+ | neglect (many care mistakes) | Chuumon |
138
+
139
+ Note: most Champion+ forms in DVPet's data are **battle-gated** (e.g. Greymon needs
140
+ 10+ battles), so without the battle system a well-raised pet reaches the classic
141
+ "default" Champions (Numemon / Bakemon / Sukamon) — authentic V-Pet behaviour.
142
+ Battles are the next system to unlock the full tree.
143
+
144
+ ## Battles
145
+
146
+ Press **b** to battle a stage-appropriate enemy (from `enemies.csv`, 462 foes).
147
+ Combat uses the canonical Digimon **attribute triangle — Vaccine > Virus > Data >
148
+ Vaccine**. Each round you pick an attack type (**1** Vaccine / **2** Data / **3**
149
+ Virus); effective power is your trained power in that attribute, boosted when it
150
+ beats the foe's shown type and dampened when it loses to it. Higher effective
151
+ power lands a hit; first to 0 HP loses. **ESC** flees.
152
+
153
+ Both **training** and **strategy** matter — vs a typical foe a well-trained pet
154
+ that counters the enemy's type wins ~85%, naive play far less. Wins grant bits and
155
+ mood; **battles/wins are tracked and feed evolution**: most Champion+ forms
156
+ (Greymon, etc.) require battle experience plus multi-attribute training, so battling
157
+ unlocks the rest of the evolution tree that care alone cannot reach.
158
+
159
+ ## Sprite extraction
160
+
161
+ All DVPet sprite sheets are RGBA with transparent backgrounds. The extractor masks on "opaque AND not the cyan LCD colour", recovering every creature (~1525), the eggs, and the food/item icons (from the food/item sheets' alpha channel). A few genuinely-unfinished cells are detected and shown as a generic blob.
162
+
163
+ ## Adventure
164
+
165
+ Press **a** to travel the Digital World — 5 maps, 26 zones parsed from
166
+ `zones.csv` + `enemies.csv` (faithful to DVPet's `WorldMap`). Your pet walks a
167
+ zone's progress bar; **wild encounters** launch battles, a **town** midway
168
+ restores adventure life, and a **zone boss** gates the way to the next zone.
169
+ Clear every zone in a map to unlock the next region. Bosses are the canonical
170
+ villains (Devimon, Etemon, the Dark Masters…). Travel tires the pet (energy +
171
+ weight, like exercise), wins grant bits, and every fight counts toward the
172
+ battle/win requirements that drive evolution. Progress persists on the pet.
173
+
174
+ Keys in adventure: **SPACE** go/stop · **ESC** leave.
175
+
176
+ ## Shop
177
+
178
+ Press **o** to open the shop and spend the bits you earn from battles and
179
+ adventures. Inventory comes from `shopConsumable.csv` (21 foods/items resolved
180
+ from `foods.csv` + `items.csv`), each with its real DVPet effects: food (hunger,
181
+ weight, mood), medicine that **cures** sickness, items that **heal** injuries,
182
+ discipline books (obedience), and **attribute chips** that add Vaccine/Data/Virus
183
+ power. Browse with **↑↓**, **ENTER** to buy, **TAB** to switch to your **bag** and
184
+ use what you own, **ESC** to leave. Items you buy persist in the pet's inventory.
185
+
186
+ ## Saving
187
+
188
+ Your pet persists automatically — there's nothing to do. tuipet writes to
189
+ `~/.local/share/tuipet/save.json` every 10 seconds and on quit, and loads it on
190
+ startup, so your Digimon (stats, evolution, bits, inventory, adventure progress)
191
+ survives between runs. While the game is closed the pet ages gently: reopening
192
+ applies a bounded "while you were away" decay to hunger/energy/mood (capped at
193
+ 12h, and never evolves or dies offline), with a "Welcome back!" greeting. Press
194
+ **n** to abandon the current pet and start a fresh egg (this overwrites the save).
195
+
196
+ ## Jogress (DNA fusion)
197
+
198
+ Press **j** at Champion or above to fuse your pet with a partner and DNA-evolve
199
+ into a special Ultimate. The partner's attribute decides the result via DVPet's
200
+ `attributeJogress` matrix (e.g. a Data pet + Virus partner → Virus fusion), and
201
+ the fusion targets come from the pet's evolution graph (`SpecialEvolution=Jogress`,
202
+ 112 of them). Jogress bypasses the normal care requirements — the partner supplies
203
+ the "DNA" — so it's a deliberate fusion you trigger. Pick a partner with **↑↓**,
204
+ **ENTER** to fuse, **ESC** to cancel. Normal (non-special) evolution is unchanged;
205
+ jogress/fusion forms no longer appear in ordinary evolution.
206
+
207
+ ## Tournaments
208
+
209
+ Press **u** at Champion or above to enter a **single-elimination cup** — three
210
+ matches (Quarterfinal → Semifinal → Final, the final a boss-tier opponent),
211
+ faithful to DVPet's 8-entrant bracket. Each match reuses the battle engine, so
212
+ cup fights count toward your battle/win record too. Win all three to be crowned
213
+ **Champion**: a trophy (tracked and shown in your stats) plus bits scaled by stage
214
+ (Rookie 60 → Mega 400). Lose a match and you're eliminated. **SPACE** to fight,
215
+ **ESC** to leave.
216
+
217
+ ## Setup (game data not included)
218
+
219
+ tuipet's code is here, but the **game data is not distributed** — the sprites and
220
+ CSVs are derived from [DVPet](https://theundersigned.itch.io/dvpet) (a Digimon fan
221
+ game, © Bandai for the franchise) and belong to their creators. To play, regenerate
222
+ them from your own free copy of DVPet:
223
+
224
+ ```sh
225
+ # 1. download DVPet from itch.io and locate DVPet.jar inside the extracted zip
226
+ # 2. regenerate assets:
227
+ tools/setup_assets.sh /path/to/DVPet.jar
228
+ # 3. install + run:
229
+ python -m venv .venv && . .venv/bin/activate
230
+ pip install -e .
231
+ tuipet
232
+ ```
233
+
234
+ `setup_assets.sh` unpacks the jar, copies the needed CSVs, and runs the sprite
235
+ extractor (`tools/extract_sprites.py`) to build `src/tuipet/data/sprites.json.gz`.
tuipet-0.1.0/README.md ADDED
@@ -0,0 +1,210 @@
1
+ # tuipet
2
+
3
+ A terminal virtual pet — Digimon V-Pet style — rendered with halfblock Unicode
4
+ sprites and animated in the terminal. Built on data mined from the free
5
+ [DVPet](https://theundersigned.itch.io/dvpet) fan game.
6
+
7
+ ## What's inside
8
+
9
+ - **1511 creatures**, 11 animation frames each, extracted from the game's sprite
10
+ atlases as 1-bit bitmaps (`src/tuipet/data/sprites.json.gz`, ~330 KB).
11
+ - Real **evolution graph** and **food** tables parsed from the game CSVs.
12
+ - A `rich`/`textual` UI: an LCD screen with an animated pet, stat bars, and care
13
+ actions (feed, train, play, clean, heal, sleep), plus time-based evolution.
14
+
15
+ ## Install
16
+
17
+ **One command** (Termux on Android, or any Linux):
18
+
19
+ ```sh
20
+ curl -fsSL https://raw.githubusercontent.com/joeltco/tuipet/main/install.sh | bash
21
+ tuipet
22
+ ```
23
+
24
+ That installs Python + tuipet with every sprite, sound, and CSV bundled — nothing
25
+ else to download. On **Termux** it also pulls `termux-api`; to actually hear the
26
+ LCD beeps you additionally need the **Termux:API** app from F-Droid/Play (the
27
+ package alone isn't enough). Over SSH, sound stays silent on purpose.
28
+
29
+ Prefer pip directly:
30
+
31
+ ```sh
32
+ pip install git+https://github.com/joeltco/tuipet
33
+ ```
34
+
35
+ ## Run from source
36
+
37
+ ```sh
38
+ python -m venv .venv && . .venv/bin/activate
39
+ pip install -e .
40
+ tuipet # or: PYTHONPATH=src python -m tuipet.app
41
+ ```
42
+
43
+ Start from an **egg** — one of 11 real DVPet egg designs (from armorEggs.png) — it wobbles, cracks, and hatches into a random Fresh baby.
44
+
45
+ Keys: **f** feed · **t** train (minigame) · **p** play · **c** clean · **h** heal ·
46
+ **s** sleep · **n** new egg · **q** quit.
47
+
48
+ **Training** is a timing minigame: strike **SPACE** when the marker hits the green
49
+ target zone. Three reps raise effort and the pet's attribute power (Vaccine/Data/Virus).
50
+
51
+ ## Asset pipeline
52
+
53
+ Raw game files live under `_extract/` (gitignored). Re-extract with:
54
+
55
+ ```sh
56
+ python tools/extract_sprites.py # rebuilds data/sprites.json.gz
57
+ python tools/preview.py Agumon # preview a creature as halfblocks
58
+ python tools/allframes.py Agumon # see all 11 frames
59
+ ```
60
+
61
+ The atlases are 672×672, an 11×11 grid: each **column** is one creature, each of
62
+ the 11 **rows** is an animation frame. Creatures are authored at 3× scale on a
63
+ cyan LCD background; the extractor box-downsamples 3× (recovering native ~20px
64
+ sprites and dropping the dev-build column labels) and thresholds to 1-bit.
65
+
66
+ ## Sprite frame convention
67
+
68
+ Each creature's 11-frame strip uses a fixed pose order, reverse-engineered from
69
+ the game's own `View/SpriteAnim.class` (cfr-decompiled). Animations in
70
+ `src/tuipet/data.py::ROLES` mirror the game's `cheer`/`jeer`/`eat`/`idleSleep`/etc.
71
+
72
+ | idx | pose | used by |
73
+ |-----|-------------------------------|----------------------------------|
74
+ | 0 | idle / walk A | idle bob (0,1), walk |
75
+ | 1 | idle / walk B | idle bob, play, tantrum |
76
+ | 2 | sleep / rest A | `idleSleep` (2,3), wake stretch |
77
+ | 3 | sleep / rest B | `idleSleep` |
78
+ | 4 | angry / refuse / attack | jeer, refuse head-shake, battle |
79
+ | 5 | happy / cheer-up | cheer (good), play |
80
+ | 6 | sad / unhappy | jeer (bad), tantrum, attack |
81
+ | 7 | eat-closed (chew) / cheer-down| eat (8↔7), heal, cheer |
82
+ | 8 | eat-open (mouth) / neutral | eat, heal, default expression |
83
+ | 9 | tired / sick / disliked / old | fatigue idle, geriatric, dislike |
84
+ | 10 | exhausted (very tired) | deep-fatigue idle |
85
+
86
+ `refuse` is drawn as a left/right mirror flip on alternating frames (head-shake).
87
+
88
+ ## Evolution (care-quality based)
89
+
90
+ Evolution is a faithful port of DVPet's `Model/Evolution.checkEvolReq` + selection.
91
+ Each form's row in `digimon.csv` defines gates (comparison `Key` + `Value`):
92
+ care **mistakes**, **overfeed**, **sleep disturbances**, **sickness**, **injuries**,
93
+ **weight** class (Over/Healthy/Under, ±50% of base), **mood**, **attribute power**
94
+ (Vaccine/Data/Virus), **battles/wins**, plus a probability roll.
95
+
96
+ When a stage's minimum time elapses, the engine gathers the current form's
97
+ evolution targets, keeps those whose every gate passes, then picks the one with
98
+ the highest **fulfilledReq** score (priority + per-gate rates), breaking ties by
99
+ the smallest **deviation** (closest stat match) — exactly as the game does.
100
+
101
+ Per-stage counters (mistakes, overfeed, disturbances, sickness, injuries) **reset
102
+ on evolution**; **attribute power, battles and wins carry over** for life — matching
103
+ DVPet's `resetEvolVar`.
104
+
105
+ Verified against the game data and online guides:
106
+
107
+ | Care during Koromon (In-Training) | Evolves to |
108
+ |-----------------------------------|------------|
109
+ | good care + Vaccine training | Agumon |
110
+ | good care + Data training | Gabumon |
111
+ | good care + Virus training | Goburimon |
112
+ | neglect (many care mistakes) | Chuumon |
113
+
114
+ Note: most Champion+ forms in DVPet's data are **battle-gated** (e.g. Greymon needs
115
+ 10+ battles), so without the battle system a well-raised pet reaches the classic
116
+ "default" Champions (Numemon / Bakemon / Sukamon) — authentic V-Pet behaviour.
117
+ Battles are the next system to unlock the full tree.
118
+
119
+ ## Battles
120
+
121
+ Press **b** to battle a stage-appropriate enemy (from `enemies.csv`, 462 foes).
122
+ Combat uses the canonical Digimon **attribute triangle — Vaccine > Virus > Data >
123
+ Vaccine**. Each round you pick an attack type (**1** Vaccine / **2** Data / **3**
124
+ Virus); effective power is your trained power in that attribute, boosted when it
125
+ beats the foe's shown type and dampened when it loses to it. Higher effective
126
+ power lands a hit; first to 0 HP loses. **ESC** flees.
127
+
128
+ Both **training** and **strategy** matter — vs a typical foe a well-trained pet
129
+ that counters the enemy's type wins ~85%, naive play far less. Wins grant bits and
130
+ mood; **battles/wins are tracked and feed evolution**: most Champion+ forms
131
+ (Greymon, etc.) require battle experience plus multi-attribute training, so battling
132
+ unlocks the rest of the evolution tree that care alone cannot reach.
133
+
134
+ ## Sprite extraction
135
+
136
+ All DVPet sprite sheets are RGBA with transparent backgrounds. The extractor masks on "opaque AND not the cyan LCD colour", recovering every creature (~1525), the eggs, and the food/item icons (from the food/item sheets' alpha channel). A few genuinely-unfinished cells are detected and shown as a generic blob.
137
+
138
+ ## Adventure
139
+
140
+ Press **a** to travel the Digital World — 5 maps, 26 zones parsed from
141
+ `zones.csv` + `enemies.csv` (faithful to DVPet's `WorldMap`). Your pet walks a
142
+ zone's progress bar; **wild encounters** launch battles, a **town** midway
143
+ restores adventure life, and a **zone boss** gates the way to the next zone.
144
+ Clear every zone in a map to unlock the next region. Bosses are the canonical
145
+ villains (Devimon, Etemon, the Dark Masters…). Travel tires the pet (energy +
146
+ weight, like exercise), wins grant bits, and every fight counts toward the
147
+ battle/win requirements that drive evolution. Progress persists on the pet.
148
+
149
+ Keys in adventure: **SPACE** go/stop · **ESC** leave.
150
+
151
+ ## Shop
152
+
153
+ Press **o** to open the shop and spend the bits you earn from battles and
154
+ adventures. Inventory comes from `shopConsumable.csv` (21 foods/items resolved
155
+ from `foods.csv` + `items.csv`), each with its real DVPet effects: food (hunger,
156
+ weight, mood), medicine that **cures** sickness, items that **heal** injuries,
157
+ discipline books (obedience), and **attribute chips** that add Vaccine/Data/Virus
158
+ power. Browse with **↑↓**, **ENTER** to buy, **TAB** to switch to your **bag** and
159
+ use what you own, **ESC** to leave. Items you buy persist in the pet's inventory.
160
+
161
+ ## Saving
162
+
163
+ Your pet persists automatically — there's nothing to do. tuipet writes to
164
+ `~/.local/share/tuipet/save.json` every 10 seconds and on quit, and loads it on
165
+ startup, so your Digimon (stats, evolution, bits, inventory, adventure progress)
166
+ survives between runs. While the game is closed the pet ages gently: reopening
167
+ applies a bounded "while you were away" decay to hunger/energy/mood (capped at
168
+ 12h, and never evolves or dies offline), with a "Welcome back!" greeting. Press
169
+ **n** to abandon the current pet and start a fresh egg (this overwrites the save).
170
+
171
+ ## Jogress (DNA fusion)
172
+
173
+ Press **j** at Champion or above to fuse your pet with a partner and DNA-evolve
174
+ into a special Ultimate. The partner's attribute decides the result via DVPet's
175
+ `attributeJogress` matrix (e.g. a Data pet + Virus partner → Virus fusion), and
176
+ the fusion targets come from the pet's evolution graph (`SpecialEvolution=Jogress`,
177
+ 112 of them). Jogress bypasses the normal care requirements — the partner supplies
178
+ the "DNA" — so it's a deliberate fusion you trigger. Pick a partner with **↑↓**,
179
+ **ENTER** to fuse, **ESC** to cancel. Normal (non-special) evolution is unchanged;
180
+ jogress/fusion forms no longer appear in ordinary evolution.
181
+
182
+ ## Tournaments
183
+
184
+ Press **u** at Champion or above to enter a **single-elimination cup** — three
185
+ matches (Quarterfinal → Semifinal → Final, the final a boss-tier opponent),
186
+ faithful to DVPet's 8-entrant bracket. Each match reuses the battle engine, so
187
+ cup fights count toward your battle/win record too. Win all three to be crowned
188
+ **Champion**: a trophy (tracked and shown in your stats) plus bits scaled by stage
189
+ (Rookie 60 → Mega 400). Lose a match and you're eliminated. **SPACE** to fight,
190
+ **ESC** to leave.
191
+
192
+ ## Setup (game data not included)
193
+
194
+ tuipet's code is here, but the **game data is not distributed** — the sprites and
195
+ CSVs are derived from [DVPet](https://theundersigned.itch.io/dvpet) (a Digimon fan
196
+ game, © Bandai for the franchise) and belong to their creators. To play, regenerate
197
+ them from your own free copy of DVPet:
198
+
199
+ ```sh
200
+ # 1. download DVPet from itch.io and locate DVPet.jar inside the extracted zip
201
+ # 2. regenerate assets:
202
+ tools/setup_assets.sh /path/to/DVPet.jar
203
+ # 3. install + run:
204
+ python -m venv .venv && . .venv/bin/activate
205
+ pip install -e .
206
+ tuipet
207
+ ```
208
+
209
+ `setup_assets.sh` unpacks the jar, copies the needed CSVs, and runs the sprite
210
+ extractor (`tools/extract_sprites.py`) to build `src/tuipet/data/sprites.json.gz`.
@@ -0,0 +1,45 @@
1
+ [project]
2
+ name = "tuipet"
3
+ version = "0.1.0"
4
+ description = "A terminal virtual pet (Digimon V-Pet style) rendered with halfblock sprites, built on data extracted from DVPet."
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ license = "MIT"
8
+ license-files = ["LICENSE"]
9
+ authors = [{ name = "Joel Taylor", email = "joeltaylor734@gmail.com" }]
10
+ keywords = ["terminal", "tui", "virtual-pet", "digimon", "vpet", "textual", "game"]
11
+ classifiers = [
12
+ "Development Status :: 4 - Beta",
13
+ "Environment :: Console",
14
+ "Intended Audience :: End Users/Desktop",
15
+ "Programming Language :: Python :: 3",
16
+ "Topic :: Games/Entertainment",
17
+ "Operating System :: POSIX :: Linux",
18
+ "Operating System :: Android",
19
+ ]
20
+ dependencies = ["textual>=0.50", "rich>=13", "websockets>=12"]
21
+
22
+ [project.urls]
23
+ Homepage = "https://github.com/joeltco/tuipet"
24
+ Repository = "https://github.com/joeltco/tuipet"
25
+ Issues = "https://github.com/joeltco/tuipet/issues"
26
+
27
+ [project.scripts]
28
+ tuipet = "tuipet.app:main"
29
+
30
+ [build-system]
31
+ requires = ["setuptools"]
32
+ build-backend = "setuptools.build_meta"
33
+
34
+ [tool.setuptools]
35
+ package-dir = {"" = "src"}
36
+
37
+ [tool.setuptools.packages.find]
38
+ where = ["src"]
39
+
40
+ [tool.setuptools.package-data]
41
+ tuipet = ["data/*.gz", "data/*.csv", "data/*.json", "data/sounds/*.wav"]
42
+
43
+ [tool.pytest.ini_options]
44
+ pythonpath = ["src"]
45
+ testpaths = ["tests"]
tuipet-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes