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 0000000..5de5466 Binary files /dev/null and b/app/pet/assets/beak_baby_body.png differ 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 0000000..bb91501 Binary files /dev/null and b/app/pet/assets/beak_baby_faces.png differ diff --git a/app/pet/assets/beak_faces.json b/app/pet/assets/beak_faces.json new file mode 100644 index 0000000..f1c19ec --- /dev/null +++ b/app/pet/assets/beak_faces.json @@ -0,0 +1,222 @@ +{ + "frames": [ + { + "filename": "beak_faces normal 0", + "frame": { + "x": 0, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "beak_faces smile 1", + "frame": { + "x": 16, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "beak_faces blink 2", + "frame": { + "x": 32, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "beak_faces happy 3", + "frame": { + "x": 48, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "beak_faces laugh 4", + "frame": { + "x": 64, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "beak_faces sad 5", + "frame": { + "x": 80, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "beak_faces tired 6", + "frame": { + "x": 96, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "beak_faces yawn 7", + "frame": { + "x": 112, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "beak_faces sick 8", + "frame": { + "x": 128, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "beak_faces no 9", + "frame": { + "x": 144, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "beak_faces eat_open 10", + "frame": { + "x": 160, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "beak_faces eat_closed 11", + "frame": { + "x": 176, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + }, + { + "filename": "beak_faces sleep 12", + "frame": { + "x": 192, + "y": 0, + "w": 16, + "h": 9 + }, + "duration": 1000 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "beak_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/beak_faces.png b/app/pet/assets/beak_faces.png new file mode 100644 index 0000000..7b56f3a Binary files /dev/null and b/app/pet/assets/beak_faces.png differ diff --git a/app/pet/assets/crestling_body.json b/app/pet/assets/crestling_body.json new file mode 100644 index 0000000..978ddb8 --- /dev/null +++ b/app/pet/assets/crestling_body.json @@ -0,0 +1,168 @@ +{ + "frames": [ + { + "filename": "crestling_body idle 0", + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "crestling_body idle 1", + "frame": { + "x": 32, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "crestling_body squash 2", + "frame": { + "x": 64, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "crestling_body stretch 3", + "frame": { + "x": 96, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "crestling_body flat 4", + "frame": { + "x": 128, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "crestling_body sleep 5", + "frame": { + "x": 160, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "crestling_body sleep 6", + "frame": { + "x": 192, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "crestling_body lookout_left 7", + "frame": { + "x": 224, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "crestling_body lookout_left 8", + "frame": { + "x": 256, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "crestling_body lookout_right 9", + "frame": { + "x": 288, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "crestling_body lookout_right 10", + "frame": { + "x": 320, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "crestling_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": 6, + "faceShift": -0.5 + } +} diff --git a/app/pet/assets/crestling_body.png b/app/pet/assets/crestling_body.png new file mode 100644 index 0000000..f7d19f2 Binary files /dev/null and b/app/pet/assets/crestling_body.png differ 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 0000000..7e34e6b Binary files /dev/null and b/app/pet/assets/drakwing_body.png differ diff --git a/app/pet/assets/drakwing_faces.json b/app/pet/assets/drakwing_faces.json new file mode 100644 index 0000000..ddc871e --- /dev/null +++ b/app/pet/assets/drakwing_faces.json @@ -0,0 +1,222 @@ +{ + "frames": [ + { + "filename": "drakwing_faces normal 0", + "frame": { + "x": 0, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "drakwing_faces smile 1", + "frame": { + "x": 13, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "drakwing_faces blink 2", + "frame": { + "x": 26, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "drakwing_faces happy 3", + "frame": { + "x": 39, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "drakwing_faces laugh 4", + "frame": { + "x": 52, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "drakwing_faces sad 5", + "frame": { + "x": 65, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "drakwing_faces tired 6", + "frame": { + "x": 78, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "drakwing_faces yawn 7", + "frame": { + "x": 91, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "drakwing_faces sick 8", + "frame": { + "x": 104, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "drakwing_faces no 9", + "frame": { + "x": 117, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "drakwing_faces eat_open 10", + "frame": { + "x": 130, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "drakwing_faces eat_closed 11", + "frame": { + "x": 143, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "drakwing_faces sleep 12", + "frame": { + "x": 156, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "drakwing_faces.png", + "size": { + "w": 169, + "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/drakwing_faces.png b/app/pet/assets/drakwing_faces.png new file mode 100644 index 0000000..c4e3a68 Binary files /dev/null and b/app/pet/assets/drakwing_faces.png differ diff --git a/app/pet/assets/duck_baby_body.json b/app/pet/assets/duck_baby_body.json new file mode 100644 index 0000000..1656b21 --- /dev/null +++ b/app/pet/assets/duck_baby_body.json @@ -0,0 +1,166 @@ +{ + "frames": [ + { + "filename": "duck_baby_body idle 0", + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "duck_baby_body idle 1", + "frame": { + "x": 32, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "duck_baby_body squash 2", + "frame": { + "x": 64, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "duck_baby_body stretch 3", + "frame": { + "x": 96, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "duck_baby_body flat 4", + "frame": { + "x": 128, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "duck_baby_body sleep 5", + "frame": { + "x": 160, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "duck_baby_body sleep 6", + "frame": { + "x": 192, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "duck_baby_body lookout_left 7", + "frame": { + "x": 224, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "duck_baby_body lookout_left 8", + "frame": { + "x": 256, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "duck_baby_body lookout_right 9", + "frame": { + "x": 288, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "duck_baby_body lookout_right 10", + "frame": { + "x": 320, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "duck_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/duck_baby_body.png b/app/pet/assets/duck_baby_body.png new file mode 100644 index 0000000..eebea10 Binary files /dev/null and b/app/pet/assets/duck_baby_body.png differ 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 0000000..c93e15a Binary files /dev/null and b/app/pet/assets/duck_baby_faces.png differ 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 0000000..f6d97d5 Binary files /dev/null and b/app/pet/assets/duck_faces.png differ 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 0000000..cf1eb46 Binary files /dev/null and b/app/pet/assets/hippo_baby_body.png differ 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 0000000..d368ca2 Binary files /dev/null and b/app/pet/assets/hippo_baby_faces.png differ diff --git a/app/pet/assets/hippo_faces.json b/app/pet/assets/hippo_faces.json new file mode 100644 index 0000000..96da966 --- /dev/null +++ b/app/pet/assets/hippo_faces.json @@ -0,0 +1,222 @@ +{ + "frames": [ + { + "filename": "hippo_faces normal 0", + "frame": { + "x": 0, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "hippo_faces smile 1", + "frame": { + "x": 16, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "hippo_faces blink 2", + "frame": { + "x": 32, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "hippo_faces happy 3", + "frame": { + "x": 48, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "hippo_faces laugh 4", + "frame": { + "x": 64, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "hippo_faces sad 5", + "frame": { + "x": 80, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "hippo_faces tired 6", + "frame": { + "x": 96, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "hippo_faces yawn 7", + "frame": { + "x": 112, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "hippo_faces sick 8", + "frame": { + "x": 128, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "hippo_faces no 9", + "frame": { + "x": 144, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "hippo_faces eat_open 10", + "frame": { + "x": 160, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "hippo_faces eat_closed 11", + "frame": { + "x": 176, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "hippo_faces sleep 12", + "frame": { + "x": 192, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "hippo_faces.png", + "size": { + "w": 208, + "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/hippo_faces.png b/app/pet/assets/hippo_faces.png new file mode 100644 index 0000000..d8d509b Binary files /dev/null and b/app/pet/assets/hippo_faces.png differ 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 7a8d6f5..e94dd51 100644 Binary files a/app/pet/assets/items.png and b/app/pet/assets/items.png differ diff --git a/app/pet/assets/leaf_baby_body.json b/app/pet/assets/leaf_baby_body.json new file mode 100644 index 0000000..fea3803 --- /dev/null +++ b/app/pet/assets/leaf_baby_body.json @@ -0,0 +1,166 @@ +{ + "frames": [ + { + "filename": "leaf_baby_body idle 0", + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "leaf_baby_body idle 1", + "frame": { + "x": 32, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "leaf_baby_body squash 2", + "frame": { + "x": 64, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "leaf_baby_body stretch 3", + "frame": { + "x": 96, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "leaf_baby_body flat 4", + "frame": { + "x": 128, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "leaf_baby_body sleep 5", + "frame": { + "x": 160, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "leaf_baby_body sleep 6", + "frame": { + "x": 192, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "leaf_baby_body lookout_left 7", + "frame": { + "x": 224, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "leaf_baby_body lookout_left 8", + "frame": { + "x": 256, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "leaf_baby_body lookout_right 9", + "frame": { + "x": 288, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "leaf_baby_body lookout_right 10", + "frame": { + "x": 320, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "leaf_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/leaf_baby_body.png b/app/pet/assets/leaf_baby_body.png new file mode 100644 index 0000000..759fac4 Binary files /dev/null and b/app/pet/assets/leaf_baby_body.png differ 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 0000000..28640b6 Binary files /dev/null and b/app/pet/assets/leaf_baby_faces.png differ diff --git a/app/pet/assets/leaf_faces.json b/app/pet/assets/leaf_faces.json new file mode 100644 index 0000000..78c798c --- /dev/null +++ b/app/pet/assets/leaf_faces.json @@ -0,0 +1,222 @@ +{ + "frames": [ + { + "filename": "leaf_faces normal 0", + "frame": { + "x": 0, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "leaf_faces smile 1", + "frame": { + "x": 16, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "leaf_faces blink 2", + "frame": { + "x": 32, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "leaf_faces happy 3", + "frame": { + "x": 48, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "leaf_faces laugh 4", + "frame": { + "x": 64, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "leaf_faces sad 5", + "frame": { + "x": 80, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "leaf_faces tired 6", + "frame": { + "x": 96, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "leaf_faces yawn 7", + "frame": { + "x": 112, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "leaf_faces sick 8", + "frame": { + "x": 128, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "leaf_faces no 9", + "frame": { + "x": 144, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "leaf_faces eat_open 10", + "frame": { + "x": 160, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "leaf_faces eat_closed 11", + "frame": { + "x": 176, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + }, + { + "filename": "leaf_faces sleep 12", + "frame": { + "x": 192, + "y": 0, + "w": 16, + "h": 8 + }, + "duration": 1000 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "leaf_faces.png", + "size": { + "w": 208, + "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/leaf_faces.png b/app/pet/assets/leaf_faces.png new file mode 100644 index 0000000..3305a63 Binary files /dev/null and b/app/pet/assets/leaf_faces.png differ diff --git a/app/pet/assets/lillypot_body.json b/app/pet/assets/lillypot_body.json new file mode 100644 index 0000000..03c9e99 --- /dev/null +++ b/app/pet/assets/lillypot_body.json @@ -0,0 +1,214 @@ +{ + "frames": [ + { + "filename": "lillypot_body idle 0", + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "lillypot_body idle 1", + "frame": { + "x": 32, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "lillypot_body squash 2", + "frame": { + "x": 64, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "lillypot_body stretch 3", + "frame": { + "x": 96, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "lillypot_body flat 4", + "frame": { + "x": 128, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "lillypot_body sleep 5", + "frame": { + "x": 160, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "lillypot_body sleep 6", + "frame": { + "x": 192, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "lillypot_body lookout_left 7", + "frame": { + "x": 224, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "lillypot_body lookout_left 8", + "frame": { + "x": 256, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "lillypot_body lookout_right 9", + "frame": { + "x": 288, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "lillypot_body lookout_right 10", + "frame": { + "x": 320, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "lillypot_body walk 11", + "frame": { + "x": 352, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 240 + }, + { + "filename": "lillypot_body walk 12", + "frame": { + "x": 384, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 140 + }, + { + "filename": "lillypot_body walk 13", + "frame": { + "x": 416, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 240 + }, + { + "filename": "lillypot_body walk 14", + "frame": { + "x": 448, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 140 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "lillypot_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": 6, + "faceShift": 0.5 + } +} diff --git a/app/pet/assets/lillypot_body.png b/app/pet/assets/lillypot_body.png new file mode 100644 index 0000000..d6d24b8 Binary files /dev/null and b/app/pet/assets/lillypot_body.png differ 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 0000000..7f8f1d9 Binary files /dev/null and b/app/pet/assets/lillypot_faces.png differ diff --git a/app/pet/assets/needlenub_body.json b/app/pet/assets/needlenub_body.json new file mode 100644 index 0000000..b919537 --- /dev/null +++ b/app/pet/assets/needlenub_body.json @@ -0,0 +1,168 @@ +{ + "frames": [ + { + "filename": "needlenub_body idle 0", + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "needlenub_body idle 1", + "frame": { + "x": 32, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "needlenub_body squash 2", + "frame": { + "x": 64, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "needlenub_body stretch 3", + "frame": { + "x": 96, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "needlenub_body flat 4", + "frame": { + "x": 128, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "needlenub_body sleep 5", + "frame": { + "x": 160, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "needlenub_body sleep 6", + "frame": { + "x": 192, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "needlenub_body lookout_left 7", + "frame": { + "x": 224, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "needlenub_body lookout_left 8", + "frame": { + "x": 256, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "needlenub_body lookout_right 9", + "frame": { + "x": 288, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "needlenub_body lookout_right 10", + "frame": { + "x": 320, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "needlenub_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": 5, + "faceShift": 0.5 + } +} diff --git a/app/pet/assets/needlenub_body.png b/app/pet/assets/needlenub_body.png new file mode 100644 index 0000000..0c6206c Binary files /dev/null and b/app/pet/assets/needlenub_body.png differ 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 0000000..7a92192 Binary files /dev/null and b/app/pet/assets/needlenub_faces.png differ 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 0000000..80cdb5e Binary files /dev/null and b/app/pet/assets/paddlet_body.png differ 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 0000000..b958d9d Binary files /dev/null and b/app/pet/assets/parcelbeak_body.png differ 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 0000000..b4c8edd Binary files /dev/null and b/app/pet/assets/parcelbeak_faces.png differ diff --git a/app/pet/assets/quill_body.json b/app/pet/assets/quill_body.json new file mode 100644 index 0000000..8bfff30 --- /dev/null +++ b/app/pet/assets/quill_body.json @@ -0,0 +1,214 @@ +{ + "frames": [ + { + "filename": "quill_body idle 0", + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "quill_body idle 1", + "frame": { + "x": 32, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "quill_body squash 2", + "frame": { + "x": 64, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "quill_body stretch 3", + "frame": { + "x": 96, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "quill_body flat 4", + "frame": { + "x": 128, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "quill_body sleep 5", + "frame": { + "x": 160, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "quill_body sleep 6", + "frame": { + "x": 192, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "quill_body lookout_left 7", + "frame": { + "x": 224, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "quill_body lookout_left 8", + "frame": { + "x": 256, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "quill_body lookout_right 9", + "frame": { + "x": 288, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "quill_body lookout_right 10", + "frame": { + "x": 320, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "quill_body walk 11", + "frame": { + "x": 352, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 220 + }, + { + "filename": "quill_body walk 12", + "frame": { + "x": 384, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 130 + }, + { + "filename": "quill_body walk 13", + "frame": { + "x": 416, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 220 + }, + { + "filename": "quill_body walk 14", + "frame": { + "x": 448, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 130 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "quill_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.0 + } +} diff --git a/app/pet/assets/quill_body.png b/app/pet/assets/quill_body.png new file mode 100644 index 0000000..29fe2a8 Binary files /dev/null and b/app/pet/assets/quill_body.png differ diff --git a/app/pet/assets/quill_faces.json b/app/pet/assets/quill_faces.json new file mode 100644 index 0000000..b6463a8 --- /dev/null +++ b/app/pet/assets/quill_faces.json @@ -0,0 +1,222 @@ +{ + "frames": [ + { + "filename": "quill_faces normal 0", + "frame": { + "x": 0, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "quill_faces smile 1", + "frame": { + "x": 13, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "quill_faces blink 2", + "frame": { + "x": 26, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "quill_faces happy 3", + "frame": { + "x": 39, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "quill_faces laugh 4", + "frame": { + "x": 52, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "quill_faces sad 5", + "frame": { + "x": 65, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "quill_faces tired 6", + "frame": { + "x": 78, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "quill_faces yawn 7", + "frame": { + "x": 91, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "quill_faces sick 8", + "frame": { + "x": 104, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "quill_faces no 9", + "frame": { + "x": 117, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "quill_faces eat_open 10", + "frame": { + "x": 130, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "quill_faces eat_closed 11", + "frame": { + "x": 143, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "quill_faces sleep 12", + "frame": { + "x": 156, + "y": 0, + "w": 13, + "h": 3 + }, + "duration": 1000 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "quill_faces.png", + "size": { + "w": 169, + "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/quill_faces.png b/app/pet/assets/quill_faces.png new file mode 100644 index 0000000..5c2c872 Binary files /dev/null and b/app/pet/assets/quill_faces.png differ diff --git a/app/pet/assets/rapierre_body.json b/app/pet/assets/rapierre_body.json new file mode 100644 index 0000000..60fc326 --- /dev/null +++ b/app/pet/assets/rapierre_body.json @@ -0,0 +1,168 @@ +{ + "frames": [ + { + "filename": "rapierre_body idle 0", + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 90 + }, + { + "filename": "rapierre_body idle 1", + "frame": { + "x": 32, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 90 + }, + { + "filename": "rapierre_body squash 2", + "frame": { + "x": 64, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "rapierre_body stretch 3", + "frame": { + "x": 96, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "rapierre_body flat 4", + "frame": { + "x": 128, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "rapierre_body sleep 5", + "frame": { + "x": 160, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "rapierre_body sleep 6", + "frame": { + "x": 192, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "rapierre_body lookout_left 7", + "frame": { + "x": 224, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "rapierre_body lookout_left 8", + "frame": { + "x": 256, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "rapierre_body lookout_right 9", + "frame": { + "x": 288, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "rapierre_body lookout_right 10", + "frame": { + "x": 320, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "rapierre_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.0 + } +} diff --git a/app/pet/assets/rapierre_body.png b/app/pet/assets/rapierre_body.png new file mode 100644 index 0000000..8093515 Binary files /dev/null and b/app/pet/assets/rapierre_body.png differ diff --git a/app/pet/assets/rapierre_faces.json b/app/pet/assets/rapierre_faces.json new file mode 100644 index 0000000..c09fabc --- /dev/null +++ b/app/pet/assets/rapierre_faces.json @@ -0,0 +1,222 @@ +{ + "frames": [ + { + "filename": "rapierre_faces normal 0", + "frame": { + "x": 0, + "y": 0, + "w": 6, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "rapierre_faces smile 1", + "frame": { + "x": 6, + "y": 0, + "w": 6, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "rapierre_faces blink 2", + "frame": { + "x": 12, + "y": 0, + "w": 6, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "rapierre_faces happy 3", + "frame": { + "x": 18, + "y": 0, + "w": 6, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "rapierre_faces laugh 4", + "frame": { + "x": 24, + "y": 0, + "w": 6, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "rapierre_faces sad 5", + "frame": { + "x": 30, + "y": 0, + "w": 6, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "rapierre_faces tired 6", + "frame": { + "x": 36, + "y": 0, + "w": 6, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "rapierre_faces yawn 7", + "frame": { + "x": 42, + "y": 0, + "w": 6, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "rapierre_faces sick 8", + "frame": { + "x": 48, + "y": 0, + "w": 6, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "rapierre_faces no 9", + "frame": { + "x": 54, + "y": 0, + "w": 6, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "rapierre_faces eat_open 10", + "frame": { + "x": 60, + "y": 0, + "w": 6, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "rapierre_faces eat_closed 11", + "frame": { + "x": 66, + "y": 0, + "w": 6, + "h": 3 + }, + "duration": 1000 + }, + { + "filename": "rapierre_faces sleep 12", + "frame": { + "x": 72, + "y": 0, + "w": 6, + "h": 3 + }, + "duration": 1000 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "rapierre_faces.png", + "size": { + "w": 78, + "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/rapierre_faces.png b/app/pet/assets/rapierre_faces.png new file mode 100644 index 0000000..14f55b4 Binary files /dev/null and b/app/pet/assets/rapierre_faces.png differ diff --git a/app/pet/assets/soakling_body.json b/app/pet/assets/soakling_body.json new file mode 100644 index 0000000..7b61181 --- /dev/null +++ b/app/pet/assets/soakling_body.json @@ -0,0 +1,168 @@ +{ + "frames": [ + { + "filename": "soakling_body idle 0", + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "soakling_body idle 1", + "frame": { + "x": 32, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 700 + }, + { + "filename": "soakling_body squash 2", + "frame": { + "x": 64, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "soakling_body stretch 3", + "frame": { + "x": 96, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "soakling_body flat 4", + "frame": { + "x": 128, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "soakling_body sleep 5", + "frame": { + "x": 160, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "soakling_body sleep 6", + "frame": { + "x": 192, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "soakling_body lookout_left 7", + "frame": { + "x": 224, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "soakling_body lookout_left 8", + "frame": { + "x": 256, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "soakling_body lookout_right 9", + "frame": { + "x": 288, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "soakling_body lookout_right 10", + "frame": { + "x": 320, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "soakling_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": 6, + "faceShift": -0.5 + } +} diff --git a/app/pet/assets/soakling_body.png b/app/pet/assets/soakling_body.png new file mode 100644 index 0000000..1660090 Binary files /dev/null and b/app/pet/assets/soakling_body.png differ 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 0000000..ff86e3e Binary files /dev/null and b/app/pet/assets/sproutlet_body.png differ 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 0000000..6096faf Binary files /dev/null and b/app/pet/assets/steamo_body.png differ 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 0000000..b28041b Binary files /dev/null and b/app/pet/assets/steamo_faces.png differ diff --git a/app/pet/assets/trip.json b/app/pet/assets/trip.json index 6faa82c..5e6a113 100644 --- a/app/pet/assets/trip.json +++ b/app/pet/assets/trip.json @@ -1129,13 +1129,53 @@ "h": 14 }, "duration": 1000 + }, + { + "filename": "trip egg_leaf 113", + "frame": { + "x": 1214, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 1000 + }, + { + "filename": "trip egg_duck 114", + "frame": { + "x": 1226, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 1000 + }, + { + "filename": "trip egg_hippo 115", + "frame": { + "x": 1238, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 1000 + }, + { + "filename": "trip egg_beak 116", + "frame": { + "x": 1250, + "y": 0, + "w": 12, + "h": 14 + }, + "duration": 1000 } ], "meta": { "app": "tools/build_blob_sprites.py", "image": "trip.png", "size": { - "w": 1214, + "w": 1262, "h": 24 }, "frameTags": [ @@ -1696,6 +1736,30 @@ "from": 112, "to": 112, "direction": "forward" + }, + { + "name": "egg_leaf", + "from": 113, + "to": 113, + "direction": "forward" + }, + { + "name": "egg_duck", + "from": 114, + "to": 114, + "direction": "forward" + }, + { + "name": "egg_hippo", + "from": 115, + "to": 115, + "direction": "forward" + }, + { + "name": "egg_beak", + "from": 116, + "to": 116, + "direction": "forward" } ] } diff --git a/app/pet/assets/trip.png b/app/pet/assets/trip.png index a6bfa95..45e3b9c 100644 Binary files a/app/pet/assets/trip.png and b/app/pet/assets/trip.png differ diff --git a/app/pet/assets/twiggle_body.json b/app/pet/assets/twiggle_body.json new file mode 100644 index 0000000..e4660ee --- /dev/null +++ b/app/pet/assets/twiggle_body.json @@ -0,0 +1,214 @@ +{ + "frames": [ + { + "filename": "twiggle_body idle 0", + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "twiggle_body idle 1", + "frame": { + "x": 32, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "twiggle_body squash 2", + "frame": { + "x": 64, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "twiggle_body stretch 3", + "frame": { + "x": 96, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "twiggle_body flat 4", + "frame": { + "x": 128, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 100 + }, + { + "filename": "twiggle_body sleep 5", + "frame": { + "x": 160, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "twiggle_body sleep 6", + "frame": { + "x": 192, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 1600 + }, + { + "filename": "twiggle_body lookout_left 7", + "frame": { + "x": 224, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "twiggle_body lookout_left 8", + "frame": { + "x": 256, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "twiggle_body lookout_right 9", + "frame": { + "x": 288, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 900 + }, + { + "filename": "twiggle_body lookout_right 10", + "frame": { + "x": 320, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 500 + }, + { + "filename": "twiggle_body walk 11", + "frame": { + "x": 352, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 260 + }, + { + "filename": "twiggle_body walk 12", + "frame": { + "x": 384, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 160 + }, + { + "filename": "twiggle_body walk 13", + "frame": { + "x": 416, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 260 + }, + { + "filename": "twiggle_body walk 14", + "frame": { + "x": 448, + "y": 0, + "w": 32, + "h": 32 + }, + "duration": 160 + } + ], + "meta": { + "app": "tools/build_blob_sprites.py", + "image": "twiggle_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": 12, + "faceShift": 0.5 + } +} diff --git a/app/pet/assets/twiggle_body.png b/app/pet/assets/twiggle_body.png new file mode 100644 index 0000000..3cc23e7 Binary files /dev/null and b/app/pet/assets/twiggle_body.png differ 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 0000000..318b0b0 Binary files /dev/null and b/app/pet/assets/twiggle_faces.png differ 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..3d505e0 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_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 // 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, battles: 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.battles ?? 0) / days >= DRAKWING_BATTLES_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..296d29d 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]; @@ -215,8 +223,9 @@ 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 | undefined; + let egg: string | null = null; count.battles_won = (count.battles_won ?? 0) + 1; state.stats.mood += guardian ? GUARDIAN_MOOD : WIN_MOOD; if (guardian && !state.guardians.includes(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..e4a0836 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", "battles", "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..fa8e1c9 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 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. @@ -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 0000000..6e7eaaf Binary files /dev/null and b/docs/images/pets/beak_baby.png differ diff --git a/docs/images/pets/beak_egg.png b/docs/images/pets/beak_egg.png new file mode 100644 index 0000000..8a8c1e9 Binary files /dev/null and b/docs/images/pets/beak_egg.png differ diff --git a/docs/images/pets/crestling.png b/docs/images/pets/crestling.png new file mode 100644 index 0000000..342d430 Binary files /dev/null and b/docs/images/pets/crestling.png differ diff --git a/docs/images/pets/drakwing.png b/docs/images/pets/drakwing.png new file mode 100644 index 0000000..f69e093 Binary files /dev/null and b/docs/images/pets/drakwing.png differ diff --git a/docs/images/pets/duck_baby.png b/docs/images/pets/duck_baby.png new file mode 100644 index 0000000..be6deaf Binary files /dev/null and b/docs/images/pets/duck_baby.png differ diff --git a/docs/images/pets/duck_egg.png b/docs/images/pets/duck_egg.png new file mode 100644 index 0000000..ae06c24 Binary files /dev/null and b/docs/images/pets/duck_egg.png differ diff --git a/docs/images/pets/hippo_baby.png b/docs/images/pets/hippo_baby.png new file mode 100644 index 0000000..61e8004 Binary files /dev/null and b/docs/images/pets/hippo_baby.png differ diff --git a/docs/images/pets/hippo_egg.png b/docs/images/pets/hippo_egg.png new file mode 100644 index 0000000..1bf7388 Binary files /dev/null and b/docs/images/pets/hippo_egg.png differ diff --git a/docs/images/pets/leaf_baby.png b/docs/images/pets/leaf_baby.png new file mode 100644 index 0000000..6509782 Binary files /dev/null and b/docs/images/pets/leaf_baby.png differ diff --git a/docs/images/pets/leaf_egg.png b/docs/images/pets/leaf_egg.png new file mode 100644 index 0000000..8b86615 Binary files /dev/null and b/docs/images/pets/leaf_egg.png differ diff --git a/docs/images/pets/lillypot.png b/docs/images/pets/lillypot.png new file mode 100644 index 0000000..b2ba32c Binary files /dev/null and b/docs/images/pets/lillypot.png differ diff --git a/docs/images/pets/needlenub.png b/docs/images/pets/needlenub.png new file mode 100644 index 0000000..c92b17e Binary files /dev/null and b/docs/images/pets/needlenub.png differ diff --git a/docs/images/pets/paddlet.png b/docs/images/pets/paddlet.png new file mode 100644 index 0000000..d97e90d Binary files /dev/null and b/docs/images/pets/paddlet.png differ diff --git a/docs/images/pets/parcelbeak.png b/docs/images/pets/parcelbeak.png new file mode 100644 index 0000000..4ceaf4f Binary files /dev/null and b/docs/images/pets/parcelbeak.png differ diff --git a/docs/images/pets/quill.png b/docs/images/pets/quill.png new file mode 100644 index 0000000..bc8acc0 Binary files /dev/null and b/docs/images/pets/quill.png differ diff --git a/docs/images/pets/rapierre.png b/docs/images/pets/rapierre.png new file mode 100644 index 0000000..ece7c58 Binary files /dev/null and b/docs/images/pets/rapierre.png differ diff --git a/docs/images/pets/soakling.png b/docs/images/pets/soakling.png new file mode 100644 index 0000000..c868201 Binary files /dev/null and b/docs/images/pets/soakling.png differ diff --git a/docs/images/pets/sproutlet.png b/docs/images/pets/sproutlet.png new file mode 100644 index 0000000..f605b41 Binary files /dev/null and b/docs/images/pets/sproutlet.png differ diff --git a/docs/images/pets/steamo.png b/docs/images/pets/steamo.png new file mode 100644 index 0000000..0ffa134 Binary files /dev/null and b/docs/images/pets/steamo.png differ diff --git a/docs/images/pets/twiggle.png b/docs/images/pets/twiggle.png new file mode 100644 index 0000000..2b9f65f Binary files /dev/null and b/docs/images/pets/twiggle.png differ diff --git a/docs/pets.md b/docs/pets.md index e351156..7b4c358 100644 --- a/docs/pets.md +++ b/docs/pets.md @@ -158,8 +158,18 @@ other adults, and another rule for which adult it becomes.
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,216 @@ 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 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 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: + +| 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);