tuipet 0.2.415__tar.gz → 0.2.417__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.2.415/src/tuipet.egg-info → tuipet-0.2.417}/PKG-INFO +1 -1
- {tuipet-0.2.415 → tuipet-0.2.417}/pyproject.toml +1 -1
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/app.py +4 -4
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/training.py +180 -173
- {tuipet-0.2.415 → tuipet-0.2.417/src/tuipet.egg-info}/PKG-INFO +1 -1
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_panel_smoke.py +2 -3
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_status_icons.py +2 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_training_facing.py +80 -42
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_training_strike.py +70 -146
- {tuipet-0.2.415 → tuipet-0.2.417}/LICENSE +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/README.md +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/setup.cfg +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/__init__.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/adventure.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/adventurescreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/anim.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/arena.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/assistscreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/battle.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/battlefx.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/battlescreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/bugscreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/cloudsync.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/attr_icons.json +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/backgrounds.json.gz +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/battle_overlays.json +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/careEffect.csv +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/digicoreMenuConfig.csv +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/digimon.csv +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/dropRate.csv +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/effects.json.gz +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/eggUnlock.csv +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/eggs.json.gz +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/elementAffinity.csv +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/enemies.csv +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/evolutions.csv +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/fieldAffinity.csv +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/foods.csv +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/habitats.csv +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/hp_dummies.json +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/icons.json.gz +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/items.csv +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/lines.csv +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/lootTable.csv +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/maps.csv +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/orbs.json.gz +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/shopConsumable.csv +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/alarm.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/angry.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/attack.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/attackHit.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/battle.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/cancel.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/champion.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/click.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/compatible.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/confirm.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/death.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/eat.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/error.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/evolve.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/happy.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/hatch.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/jogress.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/largePoop.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/lastBite.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/lose.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/menu.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/mischief.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/poop.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/refuse.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/reward.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/scroll.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/select.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/smallPoop.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/startBattle.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/strongAttack.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/strongHit.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/trainhit.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/wash.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/win.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sounds/wind.wav +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/sprites.json.gz +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/tournies.csv +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/towns.csv +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data/zones.csv +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/data.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/deathscreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/digicorescreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/dnascreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/egg.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/eggselectscreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/evolution.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/feedscreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/grid.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/habitatscreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/helpscreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/itemfx.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/jogress.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/jogressscreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/lines.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/lobbyscreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/loot.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/menu.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/net.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/optionsscreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/persistence.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/pet.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/placeholder.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/render.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/shop.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/shopscreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/sound.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/strikefx.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/theme.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/themescreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/titlescreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/tournament.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/tournamentscreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/townscreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/transportscreen.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/update.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/weather.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet/world.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet.egg-info/SOURCES.txt +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet.egg-info/dependency_links.txt +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet.egg-info/entry_points.txt +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet.egg-info/requires.txt +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/src/tuipet.egg-info/top_level.txt +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_adventure.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_adventure_math.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_adventure_scenery.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_album_dex.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_anim_canon.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_anim_timing.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_announce.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_audit_fixes.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_auto_care.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_battle.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_battle_math.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_bedtime.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_birthday.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_body_math.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_bugreport.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_care_asleep.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_care_bonus.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_completeness_sweep.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_data.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_dead_gate.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_death.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_device_lines.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_digicore.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_digimemory.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_discipline.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_divergence.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_dna_charge.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_effects_integrity.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_egg_economy.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_egg_unlock.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_egg_unlock_math.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_energy_system.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_evolution.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_evolution_math.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_evolution_system.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_feed.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_feeding_math.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_filth_system.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_fx.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_gift_birthday_math.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_habitat.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_habitat_math.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_help.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_hint_strips.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_hud.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_humulos_eggs.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_hunger.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_item_effects.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_item_heal.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_itemfx.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_jogress.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_jogress_math.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_line_curation.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_lines.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_lobby.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_lobby_admin.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_lobby_screens.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_medicine.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_menu_bounds.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_messages.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_mood_system.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_mortality_math.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_msg_strip.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_nav_quit.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_night_palette.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_obedience_system.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_options.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_performance.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_persistence.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_persistence_audit.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_pet_effect.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_poop_model.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_poop_placement.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_protocol_math.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_rank_system.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_refusal.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_refusal_math.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_robustness.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_save_integrity.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_scene_actors.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_screen_sweep.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_sfx_scroll.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_shop.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_shop_economy.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_shop_math.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_sickness_system.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_sleep.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_sleep_system.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_sleep_weather_math.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_sound.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_special_idles.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_stage_arrival.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_status_box.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_sync.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_theme.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_toilet.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_tournament.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_town.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_town_eggs.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_training.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_training_hp.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_training_math.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_training_system.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_ui_stats.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_update.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_verx.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_weight_system.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_whats_new.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_win_eggs.py +0 -0
- {tuipet-0.2.415 → tuipet-0.2.417}/tests/test_world.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tuipet
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.417
|
|
4
4
|
Summary: A terminal virtual pet (Digimon V-Pet style) rendered with halfblock sprites, built on data extracted from DVPet.
|
|
5
5
|
Author-email: Joel Taylor <joeltaylor734@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -250,10 +250,10 @@ class TuiPetApp(App):
|
|
|
250
250
|
"""
|
|
251
251
|
# the release-news line (title-screen msg box, first launch per build) --
|
|
252
252
|
# UPDATE THIS WITH EVERY RELEASE that ships something player-visible
|
|
253
|
-
WHATS_NEW = ("
|
|
254
|
-
"
|
|
255
|
-
"
|
|
256
|
-
"
|
|
253
|
+
WHATS_NEW = ("The Data drill is now the REAL DM20 versus training: YOU "
|
|
254
|
+
"fire high or low past the sparring partner's shield, 3 of 5 "
|
|
255
|
+
"rounds to pass -- the fan-made turret is gone, and the "
|
|
256
|
+
"manual's secret pattern chart works here too.")
|
|
257
257
|
|
|
258
258
|
BINDINGS = [
|
|
259
259
|
# battle + jogress are LOBBY-ONLY (Joel 2026-07-07: "battles and
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Attack_Contact -> Attack_Aftermath).
|
|
4
4
|
|
|
5
5
|
Every drill is fought against an on-screen OPPONENT that is present the whole time
|
|
6
|
-
-- the punching bag (HP / Vaccine / Virus) or the
|
|
6
|
+
-- the punching bag (HP / Vaccine / Virus) or the sparring partner (Data) -- and
|
|
7
7
|
the skill phase flows straight into the strike -> impact -> aftermath, exactly like
|
|
8
8
|
the hardware (no abstract gauge with the opponent conjured up only at the end):
|
|
9
9
|
|
|
@@ -12,9 +12,11 @@ the hardware (no abstract gauge with the opponent conjured up only at the end):
|
|
|
12
12
|
(drawHPTraining, first to 2 wins); builds Effort.
|
|
13
13
|
Vaccine — pet HIDDEN, bag on screen: mash the hit button (drawVaccinePre);
|
|
14
14
|
builds Vaccine power. Pet appears for the strike.
|
|
15
|
-
Data —
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
Data — the REAL DM20's versus training (canon rebuild 2026-07-13; DVPet's
|
|
16
|
+
turret duel here was pure fan invention -- Joel: "i dont think this
|
|
17
|
+
system is canon at all", and it isn't). Manual: "you choose to fire
|
|
18
|
+
a high shot or a low shot. If your shot gets past your partner's
|
|
19
|
+
shield, you succeed. You need to succeed 3 out of the 5 rounds."
|
|
18
20
|
Virus — pet HIDDEN, bag on screen: stop the sweeping power bar high
|
|
19
21
|
(drawVirusPre); builds Virus power.
|
|
20
22
|
|
|
@@ -35,7 +37,7 @@ from . import menu
|
|
|
35
37
|
# to the TARGET as the orb arrives -> fullscreen explosion -> break). Reuse the battle's
|
|
36
38
|
# pose ids + beat timings + column-bounds helper so the two stay in lockstep.
|
|
37
39
|
from .battlescreen import (IDLE, TURN, ATTACK, CHARGE, COLLAPSE, # noqa: F401
|
|
38
|
-
EXPLODE_FRAMES, EXPLODE_HOLD, FLINCH_T)
|
|
40
|
+
EXPLODE_FRAMES, EXPLODE_HOLD, FLINCH_T, FIRE_T)
|
|
39
41
|
|
|
40
42
|
# the full-screen spiky hit burst (attackHit/attackHitFlash), shared with the battle
|
|
41
43
|
# screen -- strobes outline<->filled to flash the LCD on impact (DVPet hitAnim).
|
|
@@ -53,14 +55,20 @@ VACCINE_WINDOW = 41 # drawVaccinePre = _interval*41 = 246 frames @60fp
|
|
|
53
55
|
VIRUS_BAR_MIN = 86 # VirusGameBarMin
|
|
54
56
|
VIRUS_MAX = 94 # DVPet maxBar (bar pixel width) -> the zone 86..94 is the top ~8%
|
|
55
57
|
VIRUS_SPEEDS = (4.8, 6.0, 8.0) # per-tick fill = DVPet +4 per VirusGameBarSpeed{5,4,3} frames (48/60/80 px/s / 10Hz)
|
|
56
|
-
# Data is
|
|
57
|
-
#
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
#
|
|
58
|
+
# Data is the REAL DM20's VERSUS training (humulos.com/digimon/dm20/manual): "you choose
|
|
59
|
+
# to fire a high shot or a low shot. If your shot gets past your partner's shield, you
|
|
60
|
+
# succeed. You need to succeed 3 out of the 5 rounds for training to be successful."
|
|
61
|
+
# The partner's shield follows the manual's REPEATING PATTERN -- "pressing the buttons
|
|
62
|
+
# according to the chart below will let you win tag training every time" -- the six
|
|
63
|
+
# winning-button rows ported VERBATIM (5 rounds each, sessions cycle 1..6 and repeat,
|
|
64
|
+
# indexed by the pet's stage_trainings so the cheat chart works like the hardware).
|
|
65
|
+
# The manual never says which of A/B fires high; tuipet reads A=HIGH (adaptation, the
|
|
66
|
+
# one unspecified bit) -- the shield therefore stands OPPOSITE each winning shot.
|
|
67
|
+
DATA_ROUNDS = 5 # rounds per session (manual: "3 out of the 5 rounds")
|
|
68
|
+
DATA_PASS = 3 # shots that must get past for a successful training
|
|
69
|
+
DATA_WIN_CHART = ("ABABB", "BBAAB", "BAABB", "ABBAA", "BABAB", "ABABA") # manual, verbatim
|
|
70
|
+
DATA_BLOCK_HOLD = 4 # beats the blocked tableau holds before the next round
|
|
71
|
+
# collision = the battle's exact beats: EXPLODE_FRAMES strobe (hitAnim) on a shot that gets past
|
|
64
72
|
HP_ROUNDS = 3 # DVPet _hpTrainingRounds
|
|
65
73
|
HP_ROUNDS_WON = 2 # DVPet _hpTrainingRoundsWon (first to 2 wins the drill)
|
|
66
74
|
HP_TRAIN_DIFFICULTY = 11 # DVPet _hpTrainDifficultyChange: rank = fullHealthPoints // 11
|
|
@@ -100,6 +108,17 @@ def _fit_cell(sprite):
|
|
|
100
108
|
from .render import blit as _blit # one blit for app/training/strikefx (refactor 2026-07-05)
|
|
101
109
|
|
|
102
110
|
|
|
111
|
+
def _pop(overlay, ink):
|
|
112
|
+
"""Layer `ink` on TOP of the staged overlay: punch a 1px clearance halo
|
|
113
|
+
out of everything already under it, then add the ink. On a 1-bit LCD
|
|
114
|
+
adjacency IS fusion -- the halo is how a foreground actor (a held shield,
|
|
115
|
+
a flying pellet) reads as its own object over a busy stage. Occlusion,
|
|
116
|
+
not art: no sprite's pixels change, the back actor is just behind."""
|
|
117
|
+
guard = {(x + dx, y + dy) for x, y in ink
|
|
118
|
+
for dx in (-1, 0, 1) for dy in (-1, 0, 1)}
|
|
119
|
+
return [pt for pt in overlay if pt not in guard] + list(ink)
|
|
120
|
+
|
|
121
|
+
|
|
103
122
|
def _crop(pf):
|
|
104
123
|
"""Crop a creature frame to its real body (the sheets are mostly padding) so
|
|
105
124
|
the drills can place it on exact columns. Shared by vaccine/data/hp."""
|
|
@@ -126,7 +145,7 @@ _HP_ICON_KEYS = ("atk_vaccine", "atk_data", "atk_virus") # index == hp_target
|
|
|
126
145
|
GAMES = [
|
|
127
146
|
("hp", "HP Drill", "Effort", "stop the reel on the match — best of 3"),
|
|
128
147
|
("vaccine", "Vaccine", "Vaccine", "mash the bag — fast!"),
|
|
129
|
-
("data", "Data", "Data", "
|
|
148
|
+
("data", "Data", "Data", "fire past the shield — 3 of 5"),
|
|
130
149
|
("virus", "Virus", "Virus", f"stop the bar over {VIRUS_BAR_MIN}"),
|
|
131
150
|
]
|
|
132
151
|
|
|
@@ -151,25 +170,22 @@ class TrainingPanel:
|
|
|
151
170
|
self.timer = VACCINE_WINDOW
|
|
152
171
|
self.vaccine_target = VACCINE_HITS[1] # rank-based, set per drill start (below)
|
|
153
172
|
self.virus_speed = VIRUS_SPEEDS[1] # rank-based bar fill speed
|
|
154
|
-
self.data_telegraph = DATA_TELEGRAPH[1] # rank-based feint window
|
|
155
|
-
self.data_window = DATA_WINDOW[1] # rank-based reaction window
|
|
156
173
|
self.round_len = HP_ROUND_LEN[1]
|
|
157
174
|
self.round_t = self.round_len
|
|
158
175
|
self.rounds_won = 0
|
|
159
176
|
self.hp_target = 0 # hidden attribute the bag "is" (0/1/2)
|
|
160
177
|
self.hp_pick = 0 # the player's cursor over the 3 guess buttons
|
|
161
|
-
# data
|
|
162
|
-
self.
|
|
163
|
-
self.
|
|
164
|
-
self.
|
|
165
|
-
self.
|
|
166
|
-
self.
|
|
167
|
-
self.
|
|
168
|
-
self.
|
|
169
|
-
self.
|
|
170
|
-
self.
|
|
171
|
-
self.
|
|
172
|
-
self._impact_args = None # the staged _finish() call, fired when the flinch ends
|
|
178
|
+
# data versus-training state (real DM20 tag training)
|
|
179
|
+
self.tt_round = 0 # current round, 0..DATA_ROUNDS-1
|
|
180
|
+
self.tt_past = 0 # shots that got past the shield so far
|
|
181
|
+
self.tt_log = [] # per-round outcomes (True = past), for the strip pips
|
|
182
|
+
self.tt_shield = () # the partner's 5-lane chart row (True = shield HIGH)
|
|
183
|
+
self.tt_shield_up = False # this round's revealed shield lane (set on fire)
|
|
184
|
+
self.shot_up = False # the lane the player fired
|
|
185
|
+
self.blocked = False # this round's outcome
|
|
186
|
+
self.fired = False # a shot is playing out (the round's volley timeline runs)
|
|
187
|
+
self.tt_tl = [] # the round's beat timeline (fire_out/fire_in/hit|block)
|
|
188
|
+
self.tt_i = 0 # index into tt_tl
|
|
173
189
|
self._strike_pose = None # transient hit(6)/miss(9) pose during a drill
|
|
174
190
|
self._strike_t = 0
|
|
175
191
|
self.strike_tl = [] # the post-drill strike timeline (battle-style volley)
|
|
@@ -217,9 +233,13 @@ class TrainingPanel:
|
|
|
217
233
|
self.vaccine_target = self._vaccine_threshold()
|
|
218
234
|
self.flash = "MASH the bag!"
|
|
219
235
|
elif gk == "data":
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
236
|
+
# the partner's shield lanes for THIS session: the manual's repeating
|
|
237
|
+
# chart row, cycled by lifetime drills this stage (the printed cheat
|
|
238
|
+
# sequences work on tuipet exactly as on the hardware). The row lists
|
|
239
|
+
# WINNING shots (A=HIGH); the shield stands in the opposite lane.
|
|
240
|
+
row = DATA_WIN_CHART[self.pet.stage_trainings % len(DATA_WIN_CHART)]
|
|
241
|
+
self.tt_shield = tuple(c == "B" for c in row) # win LOW -> shield was HIGH
|
|
242
|
+
self.flash = f"round 1/{DATA_ROUNDS} — UP high · DOWN low"
|
|
223
243
|
else:
|
|
224
244
|
self.virus_speed = VIRUS_SPEEDS[self._attr_rank(self.pet.virus)]
|
|
225
245
|
self.flash = "stop the bar high!"
|
|
@@ -267,8 +287,8 @@ class TrainingPanel:
|
|
|
267
287
|
self._strong = hits >= 3
|
|
268
288
|
self.result = self.pet.apply_training(hits, power, attribute, game=game)
|
|
269
289
|
if game == "data":
|
|
270
|
-
# DATA
|
|
271
|
-
#
|
|
290
|
+
# DATA already played its five volleys IN the drill (every round is a
|
|
291
|
+
# full fire -> reveal -> impact beat) -- a sixth would be noise. Reveal.
|
|
272
292
|
self.phase = "done"
|
|
273
293
|
self.flash = self.result + " (SPACE)"
|
|
274
294
|
else:
|
|
@@ -330,35 +350,19 @@ class TrainingPanel:
|
|
|
330
350
|
1 if self.taps >= thr * 0.5 else 0) # a clear overshoot = strong, near-miss = partial
|
|
331
351
|
self._finish(hits, int(self.taps), "Vaccine", "vaccine")
|
|
332
352
|
elif gk == "data":
|
|
333
|
-
if self.fired:
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
self.flinch_t -= 1
|
|
347
|
-
if self.flinch_t == 0:
|
|
348
|
-
self._finish(*self._impact_args)
|
|
349
|
-
return
|
|
350
|
-
return
|
|
351
|
-
self.data_t += 1
|
|
352
|
-
if not self.locked: # telegraph: the cannon's barrel feints up/down
|
|
353
|
-
if self.data_t % DATA_BOB == 0:
|
|
354
|
-
self.feint_up = not self.feint_up
|
|
355
|
-
if self.data_t >= self.data_telegraph: # ...then it COMMITS high or low: the barrel
|
|
356
|
-
self.locked = True # locks and the orb appears at the muzzle to
|
|
357
|
-
self.tgt_up = random.choice((True, False)) # charge (you can still toggle the shield)
|
|
358
|
-
self.data_t = 0
|
|
359
|
-
self.flash = "block it — toggle the shield!"
|
|
360
|
-
elif self.data_t >= self.data_window: # charge window closes -> EVAL (DVPet onPreFinish)
|
|
361
|
-
self._data_resolve()
|
|
353
|
+
if not self.fired: # the PICK act waits on the player --
|
|
354
|
+
return # turn-based, like the HP reel's stop
|
|
355
|
+
if self.tt_i < len(self.tt_tl) - 1: # the round's volley marches, beat by beat
|
|
356
|
+
self.tt_i += 1
|
|
357
|
+
m = self.tt_tl[self.tt_i]["m"]
|
|
358
|
+
if m != self._last_sm: # one-shot sting at each beat edge
|
|
359
|
+
if m == "hit":
|
|
360
|
+
self.sfx = "attackHit" # DVPet hitAnim: it got PAST
|
|
361
|
+
elif m == "block":
|
|
362
|
+
self.sfx = "cancel" # dead on the shield
|
|
363
|
+
self._last_sm = m
|
|
364
|
+
else:
|
|
365
|
+
self._data_next_round()
|
|
362
366
|
else: # virus -- DVPet drawVirusPre: the bar FILLS then snaps back to 0 and loops;
|
|
363
367
|
self.pos += self.virus_speed # hit captures the level at that instant
|
|
364
368
|
if self.pos >= VIRUS_MAX:
|
|
@@ -400,28 +404,57 @@ class TrainingPanel:
|
|
|
400
404
|
if gk == "hp": # the reel spins itself: SPACE stops it on the match
|
|
401
405
|
if k in ("space", "enter"):
|
|
402
406
|
self._hp_resolve(self.hp_pick == self.hp_target)
|
|
403
|
-
elif gk == "data": #
|
|
404
|
-
if not self.fired and k in ("
|
|
405
|
-
self.
|
|
407
|
+
elif gk == "data": # DM20 versus training: A/B = fire high or low
|
|
408
|
+
if not self.fired and k in ("up", "k"):
|
|
409
|
+
self._data_fire(True)
|
|
410
|
+
elif not self.fired and k in ("down", "j"):
|
|
411
|
+
self._data_fire(False)
|
|
406
412
|
elif k == "space": # vaccine mash / virus stop
|
|
407
413
|
self._strike()
|
|
408
414
|
return None
|
|
409
415
|
|
|
410
|
-
def
|
|
411
|
-
"""The shot commits (
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
the
|
|
415
|
-
|
|
416
|
+
def _data_fire(self, up):
|
|
417
|
+
"""The player's shot commits (DM20 manual: past = the partner's shield stood
|
|
418
|
+
in the OTHER lane). The round plays out in the battle's alternating-view
|
|
419
|
+
volley grammar: fire_out (the mon looses its real orb) -> fire_in (cut to
|
|
420
|
+
the partner -- the shield lane REVEALS, the orb arrives) -> the fullscreen
|
|
421
|
+
hit strobe (past) or the blocked tableau."""
|
|
422
|
+
self.shot_up = up
|
|
423
|
+
self.tt_shield_up = self.tt_shield[self.tt_round]
|
|
424
|
+
self.blocked = (up == self.tt_shield_up)
|
|
425
|
+
ft = max(3, FIRE_T // 2) # the battle's flight halved: five rounds
|
|
426
|
+
# per session need a brisker volley
|
|
427
|
+
tl = [{"m": "fire_out", "prog": (s + 1) / ft} for s in range(ft)]
|
|
428
|
+
tl += [{"m": "fire_in", "prog": (s + 1) / ft} for s in range(ft)]
|
|
416
429
|
if self.blocked:
|
|
417
|
-
|
|
418
|
-
|
|
430
|
+
tl += [{"m": "block"}] * DATA_BLOCK_HOLD
|
|
431
|
+
else:
|
|
432
|
+
tl += [{"m": "hit", "f": (s // EXPLODE_HOLD) % 2} for s in range(EXPLODE_FRAMES)]
|
|
433
|
+
self.tt_tl, self.tt_i = tl, 0
|
|
434
|
+
self.fired = True
|
|
435
|
+
self._last_sm = "fire_out"
|
|
436
|
+
self.sfx = "attack"
|
|
437
|
+
self.flash = "HIGH!" if up else "LOW!"
|
|
438
|
+
|
|
439
|
+
def _data_next_round(self):
|
|
440
|
+
"""Score the round, then the next pick -- or the session verdict (manual:
|
|
441
|
+
"You need to succeed 3 out of the 5 rounds")."""
|
|
442
|
+
past = not self.blocked
|
|
443
|
+
self.tt_log.append(past)
|
|
444
|
+
if past:
|
|
445
|
+
self.tt_past += 1
|
|
446
|
+
# the family's hit/miss tell rides the next act (pose only -- the round's
|
|
447
|
+
# own sting already played at the hit/block beat, no double beep)
|
|
448
|
+
self._strike_pose, self._strike_t = (6 if past else 9), 4
|
|
449
|
+
self.tt_round += 1
|
|
450
|
+
self.fired = False
|
|
451
|
+
self._last_sm = None
|
|
452
|
+
if self.tt_round >= DATA_ROUNDS:
|
|
453
|
+
p = self.tt_past # canon pass = 3 of 5; graded around that line
|
|
454
|
+
hits = 3 if p >= DATA_ROUNDS else 2 if p >= DATA_PASS else 1 if p >= 1 else 0
|
|
455
|
+
self._finish(hits, p * 20, "Data", "data")
|
|
419
456
|
else:
|
|
420
|
-
self.flash = "
|
|
421
|
-
self._impact_args = (0, 0, "Data", "data")
|
|
422
|
-
self.fired = True # success LOCKED -> the shot fires (cosmetic)
|
|
423
|
-
self.fly_t = DATA_FLY
|
|
424
|
-
self.sfx = "attack" # DVPet attackGreen turretShoot (cannon fires)
|
|
457
|
+
self.flash = f"round {self.tt_round + 1}/{DATA_ROUNDS} — UP high · DOWN low"
|
|
425
458
|
|
|
426
459
|
def _flash(self, pose):
|
|
427
460
|
"""Briefly show a strike (6) or recoil (9) pose, like DVPet AttackSuccess/Fail."""
|
|
@@ -500,8 +533,8 @@ class TrainingPanel:
|
|
|
500
533
|
"""The DVPet drills, rebuilt to match the real game with the real sprites:
|
|
501
534
|
Vaccine: MASH the bag (bag LEFT, 'Hit!' label flashes, pet HIDDEN).
|
|
502
535
|
Virus: the power bar FILLS L->R; stop it in the zone (bar centred, pet HIDDEN).
|
|
503
|
-
Data:
|
|
504
|
-
shield
|
|
536
|
+
Data: the REAL DM20 versus training -- fire HIGH/LOW past the sparring
|
|
537
|
+
partner's shield, 3 of 5 rounds (the fan turret is gone).
|
|
505
538
|
HP: read the target the training dummy wants, pick the matching attribute (dummy LEFT,
|
|
506
539
|
pet RIGHT face-off; the picker glyphs live in the gauge) -- on a flat LCD."""
|
|
507
540
|
gk = self.gkey
|
|
@@ -574,86 +607,57 @@ class TrainingPanel:
|
|
|
574
607
|
zx = fx + 1 + min(track_w - 1, int(track_w * VIRUS_BAR_MIN / VIRUS_MAX))
|
|
575
608
|
overlay += [(zx, fy + y) for y in range(fh)]
|
|
576
609
|
elif gk == "data":
|
|
577
|
-
#
|
|
578
|
-
#
|
|
579
|
-
#
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
610
|
+
# The REAL DM20's VERSUS TRAINING (canon rebuild 2026-07-13 -- DVPet's
|
|
611
|
+
# turret duel here was fan invention; manual: "you choose to fire a
|
|
612
|
+
# high shot or a low shot. If your shot gets past your partner's
|
|
613
|
+
# shield, you succeed"). Each round plays in the battle's
|
|
614
|
+
# alternating-view volley grammar -- ONE combatant on screen at a
|
|
615
|
+
# time, the same look every other drill's strike already wears:
|
|
616
|
+
# PICK -- faceoff: the sparring partner (the square-marked Data
|
|
617
|
+
# dummy) LEFT, the mon RIGHT, both idle; UP/DOWN commits
|
|
618
|
+
# OUT -- cut to the mon: it looses its REAL orb along the lane
|
|
619
|
+
# IN -- cut to the partner: the shield SNAPS to the chart's
|
|
620
|
+
# lane (the reveal) as the orb arrives -- pressed dead on
|
|
621
|
+
# the shield (blocked) or through into the partner (past)
|
|
622
|
+
# HIT -- past: the battle's fullscreen strobe owns the window
|
|
623
|
+
fr = self.tt_tl[min(self.tt_i, len(self.tt_tl) - 1)] if self.fired else None
|
|
624
|
+
m = fr["m"] if fr else "pick"
|
|
625
|
+
orb = data.attack_orb(self.pet.num, "Data", self.pet.data_power)
|
|
626
|
+
oh = len(orb) if orb else 8
|
|
627
|
+
ow = max(len(r) for r in orb) if orb else 8
|
|
628
|
+
lane_y = BAND_TOP if self.shot_up else BASE_Y - oh # HIGH rides the band top, LOW the floor
|
|
629
|
+
shield = E.get("train_shield", [None])[0]
|
|
630
|
+
sh_h = len(shield) if shield else 6
|
|
631
|
+
sw = len(shield[0]) if shield else 5
|
|
632
|
+
if m == "hit": # PAST: DVPet hitAnim, the window is the flash
|
|
633
|
+
ex = _EXPLODE[fr["f"]]
|
|
584
634
|
overlay += _blit(ex, GRID_X0 + max(0, (GRID_W - len(ex[0])) // 2),
|
|
585
635
|
BAND_TOP + max(0, (BASE_Y - BAND_TOP - len(ex)) // 2))
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
#
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
# edge: even a 16px mon fits (gate ends
|
|
612
|
-
# x19, the widest mon starts x20)
|
|
613
|
-
# Data layout INSIDE the 32x16 window (LAW 2026-07-11; the
|
|
614
|
-
# 07-06 measured stage still leaked into the bezel on both
|
|
615
|
-
# sides): turret x4..13 · air x14 · gate x15..19 · the mon
|
|
616
|
-
# flush right, x20..35 at its widest.
|
|
617
|
-
# Three staged acts, the MON on stage for all of them (canon
|
|
618
|
-
# drawDataPre bobs the pet through the aim; HP-drill consistency,
|
|
619
|
-
# Joel 2026-07-06 -- the old staging hid the mon until the LOCK):
|
|
620
|
-
# AIM -- barrel feinting, the mon bobbing behind its gate
|
|
621
|
-
# LOCK -- the barrel commits and the mon BRACES; the toggle
|
|
622
|
-
# window runs ("block it!")
|
|
623
|
-
# SHOOT -- the turret recoils, the pellet bursts out of the barrel and
|
|
624
|
-
# flies the lane into the gate; then hitAnim's strobe.
|
|
625
|
-
floor = BASE_Y # the shared grid floor (2px above bottom)
|
|
626
|
-
cannon_x = GRID_X0 # turret on the window's left edge; the
|
|
627
|
-
# recoil beat kicks 1px past it -- a
|
|
628
|
-
# momentary LEFT-edge exit, the lawful kind
|
|
629
|
-
sx = 15 # the gate, mid-stage
|
|
630
|
-
py = floor - phh
|
|
631
|
-
cy = floor - ch # turret grounded
|
|
632
|
-
recoil = -1 if (self.fired and self.fly_t >= DATA_FLY - 1) else 0
|
|
633
|
-
overlay.extend(_blit(cannon, cannon_x + recoil, cy))
|
|
634
|
-
overlay.extend(_blit(pf, px, py)) # on stage every act
|
|
635
|
-
hi_y = STRIKE_BAND_TOP + 1 # HIGH lane gate: up near the band top
|
|
636
|
-
lo_y = floor - sh_h # LOW lane gate: grounded on the floor
|
|
637
|
-
# ONE solid shield, drawn only in the lane it guards -- the open lane
|
|
638
|
-
# is empty. (DVPet's transparent shieldTransp ghost was a mouse
|
|
639
|
-
# click-target; on a 1-bit LCD with a keyboard toggle it's just
|
|
640
|
-
# noise -- the old 1-in-4 dither read as scattered dots.)
|
|
641
|
-
on_y = hi_y if self.shield_up else lo_y
|
|
642
|
-
if shield:
|
|
643
|
-
overlay.extend(_blit(shield, sx, on_y))
|
|
644
|
-
if self.fired and self.fly_t > 0: # the shoot animation (DVPet attackGreen):
|
|
645
|
-
# the PELLET (the Data orb, /2 through the standard downsample pipeline --
|
|
646
|
-
# the full 8px orb is wider than the old gap) bursts out of the barrel
|
|
647
|
-
# and flies the committed lane into the gate: 10px over DATA_FLY ticks.
|
|
648
|
-
from .render import downsample
|
|
649
|
-
orb = downsample(data.load_orbs()["generic"]["Data"][0], 2)
|
|
650
|
-
ow, oh = max(len(r) for r in orb), len(orb)
|
|
651
|
-
lane_top = hi_y if self.tgt_up else lo_y # the lane follows the ATTACK (tgt_up)
|
|
652
|
-
lane_y = lane_top + sh_h // 2 - oh // 2 # pellet centred on that gate's row
|
|
653
|
-
mx = cannon_x + 4 # in the barrel's mouth...
|
|
654
|
-
end_x = sx - ow + 2 # ...to pressing the gate by 2px
|
|
655
|
-
prog = (DATA_FLY - self.fly_t) / (DATA_FLY - 1)
|
|
656
|
-
overlay += _blit(orb, int(mx + (end_x - mx) * prog), lane_y)
|
|
636
|
+
elif m == "pick": # the faceoff: partner vs mon, like the done screen
|
|
637
|
+
dummy = _fit_cell(_HP_DUMMIES["data"])
|
|
638
|
+
pf = self._frame(rec, self._pose_now(1 if (self.frame_i // 2) % 2 else 0))
|
|
639
|
+
placements = grid.faceoff(dummy, pf) # partner mirrored to face the mon
|
|
640
|
+
elif m == "fire_out": # the mon's view: it looses the shot
|
|
641
|
+
pose = ATTACK
|
|
642
|
+
xshift = -2 if fr["prog"] < 0.35 else 0 # the battle's release lunge
|
|
643
|
+
placements, mouth = strikefx.place_combatant(True, self._frame(rec, pose), xshift)
|
|
644
|
+
if orb: # from the mouth, off the near edge, in-lane
|
|
645
|
+
ox = int((mouth - ow) + ((GRID_X0 - ow) - (mouth - ow)) * fr["prog"])
|
|
646
|
+
overlay = _pop(overlay, _blit(orb, ox, lane_y))
|
|
647
|
+
else: # fire_in / block: the partner's view
|
|
648
|
+
dummy = _fit_cell(_HP_DUMMIES["data"])
|
|
649
|
+
dm = [r[::-1] for r in dummy] # creature stand-in faces the mon (canon mirror)
|
|
650
|
+
overlay.extend(_blit(dm, GRID_X0, BASE_Y - len(dm)))
|
|
651
|
+
dw = max(len(r) for r in dummy)
|
|
652
|
+
sx = GRID_X0 + dw - sw + 2 # the shield WORN on the partner's front edge,
|
|
653
|
+
on_y = BAND_TOP + 1 if self.tt_shield_up else BASE_Y - sh_h # snapped to the chart's lane
|
|
654
|
+
if shield: # _pop: it reads as a held object, not a growth
|
|
655
|
+
overlay = _pop(overlay, _blit(shield, sx, on_y))
|
|
656
|
+
if orb:
|
|
657
|
+
stop_x = (sx + sw - 1) if self.blocked else (GRID_X0 + 2) # dead on the shield / through
|
|
658
|
+
prog = 1.0 if m == "block" else fr["prog"]
|
|
659
|
+
ox = int(grid.X1 + (stop_x - grid.X1) * prog) # arrives from the far (right) edge
|
|
660
|
+
overlay = _pop(overlay, _blit(orb, ox, lane_y))
|
|
657
661
|
else: # hp: pick the shape the dummy wants
|
|
658
662
|
# The marked training dummy (battle bag) LEFT, full height, grounded,
|
|
659
663
|
# and -- canon drawHPTraining (restaged 2026-07-04, the vaccine
|
|
@@ -718,9 +722,11 @@ class TrainingPanel:
|
|
|
718
722
|
return (f"{cue} {self.taps}/{self.vaccine_target} "
|
|
719
723
|
f"{'▓' * filled}{'░' * (8 - filled)}")
|
|
720
724
|
if gk == "data":
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
725
|
+
# round pips: ▓ past / ░ blocked / · to play (3 of 5 passes) -- the
|
|
726
|
+
# pips ARE the score; raw numbers and game glyphs stay off the strip
|
|
727
|
+
pips = "".join("▓" if p else "░" for p in self.tt_log).ljust(DATA_ROUNDS, "·")
|
|
728
|
+
cue = "[b]...[/]" if self.fired else "[b]UP[/] high · [b]DOWN[/] low"
|
|
729
|
+
return f"{cue} {pips}"
|
|
724
730
|
cue = ("[b]IN THE ZONE — SPACE![/]" if int(self.pos) >= VIRUS_BAR_MIN
|
|
725
731
|
else "[b]SPACE[/] stops it in the zone")
|
|
726
732
|
return cue # the bar itself shows in the scene
|
|
@@ -739,7 +745,7 @@ class TrainingPanel:
|
|
|
739
745
|
# keep every hint <= menu.W (38 cols) or footer() clips it mid-word
|
|
740
746
|
return {"hp": "SPACE stops the reel ESC out",
|
|
741
747
|
"vaccine": "SPACE punch the bag! ESC out",
|
|
742
|
-
"data": "
|
|
748
|
+
"data": "UP/DOWN fires past ESC out",
|
|
743
749
|
"virus": "watch the marker SPACE stops it"}[self.gkey]
|
|
744
750
|
|
|
745
751
|
def _attr_pow(self):
|
|
@@ -748,20 +754,21 @@ class TrainingPanel:
|
|
|
748
754
|
"Virus": self.pet.virus}.get(self.strike_attr, 0)
|
|
749
755
|
|
|
750
756
|
def _target_mirror(self):
|
|
751
|
-
"""Canon facing for the drill's target. The HP dummy
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
the
|
|
755
|
-
|
|
756
|
-
return self.gkey
|
|
757
|
+
"""Canon facing for the drill's target. The HP dummy and the Data drill's
|
|
758
|
+
sparring partner are CREATURE stand-ins: DVPet drawHPTraining places its
|
|
759
|
+
dummy left with drawNumMirror(.., true) -- mirrored (drawNum keeps
|
|
760
|
+
_isMirror, so the taunt flips with it). The punching bag is a PROP drawn
|
|
761
|
+
via setAltIcon -- never flipped."""
|
|
762
|
+
return self.gkey in ("hp", "data")
|
|
757
763
|
|
|
758
764
|
def _target_sprite(self, broken):
|
|
759
|
-
"""The thing being struck: the
|
|
760
|
-
shows its BROKEN frame on a successful break
|
|
761
|
-
16px band so the strike animation sits
|
|
765
|
+
"""The thing being struck: the sparring partner (Data), the marked dummy (HP),
|
|
766
|
+
or the punching bag, which shows its BROKEN frame on a successful break
|
|
767
|
+
(DVPet aftermathDefault). Fit to the 16px band so the strike animation sits
|
|
768
|
+
in the same grid as the drill sprites."""
|
|
762
769
|
E = data.load_effects()
|
|
763
|
-
if self._is_data:
|
|
764
|
-
return
|
|
770
|
+
if self._is_data: # the versus partner, intact either way
|
|
771
|
+
return _HP_DUMMIES["data"]
|
|
765
772
|
if self.gkey == "hp": # HP fires at the training dummy (full height)
|
|
766
773
|
return _HP_DUMMIES[("vaccine", "data", "virus")[self.hp_target]]
|
|
767
774
|
return _fit_cell(E.get("punching_bag_broken" if broken else "punching_bag", [None])[0])
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tuipet
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.417
|
|
4
4
|
Summary: A terminal virtual pet (Digimon V-Pet style) rendered with halfblock sprites, built on data extracted from DVPet.
|
|
5
5
|
Author-email: Joel Taylor <joeltaylor734@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -354,9 +354,8 @@ def test_every_drill_completes_through_its_strike_within_budget():
|
|
|
354
354
|
|
|
355
355
|
plays = {
|
|
356
356
|
"vaccine": lambda pan: pan.key("space"),
|
|
357
|
-
"data": lambda pan: (pan.key("
|
|
358
|
-
if
|
|
359
|
-
and pan.shield_up != pan.tgt_up else None),
|
|
357
|
+
"data": lambda pan: (pan.key("down" if pan.tt_shield[pan.tt_round] else "up")
|
|
358
|
+
if not pan.fired else None),
|
|
360
359
|
"virus": lambda pan: pan.key("space") if getattr(pan, "pos", 0) > 80 else None,
|
|
361
360
|
"hp": lambda pan: (setattr(pan, "hp_pick", pan.hp_target), pan.key("enter")),
|
|
362
361
|
}
|
|
@@ -41,6 +41,8 @@ ALLOWED_SILENT = {
|
|
|
41
41
|
"train_button": "the mouse mash button; tuipet is keyboard-driven",
|
|
42
42
|
"train_cannon": "duplicate alias of train_green in the generated json",
|
|
43
43
|
"train_cannon_up": "duplicate alias of train_green_up",
|
|
44
|
+
"train_green": "DVPet's fan turret, retired by the canon DM20 versus training (2026-07-13)",
|
|
45
|
+
"train_green_up": "DVPet's fan turret (up-aim frame), retired with train_green",
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
|