From 30f28015ae02f8ba1a8d04413c8d522d60843f18 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 18:05:39 +0000 Subject: [PATCH 1/2] Add the leaf, duck, hippo and beak lines Four new egg lines, each with egg, baby, child and two adult forms: leaf (Twiggle, Needlenub), duck (Captain Quill, Drakwing), hippo (Lillypot, Steamo) and beak (Parcelbeak, Rapierre). Leaf and hippo eggs come from wild friends in the forest and at the stream; the meadow and stream guardians now leave the beak and duck eggs. A guardian that was passed before it had an egg leaves it at the end of a later trip. The care diary also counts scuffles won, baths and tricks practiced. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_018m5J9V7X4cXFquP3ZLE9Le --- README.md | 2 +- app/locales/de.json | 26 +- app/locales/en.json | 26 +- app/pet/assets/beak_baby_body.json | 166 ++++++ app/pet/assets/beak_baby_body.png | Bin 0 -> 875 bytes app/pet/assets/beak_baby_faces.json | 222 ++++++++ app/pet/assets/beak_baby_faces.png | Bin 0 -> 224 bytes app/pet/assets/beak_faces.json | 222 ++++++++ app/pet/assets/beak_faces.png | Bin 0 -> 366 bytes app/pet/assets/crestling_body.json | 168 ++++++ app/pet/assets/crestling_body.png | Bin 0 -> 1252 bytes app/pet/assets/drakwing_body.json | 214 ++++++++ app/pet/assets/drakwing_body.png | Bin 0 -> 1824 bytes app/pet/assets/drakwing_faces.json | 222 ++++++++ app/pet/assets/drakwing_faces.png | Bin 0 -> 292 bytes app/pet/assets/duck_baby_body.json | 166 ++++++ app/pet/assets/duck_baby_body.png | Bin 0 -> 772 bytes app/pet/assets/duck_baby_faces.json | 222 ++++++++ app/pet/assets/duck_baby_faces.png | Bin 0 -> 252 bytes app/pet/assets/duck_faces.json | 222 ++++++++ app/pet/assets/duck_faces.png | Bin 0 -> 379 bytes app/pet/assets/hippo_baby_body.json | 166 ++++++ app/pet/assets/hippo_baby_body.png | Bin 0 -> 777 bytes app/pet/assets/hippo_baby_faces.json | 222 ++++++++ app/pet/assets/hippo_baby_faces.png | Bin 0 -> 228 bytes app/pet/assets/hippo_faces.json | 222 ++++++++ app/pet/assets/hippo_faces.png | Bin 0 -> 353 bytes app/pet/assets/items.json | 378 ++++++++++++- app/pet/assets/items.png | Bin 2705 -> 4210 bytes app/pet/assets/leaf_baby_body.json | 166 ++++++ app/pet/assets/leaf_baby_body.png | Bin 0 -> 801 bytes app/pet/assets/leaf_baby_faces.json | 222 ++++++++ app/pet/assets/leaf_baby_faces.png | Bin 0 -> 229 bytes app/pet/assets/leaf_faces.json | 222 ++++++++ app/pet/assets/leaf_faces.png | Bin 0 -> 356 bytes app/pet/assets/lillypot_body.json | 214 ++++++++ app/pet/assets/lillypot_body.png | Bin 0 -> 1709 bytes app/pet/assets/lillypot_faces.json | 222 ++++++++ app/pet/assets/lillypot_faces.png | Bin 0 -> 374 bytes app/pet/assets/needlenub_body.json | 168 ++++++ app/pet/assets/needlenub_body.png | Bin 0 -> 1361 bytes app/pet/assets/needlenub_faces.json | 222 ++++++++ app/pet/assets/needlenub_faces.png | Bin 0 -> 367 bytes app/pet/assets/paddlet_body.json | 168 ++++++ app/pet/assets/paddlet_body.png | Bin 0 -> 1026 bytes app/pet/assets/parcelbeak_body.json | 214 ++++++++ app/pet/assets/parcelbeak_body.png | Bin 0 -> 1876 bytes app/pet/assets/parcelbeak_faces.json | 222 ++++++++ app/pet/assets/parcelbeak_faces.png | Bin 0 -> 252 bytes app/pet/assets/quill_body.json | 214 ++++++++ app/pet/assets/quill_body.png | Bin 0 -> 1601 bytes app/pet/assets/quill_faces.json | 222 ++++++++ app/pet/assets/quill_faces.png | Bin 0 -> 272 bytes app/pet/assets/rapierre_body.json | 168 ++++++ app/pet/assets/rapierre_body.png | Bin 0 -> 1392 bytes app/pet/assets/rapierre_faces.json | 222 ++++++++ app/pet/assets/rapierre_faces.png | Bin 0 -> 220 bytes app/pet/assets/soakling_body.json | 168 ++++++ app/pet/assets/soakling_body.png | Bin 0 -> 1017 bytes app/pet/assets/sproutlet_body.json | 168 ++++++ app/pet/assets/sproutlet_body.png | Bin 0 -> 1081 bytes app/pet/assets/steamo_body.json | 214 ++++++++ app/pet/assets/steamo_body.png | Bin 0 -> 1640 bytes app/pet/assets/steamo_faces.json | 222 ++++++++ app/pet/assets/steamo_faces.png | Bin 0 -> 336 bytes app/pet/assets/trip.json | 66 ++- app/pet/assets/trip.png | Bin 8616 -> 9511 bytes app/pet/assets/twiggle_body.json | 214 ++++++++ app/pet/assets/twiggle_body.png | Bin 0 -> 1560 bytes app/pet/assets/twiggle_faces.json | 222 ++++++++ app/pet/assets/twiggle_faces.png | Bin 0 -> 319 bytes core/src/food.ts | 12 + core/src/home.ts | 6 +- core/src/life.ts | 31 +- core/src/model.ts | 2 + core/src/scene.ts | 58 +- core/src/state.ts | 7 + core/src/trip.ts | 28 +- core/src/wild.ts | 4 +- core/test/battle.test.ts | 23 +- core/test/life.test.ts | 20 + core/test/scene.test.ts | 2 +- core/test/wild.test.ts | 6 +- docs/gameplay.md | 10 +- docs/images/pets/beak_baby.png | Bin 0 -> 557 bytes docs/images/pets/beak_egg.png | Bin 0 -> 475 bytes docs/images/pets/crestling.png | Bin 0 -> 735 bytes docs/images/pets/drakwing.png | Bin 0 -> 790 bytes docs/images/pets/duck_baby.png | Bin 0 -> 558 bytes docs/images/pets/duck_egg.png | Bin 0 -> 458 bytes docs/images/pets/hippo_baby.png | Bin 0 -> 553 bytes docs/images/pets/hippo_egg.png | Bin 0 -> 471 bytes docs/images/pets/leaf_baby.png | Bin 0 -> 558 bytes docs/images/pets/leaf_egg.png | Bin 0 -> 463 bytes docs/images/pets/lillypot.png | Bin 0 -> 805 bytes docs/images/pets/needlenub.png | Bin 0 -> 751 bytes docs/images/pets/paddlet.png | Bin 0 -> 652 bytes docs/images/pets/parcelbeak.png | Bin 0 -> 769 bytes docs/images/pets/quill.png | Bin 0 -> 687 bytes docs/images/pets/rapierre.png | Bin 0 -> 689 bytes docs/images/pets/soakling.png | Bin 0 -> 653 bytes docs/images/pets/sproutlet.png | Bin 0 -> 682 bytes docs/images/pets/steamo.png | Bin 0 -> 783 bytes docs/images/pets/twiggle.png | Bin 0 -> 756 bytes docs/pets.md | 238 ++++++++- tools/build_blob_sprites.py | 771 +++++++++++++++++++++++++++ tools/pet_preview.ts | 47 +- 107 files changed, 8228 insertions(+), 43 deletions(-) create mode 100644 app/pet/assets/beak_baby_body.json create mode 100644 app/pet/assets/beak_baby_body.png create mode 100644 app/pet/assets/beak_baby_faces.json create mode 100644 app/pet/assets/beak_baby_faces.png create mode 100644 app/pet/assets/beak_faces.json create mode 100644 app/pet/assets/beak_faces.png create mode 100644 app/pet/assets/crestling_body.json create mode 100644 app/pet/assets/crestling_body.png create mode 100644 app/pet/assets/drakwing_body.json create mode 100644 app/pet/assets/drakwing_body.png create mode 100644 app/pet/assets/drakwing_faces.json create mode 100644 app/pet/assets/drakwing_faces.png create mode 100644 app/pet/assets/duck_baby_body.json create mode 100644 app/pet/assets/duck_baby_body.png create mode 100644 app/pet/assets/duck_baby_faces.json create mode 100644 app/pet/assets/duck_baby_faces.png create mode 100644 app/pet/assets/duck_faces.json create mode 100644 app/pet/assets/duck_faces.png create mode 100644 app/pet/assets/hippo_baby_body.json create mode 100644 app/pet/assets/hippo_baby_body.png create mode 100644 app/pet/assets/hippo_baby_faces.json create mode 100644 app/pet/assets/hippo_baby_faces.png create mode 100644 app/pet/assets/hippo_faces.json create mode 100644 app/pet/assets/hippo_faces.png create mode 100644 app/pet/assets/leaf_baby_body.json create mode 100644 app/pet/assets/leaf_baby_body.png create mode 100644 app/pet/assets/leaf_baby_faces.json create mode 100644 app/pet/assets/leaf_baby_faces.png create mode 100644 app/pet/assets/leaf_faces.json create mode 100644 app/pet/assets/leaf_faces.png create mode 100644 app/pet/assets/lillypot_body.json create mode 100644 app/pet/assets/lillypot_body.png create mode 100644 app/pet/assets/lillypot_faces.json create mode 100644 app/pet/assets/lillypot_faces.png create mode 100644 app/pet/assets/needlenub_body.json create mode 100644 app/pet/assets/needlenub_body.png create mode 100644 app/pet/assets/needlenub_faces.json create mode 100644 app/pet/assets/needlenub_faces.png create mode 100644 app/pet/assets/paddlet_body.json create mode 100644 app/pet/assets/paddlet_body.png create mode 100644 app/pet/assets/parcelbeak_body.json create mode 100644 app/pet/assets/parcelbeak_body.png create mode 100644 app/pet/assets/parcelbeak_faces.json create mode 100644 app/pet/assets/parcelbeak_faces.png create mode 100644 app/pet/assets/quill_body.json create mode 100644 app/pet/assets/quill_body.png create mode 100644 app/pet/assets/quill_faces.json create mode 100644 app/pet/assets/quill_faces.png create mode 100644 app/pet/assets/rapierre_body.json create mode 100644 app/pet/assets/rapierre_body.png create mode 100644 app/pet/assets/rapierre_faces.json create mode 100644 app/pet/assets/rapierre_faces.png create mode 100644 app/pet/assets/soakling_body.json create mode 100644 app/pet/assets/soakling_body.png create mode 100644 app/pet/assets/sproutlet_body.json create mode 100644 app/pet/assets/sproutlet_body.png create mode 100644 app/pet/assets/steamo_body.json create mode 100644 app/pet/assets/steamo_body.png create mode 100644 app/pet/assets/steamo_faces.json create mode 100644 app/pet/assets/steamo_faces.png create mode 100644 app/pet/assets/twiggle_body.json create mode 100644 app/pet/assets/twiggle_body.png create mode 100644 app/pet/assets/twiggle_faces.json create mode 100644 app/pet/assets/twiggle_faces.png create mode 100644 docs/images/pets/beak_baby.png create mode 100644 docs/images/pets/beak_egg.png create mode 100644 docs/images/pets/crestling.png create mode 100644 docs/images/pets/drakwing.png create mode 100644 docs/images/pets/duck_baby.png create mode 100644 docs/images/pets/duck_egg.png create mode 100644 docs/images/pets/hippo_baby.png create mode 100644 docs/images/pets/hippo_egg.png create mode 100644 docs/images/pets/leaf_baby.png create mode 100644 docs/images/pets/leaf_egg.png create mode 100644 docs/images/pets/lillypot.png create mode 100644 docs/images/pets/needlenub.png create mode 100644 docs/images/pets/paddlet.png create mode 100644 docs/images/pets/parcelbeak.png create mode 100644 docs/images/pets/quill.png create mode 100644 docs/images/pets/rapierre.png create mode 100644 docs/images/pets/soakling.png create mode 100644 docs/images/pets/sproutlet.png create mode 100644 docs/images/pets/steamo.png create mode 100644 docs/images/pets/twiggle.png diff --git a/README.md b/README.md index 76c6f73..ea72285 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ a day and also tells you the time and the weather. goes on trips, scuffles with whoever gets in its way there and brings things home, among them food that gives it an edge on the next trip or in training, and the diary keeps every trip. Five areas open up one after the other, each one past a guardian, and - one of the guardians keeps a rare egg that something else hatches from. + some of the guardians keep a rare egg that something else hatches from. Every pet that gets past the last guardian adds a step to its house, from a hut of thatch to a whole house, where it sleeps and keeps more decorations. - **It makes friends.** A grown-up pet can impress a wild pet with its tricks. diff --git a/app/locales/de.json b/app/locales/de.json index 763bed1..b77dbad 100644 --- a/app/locales/de.json +++ b/app/locales/de.json @@ -44,7 +44,11 @@ "ember": "Cindlet", "stone": "Pebblet", "fox": "Kitlet", - "cloud": "Nimbit" + "cloud": "Nimbit", + "leaf": "Sproutlet", + "duck": "Paddlet", + "hippo": "Soakling", + "beak": "Crestling" }, "species": { "blob": "Blob", @@ -67,7 +71,19 @@ "filchfox": "Filchfox", "cloud": "Wolke", "rumblefluff": "Rumblefluff", - "prismist": "Prismist" + "prismist": "Prismist", + "leaf": "Blatt", + "duck": "Ente", + "hippo": "Nilpferd", + "beak": "Schnabel", + "twiggle": "Twiggle", + "needlenub": "Needlenub", + "drakwing": "Drakwing", + "quill": "Captain Quill", + "steamo": "Steamo", + "lillypot": "Lillypot", + "rapierre": "Rapierre", + "parcelbeak": "Parcelbeak" }, "tricks": { "bow": "Verbeugen", @@ -163,7 +179,11 @@ "egg_ember": "Glut-Ei", "egg_stone": "Stein-Ei", "egg_fox": "Fuchs-Ei", - "egg_cloud": "Wolken-Ei" + "egg_cloud": "Wolken-Ei", + "egg_leaf": "Blatt-Ei", + "egg_duck": "Enten-Ei", + "egg_hippo": "Nilpferd-Ei", + "egg_beak": "Schnabel-Ei" }, "pack": { "snack": "Snack", diff --git a/app/locales/en.json b/app/locales/en.json index 1f4408a..2386bfa 100644 --- a/app/locales/en.json +++ b/app/locales/en.json @@ -44,7 +44,11 @@ "ember": "Cindlet", "stone": "Pebblet", "fox": "Kitlet", - "cloud": "Nimbit" + "cloud": "Nimbit", + "leaf": "Sproutlet", + "duck": "Paddlet", + "hippo": "Soakling", + "beak": "Crestling" }, "species": { "blob": "Blob", @@ -67,7 +71,19 @@ "filchfox": "Filchfox", "cloud": "Cloud", "rumblefluff": "Rumblefluff", - "prismist": "Prismist" + "prismist": "Prismist", + "leaf": "Leaf", + "duck": "Duck", + "hippo": "Hippo", + "beak": "Beak", + "twiggle": "Twiggle", + "needlenub": "Needlenub", + "drakwing": "Drakwing", + "quill": "Captain Quill", + "steamo": "Steamo", + "lillypot": "Lillypot", + "rapierre": "Rapierre", + "parcelbeak": "Parcelbeak" }, "tricks": { "bow": "Bow", @@ -163,7 +179,11 @@ "egg_ember": "Ember egg", "egg_stone": "Stone egg", "egg_fox": "Fox egg", - "egg_cloud": "Cloud egg" + "egg_cloud": "Cloud egg", + "egg_leaf": "Leaf egg", + "egg_duck": "Duck egg", + "egg_hippo": "Hippo egg", + "egg_beak": "Beak egg" }, "pack": { "snack": "Snack", diff --git a/app/pet/assets/beak_baby_body.json b/app/pet/assets/beak_baby_body.json new file mode 100644 index 0000000..e56cb22 --- /dev/null +++ b/app/pet/assets/beak_baby_body.json @@ -0,0 +1,166 @@ +{ + "frames": [ + { + "filename": "beak_baby_body idle 0", + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "beak_baby_body idle 1", + "frame": { + "x": 32, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "beak_baby_body squash 2", + "frame": { + "x": 64, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "beak_baby_body stretch 3", + "frame": { + "x": 96, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "beak_baby_body flat 4", + "frame": { + "x": 128, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "beak_baby_body sleep 5", + "frame": { + "x": 160, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "beak_baby_body sleep 6", + "frame": { + "x": 192, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "beak_baby_body lookout_left 7", + "frame": { + "x": 224, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "beak_baby_body lookout_left 8", + "frame": { + "x": 256, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "beak_baby_body lookout_right 9", + "frame": { + "x": 288, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "beak_baby_body lookout_right 10", + "frame": { + "x": 320, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "beak_baby_body.png", + "size": { + "w": 352, + "h": 32 + }, + "frameTags": [ + { + "name": "idle", + "from": 0, + "to": 1, + "direction": "forward" + }, + { + "name": "squash", + "from": 2, + "to": 2, + "direction": "forward" + }, + { + "name": "stretch", + "from": 3, + "to": 3, + "direction": "forward" + }, + { + "name": "flat", + "from": 4, + "to": 4, + "direction": "forward" + }, + { + "name": "sleep", + "from": 5, + "to": 6, + "direction": "forward" + }, + { + "name": "lookout_left", + "from": 7, + "to": 8, + "direction": "forward" + }, + { + "name": "lookout_right", + "from": 9, + "to": 10, + "direction": "forward" + } + ] + } +} diff --git a/app/pet/assets/beak_baby_body.png b/app/pet/assets/beak_baby_body.png new file mode 100644 index 0000000000000000000000000000000000000000..5de5466e8ed10072e6d56b9c054c245e622b27aa GIT binary patch literal 875 zcmeAS@N?(olHy`uVBq!ia0y~yU`znA6*$;{q>kUBDGUtEMxHK?Ar-gY&RQ6J$3f)S z{^UigR%@M0xOODL;Nl<74&$p5A*HURqRV!%Ir2&c7w=L_J3CWY!^BK9b>;*$cRsV< zlkU7XKdfS2e0+Ls{{8Rwiada3lLC?-)rE%SerGU{?c+FDveUBk>e-ctYYr~?X}ytex7bp!OZbY+tYjc>+f&ZpZmVdAkmvy zs=Lni|H^L-p>Mxt{#*I&-knDij*9G$n7i^zwCAceE{Et3`a*JtXS?%zp6pAMejhEI zSIP3O$~OG(wm$ql-}|HbHs{~Y=(gLZPBAPOYtPXF*%tfEzJ!_Mb>6zKIbVPN z{P*tH^V8?&>~QQ>*vi=JSRekc{SI@op~LHE_SY>^f<2l_Km3-nZL?$CGBdy8uF1ol z5*H-C{C-w{!ZsnWx^`CmE5?Mp!V}A;u$+GI-SEH2af8z@51(q#`TG5A{TW*WH|CtI zxThF=Ur}yn$2|1soyX)k0Uw`Fa8vA6OmfxMvY;UY;uc%M@_4}SRYvk+q zlj~pGT3r7%dw1QpYwSUf72D?QJGSKhvfRCOuWu}`>2tnr|K->0*>&p|UyNSfF(dv^ v#LNBZO`Br&m%d51J-+a@eAVBxvH$gNymn~0vV4*SD3yD<`njxgN@xNAVxzC; literal 0 HcmV?d00001 diff --git a/app/pet/assets/beak_baby_faces.json b/app/pet/assets/beak_baby_faces.json new file mode 100644 index 0000000..d27e4c3 --- /dev/null +++ b/app/pet/assets/beak_baby_faces.json @@ -0,0 +1,222 @@ +{ + "frames": [ + { + "filename": "beak_baby_faces normal 0", + "frame": { + "x": 0, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "beak_baby_faces smile 1", + "frame": { + "x": 10, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "beak_baby_faces blink 2", + "frame": { + "x": 20, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "beak_baby_faces happy 3", + "frame": { + "x": 30, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "beak_baby_faces laugh 4", + "frame": { + "x": 40, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "beak_baby_faces sad 5", + "frame": { + "x": 50, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "beak_baby_faces tired 6", + "frame": { + "x": 60, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "beak_baby_faces yawn 7", + "frame": { + "x": 70, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "beak_baby_faces sick 8", + "frame": { + "x": 80, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "beak_baby_faces no 9", + "frame": { + "x": 90, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "beak_baby_faces eat_open 10", + "frame": { + "x": 100, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "beak_baby_faces eat_closed 11", + "frame": { + "x": 110, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "beak_baby_faces sleep 12", + "frame": { + "x": 120, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "beak_baby_faces.png", + "size": { + "w": 130, + "h": 5 + }, + "frameTags": [ + { + "name": "normal", + "from": 0, + "to": 0, + "direction": "forward" + }, + { + "name": "smile", + "from": 1, + "to": 1, + "direction": "forward" + }, + { + "name": "blink", + "from": 2, + "to": 2, + "direction": "forward" + }, + { + "name": "happy", + "from": 3, + "to": 3, + "direction": "forward" + }, + { + "name": "laugh", + "from": 4, + "to": 4, + "direction": "forward" + }, + { + "name": "sad", + "from": 5, + "to": 5, + "direction": "forward" + }, + { + "name": "tired", + "from": 6, + "to": 6, + "direction": "forward" + }, + { + "name": "yawn", + "from": 7, + "to": 7, + "direction": "forward" + }, + { + "name": "sick", + "from": 8, + "to": 8, + "direction": "forward" + }, + { + "name": "no", + "from": 9, + "to": 9, + "direction": "forward" + }, + { + "name": "eat_open", + "from": 10, + "to": 10, + "direction": "forward" + }, + { + "name": "eat_closed", + "from": 11, + "to": 11, + "direction": "forward" + }, + { + "name": "sleep", + "from": 12, + "to": 12, + "direction": "forward" + } + ] + } +} diff --git a/app/pet/assets/beak_baby_faces.png b/app/pet/assets/beak_baby_faces.png new file mode 100644 index 0000000000000000000000000000000000000000..bb91501abf1676167e578dd61cd1f1a19cf4f488 GIT binary patch literal 224 zcmV<603ZK}P)TZ4P1jsT!XD_tf`-cpAZE-;S}RbE`i6(eF35cqX%e*60QccQph>0 znP)1mDt#V3003c9C0yz7ayf2(wrjE4o7@w9=Jtwx5wuc=z`5MI=WwYPlEX>Y@pbM_ zuQ>DAFgSzQnurLt$CWPBNcr3ALQBOBwNk$(*I%u;;*c&_Qa3mQ*UWaNJ-dK^jT?I) acQ64Q&e}-a+R@Aa0000P(FhI!2GJS>COUc$P+sAY0^NiVno;eW zY`QzM`IM*xAps!)QouCtGDcwt6J!5Hi+5^vx_^WO0ALh`Pm?sw>oTs&DARnCH;}SM zD*s<;$L$}ke|69*zl@`(az#fJ7bg8+9|$V zp9;Gyqj3~ryUXaYes2G8{nK&+6)UuA2QkGLoNAYN#s9(y&eg}}4L}EPvww8mUReF- z|AF|6$fkZx=WT#}j3Hivh$u)F!8hV`fBz(lrPMI&-$>DSk#qcq=p>>e-y#DLd`bKG1~PJ=mhr*ycs5ITdaE&;fdb;V7cv z(Um}FhLQG}oqMl*Qs@{ZH=g2RQAn$H>=q8TDcwKaOcsM0uEX08xfQ@YQE3jKEa*bZ zysxLT>9Rt^11?xtVjMP?j=jvGJt~9NL7eqgfgHqFZ+T{?WdeLYK4Vn@7Y~WXF#huF zIhk~{-*{x3tsSEjGPc&&B(tDCNY#lc$yrNXWmYA$&Yf}HD(G|3rO)gKT=XV9K4|-W zUdVA@cIVok^oWXm-kq?gOQV=IN_+Fe%w7bB{Z?=A>!MJOX~G_d(nI;@-#zMmGr&UX z&-p*|`1j$V+B-#FIvCaP1D7wTX`L5h8A;nClX3@iUev)C&rvvKcpDJe0-wZfqr<`3 zkiK+B)S5`H*m(ABSY}4mjndO2TUVFD?NMWtuVM6Wd)j1_L1@n+r1yR3#bkSvu6e@k z!qWY&xf#_~sT{;sONZ?TG64QhiFK6>#Ft$*$X^bhE`AUSUGR0?JJ}>)M`XjN5*8|ZyE`D^;YQ^{PHBv4X;Vr>>F?X@%1Zy{wTDV&Z6C?YKg^SM0*mWFPU{9Osl?C*pec z>RZu=VUEy|7n3~YVO{7ReX!WEXN;KVL%S-P!%W!|O^J-IJ|kCIZ7vEg3dy&bc{WbT z%kN5FDq^m6yafGTqW2=1QeV{{j%c@R)*Zohzn)D6GwOLaX@zXqt1=m79HcLMFRuJ3 zUJ+67xXy1Srz1MIGuA#FvPng}bw0@)P&GPZ6Rc%~ZJEz=T(jL}KTe#^)N)f?s-Jpp x=G$k{<3Luv`P4!2>ra3WwzT8a_qJr3!&xI40P+}=qo_zz?UeINh; literal 0 HcmV?d00001 diff --git a/app/pet/assets/drakwing_body.json b/app/pet/assets/drakwing_body.json new file mode 100644 index 0000000..176ba84 --- /dev/null +++ b/app/pet/assets/drakwing_body.json @@ -0,0 +1,214 @@ +{ + "frames": [ + { + "filename": "drakwing_body idle 0", + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "drakwing_body idle 1", + "frame": { + "x": 32, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "drakwing_body squash 2", + "frame": { + "x": 64, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "drakwing_body stretch 3", + "frame": { + "x": 96, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "drakwing_body flat 4", + "frame": { + "x": 128, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "drakwing_body sleep 5", + "frame": { + "x": 160, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "drakwing_body sleep 6", + "frame": { + "x": 192, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "drakwing_body lookout_left 7", + "frame": { + "x": 224, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "drakwing_body lookout_left 8", + "frame": { + "x": 256, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "drakwing_body lookout_right 9", + "frame": { + "x": 288, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "drakwing_body lookout_right 10", + "frame": { + "x": 320, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "drakwing_body walk 11", + "frame": { + "x": 352, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 180 + }, + { + "filename": "drakwing_body walk 12", + "frame": { + "x": 384, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 110 + }, + { + "filename": "drakwing_body walk 13", + "frame": { + "x": 416, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 180 + }, + { + "filename": "drakwing_body walk 14", + "frame": { + "x": 448, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 110 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "drakwing_body.png", + "size": { + "w": 480, + "h": 32 + }, + "frameTags": [ + { + "name": "idle", + "from": 0, + "to": 1, + "direction": "forward" + }, + { + "name": "squash", + "from": 2, + "to": 2, + "direction": "forward" + }, + { + "name": "stretch", + "from": 3, + "to": 3, + "direction": "forward" + }, + { + "name": "flat", + "from": 4, + "to": 4, + "direction": "forward" + }, + { + "name": "sleep", + "from": 5, + "to": 6, + "direction": "forward" + }, + { + "name": "lookout_left", + "from": 7, + "to": 8, + "direction": "forward" + }, + { + "name": "lookout_right", + "from": 9, + "to": 10, + "direction": "forward" + }, + { + "name": "walk", + "from": 11, + "to": 14, + "direction": "forward" + } + ], + "faceTop": 4, + "faceShift": -4.0 + } +} diff --git a/app/pet/assets/drakwing_body.png b/app/pet/assets/drakwing_body.png new file mode 100644 index 0000000000000000000000000000000000000000..7e34e6b45f7fbde7cea6c46f2764ef0b527dffbc GIT binary patch literal 1824 zcmah~`#;kQAOG&zY$Kh~acWL%U8K>=HJQk@A!;ntD%PfRIF4i-_M&E+Tj|j$3MX?p zM(#wX3(_%{=$s?DJcb_2A_|jDn_;tkJv-+gcz*f3KRjohyrk?BY_ zOiUQqS3&k}^x_%d5($HZlI%M^X6c5sNt%zzrSEK!r^;w9+)OhU*U_o5ygF$IYvzq? zL)=g=QB@y=rFPS7(faU={|oac?wyO@sWpATe>-a=NZ4qBQvzTajazR4M;8=P3JF!M zi!Y>_<5Tmw=oT9tdiw7h#W7&fuLw(xVDfmOYvr@Rd*>MDG4syK{{Ix%w1#ej=xzCsocdn!PTvYkyhsOBpIRdj}&rI|3`XzhY%fjuQytu zYQL;6S8a+RViC1<Gk5KbJm{)T^^L7~&NLu+-DR^6~ECmoY^%aYa^r z`DVXmzp(mVlgOq}cdz^O_?Y6h=hDG3)uv-OpV^tKlt%$cRw%|W)(b_FXsi{toQ?K8 zC3?8n0&$ByvX@E1=_!Xy1@B7fffG`*$80@dc%n%-Q4w>Bk09aH4T|*0_^$i)0@VTqx!nMah+7~Lp$G`d45=3Y*L5;9(wL-TR3z- zgSW6kxlKl00OS*6&BVPC=HGAr^dm4+AzgMV&gKMbC~H83^u8S@tHv&}>)4Gk3;}CN z2mXM}b@yhr{dxSZCd=QQfy#7XhArmQLeYo;YHwOq9gJVr!I3VPK3?wW*MCo}wNJKy zlaOj}ljH&nk_G&->>diY&HOvx*>4wW7SeL{c_%f7(T|XI8^j!JeVgr=Uq0I3Ch4wn zc7cS@GG8f@;t)R1*J6q~>*2Z4z>RzVOnJ$fnJvzF^gyS!pZY4TfDvAwhbzH)h1+H3 znVm&VL8p%#`8ruYrIgR9%W7o9OE^0}e^6$<-f#O}9kE20f7MHtZaQ$P;c*jkgKW@% z*)=Z;ta7h^y|3~^^M7F8ltQ$B`6F}>r>Z%50kemdV$tW~q+?yp`5pCNH$fYIhu@AN zDlyBZ56}w-Cf~xc-=&e7TpK<$S3oLFQbVpHJ+-|d4PpE>r*XGP8fG=%p=SBE>$WA* zgkf6WX*04XgX3RnWQ0-jT+Ssjl{Lj8VbjjcB%R(GL)T9HdPPni2ZB%@;$tLnjR4d0 zxm>VS4zVrj_5r%~0mL>{dn_bqr8$A-x8sl|Y{W?Qa6$Rt6VW)d2xGf|mJ#Y@q_bm=;ertDO)<54k3yEQ^0`){tkx%hxbo!-3_l`R&0AIVDqR z#-i(|zl0{yevx!Bo&a4##R;^tpIw>UlpftXwDvE`WBWR)Pm49=M5%{CN@n zj_eaX)-BgK>)q)O5&#Q-D~4TRR@@y)7jPX zjyT&N9>pJ=^M3{$iJ>~Pz;OH2Ojs>~_e4c*gFXmjM!caKL(z{7d4td@w*Rt#v0mq{ z_e_b~xN_7s)Oui7t@ePR!;zYXRSzxRP;Qn&=8nOd$~>61jCG#79?LLjg&a?Fq!iLg zC>{w;8&e6L(oX@3=lGr>>?b<>e5>x_)+lyHDFhLM`K7m(TaQ>4&UuH%xMAO5-Q2(G zpXVe#U5zAI94=S9UOS*Czu)ByRwz-isA?~0qOUbO%Dl|YA%PuyGI()yXy(kv=JpN9 zG^oDHhkV2<#(A6Il2vO`fLqImk0b-_k*RhRQ`a#xP$digV>m=&Z%6QEpDRhJGa_9c z_TEPN(egGPdLSJ0r-QAz}56B!bn=?jp`klRUa_$(D)iYTc+xc=*7C^?p`Lnz=A>>Uy#z z$T0c43h7}4ah|SHeaEJC9`xQU`=OkAbZZ-!q74)4Ha>nG+=3L;a6{+w5ChuJ2l#mh K5SqMb>Hh7_N zhS%30GKgx*V<^HUM~)s!6409)j~I!SBUR6xOJ^Av7#RMm=ovGh%YFFu`ajH1DCWf5 zphVW2g+~|($E;l3jl|e<%7$Y3WiBodohpa@(z`%evK_SciZ_4}skpw;eoAUlM z)=gqW&wIsgCyz6*&m72Y@i0000kUBDGUrur#)R9Ln>~)owat_We172 z`$dlg3{7XunkB`vtUO?y0+29K;t+_vxR=Qw;|!O{-eyw?7E{qR2d{)IU}t=LGx$*6 zEVa+RY4hB_&RJG#eEoO)b;pHg&c~UntTnLPQ*q&IafP>r~Lfm>vW2EEFLbDZekQ_Py2OKwaGs|kL?<_ z-JQdK&x+0|AL3WeBW%sIOubr0cx!rHly8LgGX4TV|7;%0a6irDyIxH#}4F z{Q1oWrwi+6|M$y2u;BYFp8xA0)`be`G{+zQQ!8`Wr(E8REoEhW-oM*x8WngiZ2G6v zb9nNM=KHUHZ`@tF_E~qY7ju=0csOeD95{lE6h z_xJzz4ASz1c{$2T6xVhqMwruYyrSj7+jcfmIyWahL=e@gO``;B;`OfA~T=V61R`mM& lR^MXpy1)9h@;gxbe#VKPqz`!}sOW&wo~Nsy%Q~loCIBQ~Z)*Sm literal 0 HcmV?d00001 diff --git a/app/pet/assets/duck_baby_faces.json b/app/pet/assets/duck_baby_faces.json new file mode 100644 index 0000000..818eebe --- /dev/null +++ b/app/pet/assets/duck_baby_faces.json @@ -0,0 +1,222 @@ +{ + "frames": [ + { + "filename": "duck_baby_faces normal 0", + "frame": { + "x": 0, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "duck_baby_faces smile 1", + "frame": { + "x": 10, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "duck_baby_faces blink 2", + "frame": { + "x": 20, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "duck_baby_faces happy 3", + "frame": { + "x": 30, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "duck_baby_faces laugh 4", + "frame": { + "x": 40, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "duck_baby_faces sad 5", + "frame": { + "x": 50, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "duck_baby_faces tired 6", + "frame": { + "x": 60, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "duck_baby_faces yawn 7", + "frame": { + "x": 70, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "duck_baby_faces sick 8", + "frame": { + "x": 80, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "duck_baby_faces no 9", + "frame": { + "x": 90, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "duck_baby_faces eat_open 10", + "frame": { + "x": 100, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "duck_baby_faces eat_closed 11", + "frame": { + "x": 110, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "duck_baby_faces sleep 12", + "frame": { + "x": 120, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "duck_baby_faces.png", + "size": { + "w": 130, + "h": 5 + }, + "frameTags": [ + { + "name": "normal", + "from": 0, + "to": 0, + "direction": "forward" + }, + { + "name": "smile", + "from": 1, + "to": 1, + "direction": "forward" + }, + { + "name": "blink", + "from": 2, + "to": 2, + "direction": "forward" + }, + { + "name": "happy", + "from": 3, + "to": 3, + "direction": "forward" + }, + { + "name": "laugh", + "from": 4, + "to": 4, + "direction": "forward" + }, + { + "name": "sad", + "from": 5, + "to": 5, + "direction": "forward" + }, + { + "name": "tired", + "from": 6, + "to": 6, + "direction": "forward" + }, + { + "name": "yawn", + "from": 7, + "to": 7, + "direction": "forward" + }, + { + "name": "sick", + "from": 8, + "to": 8, + "direction": "forward" + }, + { + "name": "no", + "from": 9, + "to": 9, + "direction": "forward" + }, + { + "name": "eat_open", + "from": 10, + "to": 10, + "direction": "forward" + }, + { + "name": "eat_closed", + "from": 11, + "to": 11, + "direction": "forward" + }, + { + "name": "sleep", + "from": 12, + "to": 12, + "direction": "forward" + } + ] + } +} diff --git a/app/pet/assets/duck_baby_faces.png b/app/pet/assets/duck_baby_faces.png new file mode 100644 index 0000000000000000000000000000000000000000..c93e15abaa966821c2a5766741df771d67c66ec2 GIT binary patch literal 252 zcmeAS@N?(olHy`uVBq!ia0vp^O+d`b!3HEdx0%cZQinZV978H@B_}jAU623&Kiz?O zN(V2?gb=>J{(W~Gb_q}4&89LZzW(ojFqkOo+9|PgqWe0Djqj>=#Qn7Axg6Xh_RuFM zLXb(vplynmM4QUaq!WCVb>*hYb{n6UhZ`Tt@H*O2DnI?UESs(Ej2p4LIxi~C>EzW; zdc@3E_ci0s@ndNT2?;;q4d2=;mY&F3kt(;#Dy8RiT*}rfTBe<*`3v4GwOX*PedWq` x;r++{f0fGne?5E0!_aPhM!xXsji~}aU%8tuJ>X|~tOn>E22WQ%mvv4FO#uIMY7qbc literal 0 HcmV?d00001 diff --git a/app/pet/assets/duck_faces.json b/app/pet/assets/duck_faces.json new file mode 100644 index 0000000..f91ff0b --- /dev/null +++ b/app/pet/assets/duck_faces.json @@ -0,0 +1,222 @@ +{ + "frames": [ + { + "filename": "duck_faces normal 0", + "frame": { + "x": 0, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "duck_faces smile 1", + "frame": { + "x": 16, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "duck_faces blink 2", + "frame": { + "x": 32, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "duck_faces happy 3", + "frame": { + "x": 48, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "duck_faces laugh 4", + "frame": { + "x": 64, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "duck_faces sad 5", + "frame": { + "x": 80, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "duck_faces tired 6", + "frame": { + "x": 96, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "duck_faces yawn 7", + "frame": { + "x": 112, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "duck_faces sick 8", + "frame": { + "x": 128, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "duck_faces no 9", + "frame": { + "x": 144, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "duck_faces eat_open 10", + "frame": { + "x": 160, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "duck_faces eat_closed 11", + "frame": { + "x": 176, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "duck_faces sleep 12", + "frame": { + "x": 192, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "duck_faces.png", + "size": { + "w": 208, + "h": 9 + }, + "frameTags": [ + { + "name": "normal", + "from": 0, + "to": 0, + "direction": "forward" + }, + { + "name": "smile", + "from": 1, + "to": 1, + "direction": "forward" + }, + { + "name": "blink", + "from": 2, + "to": 2, + "direction": "forward" + }, + { + "name": "happy", + "from": 3, + "to": 3, + "direction": "forward" + }, + { + "name": "laugh", + "from": 4, + "to": 4, + "direction": "forward" + }, + { + "name": "sad", + "from": 5, + "to": 5, + "direction": "forward" + }, + { + "name": "tired", + "from": 6, + "to": 6, + "direction": "forward" + }, + { + "name": "yawn", + "from": 7, + "to": 7, + "direction": "forward" + }, + { + "name": "sick", + "from": 8, + "to": 8, + "direction": "forward" + }, + { + "name": "no", + "from": 9, + "to": 9, + "direction": "forward" + }, + { + "name": "eat_open", + "from": 10, + "to": 10, + "direction": "forward" + }, + { + "name": "eat_closed", + "from": 11, + "to": 11, + "direction": "forward" + }, + { + "name": "sleep", + "from": 12, + "to": 12, + "direction": "forward" + } + ] + } +} diff --git a/app/pet/assets/duck_faces.png b/app/pet/assets/duck_faces.png new file mode 100644 index 0000000000000000000000000000000000000000..f6d97d56bc3fd5f3098fc4b51b7071e7c29996fe GIT binary patch literal 379 zcmV->0fhdEP)J5~uAJ>2WAE=~jaFzY5J6{FZ#~5ZGAR-d;skld6+221mqN4mg+=fy7pGD8O z${X+7tIXo#eSBTwGbdb4g486#&!o^!>vH^R5+GUk(|6>-rtlm-|HseYUq37f;PbCX Z{zr?uZj6RPixB_-002ovPDHLkV1j*5u`d7s literal 0 HcmV?d00001 diff --git a/app/pet/assets/hippo_baby_body.json b/app/pet/assets/hippo_baby_body.json new file mode 100644 index 0000000..9733b83 --- /dev/null +++ b/app/pet/assets/hippo_baby_body.json @@ -0,0 +1,166 @@ +{ + "frames": [ + { + "filename": "hippo_baby_body idle 0", + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "hippo_baby_body idle 1", + "frame": { + "x": 32, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "hippo_baby_body squash 2", + "frame": { + "x": 64, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "hippo_baby_body stretch 3", + "frame": { + "x": 96, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "hippo_baby_body flat 4", + "frame": { + "x": 128, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "hippo_baby_body sleep 5", + "frame": { + "x": 160, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "hippo_baby_body sleep 6", + "frame": { + "x": 192, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "hippo_baby_body lookout_left 7", + "frame": { + "x": 224, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "hippo_baby_body lookout_left 8", + "frame": { + "x": 256, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "hippo_baby_body lookout_right 9", + "frame": { + "x": 288, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "hippo_baby_body lookout_right 10", + "frame": { + "x": 320, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "hippo_baby_body.png", + "size": { + "w": 352, + "h": 32 + }, + "frameTags": [ + { + "name": "idle", + "from": 0, + "to": 1, + "direction": "forward" + }, + { + "name": "squash", + "from": 2, + "to": 2, + "direction": "forward" + }, + { + "name": "stretch", + "from": 3, + "to": 3, + "direction": "forward" + }, + { + "name": "flat", + "from": 4, + "to": 4, + "direction": "forward" + }, + { + "name": "sleep", + "from": 5, + "to": 6, + "direction": "forward" + }, + { + "name": "lookout_left", + "from": 7, + "to": 8, + "direction": "forward" + }, + { + "name": "lookout_right", + "from": 9, + "to": 10, + "direction": "forward" + } + ] + } +} diff --git a/app/pet/assets/hippo_baby_body.png b/app/pet/assets/hippo_baby_body.png new file mode 100644 index 0000000000000000000000000000000000000000..cf1eb46e51005372c04133585b181c99f16fc6e3 GIT binary patch literal 777 zcmeAS@N?(olHy`uVBq!ia0y~yU`znA6*$;{q>kUBDGUru7d%}YLn>~)ougQA+d;(T zx@@b6^z@dFDJ?TvT4u0VFIci<$&M3C6kJq}sxH*+@bv8P^Z=m_FukJt$;B<5wVU35 zS$etpL~>@@`)~K}Tc0$Z1~i`(utu_9?e)iuP3x+88E$ztvEJppKl}WA6;JU?^^Vbd z&En6nS+MQ9K3`?;)@^06$JzNAeFWdk&`)dT&YYVX{;SmZ+NO$WD!Se3o|on>nSb5> z!@OhiEf?->`)OXu&~dhXiMQ*E&uj*AzSknlmhvAze6~FG$FwxzPWMP zs;mDqXK9@;&Np50tpBydCmVC#`$6}Q)-M+>2>qi{yZ`IG_CKk?Eb(kLe?R3KvxV2n z^L|+W?L)@Z6?L)yYpd_KF>JbWfB8SfYYnOY7s`j-|0&vX`q1io&kO%O`?c=Ywa?$z z#ajXulom&a*$rEYN7@&20&)Uy5C zzRtogvHRcu6<@qBm?6CXa%9=hXSI=Kk}032feqdM&F+fDuXXpo|Lcwg+IZx>J-<|~ zjMd%U6*b@TnwHkd=Dz+JT`iv^Q+xe=_5Y)5-hau!PkD(5DE)c5`njxgN@xNAI<0mG literal 0 HcmV?d00001 diff --git a/app/pet/assets/hippo_baby_faces.json b/app/pet/assets/hippo_baby_faces.json new file mode 100644 index 0000000..626796d --- /dev/null +++ b/app/pet/assets/hippo_baby_faces.json @@ -0,0 +1,222 @@ +{ + "frames": [ + { + "filename": "hippo_baby_faces normal 0", + "frame": { + "x": 0, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "hippo_baby_faces smile 1", + "frame": { + "x": 10, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "hippo_baby_faces blink 2", + "frame": { + "x": 20, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "hippo_baby_faces happy 3", + "frame": { + "x": 30, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "hippo_baby_faces laugh 4", + "frame": { + "x": 40, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "hippo_baby_faces sad 5", + "frame": { + "x": 50, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "hippo_baby_faces tired 6", + "frame": { + "x": 60, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "hippo_baby_faces yawn 7", + "frame": { + "x": 70, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "hippo_baby_faces sick 8", + "frame": { + "x": 80, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "hippo_baby_faces no 9", + "frame": { + "x": 90, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "hippo_baby_faces eat_open 10", + "frame": { + "x": 100, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "hippo_baby_faces eat_closed 11", + "frame": { + "x": 110, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "hippo_baby_faces sleep 12", + "frame": { + "x": 120, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "hippo_baby_faces.png", + "size": { + "w": 130, + "h": 5 + }, + "frameTags": [ + { + "name": "normal", + "from": 0, + "to": 0, + "direction": "forward" + }, + { + "name": "smile", + "from": 1, + "to": 1, + "direction": "forward" + }, + { + "name": "blink", + "from": 2, + "to": 2, + "direction": "forward" + }, + { + "name": "happy", + "from": 3, + "to": 3, + "direction": "forward" + }, + { + "name": "laugh", + "from": 4, + "to": 4, + "direction": "forward" + }, + { + "name": "sad", + "from": 5, + "to": 5, + "direction": "forward" + }, + { + "name": "tired", + "from": 6, + "to": 6, + "direction": "forward" + }, + { + "name": "yawn", + "from": 7, + "to": 7, + "direction": "forward" + }, + { + "name": "sick", + "from": 8, + "to": 8, + "direction": "forward" + }, + { + "name": "no", + "from": 9, + "to": 9, + "direction": "forward" + }, + { + "name": "eat_open", + "from": 10, + "to": 10, + "direction": "forward" + }, + { + "name": "eat_closed", + "from": 11, + "to": 11, + "direction": "forward" + }, + { + "name": "sleep", + "from": 12, + "to": 12, + "direction": "forward" + } + ] + } +} diff --git a/app/pet/assets/hippo_baby_faces.png b/app/pet/assets/hippo_baby_faces.png new file mode 100644 index 0000000000000000000000000000000000000000..d368ca22f580cff5f19c171cf56bd923dc2eb83b GIT binary patch literal 228 zcmVr zox9U3&Ux%;sv5pA5fQopS2|ZCwckU@mtkE8HP-=Es0Qp`r!qq@kZDRciHO z#rCtElt_bAfK&h#z&77x_#%XjwQb48H!(N5exw2bz!%|LCvEelgew!uHs9p|qUWec z|4+H&)(=;|Dj4V=vuRYi*f!4 z2jVx8%lvhncLDY>hSeTKMBaAc)nR9P|7Ri``QM|ZNP-ye-n(S4KUH&B)z*}Toc){b z|6eqbO95QkCqay(2yql4Tr_a+Ki_}u0Q?3w#hK<)kI9GX00000NkvXXu0mjfx$2}D literal 0 HcmV?d00001 diff --git a/app/pet/assets/items.json b/app/pet/assets/items.json index c6c5316..1452b8d 100644 --- a/app/pet/assets/items.json +++ b/app/pet/assets/items.json @@ -509,13 +509,293 @@ "h": 15 }, "duration": 1000 + }, + { + "filename": "items leaf_egg 51", + "frame": { + "x": 560, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 1000 + }, + { + "filename": "items leaf_egg_wobble 52", + "frame": { + "x": 572, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 150 + }, + { + "filename": "items leaf_egg_wobble 53", + "frame": { + "x": 584, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 150 + }, + { + "filename": "items leaf_egg_wobble 54", + "frame": { + "x": 596, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 150 + }, + { + "filename": "items leaf_egg_wobble 55", + "frame": { + "x": 608, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 150 + }, + { + "filename": "items leaf_egg_crack 56", + "frame": { + "x": 620, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 1000 + }, + { + "filename": "items leaf_egg_open 57", + "frame": { + "x": 632, + "y": 0, + "w": 12, + "h": 15 + }, + "duration": 1000 + }, + { + "filename": "items duck_egg 58", + "frame": { + "x": 644, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 1000 + }, + { + "filename": "items duck_egg_wobble 59", + "frame": { + "x": 656, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 150 + }, + { + "filename": "items duck_egg_wobble 60", + "frame": { + "x": 668, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 150 + }, + { + "filename": "items duck_egg_wobble 61", + "frame": { + "x": 680, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 150 + }, + { + "filename": "items duck_egg_wobble 62", + "frame": { + "x": 692, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 150 + }, + { + "filename": "items duck_egg_crack 63", + "frame": { + "x": 704, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 1000 + }, + { + "filename": "items duck_egg_open 64", + "frame": { + "x": 716, + "y": 0, + "w": 12, + "h": 15 + }, + "duration": 1000 + }, + { + "filename": "items hippo_egg 65", + "frame": { + "x": 728, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 1000 + }, + { + "filename": "items hippo_egg_wobble 66", + "frame": { + "x": 740, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 150 + }, + { + "filename": "items hippo_egg_wobble 67", + "frame": { + "x": 752, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 150 + }, + { + "filename": "items hippo_egg_wobble 68", + "frame": { + "x": 764, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 150 + }, + { + "filename": "items hippo_egg_wobble 69", + "frame": { + "x": 776, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 150 + }, + { + "filename": "items hippo_egg_crack 70", + "frame": { + "x": 788, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 1000 + }, + { + "filename": "items hippo_egg_open 71", + "frame": { + "x": 800, + "y": 0, + "w": 12, + "h": 15 + }, + "duration": 1000 + }, + { + "filename": "items beak_egg 72", + "frame": { + "x": 812, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 1000 + }, + { + "filename": "items beak_egg_wobble 73", + "frame": { + "x": 824, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 150 + }, + { + "filename": "items beak_egg_wobble 74", + "frame": { + "x": 836, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 150 + }, + { + "filename": "items beak_egg_wobble 75", + "frame": { + "x": 848, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 150 + }, + { + "filename": "items beak_egg_wobble 76", + "frame": { + "x": 860, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 150 + }, + { + "filename": "items beak_egg_crack 77", + "frame": { + "x": 872, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 1000 + }, + { + "filename": "items beak_egg_open 78", + "frame": { + "x": 884, + "y": 0, + "w": 12, + "h": 15 + }, + "duration": 1000 } ], "meta": { "app": "tools/build_blob_sprites.py", "image": "items.png", "size": { - "w": 560, + "w": 896, "h": 15 }, "frameTags": [ @@ -734,6 +1014,102 @@ "from": 50, "to": 50, "direction": "forward" + }, + { + "name": "leaf_egg", + "from": 51, + "to": 51, + "direction": "forward" + }, + { + "name": "leaf_egg_wobble", + "from": 52, + "to": 55, + "direction": "forward" + }, + { + "name": "leaf_egg_crack", + "from": 56, + "to": 56, + "direction": "forward" + }, + { + "name": "leaf_egg_open", + "from": 57, + "to": 57, + "direction": "forward" + }, + { + "name": "duck_egg", + "from": 58, + "to": 58, + "direction": "forward" + }, + { + "name": "duck_egg_wobble", + "from": 59, + "to": 62, + "direction": "forward" + }, + { + "name": "duck_egg_crack", + "from": 63, + "to": 63, + "direction": "forward" + }, + { + "name": "duck_egg_open", + "from": 64, + "to": 64, + "direction": "forward" + }, + { + "name": "hippo_egg", + "from": 65, + "to": 65, + "direction": "forward" + }, + { + "name": "hippo_egg_wobble", + "from": 66, + "to": 69, + "direction": "forward" + }, + { + "name": "hippo_egg_crack", + "from": 70, + "to": 70, + "direction": "forward" + }, + { + "name": "hippo_egg_open", + "from": 71, + "to": 71, + "direction": "forward" + }, + { + "name": "beak_egg", + "from": 72, + "to": 72, + "direction": "forward" + }, + { + "name": "beak_egg_wobble", + "from": 73, + "to": 76, + "direction": "forward" + }, + { + "name": "beak_egg_crack", + "from": 77, + "to": 77, + "direction": "forward" + }, + { + "name": "beak_egg_open", + "from": 78, + "to": 78, + "direction": "forward" } ] } diff --git a/app/pet/assets/items.png b/app/pet/assets/items.png index 7a8d6f529913ec580d8707848331d5ec94877ea8..e94dd5154a972f7825dc80bd3e3d222ffb9c71ea 100644 GIT binary patch literal 4210 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 Z*Zw$sO!tQx^}hsw?kz*DPa5_S{|8zTfQ$eD literal 2705 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 literal 0 HcmV?d00001 diff --git a/app/pet/assets/leaf_baby_faces.json b/app/pet/assets/leaf_baby_faces.json new file mode 100644 index 0000000..6a2e397 --- /dev/null +++ b/app/pet/assets/leaf_baby_faces.json @@ -0,0 +1,222 @@ +{ + "frames": [ + { + "filename": "leaf_baby_faces normal 0", + "frame": { + "x": 0, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "leaf_baby_faces smile 1", + "frame": { + "x": 10, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "leaf_baby_faces blink 2", + "frame": { + "x": 20, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "leaf_baby_faces happy 3", + "frame": { + "x": 30, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "leaf_baby_faces laugh 4", + "frame": { + "x": 40, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "leaf_baby_faces sad 5", + "frame": { + "x": 50, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "leaf_baby_faces tired 6", + "frame": { + "x": 60, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "leaf_baby_faces yawn 7", + "frame": { + "x": 70, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "leaf_baby_faces sick 8", + "frame": { + "x": 80, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "leaf_baby_faces no 9", + "frame": { + "x": 90, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "leaf_baby_faces eat_open 10", + "frame": { + "x": 100, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "leaf_baby_faces eat_closed 11", + "frame": { + "x": 110, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "leaf_baby_faces sleep 12", + "frame": { + "x": 120, + "y": 0, + "w": 10, + "h": 5 + }, + "duration": 1000 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "leaf_baby_faces.png", + "size": { + "w": 130, + "h": 5 + }, + "frameTags": [ + { + "name": "normal", + "from": 0, + "to": 0, + "direction": "forward" + }, + { + "name": "smile", + "from": 1, + "to": 1, + "direction": "forward" + }, + { + "name": "blink", + "from": 2, + "to": 2, + "direction": "forward" + }, + { + "name": "happy", + "from": 3, + "to": 3, + "direction": "forward" + }, + { + "name": "laugh", + "from": 4, + "to": 4, + "direction": "forward" + }, + { + "name": "sad", + "from": 5, + "to": 5, + "direction": "forward" + }, + { + "name": "tired", + "from": 6, + "to": 6, + "direction": "forward" + }, + { + "name": "yawn", + "from": 7, + "to": 7, + "direction": "forward" + }, + { + "name": "sick", + "from": 8, + "to": 8, + "direction": "forward" + }, + { + "name": "no", + "from": 9, + "to": 9, + "direction": "forward" + }, + { + "name": "eat_open", + "from": 10, + "to": 10, + "direction": "forward" + }, + { + "name": "eat_closed", + "from": 11, + "to": 11, + "direction": "forward" + }, + { + "name": "sleep", + "from": 12, + "to": 12, + "direction": "forward" + } + ] + } +} diff --git a/app/pet/assets/leaf_baby_faces.png b/app/pet/assets/leaf_baby_faces.png new file mode 100644 index 0000000000000000000000000000000000000000..28640b6e77f36dbf5449411aa306d67d67555c96 GIT binary patch literal 229 zcmV^P)wHb*=QsxdcY~hOD=)O3-<@2Mcf3?PI9mkqO?KE zSxG-beig~Hn*adtoyx&-iyZwU@(;cBG*z8UP4mx zdg$N3PAS56pKm{<(w;8S+;QuNt6v=q)E_U1ODCJ=xx(GA2PZpjiWd?X51%m#2~0-LSNwcCdlUA!I<<;d z<151LvL`QyaX#-U8$Y*xxcX^1fzlmX))$~9O=L5FUFU6peT-qf0}+w4SvpPF>0bYp2uuF=_}9l^=p%33C42R&o5Q-cx-{gh z-**3hViVaEz^1($`bee=B+~_KY~bF1zW>|?SOpIU`q9y^7JkwI0000p)p7WgZ zRN%1ZEX?bKT@5{ZI;KFlcJagb*CDnBjwdlG z!Xh^7FzbqGg%g^16G@UBN`sk20Md(<-@T?Zg5YF>9ijnJ0!0i)^*` zpwzX($u5!YTFm0zGk;c(>+*I3Lq#rFrX8M`OB_UY7V7h6fLK|Z1^Fj9W=?@=qg?P~ ztJ|l!$ira5&!YJ<>GI>ZS0%oWFXF-z0hCfzoBgCK*zcsTG5PIkwN>Ei=(S*|R|R^& zz{mi5)IGb&z=ldqs8w+%3aQhPUClybj5I&Sl)7x2x@k&FGPhCNsP|XX%4Bz@!K;B~ z)FlGTz(8KH`IhH$(U`@_f zgFVR3mpkP39796J6Ibz5^{oH2<@ZI=<^=aSFqzIORbruZb-<@S z3;+~fJYK|1NC*@xS^?nSIIt6-@&*j{xHyx*65}nSeK6;tt&)1SA*dX~Sgi5YjoJfo z0ai$<&mGu7IA#Z`rs=`BO?(Rk(~$EJe*>@3As#@Su#b9fV;`23%F$E({^SxRHf<>1 z9frxm@O54SbdCj1+0rRyt^grf;3-97BT2fSs&Zb?5G();t1t|)gitS7UxQdFcC}wOf^u&dne^WbTeovPTdI*btShQ3Tkg=UBd`>s7lbm@k~;p9$&L|GsYOuX@(*ong)Co9%Zp zaRE=H|5}>%9o^!Ji(K|GZgWgRdllKN?YuJkB4JlNKwm^xFO;=d5d z&(YdA{y(60LCZfLF%Dm=DlmleDVj&rGVPnas3y>#`kUuaL>J|h+H3hivq)t~CQ;RF zKedAXQgqVj@b2~Y@hEOh8&J6qcRP@9>+v7*u}Q*jf$v#+$@pjFyQAC3(PSfZJ}RbO Uk35sN^M-)XAne)hGl?bt27(f88~^|S literal 0 HcmV?d00001 diff --git a/app/pet/assets/lillypot_faces.json b/app/pet/assets/lillypot_faces.json new file mode 100644 index 0000000..5c752cc --- /dev/null +++ b/app/pet/assets/lillypot_faces.json @@ -0,0 +1,222 @@ +{ + "frames": [ + { + "filename": "lillypot_faces normal 0", + "frame": { + "x": 0, + "y": 0, + "w": 13, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "lillypot_faces smile 1", + "frame": { + "x": 13, + "y": 0, + "w": 13, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "lillypot_faces blink 2", + "frame": { + "x": 26, + "y": 0, + "w": 13, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "lillypot_faces happy 3", + "frame": { + "x": 39, + "y": 0, + "w": 13, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "lillypot_faces laugh 4", + "frame": { + "x": 52, + "y": 0, + "w": 13, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "lillypot_faces sad 5", + "frame": { + "x": 65, + "y": 0, + "w": 13, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "lillypot_faces tired 6", + "frame": { + "x": 78, + "y": 0, + "w": 13, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "lillypot_faces yawn 7", + "frame": { + "x": 91, + "y": 0, + "w": 13, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "lillypot_faces sick 8", + "frame": { + "x": 104, + "y": 0, + "w": 13, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "lillypot_faces no 9", + "frame": { + "x": 117, + "y": 0, + "w": 13, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "lillypot_faces eat_open 10", + "frame": { + "x": 130, + "y": 0, + "w": 13, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "lillypot_faces eat_closed 11", + "frame": { + "x": 143, + "y": 0, + "w": 13, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "lillypot_faces sleep 12", + "frame": { + "x": 156, + "y": 0, + "w": 13, + "h": 8 + }, + "duration": 1000 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "lillypot_faces.png", + "size": { + "w": 169, + "h": 8 + }, + "frameTags": [ + { + "name": "normal", + "from": 0, + "to": 0, + "direction": "forward" + }, + { + "name": "smile", + "from": 1, + "to": 1, + "direction": "forward" + }, + { + "name": "blink", + "from": 2, + "to": 2, + "direction": "forward" + }, + { + "name": "happy", + "from": 3, + "to": 3, + "direction": "forward" + }, + { + "name": "laugh", + "from": 4, + "to": 4, + "direction": "forward" + }, + { + "name": "sad", + "from": 5, + "to": 5, + "direction": "forward" + }, + { + "name": "tired", + "from": 6, + "to": 6, + "direction": "forward" + }, + { + "name": "yawn", + "from": 7, + "to": 7, + "direction": "forward" + }, + { + "name": "sick", + "from": 8, + "to": 8, + "direction": "forward" + }, + { + "name": "no", + "from": 9, + "to": 9, + "direction": "forward" + }, + { + "name": "eat_open", + "from": 10, + "to": 10, + "direction": "forward" + }, + { + "name": "eat_closed", + "from": 11, + "to": 11, + "direction": "forward" + }, + { + "name": "sleep", + "from": 12, + "to": 12, + "direction": "forward" + } + ] + } +} diff --git a/app/pet/assets/lillypot_faces.png b/app/pet/assets/lillypot_faces.png new file mode 100644 index 0000000000000000000000000000000000000000..7f8f1d97a1ae5b0aefe03fccca0f24ae1fc1e4b9 GIT binary patch literal 374 zcmV-+0g3*JP)6NN!WVUQ6R#yA(voMG$pQ0~M1_C1g7Wv)9t>WVbV zv3=PfI?Z>Q#yA(vlmI=yJ}6sGs(IXQ0D#iy%P;4&ChG3QadmO~V_BEi=ju0ZUz#z` z?5;?od}j_WJ9XKQQ%C_A1I4+vZsOn3^M9#IM-Aa z06?l)EMw)epjCA?7y=WwFU^!k#5M;*^EAzx*ODB-!^6YF!^7j>p-c)Ist;Mik7N## z{wed8erL|!{sPJrhP$VGB@Or7G-XoI>i7fzaP$6Vr7M$yx;|ceZ}yLfbgw3S0`ZY} Ui{1jdw*UYD07*qoM6N<$g580v8vp9EZLV@503)y7YWUyesVxX)+tCkI#w^$4suu!H@ECvZnnPS<$ zV7Bbzdpu^C_xnD0_Y`$tIPaZ%@40sv1b{#w5C{YUfj}S-2m}IwKp+qZ1OkCTAP@)y z0)aq4MSeHUNd*FdK=5q5pC>nY{^uko6DDBgAmtvi4ip4@6DB37@Ufcz=gAFv{qMRC zi7xqKHiy>FIV>(a(CT#{IU6JxA^-piHwGHL=30=CCT)1VdS81^Hd{uaMa;&FU3;rF zAl3ao>5%MV5JC}uC8A?)X1qs}HUI#OyCb+xZ=e=|cSBlZ`6-$MXK?a4HM-+8wW zIwZRq1gr)inm+(IT|=YS%$f0aTP;Wzi>=QecSmq~e+kQ{%xN4j4G5FJDE_W<0JHY0 zn!oP>VBd5|b}0y+-VKXXoUmi9ljedQoUF>D#N0asjPovk&`D3E^vWd@&f7q!*bJzg!bw%zf^B;FdTRY&m zJK9)J5w{G)b96edxF)t29rHb!w1MeRrgfPC>FhrgewFx}w|61Ju*k-<%1{8_``ij4p10mF&i{`H~0K}|AErcM1(g19lzwTvNHd`jV z9#w`?^*GyW)zpDyK%wxvh`($Ogk*ra&0lu_h+T(TC_%sy-cpug`unY*3-(~z& zav&4~)NTHz13;`glrDt-2#yI_`;0N&xXWe8MwvUG8_A4l3qrV?DCk^IYs4 z)6XCmt)t9W}#S^4DY%Mz#YLbskml-KXd>wTi#Ye5<-}Hd`i-gXiRN z@Lb4k@*eE#)jOmYX_8)~iAo}SL4LXMnn15tef1bU4NL_ki@#}B{0P6k$09AVi z8ydvUAA9}9$bV3@2tKjI0yjA>3rv1h4wZ9UtfA;!pW3UQNBm*uKk@tJKPVcN&j9kf z{-L$;`&afCvfuC0cR{iEU2tRXA6t8sb;Qmed;P`8UwRX+>@rv9cO78zt8ioQA6t7D z8pO^Yd;P`4U-@2?75CTteq1bmTin?D$JSnV9kKJrUVkz1OMOkA2~58Z5R2c|olwmE zV{31+j@bEQuRr4dkMrYpetz7}+3!`)70)pRCcg?d_WrT8cd?Gx`D3rY82JAIe**ic T5Bm8600000NkvXXu0mjfreBfR literal 0 HcmV?d00001 diff --git a/app/pet/assets/needlenub_faces.json b/app/pet/assets/needlenub_faces.json new file mode 100644 index 0000000..37d130c --- /dev/null +++ b/app/pet/assets/needlenub_faces.json @@ -0,0 +1,222 @@ +{ + "frames": [ + { + "filename": "needlenub_faces normal 0", + "frame": { + "x": 0, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "needlenub_faces smile 1", + "frame": { + "x": 13, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "needlenub_faces blink 2", + "frame": { + "x": 26, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "needlenub_faces happy 3", + "frame": { + "x": 39, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "needlenub_faces laugh 4", + "frame": { + "x": 52, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "needlenub_faces sad 5", + "frame": { + "x": 65, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "needlenub_faces tired 6", + "frame": { + "x": 78, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "needlenub_faces yawn 7", + "frame": { + "x": 91, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "needlenub_faces sick 8", + "frame": { + "x": 104, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "needlenub_faces no 9", + "frame": { + "x": 117, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "needlenub_faces eat_open 10", + "frame": { + "x": 130, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "needlenub_faces eat_closed 11", + "frame": { + "x": 143, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "needlenub_faces sleep 12", + "frame": { + "x": 156, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "needlenub_faces.png", + "size": { + "w": 169, + "h": 5 + }, + "frameTags": [ + { + "name": "normal", + "from": 0, + "to": 0, + "direction": "forward" + }, + { + "name": "smile", + "from": 1, + "to": 1, + "direction": "forward" + }, + { + "name": "blink", + "from": 2, + "to": 2, + "direction": "forward" + }, + { + "name": "happy", + "from": 3, + "to": 3, + "direction": "forward" + }, + { + "name": "laugh", + "from": 4, + "to": 4, + "direction": "forward" + }, + { + "name": "sad", + "from": 5, + "to": 5, + "direction": "forward" + }, + { + "name": "tired", + "from": 6, + "to": 6, + "direction": "forward" + }, + { + "name": "yawn", + "from": 7, + "to": 7, + "direction": "forward" + }, + { + "name": "sick", + "from": 8, + "to": 8, + "direction": "forward" + }, + { + "name": "no", + "from": 9, + "to": 9, + "direction": "forward" + }, + { + "name": "eat_open", + "from": 10, + "to": 10, + "direction": "forward" + }, + { + "name": "eat_closed", + "from": 11, + "to": 11, + "direction": "forward" + }, + { + "name": "sleep", + "from": 12, + "to": 12, + "direction": "forward" + } + ] + } +} diff --git a/app/pet/assets/needlenub_faces.png b/app/pet/assets/needlenub_faces.png new file mode 100644 index 0000000000000000000000000000000000000000..7a921921b6e6807cc0fd8fee5a806fc544bf2685 GIT binary patch literal 367 zcmV-#0g(QQP)o1N5Pdh(pE$%-$0mY^DE^>-fIuNodXKxvNXCl5LWlWqLJnJ{=rprl z5v57z9(+9Y@yBUMDKF@Jc`*%CgHc`(0Jw6*cp%zeAQyfOqr9NreE3x-V?}Ka$Bv`d z&vP9)VmuH&2E9#|SBJoa-HUU}60z}Acb}%a=DEupbhlRaUBq+arVE_IAM5SySnvIp z@Hi)AZGREMGz_Pe{fZ8iBQr${WB`B{tgLu4Q`FS){9l{>5^?p_6d&|sYp?02_-_CJ N002ovPDHLkV1hcDr<(u( literal 0 HcmV?d00001 diff --git a/app/pet/assets/paddlet_body.json b/app/pet/assets/paddlet_body.json new file mode 100644 index 0000000..9f45a5c --- /dev/null +++ b/app/pet/assets/paddlet_body.json @@ -0,0 +1,168 @@ +{ + "frames": [ + { + "filename": "paddlet_body idle 0", + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "paddlet_body idle 1", + "frame": { + "x": 32, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "paddlet_body squash 2", + "frame": { + "x": 64, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "paddlet_body stretch 3", + "frame": { + "x": 96, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "paddlet_body flat 4", + "frame": { + "x": 128, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "paddlet_body sleep 5", + "frame": { + "x": 160, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "paddlet_body sleep 6", + "frame": { + "x": 192, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "paddlet_body lookout_left 7", + "frame": { + "x": 224, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "paddlet_body lookout_left 8", + "frame": { + "x": 256, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "paddlet_body lookout_right 9", + "frame": { + "x": 288, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "paddlet_body lookout_right 10", + "frame": { + "x": 320, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "paddlet_body.png", + "size": { + "w": 352, + "h": 32 + }, + "frameTags": [ + { + "name": "idle", + "from": 0, + "to": 1, + "direction": "forward" + }, + { + "name": "squash", + "from": 2, + "to": 2, + "direction": "forward" + }, + { + "name": "stretch", + "from": 3, + "to": 3, + "direction": "forward" + }, + { + "name": "flat", + "from": 4, + "to": 4, + "direction": "forward" + }, + { + "name": "sleep", + "from": 5, + "to": 6, + "direction": "forward" + }, + { + "name": "lookout_left", + "from": 7, + "to": 8, + "direction": "forward" + }, + { + "name": "lookout_right", + "from": 9, + "to": 10, + "direction": "forward" + } + ], + "faceTop": 2, + "faceShift": -0.5 + } +} diff --git a/app/pet/assets/paddlet_body.png b/app/pet/assets/paddlet_body.png new file mode 100644 index 0000000000000000000000000000000000000000..80cdb5ea72fed5e1f23dcf3face70fe9121cb128 GIT binary patch literal 1026 zcmV+d1pWJoP)s7=`cVM5O|Q!NkO@X+;hHpa={G6N9RV20=s-sR$z2R#agy2vi09g2o`g#6*C` zL==&Vt;h*Y(j=SRoteA4b03v2a%b-QHM<86fDl3mA%qY@2qAr13(#k2uz7z^+#Y8|3j}HeK>gz zTo&JK@NEx()5EQ3S>s*B^I(YYS1(p$!E8Wm{bliXaR^}5-n!vGOZ%+vqz9DAhoERd z@NEFhHQ$)V>#7N}8c<&J89BhJy`;n6X6}{IhoC4y$io0w*8Blj8vt{@4^I;Ryo-}C z>nenyzbgLDa=>xzr5*mZ>c5OWRBegZ!vYMz6@Hb2XyhshH_ZVJF*1ImMbmiQaX0YdGW82-j#!(tx({bkm69){zH&8}Vo7U{UJNH~oss1Y~W#2-@1e^yPtn`ju60yzU$W0RHTB zFc=+Vew-AheiCi={@LE!@W6L{-|NpO{b1D;==`_^01OBBXoMf%-b?cw04^`uNOBL3 zrJqzA0CoSfFub2)$^+l^eXl>?^eb_TSuFOf&y&K`-{ia5`)7M^(*xi2eXlzmYO@1N~`nsxZD?|c3ErXPDbc68iLHBHhS{qv-sMVq~U zw)ZC1;k&-?_2-NJM)#utV0Iy!aCy;wn>1m!2kdN literal 0 HcmV?d00001 diff --git a/app/pet/assets/parcelbeak_body.json b/app/pet/assets/parcelbeak_body.json new file mode 100644 index 0000000..71eebb6 --- /dev/null +++ b/app/pet/assets/parcelbeak_body.json @@ -0,0 +1,214 @@ +{ + "frames": [ + { + "filename": "parcelbeak_body idle 0", + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "parcelbeak_body idle 1", + "frame": { + "x": 32, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "parcelbeak_body squash 2", + "frame": { + "x": 64, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "parcelbeak_body stretch 3", + "frame": { + "x": 96, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "parcelbeak_body flat 4", + "frame": { + "x": 128, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "parcelbeak_body sleep 5", + "frame": { + "x": 160, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "parcelbeak_body sleep 6", + "frame": { + "x": 192, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "parcelbeak_body lookout_left 7", + "frame": { + "x": 224, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "parcelbeak_body lookout_left 8", + "frame": { + "x": 256, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "parcelbeak_body lookout_right 9", + "frame": { + "x": 288, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "parcelbeak_body lookout_right 10", + "frame": { + "x": 320, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "parcelbeak_body walk 11", + "frame": { + "x": 352, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 220 + }, + { + "filename": "parcelbeak_body walk 12", + "frame": { + "x": 384, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 130 + }, + { + "filename": "parcelbeak_body walk 13", + "frame": { + "x": 416, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 220 + }, + { + "filename": "parcelbeak_body walk 14", + "frame": { + "x": 448, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 130 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "parcelbeak_body.png", + "size": { + "w": 480, + "h": 32 + }, + "frameTags": [ + { + "name": "idle", + "from": 0, + "to": 1, + "direction": "forward" + }, + { + "name": "squash", + "from": 2, + "to": 2, + "direction": "forward" + }, + { + "name": "stretch", + "from": 3, + "to": 3, + "direction": "forward" + }, + { + "name": "flat", + "from": 4, + "to": 4, + "direction": "forward" + }, + { + "name": "sleep", + "from": 5, + "to": 6, + "direction": "forward" + }, + { + "name": "lookout_left", + "from": 7, + "to": 8, + "direction": "forward" + }, + { + "name": "lookout_right", + "from": 9, + "to": 10, + "direction": "forward" + }, + { + "name": "walk", + "from": 11, + "to": 14, + "direction": "forward" + } + ], + "faceTop": 4, + "faceShift": 1.0 + } +} diff --git a/app/pet/assets/parcelbeak_body.png b/app/pet/assets/parcelbeak_body.png new file mode 100644 index 0000000000000000000000000000000000000000..b958d9df0baf81105b1cc84ce9f6814cb2cbb753 GIT binary patch literal 1876 zcmZuyX;@Q-61_=~%f1Fe0Ta}!)YkRMQWS2WAOVFSAfd8^O%|1X2{phC^(lf#eIjKE z8tR51BJx0>DFh^fU{U(S5|$8%5OzWU2}`(XZ2!LVW4`${XXebAZ?Zkyoi){r)c^p{ zbRju<0sv}Mk(;R~D`NM_Cj|finz%UHd#4W02kcKWan`x}M&Hw(l#Ou=i&Ks;!{Dyn zZfr&GF^nXU;)!bhIvDV%W0~~>?lwK$IHHrQ(s><}x}(`nw1ukbV^W*J>)BFrIlH;J z_)Y;$WDBiNPlj{W2gE~?0c9Qi{|~G%M44C~s#X0J54y`rc>!a1 zS6L>OV7DInBsK;u+G&Q9F-3&?%KlTf`GfbXA%U>f?MHuJfDWT??Sc)ivKG)_{&eZW zyZO96nr&^qkM8=U8smh@p_x~{%-+-^ms7s(%QzUWQL8c){So`W2Ss(}$Mc?_2=Ygg zm&gH_;pWMlbv#IwKqkYAh$qUB?j|)InW#Eb#rr)TIZ6@ zWcZu43T5weh`6fUwRS^>9@vHyN&3G;9UYI|_gTsX)`9-JEVn|^wHZGr;xO`LoN!WU zaIU#hsO<%~nx-zYuktOWJT5g~nD|C?J*szml~4c$I2g^B`P1aGH(Q??vK1smX2$@1 zMM$Os8+h=5Y?#;7)M<&7e3ph{0GyBJ+he6;hWGj@75@I;8Ep^GNZELV;oApffJO1L zu(OKMoOdJLfA1ojrO#F$4mE*qIx`L!5FSnFdjENc_VrG%&l(%;xKB$u?iX8)FH8gg zqqP3a_niMy+jj;hgFy!9jfzdvN|^@l1#Gf@&?YlZKPY@F>KZgRxcsfwfzip<1=o@2 zG3^IybGP9C0OmQ(wV=|eUSL>>J0|c!lFu{pfn+WLxT#Le#)$F1XY;qAA~A4J7%Dia zh|QS#WU%s!qUEq8@O**p#ey$A@(A6Phw6W}OIncZjW6$_H2V~!O*<2r&i2Dd#WFQT zjr#|^IHjS&h~r+Px}gJ>FZyv8{6|zJ{SVgSx(HrZ`1&u))N_g+wfBex^gs|u_RAi2lsPfA!_i46YMAKE!&g6i0r8BW3N|Bo zLFCqgOIHdlW>{|(c0p$}<5mL`G+i~OeQ6&3cNa;fFEEOu#4W{OV6#^d?ua+q%&n!n zFQ9(fdG!Mk;sRZmhxQPTDyt@hOd2vQ7yDIkIz#xjklbLmPHi6A zY*tEzwBf+?_m`$%{T;Au1+`mya2Ng_Yun&zYzbUxT*IeNZ+Ow}MSM70JK{Ne?YU(z z>+d5wW+mmlBm|YVn!5)NJ#MY>=Iue_?>=)6+>4_$vB)CyEVk;{#={Z^-seKO#-j=& z)@Pl8^+3CSJhcZg?oiDYVqe@))9||zU(&Ub8KTxUAvh}cw&;zya_G3YHLkG*b#W$( zwskVH;iaeTA?m5i&HT&t2-MVgb{!I9V~F!UDj&NvI`WH8%b78ZF6;4mgCW z)HYV5lE>*5phT;&LZ%5sn>*Y;#)bu(WLbp#d!KV0q;Z!7WKfYtKIvZ12`oDgdhDs> zv=9C9^}A_7pOsa{0x$GwJ5AmqWvx*MIGkt5{h^DO)Pw6Vg5Qilr`e_5$nvYBuXD70 z<|-uMqir6dd z`7Q4Z!xTxb?#X5yTkSi%$mfW+_97I=gkC1t)%gv2$pUeb#BZ0&-~L|NOg2QfD841& M;^gjF?GW_iU-xyFZU6uP literal 0 HcmV?d00001 diff --git a/app/pet/assets/parcelbeak_faces.json b/app/pet/assets/parcelbeak_faces.json new file mode 100644 index 0000000..329def3 --- /dev/null +++ b/app/pet/assets/parcelbeak_faces.json @@ -0,0 +1,222 @@ +{ + "frames": [ + { + "filename": "parcelbeak_faces normal 0", + "frame": { + "x": 0, + "y": 0, + "w": 12, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "parcelbeak_faces smile 1", + "frame": { + "x": 12, + "y": 0, + "w": 12, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "parcelbeak_faces blink 2", + "frame": { + "x": 24, + "y": 0, + "w": 12, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "parcelbeak_faces happy 3", + "frame": { + "x": 36, + "y": 0, + "w": 12, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "parcelbeak_faces laugh 4", + "frame": { + "x": 48, + "y": 0, + "w": 12, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "parcelbeak_faces sad 5", + "frame": { + "x": 60, + "y": 0, + "w": 12, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "parcelbeak_faces tired 6", + "frame": { + "x": 72, + "y": 0, + "w": 12, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "parcelbeak_faces yawn 7", + "frame": { + "x": 84, + "y": 0, + "w": 12, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "parcelbeak_faces sick 8", + "frame": { + "x": 96, + "y": 0, + "w": 12, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "parcelbeak_faces no 9", + "frame": { + "x": 108, + "y": 0, + "w": 12, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "parcelbeak_faces eat_open 10", + "frame": { + "x": 120, + "y": 0, + "w": 12, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "parcelbeak_faces eat_closed 11", + "frame": { + "x": 132, + "y": 0, + "w": 12, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "parcelbeak_faces sleep 12", + "frame": { + "x": 144, + "y": 0, + "w": 12, + "h": 3 + }, + "duration": 1000 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "parcelbeak_faces.png", + "size": { + "w": 156, + "h": 3 + }, + "frameTags": [ + { + "name": "normal", + "from": 0, + "to": 0, + "direction": "forward" + }, + { + "name": "smile", + "from": 1, + "to": 1, + "direction": "forward" + }, + { + "name": "blink", + "from": 2, + "to": 2, + "direction": "forward" + }, + { + "name": "happy", + "from": 3, + "to": 3, + "direction": "forward" + }, + { + "name": "laugh", + "from": 4, + "to": 4, + "direction": "forward" + }, + { + "name": "sad", + "from": 5, + "to": 5, + "direction": "forward" + }, + { + "name": "tired", + "from": 6, + "to": 6, + "direction": "forward" + }, + { + "name": "yawn", + "from": 7, + "to": 7, + "direction": "forward" + }, + { + "name": "sick", + "from": 8, + "to": 8, + "direction": "forward" + }, + { + "name": "no", + "from": 9, + "to": 9, + "direction": "forward" + }, + { + "name": "eat_open", + "from": 10, + "to": 10, + "direction": "forward" + }, + { + "name": "eat_closed", + "from": 11, + "to": 11, + "direction": "forward" + }, + { + "name": "sleep", + "from": 12, + "to": 12, + "direction": "forward" + } + ] + } +} diff --git a/app/pet/assets/parcelbeak_faces.png b/app/pet/assets/parcelbeak_faces.png new file mode 100644 index 0000000000000000000000000000000000000000..b4c8edde1c1b6caf6b2b21e1a335157e55aaf9f1 GIT binary patch literal 252 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 literal 0 HcmV?d00001 diff --git a/app/pet/assets/sproutlet_body.json b/app/pet/assets/sproutlet_body.json new file mode 100644 index 0000000..bbb32cf --- /dev/null +++ b/app/pet/assets/sproutlet_body.json @@ -0,0 +1,168 @@ +{ + "frames": [ + { + "filename": "sproutlet_body idle 0", + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "sproutlet_body idle 1", + "frame": { + "x": 32, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "sproutlet_body squash 2", + "frame": { + "x": 64, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "sproutlet_body stretch 3", + "frame": { + "x": 96, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "sproutlet_body flat 4", + "frame": { + "x": 128, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "sproutlet_body sleep 5", + "frame": { + "x": 160, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "sproutlet_body sleep 6", + "frame": { + "x": 192, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "sproutlet_body lookout_left 7", + "frame": { + "x": 224, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "sproutlet_body lookout_left 8", + "frame": { + "x": 256, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "sproutlet_body lookout_right 9", + "frame": { + "x": 288, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "sproutlet_body lookout_right 10", + "frame": { + "x": 320, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "sproutlet_body.png", + "size": { + "w": 352, + "h": 32 + }, + "frameTags": [ + { + "name": "idle", + "from": 0, + "to": 1, + "direction": "forward" + }, + { + "name": "squash", + "from": 2, + "to": 2, + "direction": "forward" + }, + { + "name": "stretch", + "from": 3, + "to": 3, + "direction": "forward" + }, + { + "name": "flat", + "from": 4, + "to": 4, + "direction": "forward" + }, + { + "name": "sleep", + "from": 5, + "to": 6, + "direction": "forward" + }, + { + "name": "lookout_left", + "from": 7, + "to": 8, + "direction": "forward" + }, + { + "name": "lookout_right", + "from": 9, + "to": 10, + "direction": "forward" + } + ], + "faceTop": 10, + "faceShift": -0.5 + } +} diff --git a/app/pet/assets/sproutlet_body.png b/app/pet/assets/sproutlet_body.png new file mode 100644 index 0000000000000000000000000000000000000000..ff86e3e71f900b11f09d549637aa7adf5b0472ad GIT binary patch literal 1081 zcmV-91jhS`P)6n=6h^@(` z;m9TT=k3nk?Tku(IWo61@6Fpyf(Stn1VIo4K@bE%5ClOG1VIo4K@bE%5ClOG1VIo4 zK@fd|p#=TM{hw>Q{rv9poW2qS1DMbZ*mAIzgO?#pa0AdU9Sltf-_)0v-;$=Y54xT` zoLUjtyjGyNo*uCAT@C*bHvoOq!3@QOArFA<5YFbAJl$ocN_U2D9H$>2y|-`p7q9u+ z01Q*AyCy%nI+njr%lDkw z!ng`GWB{S~>-g`p29N<5((oUW4yJD=_!fU(`0r{u?ZzvD_xgM)A|hG7lw^AR;jxIw z{AaEj#OMGDApj5g@1q9Ly;o=WyV?K@T?f-g6Ho(SSNOXe0BJI@yMnh)5W5IrL;!^p zfK~px-UOg}Z{P6uu>pud2h$f5LKy(Q!oLXLCc(S?Tr-5x0Tc?q@8OT^y}HBS^#)+* zI+)N+2w?!!4Sy}($>r2uuf{6(J|C}S@tm7J22kIQo|-j)?7cd}-`56U=sK8?O+XKT zL*egg08B2Y_RIGRIh&*+BJ%C^vDN$Jzm}4}E;|P>B7j2Ruj9Xq8bJ1*=J4;j0f<2d z6RHX50njA;H3z_U__hsRtq?{9Pzd}@{nx4ibnj^m|E{$ciw>izKbk(IYUJ{|Y%G4V z8cUWhH-%j;^g7RzlOst^j%-u$%i&-C%ym~YmakbiuWcIw8sV#b^sD;pxnk{|){o?G z;=hX;K=q#X@SmP;bh2$iI0hX?p_+gcze)JJ7yxg19z^(}0tm_9#(%9E2&MPX!#^e+ zMxmJyg7{kD-}VH6E`C%1g}|@vf14UW1|WL)$EL$5R1*;5YlpwaF$@880HOF@_}`=k z7SFl)DnD#`GxN?}@V|(__zMrxo0)0`HTf*M;MYW}&ww?_k<+Is|688RTmA@LKZ+Y2 zKxlp!{`aj0$nTebBm@yq01Yhw31S~Uxh&YW?}OymY*ys@(b~6tzu5U>@4wjiKkR_l zM>JbHx^*IN@>@V8zZN%o{b=pm-bd{GvG-q${G&rR(WwB}UwkzE@(IbW#f@G+TKl&5 z5j%hE{TCbm!QUl{h!p>kG9Rz@5|*#)`mH~bzbQ9*{b=pA?<02p*!z$CYusMU?Cr(O z7LWH`SH4~YNdCIq==GzucXc1J^T*zQG4THbHn`95NTIjwK literal 0 HcmV?d00001 diff --git a/app/pet/assets/steamo_body.json b/app/pet/assets/steamo_body.json new file mode 100644 index 0000000..180c524 --- /dev/null +++ b/app/pet/assets/steamo_body.json @@ -0,0 +1,214 @@ +{ + "frames": [ + { + "filename": "steamo_body idle 0", + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "steamo_body idle 1", + "frame": { + "x": 32, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "steamo_body squash 2", + "frame": { + "x": 64, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "steamo_body stretch 3", + "frame": { + "x": 96, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "steamo_body flat 4", + "frame": { + "x": 128, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "steamo_body sleep 5", + "frame": { + "x": 160, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "steamo_body sleep 6", + "frame": { + "x": 192, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "steamo_body lookout_left 7", + "frame": { + "x": 224, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "steamo_body lookout_left 8", + "frame": { + "x": 256, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "steamo_body lookout_right 9", + "frame": { + "x": 288, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "steamo_body lookout_right 10", + "frame": { + "x": 320, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "steamo_body walk 11", + "frame": { + "x": 352, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 240 + }, + { + "filename": "steamo_body walk 12", + "frame": { + "x": 384, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 140 + }, + { + "filename": "steamo_body walk 13", + "frame": { + "x": 416, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 240 + }, + { + "filename": "steamo_body walk 14", + "frame": { + "x": 448, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 140 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "steamo_body.png", + "size": { + "w": 480, + "h": 32 + }, + "frameTags": [ + { + "name": "idle", + "from": 0, + "to": 1, + "direction": "forward" + }, + { + "name": "squash", + "from": 2, + "to": 2, + "direction": "forward" + }, + { + "name": "stretch", + "from": 3, + "to": 3, + "direction": "forward" + }, + { + "name": "flat", + "from": 4, + "to": 4, + "direction": "forward" + }, + { + "name": "sleep", + "from": 5, + "to": 6, + "direction": "forward" + }, + { + "name": "lookout_left", + "from": 7, + "to": 8, + "direction": "forward" + }, + { + "name": "lookout_right", + "from": 9, + "to": 10, + "direction": "forward" + }, + { + "name": "walk", + "from": 11, + "to": 14, + "direction": "forward" + } + ], + "faceTop": 7, + "faceShift": 0.5 + } +} diff --git a/app/pet/assets/steamo_body.png b/app/pet/assets/steamo_body.png new file mode 100644 index 0000000000000000000000000000000000000000..6096faf57baaee33b2cbfd31c350c8ebec5c116e GIT binary patch literal 1640 zcmaJ>c~sI_6#f|nVUk&zrMaYxP1CqkN=ge;w9m42GS+lk5F_n(vpiZ}9Q@|1 zCnmPb{U_!Gt;HI{&!y*#jJ$c`Y7d#MF^W>?OcLHA-xR?b_$-yaR~9O($QYgZ?R z$im+z3w<_MRdK08o%CUfY#=AYSn&VP;9PUJm*-Oqnq?@e+#{ZNA$>Q2*|sS!l4t?| zf0RS4Cyup7%2(cpuDYuH(Ca&j)KD&dOmcQRCIL8Wwd6=3Zos^jn@ZBPG?37A(8$N~ zi{as)k}2e^tn7dXMFhU0Jw9K?E+Payz{+HHZJ#2>Nygku4x%aUTHt{cvRcO3ao?50PY+EO!1aiz zbceY2bbf85@H@HE8y~TviqSkC-GRr*l_=TUDj~IJc5d6i?8Wrm+UefQfB*XMng?y- z-7V|5B+SQ6d5K3`6@lU8gXn1K;im`srdX?8J~1DetK|Vv{S4V+HN_^I0i`;Xm5q0j zb(~lj{bW~qetZ%pAJ;g)%8wUi|GZfq8fu&AiBjtOGfYTLA@Q^8?SL?4x{D4`A1&F8 z6DvDxM$FYYw&-OTqUW6KB_%Lwj~G%L-8dRyX^7Q2TUh8$>NS%>_pVCjeT|ic#T$bA zQ43eZ;B?Peh?CQfyE!6A*P0S!$X33Vpy648vYP1jf@#xTOF)j=5pI zkDBV&6|={2Kao)vagsZOak6;_mvyToxWAT^#)0^KfLMa^GxKlT(mxeK2F^LiC+K~( zrAh%`7WD>z`Em};d7IbTlT^;$R&)6#w7+OBX@jGywo*e}1@^R}_Ke=01m>eAqSG4c zqib{sIVCiE7jo9e#UuOu#%>Zn0cXp=fcP9wE1ntoz%?Qvq6LPW~m5y z%$Y?Hx=E|B>KEjGpRym}v+Nt3?*mP%u^zYY{)|}UT@VwB+U;}VntN)jrz2GFqF@J_ z`Me9?zTay^&f0$eSxTbf z28~ADxJJLpO}CPl^gAKvp=Z=ouxVHmq}0jggg zz>OH1HrKwXIZL{njI~XICQe(HJgyQRaSN@OJ=CH=HoKHbGPY$E7aj;@GiA31N0Dr? z3Zj?xau82jnJ{x&?)AwXs2h%E&V3Z=cZplzs>1QyKKBnAr;P+r{AL43sI#f|QB;s7 zDy}xhA8Dy?W)088zsQiCMwn)g#iV_O6?}s|(Z^|c(s~otBurcQn0AJZXOj0EyCk43 zUik6}ufz2YaZu?cIawr}(SlOA$09lp3M*mxumn&0I^v_5cA~CjqL7iL#hnZg(-p~9 z|8?-fMvyCDkshZvZ-BGe&(0#FvD3eu`tqm9E9`5RcWeX=0#?-aaj3VMQ`snIVtI2E z+?6~;qN#k0T-D;1=nOpWKCZ@afT&#Qi3E-|)E{hSz^2QURT2B OZI1N~#MEw!Nc$Hb#!!<0 literal 0 HcmV?d00001 diff --git a/app/pet/assets/steamo_faces.json b/app/pet/assets/steamo_faces.json new file mode 100644 index 0000000..dbdac84 --- /dev/null +++ b/app/pet/assets/steamo_faces.json @@ -0,0 +1,222 @@ +{ + "frames": [ + { + "filename": "steamo_faces normal 0", + "frame": { + "x": 0, + "y": 0, + "w": 15, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "steamo_faces smile 1", + "frame": { + "x": 15, + "y": 0, + "w": 15, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "steamo_faces blink 2", + "frame": { + "x": 30, + "y": 0, + "w": 15, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "steamo_faces happy 3", + "frame": { + "x": 45, + "y": 0, + "w": 15, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "steamo_faces laugh 4", + "frame": { + "x": 60, + "y": 0, + "w": 15, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "steamo_faces sad 5", + "frame": { + "x": 75, + "y": 0, + "w": 15, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "steamo_faces tired 6", + "frame": { + "x": 90, + "y": 0, + "w": 15, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "steamo_faces yawn 7", + "frame": { + "x": 105, + "y": 0, + "w": 15, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "steamo_faces sick 8", + "frame": { + "x": 120, + "y": 0, + "w": 15, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "steamo_faces no 9", + "frame": { + "x": 135, + "y": 0, + "w": 15, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "steamo_faces eat_open 10", + "frame": { + "x": 150, + "y": 0, + "w": 15, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "steamo_faces eat_closed 11", + "frame": { + "x": 165, + "y": 0, + "w": 15, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "steamo_faces sleep 12", + "frame": { + "x": 180, + "y": 0, + "w": 15, + "h": 8 + }, + "duration": 1000 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "steamo_faces.png", + "size": { + "w": 195, + "h": 8 + }, + "frameTags": [ + { + "name": "normal", + "from": 0, + "to": 0, + "direction": "forward" + }, + { + "name": "smile", + "from": 1, + "to": 1, + "direction": "forward" + }, + { + "name": "blink", + "from": 2, + "to": 2, + "direction": "forward" + }, + { + "name": "happy", + "from": 3, + "to": 3, + "direction": "forward" + }, + { + "name": "laugh", + "from": 4, + "to": 4, + "direction": "forward" + }, + { + "name": "sad", + "from": 5, + "to": 5, + "direction": "forward" + }, + { + "name": "tired", + "from": 6, + "to": 6, + "direction": "forward" + }, + { + "name": "yawn", + "from": 7, + "to": 7, + "direction": "forward" + }, + { + "name": "sick", + "from": 8, + "to": 8, + "direction": "forward" + }, + { + "name": "no", + "from": 9, + "to": 9, + "direction": "forward" + }, + { + "name": "eat_open", + "from": 10, + "to": 10, + "direction": "forward" + }, + { + "name": "eat_closed", + "from": 11, + "to": 11, + "direction": "forward" + }, + { + "name": "sleep", + "from": 12, + "to": 12, + "direction": "forward" + } + ] + } +} diff --git a/app/pet/assets/steamo_faces.png b/app/pet/assets/steamo_faces.png new file mode 100644 index 0000000000000000000000000000000000000000..b28041bbfcaf8e916e760810e673b311556b0a43 GIT binary patch literal 336 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 literal 8616 zcmZ8{cQjm4*Y_k!h)%TVqW2Kdi57(D6Qa!Mk_e*rL9{`1G9)_D83dyfy$dmVXQGZW zdVeR+_x|y`-*2t6@4f4ub?-g+*a&49RWU8 z9&bL|1pwHbHB=N0y=T$p=IA(viGQfaqcAc72;JV-1;P>=lovKQ| zLTNsQ(W_#@ibe@wL-Z6NC|fl5DzRL(ym^QUG5I_5eBEmHbl- zcga6 z!1LV~dX#*TJY{YjQO0)ZUuWr)W1ni4A7q>B3VSI5K$+4%@(K=DR;DbIe|r=5Ip1lu z%AbYe033I|Y}^dge!qK*K-1C)`+P*f1IXVw{6)h3)~9X{3SV3d&F%ZF54PRfX8Z4% zE*h_JdLfP3Pr!ob1~VUX)76hiOow=kL%L|3!}CqD6g+&fT;YA{cn(| zXm(A})mDKgx3KCV$cN8=)XshhqUZ-{B+s6-*x6OT3;26JG{h(@H1UGv@iGU|plnh` zcogn;tVO~!8D3FpakNAgKLoVbdC9GRQ-5c>FFl%$ljFnB(5 zf5U5hh9RtDrf(aQL^v^V+}DOIMjlgM0k$;_Pm=oB8ZvQH1h|Ktmp*eJrM_Ux27Tz&1`7ZWhzbvpMTzSe|9B{cf-=T9R504wGlP)35D z@YFRGr?EP%@EK2%RYVkVQWmctVr8bziy;U7g3%uvYJ?v}nWjmIu{kGcrGkVcsEX9C`fVtmeLZMmK{i+&(zr$=vVW2n z4DHXKLU$;vc&=o9+8QTw!L~W5NZK*q z^-&WKw$J}V-I+>M1_~L6FECcokmvmkq=CwR2|~PtQ3l56=MKWb%n6l5T_1@NaSEDS@j-A2~G21Vk#*@gF8O>g*Tu-s3dY4uYcY8f!S6B@Z zT@BnilgTB0rh?I|t!CE=XL_@h9dkg@U#{i(xW7ZRFgQ;=Dn*lFFG&CRxOz8S6B3!^ zIu=bd8LSDp_bE~^P79r`2}vMM0BIaIWr<))|3m`G8&GQZ?~lCNoi!n>YuPz0!f9Rv zt=hA)ck?k~jDvYfW3;#Dk)zA{1^&@B7*;2%{g|7sak~$}^5$3;<{l zRiqSR@!1@U&-Y7$whdQ1yAi=9H;+OyG3-)hrkblYnRnFa;U_7#EJJ5zZr-`Q{n%4t z(u~qnyuOkFbYF{O1JHY9!1Xsu)m{{+1q?z;WZY918ZIWwBV(eKYljl#IWuASh0-wC zuPGXWz)HP^zSy)d=62dbK@3Kl~1P^2^8ai>YT`dBBzm zH?)jhRFiAa-93|f3)v5liEWkfDSi_)MrdI%cHxw0aow*JJ)gU_rDKXY@C}Z%jyy^k zR39pV-C^_C!g%f3^UAe!e=(G1nP>OZa=H+4WwynlXn zOtIgEAL9nd{+iKV4(W~cxFO%lI%%2%$f|rT+aPVJV6j>o2!=CnaU^L#qZyr=_yu`z zeZqXg{n_%9Dq5Q@=wAY8qY?4b7muE`YVP_!L|R3v8%Gkcts1kI$!)5D!+LfTHcU&M zQ+kv}$6E=$(f*sB5ej_t!<{z2LTjB(r

RzJYKtL_*7%3|FDAjl!3*#8I`Beeo^v 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 KMNUMnLSTYgrXmRd literal 0 HcmV?d00001 diff --git a/app/pet/assets/twiggle_faces.json b/app/pet/assets/twiggle_faces.json new file mode 100644 index 0000000..3ff7d5e --- /dev/null +++ b/app/pet/assets/twiggle_faces.json @@ -0,0 +1,222 @@ +{ + "frames": [ + { + "filename": "twiggle_faces normal 0", + "frame": { + "x": 0, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "twiggle_faces smile 1", + "frame": { + "x": 13, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "twiggle_faces blink 2", + "frame": { + "x": 26, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "twiggle_faces happy 3", + "frame": { + "x": 39, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "twiggle_faces laugh 4", + "frame": { + "x": 52, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "twiggle_faces sad 5", + "frame": { + "x": 65, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "twiggle_faces tired 6", + "frame": { + "x": 78, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "twiggle_faces yawn 7", + "frame": { + "x": 91, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "twiggle_faces sick 8", + "frame": { + "x": 104, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "twiggle_faces no 9", + "frame": { + "x": 117, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "twiggle_faces eat_open 10", + "frame": { + "x": 130, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "twiggle_faces eat_closed 11", + "frame": { + "x": 143, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + }, + { + "filename": "twiggle_faces sleep 12", + "frame": { + "x": 156, + "y": 0, + "w": 13, + "h": 5 + }, + "duration": 1000 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "twiggle_faces.png", + "size": { + "w": 169, + "h": 5 + }, + "frameTags": [ + { + "name": "normal", + "from": 0, + "to": 0, + "direction": "forward" + }, + { + "name": "smile", + "from": 1, + "to": 1, + "direction": "forward" + }, + { + "name": "blink", + "from": 2, + "to": 2, + "direction": "forward" + }, + { + "name": "happy", + "from": 3, + "to": 3, + "direction": "forward" + }, + { + "name": "laugh", + "from": 4, + "to": 4, + "direction": "forward" + }, + { + "name": "sad", + "from": 5, + "to": 5, + "direction": "forward" + }, + { + "name": "tired", + "from": 6, + "to": 6, + "direction": "forward" + }, + { + "name": "yawn", + "from": 7, + "to": 7, + "direction": "forward" + }, + { + "name": "sick", + "from": 8, + "to": 8, + "direction": "forward" + }, + { + "name": "no", + "from": 9, + "to": 9, + "direction": "forward" + }, + { + "name": "eat_open", + "from": 10, + "to": 10, + "direction": "forward" + }, + { + "name": "eat_closed", + "from": 11, + "to": 11, + "direction": "forward" + }, + { + "name": "sleep", + "from": 12, + "to": 12, + "direction": "forward" + } + ] + } +} diff --git a/app/pet/assets/twiggle_faces.png b/app/pet/assets/twiggle_faces.png new file mode 100644 index 0000000000000000000000000000000000000000..318b0b09fe137a259a8112a3c455e16b4125ebea GIT binary patch literal 319 zcmV-F0l@x=P)_b8XhB1x1r7CDVb%lAyG=OH#7QpM zWNz5mUG@N&=-L{)w#IZ7V!8^^l=Bs)K7XYi>R0tVH5XrJx&Q#!ZR5A3`@<#ZV;z?X z0jKL7HtXf!!#a-p1D$V=z?8Gq9IFZd05c&#<+`@Uz9tGz-&|>?Jd;`>6JpQ@&P+M; zVZDm|hKy~H$~8rfHkzi$k#4YVyVX4O-k65QO_3uwnWIZZp+qZ9M=B~%4*ScAo za4*O>!m(Hf-!=4@F0So;E;xC7_T~((8s|bI;|NQcU?~%va~b~L_z%J-JOS3Eqjr(y R2y*}c002ovPDHLkV1limi;VyP literal 0 HcmV?d00001 diff --git a/core/src/food.ts b/core/src/food.ts index 2d9dbf6..93f20e0 100644 --- a/core/src/food.ts +++ b/core/src/food.ts @@ -58,6 +58,18 @@ export const TASTES: Record = { cloud: ["fruit_cherry", "fruit_sunflower"], rumblefluff: ["hazelnut", "glowberry"], prismist: ["glowberry", "pinenut"], + leaf: ["fruit_herb", "fruit_cherry"], + twiggle: ["watercress", "honeycomb"], + needlenub: ["honeycomb", "watercress"], // a cactus: water is the last thing it wants + duck: ["fruit_berry", "fruit_herb"], + drakwing: ["pinenut", "watercress"], + quill: ["hazelnut", "glowberry"], + hippo: ["fruit_cherry", "fruit_herb"], + steamo: ["honeycomb", "pinenut"], + lillypot: ["watercress", "hazelnut"], + beak: ["fruit_sunflower", "fruit_berry"], + rapierre: ["honeycomb", "hazelnut"], // nectar + parcelbeak: ["hazelnut", "glowberry"], // the old slime forms, which live on as wild pets sneezle: ["fruit_herb", "pinenut"], flicker: ["honeycomb", "watercress"], diff --git a/core/src/home.ts b/core/src/home.ts index 70138b4..1ac437d 100644 --- a/core/src/home.ts +++ b/core/src/home.ts @@ -44,6 +44,10 @@ export const ITEMS: Record = { egg_stone: "egg", egg_fox: "egg", egg_cloud: "egg", + egg_leaf: "egg", + egg_duck: "egg", + egg_hippo: "egg", + egg_beak: "egg", }; export const MAX_SEEDS = 9; // per kind; decorations and hats exist only once export const MAX_FOOD = 3; // per kind: fruits and food from trips are kept in small numbers (food.ts) @@ -51,7 +55,7 @@ export const MAX_EGGS = 9; // this many are kept // Egg: the line that hatches from it (life.LINES). An egg is kept in state.eggs, as {line: ...} plus // what a pet has passed on to it (wild.ts), until it is brooded (model.nextPet). export const EGGS: Record = { egg_blob: "blob", egg_ember: "ember", egg_stone: "stone", egg_fox: "fox", - egg_cloud: "cloud" }; + egg_cloud: "cloud", egg_leaf: "leaf", egg_duck: "duck", egg_hippo: "hippo", egg_beak: "beak" }; export const MAX_DECO = 2; // this many spots the scene has outside // Plant: [stat, effect of one fruit] diff --git a/core/src/life.ts b/core/src/life.ts index 17e8943..7b37014 100644 --- a/core/src/life.ts +++ b/core/src/life.ts @@ -32,6 +32,10 @@ export const LINES: Record = { stone: ["glimmerock", "bouldergrin"], fox: ["roamtail", "filchfox"], cloud: ["prismist", "rumblefluff"], + leaf: ["twiggle", "needlenub"], + duck: ["quill", "drakwing"], + hippo: ["lillypot", "steamo"], + beak: ["parcelbeak", "rapierre"], }; /** * The language key for the name of a form: an adult's species, the child of its line (every line's @@ -56,6 +60,10 @@ export const FLARELET_PLAYS_PER_DAY = 2.5; // the ember line: played with this o export const GLIMMEROCK_LOVE_PER_DAY = 5; // the stone line: petting polishes it → glimmerock, otherwise bouldergrin export const ROAMTAIL_TRIPS_PER_DAY = 1; // the fox line: a trip a day makes a wanderer → roamtail, otherwise filchfox // The cloud line is decided by the weather when it grows up: in the rain → rumblefluff, otherwise prismist +export const NEEDLENUB_LOVE_PER_DAY = 5; // the leaf line: a cactus that gets cuddled → needlenub, otherwise twiggle +export const DRAKWING_WINS_PER_DAY = 1; // the duck line: a scuffle won a day → drakwing, otherwise quill +export const STEAMO_BATHS_PER_DAY = 2; // the hippo line: bathed this often → steamo, otherwise lillypot +export const RAPIERRE_TRICKS_PER_DAY = 2; // the beak line: tricks practiced → rapierre, otherwise parcelbeak export const HINT_AFTER = 1440; // minutes in the diary before the child's lure shows where it is heading // Character: factors on decay (awake) and on rewards. Small on purpose. @@ -75,6 +83,12 @@ export const DECAY_FACTORS: Record> = { filchfox: { satiety: 1.15 }, // always after something to eat rumblefluff: { mood: 0.85 }, // grumpy anyway: a bad day hardly makes it worse prismist: { hygiene: 0.8 }, // light as air: dirt doesn't weigh it down + twiggle: { energy: 0.85 }, // an old tree is patient + drakwing: { satiety: 1.15 }, // a fire needs feeding + steamo: { hygiene: 0.7 }, // always fresh from the sauna + lillypot: { energy: 0.85 }, // half asleep in the pond anyway + rapierre: { energy: 1.2, satiety: 1.15 }, // a hummingbird burns through everything + parcelbeak: { mood: 0.85 }, // a letter for everyone: it is always in a good mood }; export const BONUS_FACTORS: Record> = { flicker: { play: 1.25 }, @@ -87,10 +101,13 @@ export const BONUS_FACTORS: Record> = { glimmerock: { pet: 1.5 }, // loves being polished filchfox: { play: 1.25 }, // up for any mischief prismist: { pet: 1.25 }, // fluffy, and it knows how nice that is + needlenub: { pet: 1.5 }, // a cactus that wants to be petted: nothing makes it happier + quill: { play: 1.25 }, // an old sailor loves a good game + steamo: { sick: 0.5 }, // the sauna keeps it healthy }; export function newDiary(): Record { - return { minutes: 0, good_minutes: 0, meals: 0, snacks: 0, plays: 0, love: 0, trips: 0 }; + return { minutes: 0, good_minutes: 0, meals: 0, snacks: 0, plays: 0, love: 0, trips: 0, wins: 0, baths: 0, tricks: 0 }; } /** The line a species belongs to. */ @@ -169,6 +186,18 @@ export function decideSpecies(diary: Record, line = "blob", rain if (line === "cloud") { return raining ? "rumblefluff" : "prismist"; } + if (line === "leaf") { + return (diary.love ?? 0) / days >= NEEDLENUB_LOVE_PER_DAY ? "needlenub" : "twiggle"; + } + if (line === "duck") { + return (diary.wins ?? 0) / days >= DRAKWING_WINS_PER_DAY ? "drakwing" : "quill"; + } + if (line === "hippo") { + return (diary.baths ?? 0) / days >= STEAMO_BATHS_PER_DAY ? "steamo" : "lillypot"; + } + if (line === "beak") { + return (diary.tricks ?? 0) / days >= RAPIERRE_TRICKS_PER_DAY ? "rapierre" : "parcelbeak"; + } const care = minutes ? (diary.good_minutes ?? 0) / minutes : 1.0; if ((diary.love ?? 0) / days >= PURRLOOP_LOVE_PER_DAY) { return "purrloop"; diff --git a/core/src/model.ts b/core/src/model.ts index 00ab670..439ebb4 100644 --- a/core/src/model.ts +++ b/core/src/model.ts @@ -1039,6 +1039,7 @@ function apply(state: PetState, action: string, now: number, bedtime: Bedtime, i care.addBond(state, "clean"); setActivity(state, "clean", now); count(state, "cleanups"); + life.record(state, "baths"); // in a child's care diary (the hippo line) return null; } @@ -1107,6 +1108,7 @@ function apply(state: PetState, action: string, now: number, bedtime: Bedtime, i } s.energy -= 5; care.addBond(state, "trick", factor); + life.record(state, "tricks"); // practiced, in a child's care diary (the beak line) state.game = null; // this ends a mini-game in progress setActivity(state, "trick", now, `${trick}:${result}`); count(state, "tricks"); diff --git a/core/src/scene.ts b/core/src/scene.ts index f48e4bc..ad67ae5 100644 --- a/core/src/scene.ts +++ b/core/src/scene.ts @@ -201,9 +201,14 @@ const STAGE_SHEETS: Record> = stone: { baby: ["stone_baby_body", "stone_baby_faces"], child: ["pebblet_body", "stone_faces"] }, fox: { baby: ["fox_baby_body", "fox_baby_faces"], child: ["kitlet_body", "fox_faces"] }, cloud: { baby: ["cloud_baby_body", "cloud_baby_faces"], child: ["nimbit_body", "cloud_faces"] }, + leaf: { baby: ["leaf_baby_body", "leaf_baby_faces"], child: ["sproutlet_body", "leaf_faces"] }, + duck: { baby: ["duck_baby_body", "duck_baby_faces"], child: ["paddlet_body", "duck_faces"] }, + hippo: { baby: ["hippo_baby_body", "hippo_baby_faces"], child: ["soakling_body", "hippo_faces"] }, + beak: { baby: ["beak_baby_body", "beak_baby_faces"], child: ["crestling_body", "beak_faces"] }, }; // The egg of a line: the tags in the items sheet start with this -const EGGS: Record = { ember: "ember_egg", stone: "stone_egg", fox: "fox_egg", cloud: "cloud_egg" }; +const EGGS: Record = { ember: "ember_egg", stone: "stone_egg", fox: "fox_egg", cloud: "cloud_egg", + leaf: "leaf_egg", duck: "duck_egg", hippo: "hippo_egg", beak: "beak_egg" }; // Color per adult species: hue shift (0–255) starting from teal. // Fallback for a species without pixel art of its own. const SPECIES_HUE: Record = { @@ -228,18 +233,32 @@ const SPECIES_SHEETS: Record = { filchfox: ["filchfox_body", "filchfox_faces", 0], rumblefluff: ["rumblefluff_body", "rumblefluff_faces", 0], prismist: ["prismist_body", "prismist_faces", 0], + twiggle: ["twiggle_body", "twiggle_faces", 0], + needlenub: ["needlenub_body", "needlenub_faces", 0], + drakwing: ["drakwing_body", "drakwing_faces", 0], + quill: ["quill_body", "quill_faces", 0], + steamo: ["steamo_body", "steamo_faces", 0], + lillypot: ["lillypot_body", "lillypot_faces", 0], + rapierre: ["rapierre_body", "rapierre_faces", 0], + parcelbeak: ["parcelbeak_body", "parcelbeak_faces", 0], }; // What grows on a child's head hints at the adult form it is heading for. Per line, the three // colors the code replaces: the bulb of the slime's lure (glow, shadow, highlight), the flame // of the ember slime (edge, middle, heart), the pebble's quartz band (band, shadow, sparkle), the -// white tip of the fox cub's tail (tip, shadow) and the bell of the cloud lamb (bell, shadow) – -// as in the palettes of tools/build_blob_sprites.py. +// white tip of the fox cub's tail (tip, shadow), the bell of the cloud lamb (bell, shadow), the +// seedling's leaves (light, dark), the duckling's curl (curl, shadow), the stripe of the young +// hippo's towel and the young bird's goggles (lenses, frame) – as in the palettes of +// tools/build_blob_sprites.py. const LURES: Record = { blob: [[255, 235, 150], [240, 190, 90], [255, 255, 255]], ember: [[225, 60, 30], [250, 130, 30], [255, 200, 60]], stone: [[245, 238, 215], [205, 192, 165], [255, 252, 232]], fox: [[255, 255, 250], [225, 225, 215]], cloud: [[255, 215, 70], [215, 160, 40]], + leaf: [[130, 220, 90], [60, 150, 50]], + duck: [[245, 185, 40], [210, 140, 30]], + hippo: [[240, 130, 160]], + beak: [[150, 220, 240], [95, 70, 50]], }; const LURE_HINT: Record = { sneezle: [[125, 220, 105], [60, 170, 70], [235, 255, 205]], @@ -258,11 +277,26 @@ const LURE_HINT: Record = { filchfox: [[150, 125, 175], [100, 80, 125]], // dusky, like its mask rumblefluff: [[125, 140, 205], [75, 85, 145]], // storm blue: it rains right now prismist: [[255, 150, 200], [215, 95, 160]], // the pink of a rainbow + twiggle: [[80, 150, 60], [40, 100, 40]], // the deep green of an old tree + needlenub: [[255, 150, 190], [220, 90, 140]], // its flower + drakwing: [[60, 190, 110], [25, 120, 70]], // a mallard's green + quill: [[70, 100, 170], [40, 60, 120]], // the navy of its cap + steamo: [[245, 95, 90]], // hot + lillypot: [[110, 200, 140]], // a lily pad + rapierre: [[80, 220, 150], [30, 120, 90]], // its shimmering green + parcelbeak: [[245, 160, 60], [45, 70, 120]], // its bill, and the post's blue }; // Forms that walk and now and then hop: how many seconds a round of walking and one hop takes const WALK_HOPS: Record = { grumpcap: 2.5 }; // a toad -// the rain can't get at its flame anyway; a toad likes the rain; a cloud is rain -export const NO_UMBRELLA = ["lanternling", "grumpcap", "cloud", "rumblefluff", "prismist"]; +// the rain can't get at its flame anyway; a toad likes the rain; a cloud is rain; a plant and a +// duck like it too, and a pond hippo is wet anyway +export const NO_UMBRELLA = ["lanternling", "grumpcap", "cloud", "rumblefluff", "prismist", "leaf", "twiggle", + "needlenub", "duck", "drakwing", "quill", "lillypot"]; +// Needlenub's flower opens only when it is happy; otherwise it is a bud (the colors as in the +// palette of tools/build_blob_sprites.py) +const BUD: readonly (readonly [Color, Color])[] = [ + [[255, 150, 190], [120, 200, 90]], [[220, 90, 140], [70, 150, 60]], [[255, 225, 90], [240, 140, 180]], +]; // Species that glow at night ([day color, night color], the day colors as in the palettes of // tools/build_blob_sprites.py): Lumoth's hearts, antennae and dots, Glimmerock's crystals, // Gemperor's crystals and core, the bulb of Angloop's lure @@ -315,6 +349,8 @@ const PEBBLE: Bitmap = [[192, 203, 220], ["XX", "XX"]]; const LOOT: Bitmap = [[255, 210, 80], ["XX", "XX"]]; // what Filchfox has filched const BOLT: Bitmap = [[255, 225, 60], ["X.", ".X", "X."]]; // Rumblefluff's lightning const SHIMMER: Bitmap = [[255, 170, 210], [".X.", "X.X", ".X."]]; // the shimmer of Prismist's rainbow +const LEAFLET: Bitmap = [[150, 225, 110], ["XX", ".X"]]; // a leaf off Twiggle's crown +const LETTER: Bitmap = [[250, 240, 215], ["XXX", "XXX"]]; // a letter out of Parcelbeak's pouch const DIRT: Bitmap = [[60, 60, 60], ["X"]]; const SICK_TINT: readonly [Color, number] = [[185, 195, 90], 0.28]; // sickly pale, for everything that isn't the teal slime const STEAM: Bitmap = [[215, 235, 245], [".X.", "XXX"]]; @@ -738,7 +774,8 @@ export class PetScene { const [stage, species] = pose.form; let pet: Image; [pet, top] = this.pet(stage, species, pose.body, t, pose.face, { - sick: view.sick, whiteOut: pose.white, flame: species === "flicker" ? flickerFlame(view.mood) : null, + sick: view.sick, whiteOut: pose.white, + flame: species === "flicker" ? flickerFlame(view.mood) : species === "needlenub" && view.mood !== "happy" ? "bud" : null, heavy: view.weight_status === "heavy", hat: view.hat, hint: view.hint || view.species, glow: this.night > 0.5, lookLeft: this.facing < 0, sky: this.skyLook, }); @@ -1242,7 +1279,7 @@ export class PetScene { return phase < 0.75 ? ["stretch", Math.sin((phase - 0.15) / 0.6 * Math.PI) * 3] : null; } - /** Whether the body sheet of this form has a walk of its own (Cyclopuff, Grumpcap, Sneezle, the stone, fox and cloud adults). */ + /** Whether the body sheet of this form has a walk of its own (Cyclopuff, Grumpcap, Sneezle and most adults of the other lines). */ private walks(stage: string, species: string): boolean { return stage === "adult" && species in SPECIES_SHEETS && this.sheet(SPECIES_SHEETS[species][0]).has("walk"); } @@ -1642,7 +1679,8 @@ export class PetScene { const sprite = ({ sneezle: STEAM, flicker: EMBER, grumpcap: SPORE, lumoth: DUST, lanternling: EMBER, flarelet: EMBER, glimmerock: GLINT, bouldergrin: PEBBLE, gemperor: GLINT, angloop: BUBBLE, purrloop: LOVE, - roamtail: DUST, filchfox: LOOT, rumblefluff: BOLT, prismist: SHIMMER, + roamtail: DUST, filchfox: LOOT, rumblefluff: BOLT, prismist: SHIMMER, twiggle: LEAFLET, needlenub: LOVE, + drakwing: EMBER, quill: BUBBLE, steamo: STEAM, lillypot: BUBBLE, rapierre: GLINT, parcelbeak: LETTER, } as Record)[view.species] ?? SPARK; for (let i = 0; i < 10; i++) { this.particles.push({ @@ -2525,7 +2563,9 @@ export class PetScene { if (weathered) { img = swapColors(img, weathered[1]); } - if (ownArt && flame) { + if (ownArt && flame === "bud") { + img = swapColors(img, BUD); + } else if (ownArt && flame) { img = recolor(img, 0, 40, FLICKER_FLAME[flame]); } let face = this.sheet(faceSheet).image(faceName); diff --git a/core/src/state.ts b/core/src/state.ts index 0df41b6..c17a0ae 100644 --- a/core/src/state.ts +++ b/core/src/state.ts @@ -184,6 +184,8 @@ export interface PetState { trip: Trip | null; /** Areas whose guardian it has got past (trip.AREAS). */ guardians: string[]; + /** Areas whose guardian has left it its egg (trip.GUARDIAN_EGGS). */ + guardian_eggs: string[]; /** The trips it has been on, the latest last, at most trip.MAX_TRAVELS. */ travels: Travel[]; /** Brought home but not unpacked yet. */ @@ -260,6 +262,7 @@ export function newState(): PetState { training: null, trip: null, guardians: [], + guardian_eggs: [], travels: [], backpack: [], items: {}, @@ -303,6 +306,10 @@ export function fromDict(data: Record): PetState { if (!("house" in data) && state.guardians.includes("mountain")) { state.house = 1; // saved before there was a house, by a pet that has already earned the hut } + if (!("guardian_eggs" in data)) { + // saved before guardians kept track of their eggs: back then only the cave's guardian had one + state.guardian_eggs = state.guardians.filter((area) => area === "cave"); + } if (!("form_rules" in data)) { state.form_rules = 1; // saved before the slime line was redrawn } diff --git a/core/src/trip.ts b/core/src/trip.ts index 9ab75e4..a297edf 100644 --- a/core/src/trip.ts +++ b/core/src/trip.ts @@ -56,8 +56,10 @@ export const HEARTS = [45, 75]; // the day's condition (satiety, energy, health) export const WIN_MOOD = 5; export const LOSE_MOOD = -3; export const GUARDIAN_MOOD = 15; // getting past a guardian makes it proud -// Area: the rare egg its guardian leaves behind the first time the pet gets past it (home.EGGS) -export const GUARDIAN_EGGS: Record = { cave: "egg_ember" }; +// Area: the rare egg its guardian leaves behind the first time the pet gets past it (home.EGGS). If +// there was no room for it, or the pet got past before the guardian had an egg, it leaves it at +// the end of the path on a later trip. +export const GUARDIAN_EGGS: Record = { meadow: "egg_beak", stream: "egg_duck", cave: "egg_ember" }; // What can go into the backpack: a snack heals a heart on the way, a ball distracts an opponent export const PACKABLE = ["snack", "ball"]; export const MAX_PACK = 2; @@ -78,6 +80,12 @@ export function unlocked(state: PetState, area: string): boolean { return blocker === null || state.guardians.includes(blocker); } +/** The egg the guardian of this area still has for the pet, if there is room for it at home. */ +function guardianEgg(state: PetState, area: string): string | null { + const egg = GUARDIAN_EGGS[area]; + return egg && !state.guardian_eggs.includes(area) && home.canAdd(state, egg) ? egg : null; +} + /** The guardian of this area, as long as the pet hasn't got past it yet. */ export function guardianWaiting(state: PetState, area: string): string | null { return state.guardians.includes(area) ? null : battle.GUARDIANS[area]; @@ -216,8 +224,9 @@ function encounter(state: PetState, trip: Trip, foe: string, rng: Random, weathe events.push(["battle", `${foe}:${outcome}`]); count.battles = (count.battles ?? 0) + 1; if (outcome === "win") { - let egg: string | undefined; + let egg: string | null = null; count.battles_won = (count.battles_won ?? 0) + 1; + life.record(state, "wins"); // in a child's care diary too (the duck line) state.stats.mood += guardian ? GUARDIAN_MOOD : WIN_MOOD; if (guardian && !state.guardians.includes(trip.area)) { state.guardians.push(trip.area); @@ -225,15 +234,16 @@ function encounter(state: PetState, trip: Trip, foe: string, rng: Random, weathe for (const area of AREAS.filter((area) => blockedBy(area) === trip.area)) { events.push(["unlock", area]); } - egg = GUARDIAN_EGGS[trip.area]; + egg = guardianEgg(state, trip.area); const step = trip.area === AREAS.at(-1) ? home.buildHouse(state) : null; if (step !== null) { events.push(["house", String(step)]); // past the last guardian: the house grows } } let item = find(state, trip, rng, weather, true); - if (egg && home.canAdd(state, egg)) { + if (egg) { item = egg; // what it was sitting on, instead of something from along the path + state.guardian_eggs.push(trip.area); } if (item) { trip.found.push(item); @@ -284,6 +294,14 @@ export function step(state: PetState, t: number, weather: sky.WeatherCode, const rng = new Random(`station:${Math.trunc(at)}`); // the end of the path: this is where the guardian waits const guardian = returning(trip) ? trip.guardian : null; + const late = returning(trip) && !guardian ? guardianEgg(state, trip.area) : null; + if (late) { // a guardian it got past long ago has its egg waiting for it + state.guardian_eggs.push(trip.area); + trip.found.push(late); + events.push(["find", late]); + happened(trip, { kind: "find", item: late, at: t }); + continue; + } const met = guardian ? null : wild.meet(state, trip.area, at, weather); if (met) { const shown = wild.show(state, met, rng, t); diff --git a/core/src/wild.ts b/core/src/wild.ts index efa821b..fa3ac03 100644 --- a/core/src/wild.ts +++ b/core/src/wild.ts @@ -23,8 +23,8 @@ import type { Egg, PetState } from "./state"; export const WILD: Record = { meadow: [["cyclopuff", 4, null], ["sneezle", 3, null], ["flicker", 3, null], ["grumpcap", 3, "rain"], ["lumoth", 1, null]], - forest: [["filchfox", 3, null], ["roamtail", 1, null]], - stream: [["bouldergrin", 3, null], ["glimmerock", 1, null]], + forest: [["filchfox", 3, null], ["roamtail", 1, null], ["twiggle", 2, null], ["needlenub", 1, null]], + stream: [["bouldergrin", 3, null], ["glimmerock", 1, null], ["lillypot", 2, null], ["steamo", 1, null]], mountain: [["rumblefluff", 3, "rain"], ["prismist", 1, null]], // the thundercloud only comes out in the rain }; export const MEET_CHANCE = 0.2; // how often a wild pet is at a station, while the pet is looking for a friend diff --git a/core/test/battle.test.ts b/core/test/battle.test.ts index 07986ce..5058a1a 100644 --- a/core/test/battle.test.ts +++ b/core/test/battle.test.ts @@ -9,7 +9,7 @@ import * as home from "../src/home"; import * as life from "../src/life"; import * as model from "../src/model"; import { Random } from "../src/random"; -import { STATS, toDict, type PetState, type Trip } from "../src/state"; +import { STATS, fromDict, toDict, type PetState, type Trip } from "../src/state"; import * as trip from "../src/trip"; import { ALL_TRICKS, BEDTIME, HOUR, act, at, grown, refused, withRules } from "./helpers"; @@ -197,6 +197,27 @@ test("a guardian leaves its rare egg behind", () => { assert.equal(home.eggOf(home.EGGS[egg]), egg); }); +test("a guardian it got past before it had an egg leaves the egg at the end of the path", () => { + pet.guardians = [...trip.AREAS]; // got past them all, from a save before the stream had an egg + pet.guardian_eggs = ["cave"]; + withRules(trip.rules, { encounterChance: 0.0, fight: battle.fight }, () => { + assert.deepEqual(act(pet, "trip", start, { item: "stream" }), [true, null]); + assert.equal(pet.trip!.guardian, null); + runUntil(pet.trip!.stations.at(-1)! + 60); + assert.equal(pet.trip!.found.at(-1), "egg_duck"); + runUntil(start + 3 * HOUR); + assert.deepEqual(pet.guardian_eggs, ["cave", "stream"]); + assert.deepEqual(act(pet, "unpack", start + 3 * HOUR), [true, null]); + assert.deepEqual(act(pet, "trip", start + 30 * HOUR, { item: "stream" }), [true, null]); // only once + runUntil(start + 33 * HOUR); + assert.equal(pet.trip, null); + assert.ok(!pet.backpack.includes("egg_duck")); + }); + // a save from before: only the cave's guardian had an egg to give + const { guardian_eggs: _, ...old } = toDict(pet); + assert.deepEqual(fromDict({ ...old, guardians: ["meadow", "cave"] }).guardian_eggs, ["cave"]); +}); + test("the next pet keeps what is at home", () => { const old = pet; old.items = { daisy: 1, flag: 1, seed_berry: 2 }; diff --git a/core/test/life.test.ts b/core/test/life.test.ts index 471d166..1a6211d 100644 --- a/core/test/life.test.ts +++ b/core/test/life.test.ts @@ -163,6 +163,26 @@ test("a cloud lamb that grows up in the rain becomes a thundercloud", () => { assert.equal(life.decideSpecies({ ...life.newDiary(), minutes: 10080 }, "cloud", true), "rumblefluff"); }); +test("the leaf, duck, hippo and beak lines grow up by what the child did most", () => { + const week = { ...life.newDiary(), minutes: 10080, good_minutes: 10080 }; + const cases: [string, string, string, string][] = [ + ["leaf", "love", "needlenub", "twiggle"], ["duck", "wins", "drakwing", "quill"], + ["hippo", "baths", "steamo", "lillypot"], ["beak", "tricks", "rapierre", "parcelbeak"], + ]; + for (const [line, kind, often, otherwise] of cases) { + assert.deepEqual(life.LINES[line].map(life.lineOf), [line, line]); + assert.equal(life.decideSpecies({ ...week, [kind]: 7 * 6 }, line), often); + assert.equal(life.decideSpecies({ ...week, [kind]: 2 }, line), otherwise); + } + // bathing and practicing a trick go into the child's diary + const hippo = model.newPet(start, "", "hippo"); + Object.assign(hippo, { stage: "child", stage_since: start, diary: life.newDiary(), poops: 1 }); + assert.equal(act(hippo, "clean", start + 600)[0], true); + assert.equal(hippo.diary.baths, 1); + assert.equal(act(hippo, "trick", start + 700, { item: "bow" })[0], true); + assert.equal(hippo.diary.tricks, 1); +}); + test("child keeps a diary and grows up", () => { pet.stage = "child"; pet.stage_since = start; diff --git a/core/test/scene.test.ts b/core/test/scene.test.ts index 25b1657..82b6688 100644 --- a/core/test/scene.test.ts +++ b/core/test/scene.test.ts @@ -127,7 +127,7 @@ test("the status line: clock, temperature and what the pet needs", () => { test("every form of the pet can be drawn, in every state", () => { const forms = [...Object.keys(life.LINES).flatMap((line) => life.STAGES.map((stage) => [stage, line])), ...Object.values(life.LINES).flat().map((name) => ["adult", name])]; - assert.equal(forms.length, 5 * 4 + 16); + assert.equal(forms.length, 9 * 4 + 24); const moods = ["normal", "happy", "sad", "hungry", "dirty", "sick", "tired"]; for (const [stage, species] of forms) { for (const mood of moods) { diff --git a/core/test/wild.test.ts b/core/test/wild.test.ts index 60b422e..be8127a 100644 --- a/core/test/wild.test.ts +++ b/core/test/wild.test.ts @@ -44,8 +44,10 @@ test("only an adult without a friend is looking", () => { assert.deepEqual(met(pet, "meadow"), new Set([null, "cyclopuff", "sneezle", "flicker", "lumoth"])); assert.ok(met(pet, "meadow", 63).has("grumpcap")); assert.deepEqual(met(pet, "cave"), new Set([null])); - assert.deepEqual(met(pet, "stream"), new Set([null, "bouldergrin", "glimmerock"])); // the stone line - assert.deepEqual(met(pet, "forest"), new Set([null, "filchfox", "roamtail"])); // the fox line + // the stone line and the hippo line + assert.deepEqual(met(pet, "stream"), new Set([null, "bouldergrin", "glimmerock", "lillypot", "steamo"])); + // the fox line and the leaf line + assert.deepEqual(met(pet, "forest"), new Set([null, "filchfox", "roamtail", "twiggle", "needlenub"])); assert.deepEqual(met(pet, "mountain"), new Set([null, "prismist"])); // the cloud line; the thundercloud only in the rain assert.ok(met(pet, "mountain", 63).has("rumblefluff")); const changes = [{ stage: "child" }, { friend: { species: "sneezle" } }, { nest: { line: "blob" } }, diff --git a/docs/gameplay.md b/docs/gameplay.md index 4e8a179..fc84bcd 100644 --- a/docs/gameplay.md +++ b/docs/gameplay.md @@ -158,8 +158,8 @@ child grow 30 % faster: the baby in about two days, the child in about five. A grown-up has no use for it. The care diary of the child stage decides the adult form: how well the pet was -looked after, how often it was played with and petted, and how often it went -on a trip. For one line, the weather at the moment it grows up decides. Each +looked after, how often it was played with, petted, bathed and taught tricks, +how often it went on a trip and how many scuffles it won. For one line, the weather at the moment it grows up decides. Each form has a character of its own, with small effects on the game. From its second day on, the bulb on the child's lure shows by its color which form it is heading for. @@ -485,8 +485,10 @@ can get past Crowcomb with some luck; for the later ones the pet needs its tricks and a good deal of training. Progress counts per pet: a new egg starts in the meadow again. -One of the guardians has been sitting on a rare egg. It leaves the egg behind -the first time a pet gets past it, so every pet can earn it once. Getting +Some of the guardians have been sitting on a rare egg. A guardian leaves its +egg behind the first time a pet gets past it, so every pet can earn it once. +If the pet got past it before (or there was no room among the finds), the egg +waits at the end of the path on a later trip to that area. Getting past the last one, on the mountain, adds a step to the house (see [The house](#the-house)). diff --git a/docs/images/pets/beak_baby.png b/docs/images/pets/beak_baby.png new file mode 100644 index 0000000000000000000000000000000000000000..6e7eaaf4a92488fdd6ecf244384ebfa281969690 GIT binary patch literal 557 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8I2}rW6{ZPfg!1%?}#WAGf*4sO}L5CeA8Xm?q z9(<6UwaV~nhDn?Bf@yPyT+h3Qy{QY`y_}7h+4-Au`7XN3IS(vuL_&5{9 z3~!b`v+wEk8dtNkmb|M7?`l|V`qgrAHX}r~m~EZ8;jKF_j)$|%bUYg)4sj>j9e%sd z?oMo?5N_Nl=knxp&gEd2R-Dss=&!6`lmW|~|LL3o40&kmlqT+13Xrg0xRE0Om<$*^ MUHx3vIVCg!0E5}Vi2wiq literal 0 HcmV?d00001 diff --git a/docs/images/pets/beak_egg.png b/docs/images/pets/beak_egg.png new file mode 100644 index 0000000000000000000000000000000000000000..8a8c1e9aaed829388697fcf7cf715feacfb9ddd3 GIT binary patch literal 475 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8I2}rW6{ZPfgz_`fM#WAGf*4sN9c@G%~I9y!Q zkRj37W_qJRP5OcX%WeY}=?fbeoi8j|?yM(sQ&HVp#s636lT-RfPfoj&yUkj6$2l?j4V$(Um1VKCz4XiN4$i0C9f|#+W)H#4vO@Id0q z@#+(0wfi>dib@+K8~_UE_0D<}+t;3xeE_5YC=|`m-*}Z_`F)6vgafHpW-ZM0``^b4 zmSx;7x8@kzidkR(zWv7wF@f!m^@ln08K9gPyB8f+Ukp+hA;x_?V4BSUwmad#TRtlo z)9^<2z9;NZ3z?UD1nd8V+4u2=X(b2L=)U9M6fD5bgoYO)uq0q1#chzVn*khvqW9Qa XT3H_0oH{ZC7-`|ZNNukSBDn)~lho!lOw3XnByJQc4F zNWQxK_x$Q?E^b4pkjIs`x1XQf^t~+B;p&ZcL-8btjRl%nHkyG(J3qD@TiUSu-Qj01 z9|q*+K=k~Od0u14J8ko4EmVrkC-cT1)-*5__>*PeN&|NH;ukWY~}>(UNv{=sAc_WHh8`VHl=S5iEF->qH# zD1AsBO?*n8u*m zz1Z$C1H@;=@hMYv7G(7^Lwt1}lyYFn=G+_U=|%ZMdvtZBfC-nu)78&qol`;+0MvpU Ai2wiq literal 0 HcmV?d00001 diff --git a/docs/images/pets/drakwing.png b/docs/images/pets/drakwing.png new file mode 100644 index 0000000000000000000000000000000000000000..f69e093048025ff7d56defcd8677527c9135e62b GIT binary patch literal 790 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8I2}rW6{ZPfgz;xHs#WAGf*4w*^MYkP98Xm?h zyxcIYWy%YIg9neQ?Q|?G*igtXcq#h_+tH(Y9Xn4?$yLvPmK&D6_R0Cr%Kl3>e&fE7 z5q{}xd;k0`kMnpK6Bxyy=m3)r6g99$z>vfS25ty4z^0Ok2dJ{5rJ2XBfsvVwN5bI2 zz7>~CzNcMp;FT~)IMBejzO%~0_BMk_v4=m{#Z@7 zT-d#h6=J-8?=9&f%{Ls+UVbqVPfUjkZ;HrcxWZGwrnc(O?=#yVE-m=Hq{L+91j!dK z-<_THLFo4z#u#akgPGa>*kAf-aCWOt#&qVYx_@TV8`m6NcQ^fKbro~EnmPl>0^Pvfw9;*ET+i38> zF~Io1OyPAO78)z-)Uboqg|o)+-MQAdT7Heyr$gmnC+x|5AogbKgT?m+n8No}tUlds z0M*XA(fGsO?mGXst$p{pA43J>^gGV|5&p8G?BSg#^F`3O-J2(;Z-0^b>Z$koJLfAN zaK|B!+tPmuzfq@%_n8gwpA&3o&%7_L=Y$|ia@Ef3W0A|&WH>cUz6Am;m zGPCjQ(0g^h(mc}t2AC&N(7ocK(rWb_sN__6!y-NiTjImp3CI6lPT4tZnZf6rcpz%uFgTe~DWM4f1C+_r literal 0 HcmV?d00001 diff --git a/docs/images/pets/duck_egg.png b/docs/images/pets/duck_egg.png new file mode 100644 index 0000000000000000000000000000000000000000..ae06c24882daa22b0c799c4ecb43d42e964425b2 GIT binary patch literal 458 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8I2}rW6{ZPfgz&O#<#WAGf*4sP#d7B(W4kU&d znB^Uky5{#th3BEbwVVfRW@cB+E(m&_`|;zkq<;J-?Unc39S_}IUG}?~Yn>6(0VW+N zYG93kB1Y~F3{Yf{z$gYq*i^DgU{$${0cI371^+I*j5yC_kZ_=Zk(q4|Z`OVLNw&Mq zB3Ir3@p&W)@~)ImnCNu~$ONe=W?1jY3Slz-XWJT*1J=g#V}3(^t}z=}30ND{Jg7?l zI-Zz!C!g6dLlyAFyyI(FTgAx$vH_^Hd!zEz=dWipzlYfQq38jp1jIo+7Si9eBUHLC zK$Jevuc?XT;DZ#e5(I5Fpd~JUHx3vIVCg! E0OwVcx&QzG literal 0 HcmV?d00001 diff --git a/docs/images/pets/hippo_baby.png b/docs/images/pets/hippo_baby.png new file mode 100644 index 0000000000000000000000000000000000000000..61e8004efe4fa76ceeaa965d46d4e8580bbc7c64 GIT binary patch literal 553 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8I2}rW6{ZPfg!1%$_#WAGf*4sOZL5Ceg8Xm?p z9{j?Q!NV5Yd$53)$NT}Csp(!v-%?(-=7($-C3vLnoa@?`SU#!b(%J2wSNrUmyYKuP zALEzn)`e&7ILE=jy#b1t#S$1Hh)w4J6AU%5MnDlG7L{TNSXItuf*FNf0jmVeQf>pF z$_K@N8xmqq{cB)kX5*3guyoP7_j3N%dbfCeW9N}DNI1|C&DPiUZ|}|dI!!Crru?@| z1}OuIKR@u#;@isg|J0|(pTC`de|6CbCa^ePzwaXU0R{ee@ z32Lb>^K*v%`m;k?zL)%;AXVi5B^GLkP-D9TU!(myK24BbHl7`+4{ACDk6n4X0HCN~=tH!(`5uvlrkt~oO4bMx0F>q|=4Z(O(IRe{aQ2U^Mu zItQ2_h$o_f6@nx-FmS^VvseNn1hHXJ8PULqO=S)j%qVOM9(2B&?jF>@$jrtgVer6a z#r<{iZ$H0t(-xIBNH_o#j*~WJvs^xD15|-&Lvljx7pf#5piofof>kN}m-RSMa3X$2) zBG<$SRdxNaT+`W;iY6duvGG{gZ)<)4(E$k_16bIICBQ;a=RkumBUo0u+P>j@Ib&i( Sc?U4U7(8A5T-G@yGywpoN|odQ literal 0 HcmV?d00001 diff --git a/docs/images/pets/leaf_baby.png b/docs/images/pets/leaf_baby.png new file mode 100644 index 0000000000000000000000000000000000000000..650978269daae688e0904bd1a8d2e22faceebd5d GIT binary patch literal 558 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8I2}rW6{ZPfg!1&eE#WAGf*4sO}L5CeA8Xm?q z9u$aeUU@KKk)i1fDIW6`2N$fqcu|Jwtl|ZUb&ZVMH#g1w>16yi?Q=@p)SG|aCL2wj zfA#3osZx2VTnyYBpom#4ff0h(bPh1VPy=fO6ft5^DVBg$JCB4x!hr@x|K?l#<|}LdKK!g`TAl+GU}odlA$CQmpl_FTPLS%God41cuN?m#{pw?F^`>9bZ;OB&!_0Pvser|l>B8Fbl^ZK2<`zGg zwGreX34;g04AT>o5|X#GLfk!_DW>UXrCgBfo&$Bq5k(nu9N@*l{K`@_Kt*1P?WvI#IkpdtAyegEb)OPihKCY1ow O0fVQjpUXO@geCy|N6?D^ literal 0 HcmV?d00001 diff --git a/docs/images/pets/leaf_egg.png b/docs/images/pets/leaf_egg.png new file mode 100644 index 0000000000000000000000000000000000000000..8b86615fb790827a9462d594c352ae36ea1895f0 GIT binary patch literal 463 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8I2}rW6{ZPfgz&Op*#WAGf*4sO4d6^sq8ZKrx zCU8t+D*~vkh9o$ zDzt7`{uGpgD6~1}{wVN0BgDy&0AquN7E%~QG%$ig>)#dO8Gkn%UXob70vJ&Yp00i_ I>zopr0QN1J=Kufz literal 0 HcmV?d00001 diff --git a/docs/images/pets/lillypot.png b/docs/images/pets/lillypot.png new file mode 100644 index 0000000000000000000000000000000000000000..b2ba32cdb48a3cbceea93c2a9532582ce9f2d4fa GIT binary patch literal 805 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8I2}rW6{ZPfg!1Tt`#WAGf*4w*^#lnsf4G;gZ zvK{t6kYHeX)l|aA*Ho%`<+_6lvJFgU%*x`iQd_o+?Q*?9a4>W8&d9WPvukGWKK)kJ z|5@nV*|YD~YHiz@R{ZJJS83S-^=S+n7`P$GAc0W~iViU8zz|PF11khcU{lG+23Pqf z|Ik5hgM(UA5i$C>xIiNa*|COs>HBX0i2k^{=`%Oy8%;3=v=MWLy6| zG5g{%Ev@47OB0wO%7Yi~v&m1()Vu*Qibvu@$covoZ%0OPnL!Qz(&)IegMW2tu4gnRuDWv!Z>$`#qV! z&SHGO>15Z0sD?FfUr)ci?$+7s0u^BA^H^}(h~4Hy+4(AHREI z&oes~X-L4{OHB&S*`#;gu8enQ+6lGQWuI9g9`XMgp!lou%Yxl8M~=(e?`})rckDeT zaCT`~FelWfOftSY#wX9%&zstPJ4$lTnO_W$z)ns|S2Mdd`>XDK^{C0N|J>QZft>fM zr!VSFa$cA7MQ})d_{fyL;WWR?^sO};Zcb>vV8p&j=1S&fu!kxH*%!KU7ka$?d|C$_ zVFnL$K1?`l^Sr9pv&g>gTe~DWM4fqsK;= literal 0 HcmV?d00001 diff --git a/docs/images/pets/needlenub.png b/docs/images/pets/needlenub.png new file mode 100644 index 0000000000000000000000000000000000000000..c92b17ebd73af469d3ca9a897d3079ba2cb39b64 GIT binary patch literal 751 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8I2}rW6{ZPfgz_iWN#WAGf*4w*=euoVt8ZO2$ zZai>^HzHz}!DfTa8w#55HAowLm%6jydP3qufioLi-BvBVUnDc zD=(~E%Ddf|rGYg9iWs>!FhCHqSOOyq9bnRdB5W$T4S*^i-1D>e%)ldIkZ_=ZaeM0@ z%X#Ovh2{X+%xpXrnO8*KfBu>K>iO%+SLZ)VA7z86n?BE{b%XJWiR>Uf%xpGX1$hhB zzt8Wgvb6P^`fm0%u?mR(9b%?T)4qMIopmZVcym6B9M}%#IN<_5Q}YYQ*B=hiO!0l$ zp74L${8zlvV99>gm|YwKj=qZ7Y5}@xshOrXbjAD`fKHM4@U2m~TWF#_Pt^>EvtJ)} zBuwv^F&mFD=Tymn}8#b!FQtvh0iL<;R^dK&x4yUObk!@j{>#W6s_S7o|jDZfo9~ zVmf)Z*oU?Hv)IAvk{QpJ3V)v@zGi#HdXALWv#&zjy5qo7`?PJxx?gAQ`;cEd*#hR! znx)N`4!5j6dL-+ld^#hy`8{*nII41DpI#Y)47qffO!C_~v!*{Z{p3u@^KBk92?h!whl3 zJ6VhN+KN54(Rs6Do86z(7T+#0oCh_r$Ntu&+snQhPLYEK>z*)BI)WyjSv%u(I~Wrc T8@9It6EcIRtDnm{r-UW|i$XKu literal 0 HcmV?d00001 diff --git a/docs/images/pets/paddlet.png b/docs/images/pets/paddlet.png new file mode 100644 index 0000000000000000000000000000000000000000..d97e90d0145528c063eaa73c5df21285eb083358 GIT binary patch literal 652 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8I2}rW6{ZPfgz!dE1;uunK>+M}zzrzL+4G-@z zD2nacQ1a4qhhzG>i_RtQOlRzLe5N;dW@JRft^;B*n$vPj{bZka-dnlp*W>g~yQn=? zHC17U*XA%LFp5FZ0VW+NYG93kA&CtP+z@1dO(hc#HkA*S);>7FDq)atpn;KDulv{M zjk0S(b3hz6o*iOWZuo|+z5(V)e6Veo(7gWg!=>w&3|JuQ=P?!SuRihW`=49lOvkUC z7nFkt%L$uueJlO(zDP=>x>fg0}~Du6TVmZ^On9 zMf3NY!R!^u;yRtu+4hKBxwQf0LJ5NhDGv(bza4*= z_1U{(KFpzw$txbV%V%HKZ-1*Xb;rqBLJ(v0#VuI3vJ^yo-*#@*mj%oaqt~(ixFh>} zUEY*^yZ7x}&j>UUXh*h8Ny}`Z+Y4^Y+PQ{5`i{Ib1IV%uZyKVxpt}Bgmj^&y@H_c9 z8|zNyc1^`>2UduFZ`pklne0NbO`CEjRrtM~6 PDr4|;^>bP0l+XkKmk0hX literal 0 HcmV?d00001 diff --git a/docs/images/pets/parcelbeak.png b/docs/images/pets/parcelbeak.png new file mode 100644 index 0000000000000000000000000000000000000000..4ceaf4f44ae838f361f0fc7fc85461f9693fbdff GIT binary patch literal 769 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8I2}rW6{ZPfgz;wdX#WAGf*4w)ai*6gp9C*0r zP+m%gN{Y&kB{wSgH=0YFd_1G)jiQ$u5dLC2tgNgm`*~&g&-Y6_i$s2Z{u`ioRrMcN z$uwp8dwc&c;4LrUV&L8YMa*Iej1a`8bASnk8dxKsh!Lu?;LFiTi=UMqXkcV!MsnB|5GIx5=gD+n%8RoOf86<#= z$m^VSs3(AhUjod%FI3QCRXg+l?(5Ibi?5b6&N9h?*i+HVEwz{xq9~v7$5S^xsQCK> z7mqCeZUMFE#Q{t6>F(-Z9)8SxSvqgJ7h}|3^C@*FL*`07;uUXvAYtI%fm0rK&0wdV`{LGCDOBQb`ah|qi z7O!h`ujL^Z9!Rjg+j{f+_s=C8P0bn4|7_nOW(IXFcZ~5$&;Mpk>sNj;W`G!5&Df_F zzx-v*#uo=KUi__`Gg${5bbDHlwwX41pJv=Piv?`i_JYf?t6RUziCZl?|BU?s*dG+N0bpu-Lf4G&`) z4>laUawTEaMG2l=ZI2UHt=`Fa-60uBIr$W%6-3e5wCSK60fj|_)N&gr_fZMoKLE@_Cxer$d_3=NJ$t$ozE zzijinAN#DHJF$b!S|@2yHQAn7GkrG1!h+HRzyI!>;`pBHa^>uU9~nT7O*o)evf~0H zh|$1U?r8h=+STnH(*Gd#UppYLzde)+K!Ipu-Ll4Hx4Y z7czwg3pcNG{LW@7k#~UC;Of;o4bE3W!jpG6^0rAga0}i|G~cb6`K{D$>P&}+GwUba zoqPArz05;r|8O&KZ-63Zu>?j4V$(Um1Vat15m3a4MWt8*Nag>p?W}eUjLd925(W&JqTi32IKWu&O$`uQ% zp?<#AzGepFtIuC9?!L7FEcD^aceP$gQ_*TK_N@@}c70=?UUjnG^Nmae#P1bZ=_MuN zCwO~hfBn4so&g+KjMpm!qB1^Kom;e9A_SuBM&pC}+M~|pu-L#4G-fQ z4;HYPur;qcmav13t@k0D>5O{|*kYSku6)V6%Fxtw#v`NCK8JE<<^GyfH#0uXYWDY; zbC>z5gaK|B!+tPmuzfq@%_n8gwpA&3o&%7_L=Y$|PzxUyR_FthPU z7(6g!Ud}xCo_(v9ky*ll21aJK7@@D}`?*6?a=<*E9V)Nh<;tx(aRVgBBk{q|oL?z_ z%_XzdrJ=$fcIJgJfJ{j^aQu!p4%<4Cbz;+arJdn9k(ow$s@+~jLslWcH zK~-8PWu3dQdrtAX^Y4YFAvT<2?faJMIzPSv>Wl!e0R|5~GCk*c^ucPiu2jVBQYMHK zFE(zEpRHtTZxdE(sjfa-2kbu^l?Oo+ayNP}+}6qt_DDlJOO4(Pz3hl{_N$>md+5bK+8}KKe3Cai#ESL4r(%b%$=*lOmYq8ubk4C6CP5wS#>jBRGs5ZF;tx z?mzn5#%t}*M{$0fpa5%N{}|Lar%Lvkz;zyp4T(U77R3d*{Mlf)9%fq8!3dAgUzhb) Y#^?Q?DH^^Mn9LYFUHx3vIVCg!04V+ImjD0& literal 0 HcmV?d00001 diff --git a/docs/images/pets/sproutlet.png b/docs/images/pets/sproutlet.png new file mode 100644 index 0000000000000000000000000000000000000000..f605b415c65b8f6eabd7b6d7f16fb902fc39bb7b GIT binary patch literal 682 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8I2}rW6{ZPfgz*Okz;uunK>+N0Lpu-Ll4G-fQ z4+g|GuRNHr%FuL%6p#6eg9}z)yeh+VR`G(wx<wP0 zGo`Swa;b4%B1;2n1QaoHZ(x8RX0ZfD7&^eD14Y zK`M_QxF>tf*V5YS?Fy)IH^d*_KCp7aO7_C7F@M-0s+J##`|_pmu{FqO=6R1h`@TKT z+v~HcckZvdWqCCaMa4TG$V+{BU3dBBg*o#q(&Nmh+ s@)_Qlky~l03O2zm9Tcz7h<~*+zT(Q);~X-ZKxvS{)78&qol`;+03}fn6951J literal 0 HcmV?d00001 diff --git a/docs/images/pets/steamo.png b/docs/images/pets/steamo.png new file mode 100644 index 0000000000000000000000000000000000000000..0ffa1343b76905a9dd2fd09d86479064a47d1120 GIT binary patch literal 783 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8I2}rW6{ZPfgz;w;i#WAGf*4w+fMRyD&8Xm?h z48G(o@|{if=w7$N0)9amA(4(HZRo=XZ5QNG%zx=)o47Bd3E_^X`W^o%cr7wVVX?$ ze=TB%=*!mIRJ7vd6F>X+>#s2tz1&!IW2+uS7tfBXY0fM=Skf|8yVu`2JK?PUCI)6U z9*Gaj_Lqp?wE6M3W>)m;Hn$~TY%XWz`Y`}yfbK92R5pKId_!4W(mSP?3FI(F=Db#` zyS8zwDqnw>&+gom)3dm(#ZO2YZvJqU6EE{ID;3 z7&ooHs{$6>`n&ldZdu1E^E0s6szK<=o!)=*Jhq-&Xle#_KNBQ`to1itI=H6v@WSUwZ)LT>irMx&N^`cFQC|IEX6KDFZccng z4P4+@VEq1LQEXm<;2U2t2UdvoYKHzl0q+H&hE+3suQ~W6>T1>dAt5n@L9%^Zsx&JlgvXS09>uGa}fr7-{Dc>B$>JOdOm6~g*YH7YZnbIgxQzWFvf z91<;Raek63k1lzWsiVdU_U!-j{Ku5%3!bZgvJo0PQ7@Z}5s5Feo{@dVU)jE?!py*g O&fw|l=d#Wzp$P!V!$MC0 literal 0 HcmV?d00001 diff --git a/docs/images/pets/twiggle.png b/docs/images/pets/twiggle.png new file mode 100644 index 0000000000000000000000000000000000000000..2b9f65fe907379c9e20978541d5ec3f9e788a9d5 GIT binary patch literal 756 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8I2}rW6{ZPfgz_i=b#WAGf*4w)a{SG_G9C)~o zsZqc{f`_en=D~!t3ol;Id?|U4q1o{>+aAXEO%E*#mM+?U=jpn)TmMd*ueAN?r~h7; za^7B>GdDi-ps5=}L<1`XNo-)?h9H9kMll#-(>cHdK|Clb3x1vzt-7+!{6GUEGaJti zu?H6v*2(90O)-9<_|5E9BZq`R0#ItcL`;T&ynXwUvis-v9_6Vzvv=vC=Q1o{JrW;Q z9(?-Xsfg6OkZNyRM`j+dmgg#g_T6?!90D8*r6rd0oXk<1Zn5=GgMYuH=_s06I^?;K4#YC4bp~ z?SH?m+a4r-bNViheOFjNLQOe2du8!~q-*BNc44*579e*s&$~apS~Y1suPE3X%yNH| ze*L}tWT~7FM9YUu0sHTl=b9#f4No}W&9;sas+8@||L-(9&K8R$P{!8$gz=6{r7wU@YKij!<-vm~O>*fi4{rYs@+t;PHr+xk&^x^K;rQa-B z%)tI&o6{|2yg+sB%%|c_kbsC}Ue9Z^g$<&!&33=AHY5rwR+u|Xo1$$64zCY$@+_jW zpuzL@M*H*M_nfk4b;=o5bFXEDL{zp*@6JZ6XFHSM89zJrP4OGluhV57%{V{zw;d=| n0DbBEr9Y7cmck

Show where a rare egg comes from -The guardian of the cave has been sitting on the **ember egg**. It leaves the -egg behind the first time a pet gets past it, so every pet can earn it once. +Three guardians have been sitting on a rare egg: + +| Area | Guardian | Egg | +|---|---|---| +| Meadow | Crowcomb | **beak egg** | +| Stream | Ripplesprite | **duck egg** | +| Cave | Gloompeep | **ember egg** | + +A guardian leaves its egg behind the first time a pet gets past it, so every +pet can earn each of them once. A pet that got past a guardian before that +guardian had an egg for it (or while there was no room for one among the +finds) finds the egg at the end of the path on a later trip to that area. After unpacking, the egg is among the finds and stays there, from one pet to the next, until you tap **brood** next to it. @@ -179,18 +189,22 @@ a pet meets most often, Lumoth the rarest, and Grumpcap only comes out in the rain. At the stream live the two adults of the stone line (below): Bouldergrin, and -more rarely Glimmerock. A friend of theirs is the only way to a stone egg. +more rarely Glimmerock. A friend of theirs is the only way to a stone egg. The +two adults of the hippo line bathe there too: Lillypot, and more rarely +Steamo; they are the only way to a hippo egg. In the forest live the two adults of the fox line (below): Filchfox, and more -rarely Roamtail. A friend of theirs is the only way to a fox egg. +rarely Roamtail. A friend of theirs is the only way to a fox egg. The two +adults of the leaf line live there too: Twiggle, and more rarely Needlenub; +they are the only way to a leaf egg. On the mountain live the two adults of the cloud line (below): Rumblefluff, which only comes out in the rain, and more rarely Prismist. A friend of theirs is the only way to a cloud egg. -The cave has no wild pets so far. The ember line -has none: its egg comes from a guardian. An ember pet with a slime for a -friend can still lay an ember egg, though. +The cave has no wild pets so far. The ember, duck and beak lines have none: +their eggs come from guardians. A pet of one of them with a slime for a friend +can still lay an egg of its own line, though. The values are in `core/src/wild.ts`. @@ -420,4 +434,214 @@ The values are in `core/src/life.ts`. +### The leaf line + +
+Show the leaf line + +| | Stage | +|---|---| +| ![Leaf egg](images/pets/leaf_egg.png) | **Leaf egg** – a seed with an acorn cap of woven husk and small leaves for speckles | +| ![Leaf baby](images/pets/leaf_baby.png) | **Baby** – a green slime wearing the top of its seed as a tilted cap, with a sprout on top | +| ![Sproutlet](images/pets/sproutlet.png) | **Child: Sproutlet** – a seedling with its seed cap pulled down to the eyes like a helmet, two leaves on top (a small one and a big one that flops to the right) and two little roots for feet | + +The stages last as long as the slime's. What the adults keep is the seed cap, +grown and woven into a pot. A plant likes the rain, so nothing of this line +needs an umbrella. + +![Twiggle](images/pets/twiggle.png) + +**Twiggle**, an old bonsai master that walks around in its pot. Pads of +leaves like clouds sit on a gnarled trunk, one reaching far to the right, and +the pot stands on its roots. It has a calm old face with half-shut eyes and a +beard of moss, and it is patient: it gets tired more slowly. In a scuffle, +leaves fly off its crown. + +![Needlenub](images/pets/needlenub.png) + +**Needlenub**, a round cactus in the same pot that wants nothing more than to +be petted. Its little arms are always up for a hug, petting means more to it +than to anyone, and the one flower on its head only opens when it is happy; +otherwise it is a bud. It stays in its pot rather than walking. + +
+ +
+Show how to get them + +Only petting counts for this line: a cactus that gets cuddled. + +| Form | Rule | +|---|---| +| Needlenub | the child was petted at least 5 times a day on average | +| Twiggle | everything else | + +From its second day on, Sproutlet's leaves show where it is heading: + +| Leaves | Heading for | +|---|---| +| fresh green | nothing yet (the first day) | +| the deep green of an old tree | Twiggle | +| pink, like a cactus flower | Needlenub | + +The values are in `core/src/life.ts`. + +
+ +### The duck line + +
+Show the duck line + +| | Stage | +|---|---| +| ![Duck egg](images/pets/duck_egg.png) | **Duck egg** – a cream egg whose lower half floats in pond water | +| ![Duck baby](images/pets/duck_baby.png) | **Baby** – a yellow slime with a curl of down on top, a little bill and orange webbed feet | +| ![Paddlet](images/pets/paddlet.png) | **Child: Paddlet** – a duckling that still sits in the bottom half of its eggshell and paddles it like a little boat | + +The stages last as long as the slime's. What the adults keep is the curl. A +duck likes the rain, so nothing of this line needs an umbrella. + +![Drakwing](images/pets/drakwing.png) + +**Drakwing**, a duck that is a little dragon. Its mallard-green head has a +horn where the curl was, its wide orange bill puffs little flames, it has +small bat wings and a spiky tail, and its belly is still duckling yellow. A +fire needs feeding: it gets hungry faster. In a scuffle, it breathes embers. + +![Captain Quill](images/pets/quill.png) + +**Captain Quill**, an old sea duck in a captain's cap with the curl sticking +out under it, a sailor collar and a red scarf. It loves a good game, and in a +scuffle it blows bubbles. + +
+ +
+Show how to get them + +Only scuffles won count for this line, on trips (guardians included). + +| Form | Rule | +|---|---| +| Drakwing | the child won at least one scuffle a day on average | +| Captain Quill | everything else | + +From its second day on, Paddlet's curl shows where it is heading: + +| Curl | Heading for | +|---|---| +| yellow | nothing yet (the first day) | +| a mallard's green | Drakwing | +| the navy of a captain's cap | Captain Quill | + +The values are in `core/src/life.ts`. + +
+ +### The hippo line + +
+Show the hippo line + +| | Stage | +|---|---| +| ![Hippo egg](images/pets/hippo_egg.png) | **Hippo egg** – a lavender egg that has been in the mud, caked at the bottom with drips going up | +| ![Hippo baby](images/pets/hippo_baby.png) | **Baby** – a round lavender baby with two little ears, a big pale muzzle and pink cheeks; wider and lower than the slime | +| ![Soakling](images/pets/soakling.png) | **Child: Soakling** – a young hippo on its way to the bath, a striped towel folded on its head with its little ears poking out | + +The stages last as long as the slime's. What the adults keep is the towel. + +![Lillypot](images/pets/lillypot.png) + +**Lillypot**, a pond hippo. Lily pads grow on its back like a coat and a lotus +is tucked into the towel on its head. It is calm and half asleep anyway: it +gets tired more slowly, and it is wet enough not to need an umbrella. In a +scuffle, it blows bubbles. + +![Steamo](images/pets/steamo.png) + +**Steamo**, the sauna master. Pink from the heat, eyes closed in bliss, a +towel wound round its head like a turban and steam rising off it. It is +always fresh from the sauna: it stays clean longer and gets sick less often. +In a scuffle, it lets off steam. + +
+ +
+Show how to get them + +Only baths count for this line. + +| Form | Rule | +|---|---| +| Steamo | the child was bathed at least twice a day on average | +| Lillypot | everything else | + +From its second day on, the stripe on Soakling's towel shows where it is +heading: + +| Stripe | Heading for | +|---|---| +| pink | nothing yet (the first day) | +| red hot | Steamo | +| the green of a lily pad | Lillypot | + +The values are in `core/src/life.ts`. + +
+ +### The beak line + +
+Show the beak line + +| | Stage | +|---|---| +| ![Beak egg](images/pets/beak_egg.png) | **Beak egg** – a wild bird's egg, robin blue with brown freckles of every size | +| ![Beak baby](images/pets/beak_baby.png) | **Baby** – a fluffy chick, grey-brown down with a lighter belly and a red crest | +| ![Crestling](images/pets/crestling.png) | **Child: Crestling** – a round young bird whose crest has grown into three feathers, with flying goggles pushed up on it: it wants to fly long before it can | + +The stages last as long as the slime's. What the adults keep is the red +crest; only the beak tells them apart. + +![Rapierre](images/pets/rapierre.png) + +**Rapierre**, a hummingbird fencer. Slim and shimmering green, it holds its +long needle beak like a rapier, the crest swept back like a musketeer's plume. +It never lands: it hovers, one wing a blur. A hummingbird burns through +everything: it gets tired and hungry faster. + +![Parcelbeak](images/pets/parcelbeak.png) + +**Parcelbeak**, a pelican mail carrier with a postman's cap, the crest +sticking through it, a huge orange bill and a mail bag across its chest. With +a letter for everyone, it is always in a good mood: its mood drops more +slowly. In a scuffle, letters fly out of its bag. + +
+ +
+Show how to get them + +Only practicing tricks together counts for this line (showing a trick it +already knows doesn't). + +| Form | Rule | +|---|---| +| Rapierre | the child practiced tricks at least twice a day on average | +| Parcelbeak | everything else | + +From its second day on, Crestling's goggles show where it is heading: + +| Goggles | Heading for | +|---|---| +| light blue lenses in a brown frame | nothing yet (the first day) | +| shimmering green | Rapierre | +| orange, with a post-blue frame | Parcelbeak | + +The values are in `core/src/life.ts`. + +
+ More lines are ideas so far; the [issues](https://github.com/mLampir/blobling/issues) collect them. diff --git a/tools/build_blob_sprites.py b/tools/build_blob_sprites.py index 5126174..dd24187 100644 --- a/tools/build_blob_sprites.py +++ b/tools/build_blob_sprites.py @@ -25,6 +25,10 @@ - roamtail_body / roamtail_faces, filchfox_body / filchfox_faces – its adults (faces of their own) - cloud_baby_body / cloud_baby_faces, nimbit_body / cloud_faces – baby and child of the cloud line - rumblefluff_body / rumblefluff_faces, prismist_body / prismist_faces – its adults (faces of their own) +- _baby_body / _baby_faces, _body / _faces – baby and child of the leaf + (sproutlet), duck (paddlet), hippo (soakling) and beak (crestling) lines +- twiggle, needlenub, drakwing, quill, steamo, lillypot, rapierre, parcelbeak (_body / _faces) – + their adults (faces of their own) - items – eggs, bowl, food, poop, ball, umbrella, clouds, medicine - trip – backpack, plants, decorations, hats, things along the path, opponents and guardians @@ -2477,6 +2481,749 @@ def egg_tags(egg): "cloud": {"o": (60, 88, 150), "e": (165, 200, 245), "E": (120, 155, 215), "h": (220, 236, 255), "t": (255, 255, 255), "x": (40, 60, 120)}, } + + +# ---------------------------------------------------------------- The leaf, duck, hippo and beak lines + +# Four more lines, each with its egg (EGG_GRIDS), baby, child and two adults. What every form of a +# line keeps: the seed shell (leaf: the baby's cap, the child's helmet, the adults' pot), the curl +# (duck), the towel (hippo) and the red crest (beak; only the beak changes between its adults). +# The child carries the colors the code recolors as a hint at its adult form (LURES in +# core/src/scene.ts): the leaves of the sprout, the curl, the towel's stripe, the goggles. + +def face_place(grid, eye_row, left, width): + """faceTop and faceShift for a face `width` wide whose top row is `eye_row` and whose left + edge is column `left` of the grid, as faceAnchor (core/src/sprites.ts) places it.""" + xs = [x for x, ch in enumerate(grid[eye_row]) if ch != "."] + return face_top(grid, eye_row), left + width / 2 - (xs[0] + xs[-1] + 1) / 2 + + +# The eggs: a seed with an acorn cap and little leaves; a cream egg floating in a pond; a lavender +# egg caked with mud at the bottom; a robin-blue bird's egg with brown freckles. +LEAF_EGG = [ + "....oooo....", + "...okKkKo...", + "..oKkKkKko..", + "..okKkKkKo..", + ".oooooooooo.", + ".oeeeeeeeEo.", + ".oeetteeeEo.", + ".oeeetteeEo.", + ".oeeeeeeeEo.", + ".oeeeeetteo.", + "..oeeetteo..", + "..oEeeeeEo..", + "...oEEEEo...", + "....oooo....", +] +DUCK_EGG = [ + "....oooo....", + "...ohheeo...", + "..oheeeeeo..", + "..oeeeeeeo..", + ".oeeeeeeeeo.", + ".oeeeeeeeEo.", + ".oeeeeeeeEo.", + ".oeeeeeeeEo.", + ".oettetteEo.", + ".otteetteto.", + "..otttttTo..", + "..otTtttTo..", + "...oTTTTo...", + "....oooo....", +] +HIPPO_EGG = [ + "....oooo....", + "...ohheeo...", + "..oheeeeeo..", + "..oeeteeeo..", + ".oeeeeeeeeo.", + ".oeeeeeteEo.", + ".oeteeeeeEo.", + ".oeeeeeeeEo.", + ".omeemeemEo.", + ".ommmmmmmMo.", + "..ommmmmMo..", + "..omMmmmMo..", + "...oMMMMo...", + "....oooo....", +] +BEAK_EGG = [ + "....oooo....", + "...ohheeo...", + "..ohetteeo..", + "..oeetteto..", + ".oteeeeeeeo.", + ".oeeeteeeEo.", + ".oeeeeeeteo.", + ".otteeeeeEo.", + ".otteeteeEo.", + ".oeeeeeeeEo.", + "..oeteeeEo..", + "..oEeeetEo..", + "...oEEEEo...", + "....oooo....", +] +EGG_GRIDS |= {"leaf": LEAF_EGG, "duck": DUCK_EGG, "hippo": HIPPO_EGG, "beak": BEAK_EGG} +RARE_EGG_PALETTES |= { + "leaf": {"o": (70, 48, 26), "e": (215, 185, 130), "E": (170, 135, 85), "h": (240, 220, 175), "t": (95, 175, 60), + "x": (60, 40, 20), "k": (140, 95, 50), "K": (105, 70, 35)}, + "duck": {"o": (90, 80, 55), "e": (250, 240, 200), "E": (215, 200, 150), "h": (255, 255, 235), "t": (90, 170, 230), + "T": (55, 120, 190), "x": (60, 50, 35)}, + "hippo": {"o": (70, 55, 85), "e": (190, 170, 210), "E": (150, 130, 175), "h": (225, 210, 240), "t": (240, 150, 175), + "m": (130, 90, 60), "M": (95, 62, 40), "x": (50, 35, 60)}, + "beak": {"o": (40, 85, 105), "e": (130, 205, 220), "E": (90, 165, 185), "h": (200, 240, 245), "t": (110, 70, 45), + "x": (30, 55, 70)}, +} + +# Shared by the adults of these lines: eyes 4×3 and the slime's mouths. A face: the two eyes +# `gap` apart, rosy cheeks on their outer sides, the mouth `mouth_row` rows below the top, +# centered (none for a beak or a bill: that is part of the body). +KIT_EYES = { # (left, right) + "open": (["wwpp", "wpgp", "wppp"],) * 2, + "closed": (["....", "....", "pppp"],) * 2, + "happy": (["....", ".pp.", "p..p"],) * 2, + "half": (["....", "dddd", "wppp"],) * 2, + "sad": (["p...", "wwpp", "wpgp"], ["...p", "wwpp", "wpgp"]), + "cross": (["..pp", "wwpp", "wpgp"], ["pp..", "wwpp", "wpgp"]), +} + + +def kit_face(gap, mouth_row=3, single=False): + """A face grid function for one of these adults; `single`: one eye, seen from the side.""" + width = 1 + (4 if single else gap + 4) + 1 + height = max(3, mouth_row + 2) + + def grid(eyes, mouth, blush): + rows = [list("." * width) for _ in range(height)] + left, right = KIT_EYES[eyes] + for y in range(3): + for x in range(4): + rows[y][1 + x] = left[y][x] + if not single: + rows[y][1 + gap + x] = right[y][x] + if mouth_row: + mx = (width - 4) // 2 + for y in range(2): + for x in range(4): + rows[mouth_row + y][mx + x] = MOUTHS[mouth][y][x] + if blush: + rows[2][0] = "k" + if not single: + rows[2][width - 1] = "k" + return ["".join(r) for r in rows] + grid.width = width + return grid + + +def kit_faces(**changes): + """FACES with some of them changed; a form with a beak has no mouth of its own.""" + return FACES | changes + + +BEAKED_FACES = {name: (eyes, "none", blush) for name, (eyes, mouth, blush) in FACES.items()} + +# ---- The leaf line: a seed that grows up into a plant with a pot of its own + +LEAF_PALETTE = { + "o": (25, 80, 35), # outline + "d": (60, 140, 55), # shadow + "b": (95, 190, 75), # leaf green + "l": (150, 225, 110), # lit + "h": (210, 250, 180), # highlight + "k": (160, 110, 60), # the seed shell + "K": (115, 75, 40), + "x": (70, 45, 25), + "g": (130, 220, 90), # the sprout's leaves (the hint) + "G": (60, 150, 50), + "s": (85, 130, 45), # its stem +} +# Baby: the baby slime wearing the top of its seed as a cap, a little askew, a sprout on top +LEAF_BABY = [ + "........G.g.....", + "........Ggsg....", + "......xxxxsxxx..", + "....xxkkKkkkKkx.", + "..xxkKkkkKkkkxx.", + ".oKKKKKKKKKKKKo.", + ".olhbbbbbbbbbdo.", + "olbbbbbbbbbbbddo", + "olbbbbbbbbbbbddo", + "obbbbbbbbbbbbddo", + "odbbbbbbbbbbdddo", + "oddddddddddddddo", + ".oooooooooooooo.", +] +LEAF_BABY_TAGS = body_tags(LEAF_BABY, 8, 8, flat_rows=3) +# Sproutlet, the child: a seedling with its seed shell pulled down to the eyes like a helmet; the +# sprout has grown into a small leaf and a big one that flops to the right; two roots for feet +SPROUTLET = [ + "..............gggg......", + ".....gg.....ggggggg.....", + "....gGgg...gGGggggGg....", + ".....gGgs.gGgggggGg.....", + "........sGgggGgg........", + ".........s..............", + "......xxxxsxxxxx........", + "....xxkkKkkkKkkkxx......", + "...xkkKkkkKkkkKkkkx.....", + "..xkKkkkKkkkKkkkKkkx....", + ".oKKKKKKKKKKKKKKKKKKKo..", + ".olhhbbbbbbbbbbbbbbbdo..", + "olhbbbbbbbbbbbbbbbbbbdo.", + "olbbbbbbbbbbbbbbbbbbbdo.", + "obbbbbbbbbbbbbbbbbbbbdo.", + "obbbbbbbbbbbbbbbbbbbddo.", + "obbbbbbbbbbbbbbbbbbbddo.", + "odbbbbbbbbbbbbbbbbbdddo.", + ".odbbbbbbbbbbbbbbbdddo..", + "..oddddddddddddddddoo...", + "...ooKKooooooooKKoo.....", + "....KK.K......K.KK......", +] +SPROUTLET_FACE_TOP, SPROUTLET_FACE_SHIFT = face_place(SPROUTLET, 11, 3, FACE_W) +SPROUTLET_TAGS = body_tags(SPROUTLET, 14, 11, flat_rows=3) +LEAF_ADULT_PALETTE = { + "o": (25, 60, 30), "g": (150, 225, 110), "G": (95, 190, 75), "v": (55, 140, 55), # leaves + "T": (150, 105, 65), "U": (105, 70, 40), "t": (190, 145, 95), # bark + "k": (175, 125, 70), "K": (125, 85, 45), # the pot: the seed shell, grown and woven + "m": (120, 160, 70), "M": (85, 120, 50), # moss + "r": (110, 75, 45), # roots + "s": (215, 245, 190), # the cactus' spines + "p": (255, 150, 190), "P": (220, 90, 140), "y": (255, 225, 90), # its flower +} +# Twiggle: an old bonsai master that walks around in its pot. Pads of leaves like clouds, one +# reaching far to the right; a gnarled trunk with a calm old face and a beard of moss; the pot +# stands on its roots. It walks, slowly. +TWIGGLE = [ + "........oooooo.......ooooo......", + "......ooggggGGoo...ooggggGoo....", + ".....ogggGGGGGGGo.ogggGGGGGGooo.", + "....ogggGGGGGGGGvoogGGGGGGGGgGGo", + "...oggGGGGGGGGGvvvGGGGGGGGGGGGvo", + "...oGGGGGGGGGGvvvvGGGGGGGGGGvvo.", + "....oovvvGGvvvvoovvvvvvvvvvvoo..", + "......oooovvoooUUoooooooooo.....", + "..........oUUooUUo..............", + "...........oUUUUo...............", + "...........oTTTTTTTTTTTUUo......", + "..........oTTtTTTTTTTTTTUo......", + "..........oTtTTTTTTTTTTTUo......", + "..........oTtTTTTTTTTTTTUo......", + "..........oTTTTTTTTTTTTTUo......", + "..........oTTTTTTTTTTTTTUo......", + "..........oTTmmmmmmmmmmTUo......", + "........ooooommMmmmmMmmooooo....", + ".......oKkKkKkKmmMmmmMKkKkKko...", + "......oKkkKkkKkkKkkKkkKkkKkkKo..", + "......okKkkKkkKkkKkkKkkKkkKkko..", + ".......okKkkKkkKkkKkkKkkKkkKo...", + "........oKKKKKKKKKKKKKKKKKKo....", + ".........ooooooooooooooooooo....", + "..........rr.r..........r.rr....", + ".........r....r........r....r...", +] +TWIGGLE_FACE_TOP, TWIGGLE_FACE_SHIFT = face_place(TWIGGLE, 12, 12, 13) +TWIGGLE_TAGS = species_tags([TWIGGLE, drop_rows(TWIGGLE, 13)], 13, 18, idle_ms=900) +TWIGGLE_TAGS["walk"] = walk_tags(TWIGGLE, 13, range(9, 15), range(23, 30), 24, ms=(260, 160)) +# Needlenub: a round cactus that wants to be petted. Its little arms are always up for a hug, the +# one flower on its head opens when it is happy (closed, the code colors it as a bud); it sits in +# the same seed-shell pot and hops. +NEEDLENUB = [ + "...............pp...............", + ".............pPyPp..............", + "..............pPp...............", + "...........ooooGooooo...........", + ".........ooGGsGGGGsGGoo.........", + "........oGGgGGGGGGGGGsvo........", + ".......oGgsGGGGGGsGGGGGvo.......", + "..oo..oGgGGGGGGGGGGGGGsGvo..oo..", + ".oGso.oGsGGGGGGGGGGGGGGGvo.osGo.", + ".oGGo.oGgGGGGGGGGGGGGGGGvo.oGvo.", + ".oGGvooGGGGGGGGGGGGGGGGsvooGvvo.", + "..oGGvoGsGGGGGGGGGGGGGGGvoGvvo..", + "...oGGGGGGGGGGGGGGGGGGGGGGvvo...", + "....ooGGGGGsGGGGGGGGsGGGvvoo....", + "......oGGGGGGGGGGGGGGGGGvo......", + "......ovGGGGsGGGGGGsGGGvvo......", + ".....ooooooooooooooooooooo......", + "....oKkKkKkKkKkKkKkKkKkKkKko....", + "....okkKkkKkkKkkKkkKkkKkkKko....", + ".....okKkkKkkKkkKkkKkkKkko......", + ".....oKkKkkKkkKkkKkkKkkKko......", + "......oKKKKKKKKKKKKKKKKKo.......", + ".......ooooooooooooooooo........", + "........rr.r.......r.rr.........", +] +NEEDLENUB_FACE_TOP, NEEDLENUB_FACE_SHIFT = face_place(NEEDLENUB, 8, 10, 13) +NEEDLENUB_TAGS = species_tags([NEEDLENUB, drop_rows(NEEDLENUB, 14)], 14, 16) + +# ---- The duck line: a duckling that never quite leaves the water + +DUCK_PALETTE = { + "o": (120, 85, 15), # outline + "d": (225, 175, 35), # shadow + "b": (255, 215, 70), # duckling yellow + "l": (255, 235, 140), # lit + "h": (255, 250, 210), # highlight + "a": (250, 140, 40), # feet and bill + "A": (200, 95, 25), + "q": (245, 185, 40), # the curl (the hint) + "Q": (210, 140, 30), + "e": (250, 240, 200), # the eggshell + "E": (215, 200, 150), +} +# Baby: a yellow slime with a curl of down on top and orange webbed feet +DUCK_BABY = [ + "........dd......", + ".......d..d.....", + "..........d.....", + ".....oobbdo.....", + "...oolhllbboo...", + "..olhhlbbbbbdo..", + ".ollhbbbbbbbbdo.", + ".olbbbbbbbbbbdo.", + "olbbbbbbbbbbbddo", + "olbbbbbbbbbbbddo", + "obbbbbbbbbbbbddo", + "odbbbbbbbbbbdddo", + "oddddddddddddddo", + ".oaAaooooooaAao.", +] +DUCK_BABY = [row.replace("d", "q") if y < 3 else row for y, row in enumerate(DUCK_BABY)] +DUCK_BABY_TAGS = body_tags(DUCK_BABY, 9, 8, flat_rows=3) +# Paddlet, the child: a duckling that still sits in the bottom half of its eggshell and paddles it +# like a little boat, its webbed feet sticking out underneath; a bill instead of a mouth +PADDLET = [ + "...........qq...........", + "..........q..q..........", + ".............Q..........", + "........oooobQoo........", + "......oolhhlbbbboo......", + ".....olhhlbbbbbbbbdo....", + "....olhlbbbbbbbbbbbdo...", + "...olhbbbbbbbbbbbbbbdo..", + "...olbbbbbbbbbbbbbbbdo..", + "..olbbbbbbbbbbbbbbbbbdo.", + "..obbbbbbbbbbbbbbbbbbdo.", + ".odbbbbbbbbbbbbbbbbbbddo", + "oddbbbbbbbbbbbbbbbbbbddo", + "odEbeEbeEbeEbeEbeEbeEddo", + ".oeeEeeeEeeeEeeeEeeeEEo.", + ".oeeeeeeeeeeeeeeeeeeeEo.", + "..oeeeeeeeeeeeeeeeeeEo..", + "...oEEEeeeeeeeeeeeEEo...", + "....ooEEEEEEEEEEEEoo....", + "......oaAao..oaAao......", + ".....aAaAa....aAaAa.....", +] +PADDLET_FACE_TOP, PADDLET_FACE_SHIFT = face_place(PADDLET, 5, 4, FACE_W) +PADDLET_TAGS = body_tags(PADDLET, 9, 12, flat_rows=3) +DUCK_ADULT_PALETTE = { + "o": (40, 40, 30), + "G": (40, 150, 90), "g": (90, 200, 130), "v": (20, 95, 60), # a mallard's green + "b": (255, 215, 70), "l": (255, 235, 140), "d": (225, 175, 35), # the duckling's yellow + "a": (250, 140, 40), "A": (200, 95, 25), # bill and feet + "w": (120, 200, 120), "W": (70, 140, 80), # the dragon's wing + "f": (255, 170, 60), "F": (255, 90, 40), # a puff of flame + "n": (35, 45, 90), "N": (60, 75, 135), "y": (255, 210, 80), "s": (255, 255, 250), # the cap + "B": (90, 160, 225), "r": (215, 50, 50), # sailor collar and scarf +} +# Drakwing: a duck that is a little dragon (a drake is a male duck). A mallard-green head whose +# curl has become a horn, a wide bill that puffs flames, small bat wings and a spiky tail; the +# belly stays duckling yellow. It walks, waddling. +DRAKWING = [ + "..............oo................", + ".............ogo................", + "...............go...............", + "...........ooooogoo.............", + ".........oogggGGGGGoo.....o....o", + "........ogggGGGGGGGGvo...oWo..oW", + ".......oggGGGGGGGGGGGvo.oWwWooWw", + ".......ogGGGGGGGGGGGGvooWwwwWWww", + ".......oGGGGGGGGGGGGGvooWwwwwwww", + "..F....oGGGGGGGGGGGGGvooWwwwwwWo", + ".FfF..oaaaaaaaaaaaaaaaoooWwWwWo.", + "..FfFoaAAAAAAAAAAAAAAAAo.o.o.o..", + "....ooaaaaaaaaaaaaaaaaao........", + "......oovvGGGGGGGGGGGGvo........", + ".......ovlbbbbbbbbbbbdvo........", + "......ovlbbbbbbbbbbbbbdvo.ooo...", + "......ovbbbbbbbbbbbbbbdvo...gg..", + "......ovbbbbbbbbbbbbbddvoo.ogGo.", + "......ovdbbbbbbbbbbbbddvoggGGo..", + ".......ovddbbbbbbbbbdddvGGGo....", + "........ovvddddddddddvvvoo......", + ".........ooovvvvvvvvvooo........", + "............aAa...aAa...........", + "...........aAaAa.aAaAa..........", +] +DRAKWING_FACE_TOP, DRAKWING_FACE_SHIFT = face_place(DRAKWING, 7, 9, 13) +DRAKWING_TAGS = species_tags([DRAKWING, dots(DRAKWING, {(1, 10): ".", (2, 9): ".", (3, 10): "f"})], 16, 15) +DRAKWING_TAGS["walk"] = walk_tags(DRAKWING, 16, range(11, 15), range(18, 22), 22, ms=(180, 110)) +# Captain Quill: an old sea duck in a captain's cap with the curl sticking out under it, a +# sailor collar with a red scarf. It walks, rolling like a sailor. +QUILL = [ + "...........b....................", + "..........bobooooooo............", + ".........oonnnnnnnnnnoo.........", + "........onnnnnyyynnnnnno........", + "........onnnnnynynnnnnno........", + ".......oNNNNNNNNNNNNNNNNo.......", + "......osssssssssssssssssso......", + "......oyyyyyyyyyyyyyyyyyyo......", + "......olllllllllllllllldo.......", + "......olllllllllllllllldo.......", + "......olllllllllllllllldo.......", + "......olllllllllllllllldo.......", + ".....oaaaaaaaaaaaaaaaaaaao......", + ".....oaAAAAAAAAAAAAAAAAAAo......", + "......oaaaaaaaaaaaaaaaaaoA......", + ".....oBBsBBBBrrrrrrBBBBsBBo.....", + "....oBBBsBBBBrrrrrrBBBsBBBBo....", + "....olsBBBBBlbrrrrblBBBBBsdo....", + "....olllbbbbbbbrrbbbbbbbbbdo....", + "....olbbbbbbbbbbbbbbbbbbbbdo....", + "....odbbbbbbbbbbbbbbbbbbbddo....", + ".....odbbbbbbbbbbbbbbbbbddo.....", + "......oddddddddddddddddddo......", + ".......ooooooooooooooooooo......", + "..........aAa......aAa..........", + ".........aAaAa....aAaAa.........", +] +QUILL_FACE_TOP, QUILL_FACE_SHIFT = face_place(QUILL, 8, 9, 13) +QUILL_TAGS = species_tags([QUILL, drop_rows(QUILL, 19)], 19, 16) +QUILL_TAGS["walk"] = walk_tags(QUILL, 19, range(9, 15), range(18, 24), 24, ms=(220, 130)) + +# ---- The hippo line: a hippo that loves its bath + +HIPPO_PALETTE = { + "o": (70, 55, 85), # outline + "d": (135, 115, 160), # shadow + "b": (175, 155, 200), # lavender + "l": (205, 190, 225), # lit + "h": (235, 225, 245), # highlight + "I": (240, 150, 175), # inside the ears + "m": (225, 195, 210), # muzzle + "M": (190, 160, 180), + "n": (90, 60, 80), # nostrils + "w": (250, 245, 240), # the towel + "W": (210, 200, 205), + "T": (240, 130, 160), # its stripe (the hint) +} +# Baby: a round lavender baby with two little ears and a big pale muzzle +HIPPO_BABY = [ + "...oo......oo...", + "..oIIooooooIIo..", + "...olhllbbbbo...", + "..olhhlbbbbbdo..", + ".ollhbbbbbbbbdo.", + ".olbbbbbbbbbbdo.", + "olbbbbbbbbbbbddo", + "obbbmmmmmmmmbbdo", + "obmmmmmmmmmmmmdo", + "obmmnmmmmmmnmMdo", + "odmmmmmmmmmmMMdo", + "oddMMMMMMMMMMddo", + ".oooooooooooooo.", +] +HIPPO_BABY_TAGS = body_tags(HIPPO_BABY, 6, 8, flat_rows=3) +# Soakling, the child: a young hippo on its way to the bath, a striped towel folded on its head +# with the little ears poking out under it +SOAKLING = [ + "......oooooooooooo......", + ".....owwwwwwwwwwwwo.....", + "....owTTTTTTTTTTTTwo....", + "....owwwwwwwwwwwwwWo....", + "..oo.oWWWWWWWWWWWWWo.oo.", + ".oIIooolhhlbbbbbbbbooIIo", + "..oolhhlbbbbbbbbbbbbdoo.", + "..olhhbbbbbbbbbbbbbbbdo.", + ".olhbbbbbbbbbbbbbbbbbbdo", + ".olbbbbbbbbbbbbbbbbbbbdo", + "olbbbbbbbbbbbbbbbbbbbbdo", + "obbbbbbbbbbbbbbbbbbbbbdo", + "obbbmmmmmmmmmmmmmmmbbbdo", + "obmmmmmmmmmmmmmmmmmmmbdo", + "obmmmnnmmmmmmmmmnnmmMbdo", + "obmmmmmmmmmmmmmmmmmMMbdo", + "odbMMmmmmmmmmmmmmMMMbddo", + "oddbMMMMMMMMMMMMMMMbdddo", + ".oddddddddddddddddddddo.", + "..obbdo..........obbdo..", + "..ooooo..........ooooo..", +] +SOAKLING_FACE_TOP, SOAKLING_FACE_SHIFT = face_place(SOAKLING, 6, 4, FACE_W) +SOAKLING_TAGS = body_tags(SOAKLING, 10, 12, flat_rows=3) +HIPPO_ADULT_PALETTE = HIPPO_PALETTE | { + "o": (70, 45, 75), "d": (175, 120, 165), "b": (215, 160, 200), "l": (235, 195, 220), "h": (250, 225, 240), + "m": (245, 205, 215), "M": (215, 165, 185), "n": (110, 55, 85), # Steamo: pink from the heat + "s": (235, 240, 250), "S": (195, 205, 225), # steam + "e": (175, 155, 200), "E": (135, 115, 160), "u": (205, 190, 225), # Lillypot: still lavender + "P": (90, 170, 120), "p": (140, 210, 150), "q": (55, 120, 85), # lily pads + "L": (250, 170, 200), "Y": (255, 220, 100), # the lotus +} +# Steamo: the sauna master. Pink from the heat, eyes closed in bliss, a towel wound round its head +# like a turban and one round its middle, steam rising off it. It walks. +STEAMO = [ + "....s.......oooooooooo..........", + "...sSs....oowwwwwwwwwwoo...s....", + "....s....owTTwwwwwwwTTwwo.sSs...", + ".........owwwwTTTTTTwwwwo..s....", + "........oWwwwwwwwwwwwwwWWo......", + "......oo.oWWWWWWWWWWWWWWo.oo....", + ".....oIIooolhhlbbbbbbbbbooIIo...", + "......oolhhlbbbbbbbbbbbbbdoo....", + "......olhhbbbbbbbbbbbbbbbbdo....", + ".....olhbbbbbbbbbbbbbbbbbbdo....", + ".....olbbbbbbbbbbbbbbbbbbbbdo...", + "....olbmmmmmmmmmmmmmmmmmmmbdo...", + "..s.obmmmmnnmmmmmmmmmnnmmmmbdo..", + ".sSsobmmmmmmmmmmmmmmmmmmmmMbdo..", + "..s.odmmmmmmmmmmmmmmmmmmmMMbdo..", + "....odbMMmmmmmmmmmmmmmmMMMbddo..", + "....oddbMMMMMMMMMMMMMMMMMbdddo..", + "....owwwwwwwwwwwwwwwwwwwwwwwwo..", + "....owTTwwwwwwwwwwwwwwwwwTTwwo..", + "....oWWwwwwwwwwwwwwwwwwwwwwWWo..", + "....oddbbbbbbbbbbbbbbbbbbbbddo..", + ".....oddddddddddddddddddddddo...", + "......obbdo............obbdo....", + "......ooooo............ooooo....", +] +STEAMO_FACE_TOP, STEAMO_FACE_SHIFT = face_place(STEAMO, 7, 10, 15) +STEAMO_TAGS = species_tags([STEAMO, dots(STEAMO, {(4, 0): ".", (3, 1): ".", (5, 1): ".", (4, 2): ".", (27, 1): ".", + (26, 2): ".", (28, 2): ".", (27, 3): ".", (4, 1): "s"})], 10, 16) +STEAMO_TAGS["walk"] = walk_tags(STEAMO, 10, range(6, 11), range(23, 28), 22, ms=(240, 140)) +# Lillypot: a pond hippo. Lily pads grow on its back like a coat, a lotus is tucked into the +# towel folded on its head, and a lily leaf sticks out on the right. It walks. +LILLYPOT = [ + "...............LL...............", + "..............LhYL..............", + "...........oooLLLLooo...........", + "..........owwwwwwwwwwo..........", + ".........owTTTTTTTTTTwo.........", + ".........oWWWWWWWWWWWWo.........", + "......oo.oeeeeeeeeeeeeo.oo......", + ".....oIeooeuuueeeeeeeeeooeIo....", + "......ooueuueeeeeeeeeeeeeEoo....", + "......oueeeeeeeeeeeeeeeeeEo.ppp.", + ".....oueeeeeeeeeeeeeeeeeeeEopqqp", + "....oPPppeemmmmmmmmmmmmeePPPopq.", + "...oPpppPpmmmmmmmmmmmmmmPppPPo..", + "..oPpPPpPPmmnnmmmmmmnnmmPPpppPo.", + "..oPpppPPpmmmmmmmmmmmmmmPpPppPo.", + "..oPPpPpqpmMmmmmmmmmmmMmpqPpPPo.", + "..oqPPpPqqpMMMMMMMMMMMMMpPPqPPo.", + "...oqqPPPPpppPPPpppPPPpppPPqqo..", + "....oqqqqqqqqqqqqqqqqqqqqqqqo...", + ".....oEEeeeeeeeeeeeeeeeeeEEo....", + "......oEEEEEEEEEEEEEEEEEEEo.....", + "......oeeEo...........oeeEo.....", + "......ooooo...........ooooo.....", +] +LILLYPOT_FACE_TOP, LILLYPOT_FACE_SHIFT = face_place(LILLYPOT, 8, 11, 13) +LILLYPOT_TAGS = species_tags([LILLYPOT, drop_rows(LILLYPOT, 12)], 12, 16) +LILLYPOT_TAGS["walk"] = walk_tags(LILLYPOT, 12, range(6, 11), range(22, 27), 21, ms=(240, 140)) + +# ---- The beak line: a bird whose crest stays and whose beak decides what it becomes + +BEAK_PALETTE = { + "o": (60, 45, 40), # outline + "d": (120, 95, 80), # shadow + "b": (165, 135, 110), # downy grey-brown + "l": (200, 175, 150), # lit + "h": (230, 215, 195), # highlight + "c": (235, 225, 205), # the belly + "r": (230, 90, 60), # the crest + "R": (170, 55, 40), + "a": (230, 175, 70), # beak and legs + "A": (175, 120, 40), + "L": (150, 220, 240), # the lenses of the goggles (the hint) + "G": (95, 70, 50), # their frame +} +# Baby: a fluffy chick with a lighter belly and a crest of three feathers +BEAK_BABY = [ + "......r.r.r.....", + "......rRrRr.....", + ".....oooRooo....", + "...oolhllbboo...", + "..olhhlbbbbbdo..", + ".ollhbbbbbbbbdo.", + ".olbbbbbbbbbbdo.", + "olbbbbccccbbbddo", + "olbbbccccccbbddo", + "obdbbccccccbdbdo", + "odbdbbccccbdbddo", + "odbdbdbbbbdbdddo", + ".oooooooooooooo.", +] +BEAK_BABY_TAGS = body_tags(BEAK_BABY, 8, 8, flat_rows=3) +# Crestling, the child: a round young bird. The crest has grown into three feathers, and it wears +# flying goggles pushed up on its head: it wants to fly long before it can. Little wings, thin legs. +CRESTLING = [ + "........r...r...r.......", + "........rr..r..rr.......", + ".........rRrRrRr........", + ".......oooRRRRRooo......", + ".....oolhhlbbbbbbboo....", + "....oGGGGGGGGGGGGGGGo...", + "...oGGLLLGGbbbbGGLLLGGo.", + "..olGGLhLGGbbbbGGLhLGGdo", + "..olhGGGGGbbbbbbGGGGGbdo", + ".olbbbbbbbbbbbbbbbbbbbdo", + ".olbbbbbbbbbbbbbbbbbbbdo", + "lobbbbbbbbbbbbbbbbbbbbol", + "ldobbbbbbbbbbbbbbbbbbodl", + ".ddobbbbbbbbbbbbbbbbodd.", + "..dobbbbbccccccbbbbbod..", + "...obbbbccccccccbbbbo...", + "...odbbbccccccccbbbdo...", + "....oddbbccccccbbddo....", + ".....oooooooooooooo.....", + "........aa....aa........", + ".......aAa...aAa........", + "......aa.a..aa.a........", +] +CRESTLING_FACE_TOP, CRESTLING_FACE_SHIFT = face_place(CRESTLING, 9, 4, FACE_W) +CRESTLING_TAGS = body_tags(CRESTLING, 10, 12, flat_rows=3) +BEAK_ADULT_PALETTE = { + "o": (35, 30, 45), "r": (230, 70, 55), "R": (165, 40, 35), # the crest + "a": (240, 185, 70), "A": (185, 125, 40), # Rapierre's beak and legs + "g": (60, 190, 140), "G": (30, 130, 110), "v": (20, 85, 85), # a hummingbird's green + "q": (140, 90, 200), "Q": (95, 55, 150), "c": (235, 230, 215), # its purple collar, the belly + "S": (190, 200, 210), # the blur of its wings + "s": (250, 250, 250), "n": (45, 70, 120), "N": (70, 100, 160), "y": (255, 215, 80), # the post + "e": (250, 240, 215), "E": (210, 195, 160), # letters + "p": (245, 160, 60), "P": (205, 115, 35), # the pelican's bill and feet + "z": (235, 200, 140), "Z": (170, 120, 70), # the mail bag +} +# Rapierre: a hummingbird fencer. Slim and green, a long needle beak held like a rapier, the crest +# swept back like a musketeer's plume, its wings a blur. It never walks: it hovers. +RAPIERRE = [ + ".............rr.................", + "...........rrRr.................", + "..........rRRr..................", + "...........ooooo................", + ".........oogggggoo..............", + "........ogggGGGGGvo.............", + ".......oggGggggGGvo.............", + ".......ogGgggggGGvoaaaaaaaaaaaaa", + ".......oggGggggGGvoAAAAAAAAAAAA.", + "..S.....ogGGGGGGvo..............", + ".S.S.S...ooqqqqqoo..............", + "S.S.S.S.oqQqqqqQqo..............", + ".S.S.S.oqqcccccqQqo.............", + "..S.S.oqqcccccccqQo.............", + ".......oqqccccccccqQo...........", + ".......oGqqccccccqqGo...........", + "........oGGqqqqqqqGGo...........", + ".........oGGGGGGGGvo............", + "..........oovGGGvoo.............", + "...........oaoGGoao.............", + "............o.oGGo..............", + "..............oGvGo.............", + ".............oGo.oGo............", + ".............oo...oo............", +] +RAPIERRE_FACE_TOP, RAPIERRE_FACE_SHIFT = face_place(RAPIERRE, 6, 10, 6) +RAPIERRE_TAGS = species_tags([RAPIERRE, dots(RAPIERRE, {(x, y): ("S" if RAPIERRE[y][x] == "." else ".") + for y in range(9, 14) for x in range(0, 7) + if RAPIERRE[y][x] in ".S"})], 13, 13, idle_ms=90) +# Parcelbeak: a pelican mail carrier. A postman's cap with the crest sticking through it, a huge +# bill with a throat pouch full of letters, a mail bag across its chest, big webbed feet. It walks. +PARCELBEAK = [ + ".............r.r.r..............", + "..............rRr...............", + "..........oooonRnoooo...........", + ".........onnnnnnnnnnnno.........", + "........oNNNNNyyNNNNNNNo........", + "........oooooooooooooooo........", + "........osssssssssssssso........", + "........osssssssssssssso........", + "........osSsssssssssssSo........", + ".....ooooopppppppppppppppppppo..", + "....oPPPPPPPPPPPPPPPPPPPPPPPPo..", + ".....ooPpppppppppppppppppppoo...", + ".......oPeeeeEeeeeeeePo.........", + "......oPeesseeRReesseePo........", + "......oPeeeeeeRReeeeeePo........", + ".......oPeeEeeeeeeeEePo.........", + "........ooPPPPPPPPPPoo..........", + ".......ossoooooooooosso.........", + "......ossssSSsssssSSsssso.......", + ".....osssssZZsssssssssSSso......", + ".....osSssssSZZZZZZZsssSso......", + ".....osSsssssZnnyynnZsSSso......", + "......oSsssssZnnnnnnZsSso.......", + ".......oSSssssZZZZZZsSSo........", + "........oooooooooooooo..........", + ".........ppPp....ppPp...........", + "........pPpPpp..pPpPpp..........", +] +PARCELBEAK_FACE_TOP, PARCELBEAK_FACE_SHIFT = face_place(PARCELBEAK, 6, 11, 12) +PARCELBEAK_TAGS = species_tags([PARCELBEAK, drop_rows(PARCELBEAK, 19)], 19, 15) +PARCELBEAK_TAGS["walk"] = walk_tags(PARCELBEAK, 19, range(8, 14), range(16, 23), 24, ms=(220, 130)) + +# Faces. Babies: the slime's baby faces, mouths in the line's colors. Children: the child's +# face; the duckling and the young bird have a bill or a beak instead of a mouth. +LEAF_FACE_PALETTE = FACE_PALETTE | {"d": (60, 140, 55), "m": (25, 80, 35)} +DUCK_FACE_PALETTE = FACE_PALETTE | {"d": (225, 175, 35), "m": (250, 140, 40), "a": (250, 140, 40), + "A": (200, 95, 25), "r": (175, 40, 70)} +HIPPO_FACE_PALETTE = FACE_PALETTE | {"d": (135, 115, 160), "m": (90, 60, 80), "p": (50, 40, 70)} +BEAK_FACE_PALETTE = FACE_PALETTE | {"d": (120, 95, 80), "m": (230, 175, 70), "a": (230, 175, 70), + "A": (175, 120, 40), "p": (45, 35, 35)} +BILL_SHUT = ["aaaaaa", ".AAAA."] +BILL_OPEN = ["aaaaaa", "ArrrrA", ".AAAA."] +BEAKLET_SHUT = ["aaaa", ".AA."] +BEAKLET_OPEN = ["aaaa", "ArrA", ".AA."] + + +def billed_face_grid(shut, open_): + def grid(eyes, mouth, blush): + rows = [list(r) for r in face_grid(eyes, "none", blush)] + [list("." * FACE_W)] + bill = open_ if mouth in ("open", "laugh") else shut + left = (FACE_W - len(bill[0])) // 2 + for y, line in enumerate(bill): + for x, ch in enumerate(line): + if ch != ".": + rows[6 + y][left + x] = ch + return ["".join(r) for r in rows] + return grid + + +duck_face_grid = billed_face_grid(BILL_SHUT, BILL_OPEN) +beak_face_grid = billed_face_grid(BEAKLET_SHUT, BEAKLET_OPEN) + +# The adults' faces (kit_face): each its own set and palette +twiggle_face_grid = kit_face(7) +TWIGGLE_FACES = kit_faces(normal=("half", "small", False)) # calm, wise, a little sleepy +TWIGGLE_FACE_PALETTE = {"w": (245, 240, 225), "p": (55, 35, 20), "g": (255, 255, 255), "d": (105, 70, 40), + "m": (60, 40, 22), "r": (170, 60, 50), "k": (230, 140, 120)} +needlenub_face_grid = kit_face(7) +NEEDLENUB_FACES = kit_faces(normal=("open", "small", True)) # always hoping for a cuddle +NEEDLENUB_FACE_PALETTE = {"w": (240, 250, 235), "p": (25, 50, 30), "g": (255, 255, 255), "d": (55, 140, 55), + "m": (25, 60, 30), "r": (200, 60, 90), "k": (255, 150, 190)} +drakwing_face_grid = kit_face(7, mouth_row=0) +DRAKWING_FACE_PALETTE = {"w": (240, 250, 235), "p": (20, 40, 30), "g": (255, 255, 255), "d": (20, 95, 60), + "k": (255, 130, 110)} +quill_face_grid = kit_face(7, mouth_row=0) +QUILL_FACE_PALETTE = {"w": (255, 255, 255), "p": (35, 45, 90), "g": (255, 255, 255), "d": (225, 175, 35), + "k": (255, 150, 150)} +steamo_face_grid = kit_face(9, mouth_row=6) +STEAMO_FACES = kit_faces(normal=("closed", "small", True), smile=("closed", "small", True), + blink=("closed", "small", True)) # its eyes closed in bliss +STEAMO_FACE_PALETTE = {"w": (255, 250, 252), "p": (110, 55, 85), "g": (255, 255, 255), "d": (175, 120, 165), + "m": (110, 55, 85), "r": (200, 70, 100), "k": (245, 120, 150)} +lillypot_face_grid = kit_face(7, mouth_row=6) +LILLYPOT_FACE_PALETTE = {"w": (245, 245, 255), "p": (50, 40, 70), "g": (255, 255, 255), "d": (135, 115, 160), + "m": (90, 60, 80), "r": (200, 80, 110), "k": (250, 170, 200)} +rapierre_face_grid = kit_face(0, mouth_row=0, single=True) +RAPIERRE_FACE_PALETTE = {"w": (240, 255, 250), "p": (20, 40, 40), "g": (255, 255, 255), "d": (20, 85, 85), + "k": (255, 130, 140)} +parcelbeak_face_grid = kit_face(6, mouth_row=0) +PARCELBEAK_FACE_PALETTE = {"w": (255, 255, 255), "p": (35, 30, 45), "g": (255, 255, 255), "d": (190, 200, 210), + "k": (255, 160, 160)} ITEMS = { "bowl": ["BBBBBBBBBBB", ".bbbbbbbbD.", "..bbbbbbD..", "...DDDDD..."], "food_full": ["...fffff...", "..fffffFf..", ".fffffffFf."], @@ -3539,6 +4286,30 @@ def main(): write_sheet("prismist_body", body_sheet(PRISMIST_TAGS, PRISMIST_PALETTE), faceTop=PRISMIST_FACE_TOP, faceShift=PRISMIST_FACE_SHIFT) write_sheet("prismist_faces", face_sheet(prismist_face_grid, PRISMIST_FACE_PALETTE, PRISMIST_FACES)) + for line, palette, face_palette, baby_tags, child, child_tags, child_faces in ( + ("leaf", LEAF_PALETTE, LEAF_FACE_PALETTE, LEAF_BABY_TAGS, "sproutlet", SPROUTLET_TAGS, face_grid), + ("duck", DUCK_PALETTE, DUCK_FACE_PALETTE, DUCK_BABY_TAGS, "paddlet", PADDLET_TAGS, duck_face_grid), + ("hippo", HIPPO_PALETTE, HIPPO_FACE_PALETTE, HIPPO_BABY_TAGS, "soakling", SOAKLING_TAGS, face_grid), + ("beak", BEAK_PALETTE, BEAK_FACE_PALETTE, BEAK_BABY_TAGS, "crestling", CRESTLING_TAGS, beak_face_grid)): + write_sheet(f"{line}_baby_body", body_sheet(baby_tags, palette)) + write_sheet(f"{line}_baby_faces", face_sheet(baby_face_grid, face_palette)) + name = child.upper() + write_sheet(f"{child}_body", body_sheet(child_tags, palette), faceTop=globals()[f"{name}_FACE_TOP"], + faceShift=globals()[f"{name}_FACE_SHIFT"]) + write_sheet(f"{line}_faces", face_sheet(child_faces, face_palette)) + for name, palette, faces in (("twiggle", LEAF_ADULT_PALETTE, TWIGGLE_FACES), + ("needlenub", LEAF_ADULT_PALETTE, NEEDLENUB_FACES), + ("drakwing", DUCK_ADULT_PALETTE, BEAKED_FACES), + ("quill", DUCK_ADULT_PALETTE, BEAKED_FACES), + ("steamo", HIPPO_ADULT_PALETTE, STEAMO_FACES), + ("lillypot", HIPPO_ADULT_PALETTE, FACES), + ("rapierre", BEAK_ADULT_PALETTE, BEAKED_FACES), + ("parcelbeak", BEAK_ADULT_PALETTE, BEAKED_FACES)): + upper = name.upper() + write_sheet(f"{name}_body", body_sheet(globals()[f"{upper}_TAGS"], palette), + faceTop=globals()[f"{upper}_FACE_TOP"], faceShift=globals()[f"{upper}_FACE_SHIFT"]) + write_sheet(f"{name}_faces", face_sheet(globals()[f"{name}_face_grid"], globals()[f"{upper}_FACE_PALETTE"], + faces)) items = {name: [(to_image(rows, ITEM_PALETTE), 1000)] for name, rows in ITEMS.items()} items |= {tag: [(to_image(g, ITEM_PALETTE), ms) for g, ms in frames] for tag, frames in EGG_TAGS.items()} for line, palette in RARE_EGG_PALETTES.items(): diff --git a/tools/pet_preview.ts b/tools/pet_preview.ts index 75c89ef..0d08606 100644 --- a/tools/pet_preview.ts +++ b/tools/pet_preview.ts @@ -40,7 +40,24 @@ const PETS: Record = { roamtail: ["adult", "roamtail"], filchfox: ["adult", "filchfox"], cloud_egg: ["egg", "cloud"], cloud_baby: ["baby", "cloud"], nimbit: ["child", "cloud"], rumblefluff: ["adult", "rumblefluff"], prismist: ["adult", "prismist"], + leaf_egg: ["egg", "leaf"], leaf_baby: ["baby", "leaf"], sproutlet: ["child", "leaf"], + twiggle: ["adult", "twiggle"], needlenub: ["adult", "needlenub"], + duck_egg: ["egg", "duck"], duck_baby: ["baby", "duck"], paddlet: ["child", "duck"], + quill: ["adult", "quill"], drakwing: ["adult", "drakwing"], + hippo_egg: ["egg", "hippo"], hippo_baby: ["baby", "hippo"], soakling: ["child", "hippo"], + lillypot: ["adult", "lillypot"], steamo: ["adult", "steamo"], + beak_egg: ["egg", "beak"], beak_baby: ["baby", "beak"], crestling: ["child", "beak"], + parcelbeak: ["adult", "parcelbeak"], rapierre: ["adult", "rapierre"], }; +// The leaf, duck, hippo and beak lines: per line its line, child and adults, for the scenes below +const NEW_LINES: [string, string, string, string][] = [ + ["leaf", "sproutlet", "twiggle", "needlenub"], ["duck", "paddlet", "quill", "drakwing"], + ["hippo", "soakling", "lillypot", "steamo"], ["beak", "crestling", "parcelbeak", "rapierre"], +]; +const NEW_SCENES = (["egg", "hatch", "baby", "child", "hint", "evolve"] as const).flatMap((what) => + NEW_LINES.map(([line]) => `${line}_${what}`)).concat(NEW_LINES.flatMap(([, , a, b]) => + [a, b].flatMap((adult) => ["", "_sad", "_sleep", "_trick", "_rain"].map((what) => `${adult}${what}`))), +["wild_forest_leaf", "wild_stream_hippo", "visit_beak", "visit_duck"]); // The spoiler-free overview shows one adult form only, the one docs/pets.md shows openly. It // leaves out the scenes that are only there to show another form, another line or what the lure // gives away, and plays the remaining scenes of an adult with that form. Of the trips it shows @@ -60,7 +77,7 @@ const SPOILERS = ["hint", "evolve", "cyclopuff", "angloop_hint", "sneezle", "fli "prismist_hat", "prismist_sad", "prismist_sleep", "prismist_trip", "prismist_rain", "gemperor", "gemperor_night", "gemperor_sad", "gemperor_hint", "angloop", "angloop_night", "angloop_hungry", "angloop_hint", - "purrloop", "purrloop_happy", "purrloop_night", "purrloop_hint"]; + "purrloop", "purrloop_happy", "purrloop_night", "purrloop_hint", ...NEW_SCENES]; const PETS_DIR = "docs/images/pets"; const DAY = new Date(2026, 9, 12, 13, 0); const NIGHT = new Date(2026, 9, 12, 23, 30); @@ -415,6 +432,34 @@ const SCENES: Record = { prismist_sad: [{ stage: "adult", species: "prismist", mood: "sad", needs: ["satiety"] }, DUSK, null], prismist_sleep: [{ stage: "adult", species: "prismist", asleep: true }, NIGHT, null], prismist_trip: [{ stage: "adult", species: "prismist", hat: "cap", trip: trip("mountain") }, DAY, null], + // the leaf, duck, hippo and beak lines + ...Object.fromEntries(NEW_LINES.flatMap(([line, , often, special]) => [ + [`${line}_egg`, [{ stage: "egg", species: line, ready: true }, DAY, null]], + [`${line}_hatch`, [{ stage: "baby", species: line, activity: "hatch", activity_item: `egg:${line}` }, DAY, null]], + [`${line}_baby`, [{ stage: "baby", species: line, mood: "happy" }, DAY, null]], + [`${line}_child`, [{ species: line }, DAY, null]], + [`${line}_hint`, [{ species: line, hint: special, mood: "happy" }, DAY, null]], + [`${line}_evolve`, [{ stage: "adult", species: often, activity: "evolve", activity_item: `child:${line}` }, DAY, + null]], + ])), + ...Object.fromEntries(NEW_LINES.flatMap(([, , a, b]) => [a, b].flatMap((adult) => [ + [adult, [{ stage: "adult", species: adult, mood: "happy" }, DAY, null]], + [`${adult}_sad`, [{ stage: "adult", species: adult, mood: "sad", needs: ["satiety"] }, DUSK, null]], + [`${adult}_sleep`, [{ stage: "adult", species: adult, asleep: true }, NIGHT, null]], + [`${adult}_trick`, [{ stage: "adult", species: adult, activity: "trick", activity_item: "flip:ok" }, DAY, null]], + [`${adult}_rain`, [{ stage: "adult", species: adult }, DAY, RAIN]], + ]))), + wild_forest_leaf: [{ + stage: "adult", species: "roamtail", + trip: trip("forest", { event: "wild", event_age: 4.0, wild: "twiggle", outcome: "friend", rounds: [["bow", true]] }), + }, DAY, null], + wild_stream_hippo: [{ + stage: "adult", species: "twiggle", + trip: trip("stream", { event: "wild", event_age: 4.0, wild: "steamo", outcome: "friend", rounds: [["bow", true]] }), + }, DAY, null], + visit_beak: [{ stage: "adult", species: "needlenub", visitor: { species: "rapierre", age: 60, left: 500 } }, DAY, null], + visit_duck: [{ stage: "adult", species: "parcelbeak", visitor: { species: "drakwing", age: 60, left: 500 } }, DAY, + null], }; const assets = readAssets(BDF_FONT_DIR); From 8d9b41eff281cb99a1817911a9a915f84a5a9f80 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 18:08:39 +0000 Subject: [PATCH 2/2] Drakwing counts every scuffle, not just the ones won Whether a weak child wins is mostly luck, so the duck line now counts scuffles however they end: two a day on average make a Drakwing. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_018m5J9V7X4cXFquP3ZLE9Le --- core/src/life.ts | 6 +++--- core/src/trip.ts | 2 +- core/test/life.test.ts | 2 +- docs/gameplay.md | 2 +- docs/pets.md | 6 ++++-- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/core/src/life.ts b/core/src/life.ts index 7b37014..3d505e0 100644 --- a/core/src/life.ts +++ b/core/src/life.ts @@ -61,7 +61,7 @@ export const GLIMMEROCK_LOVE_PER_DAY = 5; // the stone line: petting polishes it export const ROAMTAIL_TRIPS_PER_DAY = 1; // the fox line: a trip a day makes a wanderer → roamtail, otherwise filchfox // The cloud line is decided by the weather when it grows up: in the rain → rumblefluff, otherwise prismist export const NEEDLENUB_LOVE_PER_DAY = 5; // the leaf line: a cactus that gets cuddled → needlenub, otherwise twiggle -export const DRAKWING_WINS_PER_DAY = 1; // the duck line: a scuffle won a day → drakwing, otherwise quill +export const DRAKWING_BATTLES_PER_DAY = 2; // the duck line: scuffles a day, won or not → drakwing, otherwise quill export const STEAMO_BATHS_PER_DAY = 2; // the hippo line: bathed this often → steamo, otherwise lillypot export const RAPIERRE_TRICKS_PER_DAY = 2; // the beak line: tricks practiced → rapierre, otherwise parcelbeak export const HINT_AFTER = 1440; // minutes in the diary before the child's lure shows where it is heading @@ -107,7 +107,7 @@ export const BONUS_FACTORS: Record> = { }; export function newDiary(): Record { - return { minutes: 0, good_minutes: 0, meals: 0, snacks: 0, plays: 0, love: 0, trips: 0, wins: 0, baths: 0, tricks: 0 }; + return { minutes: 0, good_minutes: 0, meals: 0, snacks: 0, plays: 0, love: 0, trips: 0, battles: 0, baths: 0, tricks: 0 }; } /** The line a species belongs to. */ @@ -190,7 +190,7 @@ export function decideSpecies(diary: Record, line = "blob", rain return (diary.love ?? 0) / days >= NEEDLENUB_LOVE_PER_DAY ? "needlenub" : "twiggle"; } if (line === "duck") { - return (diary.wins ?? 0) / days >= DRAKWING_WINS_PER_DAY ? "drakwing" : "quill"; + return (diary.battles ?? 0) / days >= DRAKWING_BATTLES_PER_DAY ? "drakwing" : "quill"; } if (line === "hippo") { return (diary.baths ?? 0) / days >= STEAMO_BATHS_PER_DAY ? "steamo" : "lillypot"; diff --git a/core/src/trip.ts b/core/src/trip.ts index a297edf..296d29d 100644 --- a/core/src/trip.ts +++ b/core/src/trip.ts @@ -223,10 +223,10 @@ function encounter(state: PetState, trip: Trip, foe: string, rng: Random, weathe state.replays = [...state.replays, replay].slice(-REPLAYS); events.push(["battle", `${foe}:${outcome}`]); count.battles = (count.battles ?? 0) + 1; + life.record(state, "battles"); // in a child's care diary too, however it ends (the duck line) if (outcome === "win") { let egg: string | null = null; count.battles_won = (count.battles_won ?? 0) + 1; - life.record(state, "wins"); // in a child's care diary too (the duck line) state.stats.mood += guardian ? GUARDIAN_MOOD : WIN_MOOD; if (guardian && !state.guardians.includes(trip.area)) { state.guardians.push(trip.area); diff --git a/core/test/life.test.ts b/core/test/life.test.ts index 1a6211d..e4a0836 100644 --- a/core/test/life.test.ts +++ b/core/test/life.test.ts @@ -166,7 +166,7 @@ test("a cloud lamb that grows up in the rain becomes a thundercloud", () => { test("the leaf, duck, hippo and beak lines grow up by what the child did most", () => { const week = { ...life.newDiary(), minutes: 10080, good_minutes: 10080 }; const cases: [string, string, string, string][] = [ - ["leaf", "love", "needlenub", "twiggle"], ["duck", "wins", "drakwing", "quill"], + ["leaf", "love", "needlenub", "twiggle"], ["duck", "battles", "drakwing", "quill"], ["hippo", "baths", "steamo", "lillypot"], ["beak", "tricks", "rapierre", "parcelbeak"], ]; for (const [line, kind, often, otherwise] of cases) { diff --git a/docs/gameplay.md b/docs/gameplay.md index fc84bcd..fa8e1c9 100644 --- a/docs/gameplay.md +++ b/docs/gameplay.md @@ -159,7 +159,7 @@ A grown-up has no use for it. The care diary of the child stage decides the adult form: how well the pet was looked after, how often it was played with, petted, bathed and taught tricks, -how often it went on a trip and how many scuffles it won. For one line, the weather at the moment it grows up decides. Each +how often it went on a trip and how many scuffles it had. For one line, the weather at the moment it grows up decides. Each form has a character of its own, with small effects on the game. From its second day on, the bulb on the child's lure shows by its color which form it is heading for. diff --git a/docs/pets.md b/docs/pets.md index 4e2c901..7b4c358 100644 --- a/docs/pets.md +++ b/docs/pets.md @@ -520,11 +520,13 @@ scuffle it blows bubbles.
Show how to get them -Only scuffles won count for this line, on trips (guardians included). +Only scuffles count for this line, on trips (guardians included), whether +it wins them or not. A child that is ready to grow up can still go on a few +more trips first. | Form | Rule | |---|---| -| Drakwing | the child won at least one scuffle a day on average | +| Drakwing | the child had at least 2 scuffles a day on average | | Captain Quill | everything else | From its second day on, Paddlet's curl shows where it is heading: