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.
- tuipet-0.1.0/LICENSE +30 -0
- tuipet-0.1.0/PKG-INFO +235 -0
- tuipet-0.1.0/README.md +210 -0
- tuipet-0.1.0/pyproject.toml +45 -0
- tuipet-0.1.0/setup.cfg +4 -0
- tuipet-0.1.0/src/tuipet/__init__.py +0 -0
- tuipet-0.1.0/src/tuipet/adventure.py +230 -0
- tuipet-0.1.0/src/tuipet/adventurescreen.py +92 -0
- tuipet-0.1.0/src/tuipet/anim.py +112 -0
- tuipet-0.1.0/src/tuipet/app.py +1464 -0
- tuipet-0.1.0/src/tuipet/battle.py +220 -0
- tuipet-0.1.0/src/tuipet/battlefx.py +193 -0
- tuipet-0.1.0/src/tuipet/battlescreen.py +341 -0
- tuipet-0.1.0/src/tuipet/data/backgrounds.json.gz +0 -0
- tuipet-0.1.0/src/tuipet/data/battle_overlays.json +1 -0
- tuipet-0.1.0/src/tuipet/data/careEffect.csv +2 -0
- tuipet-0.1.0/src/tuipet/data/digicoreMenuConfig.csv +85 -0
- tuipet-0.1.0/src/tuipet/data/digimon.csv +1575 -0
- tuipet-0.1.0/src/tuipet/data/dropRate.csv +43 -0
- tuipet-0.1.0/src/tuipet/data/effects.json.gz +0 -0
- tuipet-0.1.0/src/tuipet/data/eggUnlock.csv +48 -0
- tuipet-0.1.0/src/tuipet/data/eggs.json.gz +0 -0
- tuipet-0.1.0/src/tuipet/data/elementAffinity.csv +12 -0
- tuipet-0.1.0/src/tuipet/data/enemies.csv +463 -0
- tuipet-0.1.0/src/tuipet/data/evolutions.csv +1401 -0
- tuipet-0.1.0/src/tuipet/data/fieldAffinity.csv +11 -0
- tuipet-0.1.0/src/tuipet/data/foods.csv +60 -0
- tuipet-0.1.0/src/tuipet/data/habitats.csv +17 -0
- tuipet-0.1.0/src/tuipet/data/icons.json.gz +0 -0
- tuipet-0.1.0/src/tuipet/data/items.csv +85 -0
- tuipet-0.1.0/src/tuipet/data/lootTable.csv +42 -0
- tuipet-0.1.0/src/tuipet/data/maps.csv +7 -0
- tuipet-0.1.0/src/tuipet/data/orbs.json.gz +0 -0
- tuipet-0.1.0/src/tuipet/data/shopConsumable.csv +23 -0
- tuipet-0.1.0/src/tuipet/data/sounds/alarm.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/angry.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/attack.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/attackHit.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/battle.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/click.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/compatible.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/death.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/eat.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/error.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/evolve.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/happy.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/hatch.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/jogress.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/largePoop.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/lastBite.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/lose.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/menu.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/mischief.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/poop.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/rain.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/refuse.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/select.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/smallPoop.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/startBattle.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/strongAttack.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/strongHit.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/thunder.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/thunder2.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/thunder3.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/wash.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/win.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sounds/wind.wav +0 -0
- tuipet-0.1.0/src/tuipet/data/sprites.json.gz +0 -0
- tuipet-0.1.0/src/tuipet/data/tournies.csv +326 -0
- tuipet-0.1.0/src/tuipet/data/towns.csv +27 -0
- tuipet-0.1.0/src/tuipet/data/zones.csv +27 -0
- tuipet-0.1.0/src/tuipet/data.py +1072 -0
- tuipet-0.1.0/src/tuipet/deathscreen.py +44 -0
- tuipet-0.1.0/src/tuipet/digicorescreen.py +111 -0
- tuipet-0.1.0/src/tuipet/dnascreen.py +293 -0
- tuipet-0.1.0/src/tuipet/egg.py +249 -0
- tuipet-0.1.0/src/tuipet/eggselectscreen.py +154 -0
- tuipet-0.1.0/src/tuipet/evolution.py +354 -0
- tuipet-0.1.0/src/tuipet/habitatscreen.py +78 -0
- tuipet-0.1.0/src/tuipet/jogress.py +104 -0
- tuipet-0.1.0/src/tuipet/jogressscreen.py +123 -0
- tuipet-0.1.0/src/tuipet/lobbyscreen.py +541 -0
- tuipet-0.1.0/src/tuipet/loot.py +23 -0
- tuipet-0.1.0/src/tuipet/menu.py +59 -0
- tuipet-0.1.0/src/tuipet/net.py +119 -0
- tuipet-0.1.0/src/tuipet/persistence.py +269 -0
- tuipet-0.1.0/src/tuipet/pet.py +1871 -0
- tuipet-0.1.0/src/tuipet/placeholder.py +22 -0
- tuipet-0.1.0/src/tuipet/render.py +173 -0
- tuipet-0.1.0/src/tuipet/shop.py +31 -0
- tuipet-0.1.0/src/tuipet/shopscreen.py +206 -0
- tuipet-0.1.0/src/tuipet/sound.py +48 -0
- tuipet-0.1.0/src/tuipet/theme.py +165 -0
- tuipet-0.1.0/src/tuipet/themescreen.py +61 -0
- tuipet-0.1.0/src/tuipet/titlescreen.py +93 -0
- tuipet-0.1.0/src/tuipet/tournament.py +125 -0
- tuipet-0.1.0/src/tuipet/tournamentscreen.py +127 -0
- tuipet-0.1.0/src/tuipet/training.py +347 -0
- tuipet-0.1.0/src/tuipet/transportscreen.py +77 -0
- tuipet-0.1.0/src/tuipet/weather.py +110 -0
- tuipet-0.1.0/src/tuipet.egg-info/PKG-INFO +235 -0
- tuipet-0.1.0/src/tuipet.egg-info/SOURCES.txt +123 -0
- tuipet-0.1.0/src/tuipet.egg-info/dependency_links.txt +1 -0
- tuipet-0.1.0/src/tuipet.egg-info/entry_points.txt +2 -0
- tuipet-0.1.0/src/tuipet.egg-info/requires.txt +3 -0
- tuipet-0.1.0/src/tuipet.egg-info/top_level.txt +1 -0
- tuipet-0.1.0/tests/test_announce.py +89 -0
- tuipet-0.1.0/tests/test_battle.py +133 -0
- tuipet-0.1.0/tests/test_data.py +74 -0
- tuipet-0.1.0/tests/test_death.py +85 -0
- tuipet-0.1.0/tests/test_egg_unlock.py +182 -0
- tuipet-0.1.0/tests/test_evolution.py +116 -0
- tuipet-0.1.0/tests/test_fx.py +77 -0
- tuipet-0.1.0/tests/test_hud.py +43 -0
- tuipet-0.1.0/tests/test_item_effects.py +59 -0
- tuipet-0.1.0/tests/test_item_heal.py +29 -0
- tuipet-0.1.0/tests/test_msg_strip.py +43 -0
- tuipet-0.1.0/tests/test_performance.py +37 -0
- tuipet-0.1.0/tests/test_persistence.py +129 -0
- tuipet-0.1.0/tests/test_pet_effect.py +117 -0
- tuipet-0.1.0/tests/test_robustness.py +134 -0
- tuipet-0.1.0/tests/test_theme.py +73 -0
- tuipet-0.1.0/tests/test_tournament.py +143 -0
- tuipet-0.1.0/tests/test_training.py +96 -0
- 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
|
File without changes
|