From 1b98772fe6073deb31d9ecb7b07ae3da206f9df8 Mon Sep 17 00:00:00 2001 From: Index Date: Sat, 3 May 2025 19:00:02 -0500 Subject: [PATCH] v1.2 - feat: alpha hamster critter variant - style: format client JS - feat: improved login validation - style: format & update footers - fix: mods array not being populated by JWT contents - style: restructure socket.io server into multiple files - style: remove unused socket.io types --- Dockerfile | 15 - deno.json | 4 +- src/constants/items.json | 6530 +++++++++++++++++++++++++++++ src/constants/items.ts | 140 + src/constants/parties.json | 50 + src/constants/world.ts | 91 + src/io.ts | 546 --- src/main.ts | 39 +- src/schema.ts | 13 +- src/socket/handlers/connection.ts | 155 + src/socket/handlers/economy.ts | 62 + src/socket/handlers/player.ts | 73 + src/socket/handlers/social.ts | 219 + src/socket/handlers/world.ts | 116 + src/socket/index.ts | 22 + src/types.ts | 41 +- src/utils.ts | 18 +- 17 files changed, 7509 insertions(+), 625 deletions(-) delete mode 100644 Dockerfile create mode 100644 src/constants/items.json create mode 100644 src/constants/items.ts create mode 100644 src/constants/parties.json create mode 100644 src/constants/world.ts delete mode 100644 src/io.ts create mode 100644 src/socket/handlers/connection.ts create mode 100644 src/socket/handlers/economy.ts create mode 100644 src/socket/handlers/player.ts create mode 100644 src/socket/handlers/social.ts create mode 100644 src/socket/handlers/world.ts create mode 100644 src/socket/index.ts diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index b391782..0000000 --- a/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM denoland/deno:2.1.5 - -WORKDIR /app - -COPY deno.json . - -RUN deno install - -COPY . . -RUN deno cache main.ts - -ARG PORT=3257 -EXPOSE $PORT - -CMD ["task", "start"] \ No newline at end of file diff --git a/deno.json b/deno.json index 832be7c..113e601 100644 --- a/deno.json +++ b/deno.json @@ -1,9 +1,11 @@ { "imports": { + "@/": "./src/", "@std/fs": "jsr:@std/fs@^1.0.14" }, "tasks": { - "start": "deno run --watch --allow-net --allow-read --allow-env --env-file=.env --allow-write src/main.ts", + "start": "deno run --allow-net --allow-read --allow-env --env-file=.env --allow-write src/main.ts", + "dev": "deno run --watch --allow-net --allow-read --allow-env --env-file=.env --allow-write src/main.ts", "build": "deno compile --allow-net --allow-read --allow-env --env-file=.env.build --allow-write --output Localbox src/main.ts" }, "compilerOptions": { diff --git a/src/constants/items.json b/src/constants/items.json new file mode 100644 index 0000000..a23080d --- /dev/null +++ b/src/constants/items.json @@ -0,0 +1,6530 @@ +[ + { + "itemId": "3d_black", + "name": "Black 3D Glasses", + "cost": 100, + "slot": "eyes", + "theme": "movie", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/3d_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/3d_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/3d_black/sprites.png" + }, + { + "itemId": "viking", + "name": "Red Viking Helmet", + "cost": 10, + "slot": "head", + "theme": "viking", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/viking/icon.png", + "bits": { "front": "https://media.boxcritters.com/items/viking/front.png" }, + "sprites": "https://media.boxcritters.com/items/viking/sprites.png" + }, + { + "itemId": "viking_blue", + "name": "Blue Viking Helmet", + "cost": 100, + "slot": "head", + "theme": "viking", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/viking_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/viking_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/viking_blue/sprites.png" + }, + { + "itemId": "3d_white", + "name": "White 3D Glasses", + "cost": 100, + "slot": "eyes", + "theme": "movie", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/3d_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/3d_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/3d_white/sprites.png" + }, + { + "itemId": "headphones_black", + "name": "Black Headphones", + "cost": 100, + "slot": "ears", + "theme": "gamer", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/headphones_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/headphones_black/front.png", + "back": "https://media.boxcritters.com/items/headphones_black/back.png" + }, + "sprites": "https://media.boxcritters.com/items/headphones_black/sprites.png" + }, + { + "itemId": "headphones_white", + "name": "White Headphones", + "cost": 100, + "slot": "ears", + "theme": "gamer", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/headphones_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/headphones_white/front.png", + "back": "https://media.boxcritters.com/items/headphones_white/back.png" + }, + "sprites": "https://media.boxcritters.com/items/headphones_white/sprites.png" + }, + { + "itemId": "toque_pink", + "name": "Pink Toque", + "cost": 100, + "slot": "head", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/toque_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/toque_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/toque_pink/sprites.png" + }, + { + "itemId": "toque_purple", + "name": "Purple Toque", + "cost": 100, + "slot": "head", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/toque_purple/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/toque_purple/front.png" + }, + "sprites": "https://media.boxcritters.com/items/toque_purple/sprites.png" + }, + { + "itemId": "toque_white", + "name": "White Toque", + "cost": 100, + "slot": "head", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/toque_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/toque_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/toque_white/sprites.png" + }, + { + "itemId": "toque_blue", + "name": "Blue Toque", + "cost": 100, + "slot": "head", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/toque_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/toque_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/toque_blue/sprites.png" + }, + { + "itemId": "plaid_red", + "name": "Red Plaid", + "cost": 400, + "slot": "body", + "theme": "explore", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/plaid_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/plaid_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/plaid_red/sprites.png" + }, + { + "itemId": "plaid_blue", + "name": "Blue Plaid", + "cost": 400, + "slot": "body", + "theme": "explore", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/plaid_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/plaid_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/plaid_blue/sprites.png" + }, + { + "itemId": "propeller", + "name": "Propeller Cap", + "cost": 100, + "slot": "head", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/propeller/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/propeller/front.png" + }, + "sprites": "https://media.boxcritters.com/items/propeller/sprites.png" + }, + { + "itemId": "propeller_blue", + "name": "Blue Propeller Cap", + "cost": 100, + "slot": "head", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/propeller_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/propeller_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/propeller_blue/sprites.png" + }, + { + "itemId": "propeller_pink", + "name": "Pink Propeller Cap", + "cost": 100, + "slot": "head", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/propeller_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/propeller_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/propeller_pink/sprites.png" + }, + { + "itemId": "propeller_gold", + "name": "Gold Propeller Cap", + "cost": 100, + "slot": "head", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/propeller_gold/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/propeller_gold/front.png" + }, + "sprites": "https://media.boxcritters.com/items/propeller_gold/sprites.png" + }, + { + "itemId": "hoodie_black", + "name": "Black Hoodie", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hoodie_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hoodie_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hoodie_black/sprites.png" + }, + { + "itemId": "hoodie_blue", + "name": "Blue Hoodie", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hoodie_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hoodie_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hoodie_blue/sprites.png" + }, + { + "itemId": "hoodie_green", + "name": "Green Hoddie", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hoodie_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hoodie_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hoodie_green/sprites.png" + }, + { + "itemId": "hoodie_pink", + "name": "Pink Hoodie", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hoodie_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hoodie_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hoodie_pink/sprites.png" + }, + { + "itemId": "hoodie_purple", + "name": "Purple Hoodie", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hoodie_purple/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hoodie_purple/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hoodie_purple/sprites.png" + }, + { + "itemId": "hoodie_white", + "name": "White Hoodie", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hoodie_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hoodie_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hoodie_white/sprites.png" + }, + { + "itemId": "sleeping", + "name": "Sleeping Cap", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/sleeping/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/sleeping/front.png" + }, + "sprites": "https://media.boxcritters.com/items/sleeping/sprites.png" + }, + { + "itemId": "party_green", + "name": "Green and Yellow Party Hat", + "cost": 100, + "slot": "head", + "theme": "party", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/party_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/party_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/party_green/sprites.png" + }, + { + "itemId": "paperhat", + "name": "Newspaper Hat", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/paperhat/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/paperhat/front.png" + }, + "sprites": "https://media.boxcritters.com/items/paperhat/sprites.png" + }, + { + "itemId": "space_black", + "name": "Space Commander", + "cost": 100, + "slot": "body", + "theme": "space", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/space_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/space_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/space_black/sprites.png" + }, + { + "itemId": "space_blue", + "name": "Science Officer", + "cost": 100, + "slot": "body", + "theme": "space", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/space_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/space_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/space_blue/sprites.png" + }, + { + "itemId": "space_orange", + "name": "Space Engineer", + "cost": 100, + "slot": "body", + "theme": "space", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/space_orange/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/space_orange/front.png" + }, + "sprites": "https://media.boxcritters.com/items/space_orange/sprites.png" + }, + { + "itemId": "space_red", + "name": "Security Officer", + "cost": 100, + "slot": "body", + "theme": "space", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/space_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/space_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/space_red/sprites.png" + }, + { + "itemId": "ballcap_black", + "name": "Black Ball Cap", + "cost": 100, + "slot": "head", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ballcap_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ballcap_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ballcap_black/sprites.png" + }, + { + "itemId": "ballcap_blue", + "name": "Blue Ball Cap", + "cost": 100, + "slot": "head", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ballcap_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ballcap_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ballcap_blue/sprites.png" + }, + { + "itemId": "ballcap_green", + "name": "Green Ball Cap", + "cost": 100, + "slot": "head", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ballcap_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ballcap_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ballcap_green/sprites.png" + }, + { + "itemId": "ballcap_pink", + "name": "Pink Ball Cap", + "cost": 100, + "slot": "head", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ballcap_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ballcap_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ballcap_pink/sprites.png" + }, + { + "itemId": "ballcap_red", + "name": "Red Ball Cap", + "cost": 100, + "slot": "head", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ballcap_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ballcap_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ballcap_red/sprites.png" + }, + { + "itemId": "ballcap_yellow", + "name": "Yellow Ball Cap", + "cost": 100, + "slot": "head", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ballcap_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ballcap_yellow/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ballcap_yellow/sprites.png" + }, + { + "itemId": "bandana_red", + "name": "Red Bandana", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bandana_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bandana_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bandana_red/sprites.png" + }, + { + "itemId": "bandana_blue", + "name": "Blue Bandana", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bandana_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bandana_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bandana_blue/sprites.png" + }, + { + "itemId": "tshirt_black", + "name": "Black T-Shirt", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/tshirt_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/tshirt_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/tshirt_black/sprites.png" + }, + { + "itemId": "tshirt_white", + "name": "Inside Out White T-Shirt", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/tshirt_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/tshirt_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/tshirt_white/sprites.png" + }, + { + "itemId": "float_yellow", + "name": "Yellow Duck Floatie", + "cost": 100, + "slot": "hand", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/float_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/float_yellow/front.png", + "back": "https://media.boxcritters.com/items/float_yellow/back.png" + }, + "sprites": "https://media.boxcritters.com/items/float_yellow/sprites.png" + }, + { + "itemId": "pirate_patch", + "name": "Pirate Patch", + "cost": 100, + "slot": "mask", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_patch/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_patch/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_patch/sprites.png" + }, + { + "itemId": "pirate_crew_blue", + "name": "Pirate Crew Blue", + "cost": 100, + "slot": "body", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_crew_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_crew_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_crew_blue/sprites.png" + }, + { + "itemId": "pirate_capt_black", + "name": "Black Pirate Captain", + "cost": 100, + "slot": "body", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_capt_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_capt_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_capt_black/sprites.png" + }, + { + "itemId": "pirate_capt_red", + "name": "Red Pirate Captian", + "cost": 100, + "slot": "body", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_capt_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_capt_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_capt_red/sprites.png" + }, + { + "itemId": "pirate_hat_black", + "name": "Black Pirate Hat", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_hat_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_hat_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_hat_black/sprites.png" + }, + { + "itemId": "pirate_hat_blue", + "name": "Blue Pirate Hat", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_hat_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_hat_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_hat_blue/sprites.png" + }, + { + "itemId": "guitar_blue", + "name": "Blue Electric Guitar", + "cost": 100, + "slot": "hand", + "theme": "music", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/guitar_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/guitar_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/guitar_blue/sprites.png" + }, + { + "itemId": "pickle", + "name": "Pickle", + "cost": 100, + "slot": "head", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pickle/icon.png", + "bits": { "front": "https://media.boxcritters.com/items/pickle/front.png" }, + "sprites": "https://media.boxcritters.com/items/pickle/sprites.png" + }, + { + "itemId": "grass_yellow", + "name": "Yellow Grass Skirt", + "cost": 100, + "slot": "belt", + "theme": "hawaiian", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/grass_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/grass_yellow/front.png" + }, + "sprites": "https://media.boxcritters.com/items/grass_yellow/sprites.png" + }, + { + "itemId": "grass_green", + "name": "Green Grass Skirt", + "cost": 100, + "slot": "belt", + "theme": "hawaiian", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/grass_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/grass_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/grass_green/sprites.png" + }, + { + "itemId": "hawaii_blue", + "name": "Blue Hawaiian Shirt", + "cost": 100, + "slot": "body", + "theme": "hawaiian", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hawaii_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hawaii_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hawaii_blue/sprites.png" + }, + { + "itemId": "hawaii_orange", + "name": "Orange Hawaiian Shirt", + "cost": 100, + "slot": "body", + "theme": "hawaiian", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hawaii_orange/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hawaii_orange/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hawaii_orange/sprites.png" + }, + { + "itemId": "fishing_green", + "name": "Fishing Hat", + "cost": 100, + "slot": "head", + "theme": "explore", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/fishing_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/fishing_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/fishing_green/sprites.png" + }, + { + "itemId": "unclesam", + "name": "Uncle Sam Hat", + "cost": 100, + "slot": "head", + "theme": "party", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/unclesam/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/unclesam/front.png" + }, + "sprites": "https://media.boxcritters.com/items/unclesam/sprites.png" + }, + { + "itemId": "box_hat_brown", + "name": "Cardboard Box Hat", + "cost": 100, + "slot": "head", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/box_hat_brown/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/box_hat_brown/front.png" + }, + "sprites": "https://media.boxcritters.com/items/box_hat_brown/sprites.png" + }, + { + "itemId": "box_hat_purple", + "name": "Purple Cardboard Box Hat", + "cost": 100, + "slot": "head", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/box_hat_purple/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/box_hat_purple/front.png" + }, + "sprites": "https://media.boxcritters.com/items/box_hat_purple/sprites.png" + }, + { + "itemId": "monk", + "name": "Monk Robe", + "cost": 100, + "slot": "body", + "theme": "movie", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/monk/icon.png", + "bits": { "front": "https://media.boxcritters.com/items/monk/front.png" }, + "sprites": "https://media.boxcritters.com/items/monk/sprites.png" + }, + { + "itemId": "pot", + "name": "Pot Helm", + "cost": 100, + "slot": "head", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pot/icon.png", + "bits": { "front": "https://media.boxcritters.com/items/pot/front.png" }, + "sprites": "https://media.boxcritters.com/items/pot/sprites.png" + }, + { + "itemId": "goggles_black", + "name": "Black Goggles", + "cost": 100, + "slot": "eyes", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/goggles_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/goggles_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/goggles_black/sprites.png" + }, + { + "itemId": "goggles_green", + "name": "Green Goggles", + "cost": 20, + "slot": "eyes", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/goggles_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/goggles_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/goggles_green/sprites.png" + }, + { + "itemId": "goggles_white", + "name": "White Goggles", + "cost": 100, + "slot": "eyes", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/goggles_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/goggles_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/goggles_white/sprites.png" + }, + { + "itemId": "goggles_pink", + "name": "Pink Googles", + "cost": 100, + "slot": "eyes", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/goggles_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/goggles_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/goggles_pink/sprites.png" + }, + { + "itemId": "lifejacket_red", + "name": "Red Lifejacket", + "cost": 100, + "slot": "body", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/lifejacket_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/lifejacket_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/lifejacket_red/sprites.png" + }, + { + "itemId": "cone", + "name": "Critter Cone", + "cost": 100, + "slot": "neck", + "theme": "silly", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/cone/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/cone/front.png", + "back": "https://media.boxcritters.com/items/cone/back.png" + }, + "sprites": "https://media.boxcritters.com/items/cone/sprites.png" + }, + { + "itemId": "lei_red", + "name": "Red Hawaiian Lei", + "cost": 100, + "slot": "neck", + "theme": "hawaiian", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/lei_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/lei_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/lei_red/sprites.png" + }, + { + "itemId": "backpack_green", + "name": "Green Camping Backpack", + "cost": 1000, + "slot": "pack", + "theme": "explore", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/backpack_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/backpack_green/front.png", + "back": "https://media.boxcritters.com/items/backpack_green/back.png" + }, + "sprites": "https://media.boxcritters.com/items/backpack_green/sprites.png" + }, + { + "itemId": "bunny_blue", + "name": "Blue Bunny Ears", + "cost": 100, + "slot": "head", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bunny_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bunny_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bunny_blue/sprites.png" + }, + { + "itemId": "bunny_pink", + "name": "Pink Bunny Ears", + "cost": 100, + "slot": "head", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bunny_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bunny_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bunny_pink/sprites.png" + }, + { + "itemId": "bunny_white", + "name": "White Bunny Ears", + "cost": 100, + "slot": "head", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bunny_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bunny_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bunny_white/sprites.png" + }, + { + "itemId": "easteregg_a", + "name": "Easter Egg", + "cost": 100, + "slot": "head", + "theme": "event", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/easteregg_a/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/easteregg_a/front.png" + }, + "sprites": "https://media.boxcritters.com/items/easteregg_a/sprites.png" + }, + { + "itemId": "easteregg_b", + "name": "Easter Egg", + "cost": 100, + "slot": "head", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/easteregg_b/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/easteregg_b/front.png" + }, + "sprites": "https://media.boxcritters.com/items/easteregg_b/sprites.png" + }, + { + "itemId": "easteregg_c", + "name": "Easter Egg", + "cost": 100, + "slot": "head", + "theme": "event", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/easteregg_c/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/easteregg_c/front.png" + }, + "sprites": "https://media.boxcritters.com/items/easteregg_c/sprites.png" + }, + { + "itemId": "moose", + "name": "Moose Antlers", + "cost": 100, + "slot": "ears", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/moose/icon.png", + "bits": { "front": "https://media.boxcritters.com/items/moose/front.png" }, + "sprites": "https://media.boxcritters.com/items/moose/sprites.png" + }, + { + "itemId": "ninja_swords", + "name": "Ninja Swords", + "cost": 100, + "slot": "pack", + "theme": "ninja", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ninja_swords/icon.png", + "bits": { + "back": "https://media.boxcritters.com/items/ninja_swords/back.png" + }, + "sprites": "https://media.boxcritters.com/items/ninja_swords/sprites.png" + }, + { + "itemId": "overalls_orange", + "name": "Orange Overalls", + "cost": 100, + "slot": "body", + "theme": "work", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/overalls_orange/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/overalls_orange/front.png" + }, + "sprites": "https://media.boxcritters.com/items/overalls_orange/sprites.png" + }, + { + "itemId": "space_helmet_white", + "name": "Space Helmet", + "cost": 100, + "slot": "head", + "theme": "space", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/space_helmet_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/space_helmet_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/space_helmet_white/sprites.png" + }, + { + "itemId": "space_suit_white", + "name": "Space Suit", + "cost": 100, + "slot": "body", + "theme": "space", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/space_suit_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/space_suit_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/space_suit_white/sprites.png" + }, + { + "itemId": "space_pack_white", + "name": "Space Backpack", + "cost": 100, + "slot": "pack", + "theme": "space", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/space_pack_white/icon.png", + "bits": { + "back": "https://media.boxcritters.com/items/space_pack_white/back.png" + }, + "sprites": "https://media.boxcritters.com/items/space_pack_white/sprites.png" + }, + { + "itemId": "suit_dark", + "name": "Dark Suit", + "cost": 100, + "slot": "body", + "theme": "work", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/suit_dark/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/suit_dark/front.png" + }, + "sprites": "https://media.boxcritters.com/items/suit_dark/sprites.png" + }, + { + "itemId": "suit_gold", + "name": "Gold Suit", + "cost": 100, + "slot": "body", + "theme": "work", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/suit_gold/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/suit_gold/front.png" + }, + "sprites": "https://media.boxcritters.com/items/suit_gold/sprites.png" + }, + { + "itemId": "sun_orange", + "name": "Orange Sunglasses", + "cost": 100, + "slot": "eyes", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/sun_orange/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/sun_orange/front.png" + }, + "sprites": "https://media.boxcritters.com/items/sun_orange/sprites.png" + }, + { + "itemId": "sun_square", + "name": "Tamago's Shades", + "cost": 100, + "slot": "eyes", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/sun_square/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/sun_square/front.png" + }, + "sprites": "https://media.boxcritters.com/items/sun_square/sprites.png" + }, + { + "itemId": "super_cape_red", + "name": "Superhero Cape", + "cost": 100, + "slot": "pack", + "theme": "super", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/super_cape_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/super_cape_red/front.png", + "back": "https://media.boxcritters.com/items/super_cape_red/back.png" + }, + "sprites": "https://media.boxcritters.com/items/super_cape_red/sprites.png" + }, + { + "itemId": "super_mask_black", + "name": "Superhero Mask", + "cost": 100, + "slot": "mask", + "theme": "super", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/super_mask_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/super_mask_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/super_mask_black/sprites.png" + }, + { + "itemId": "tophat_dark", + "name": "Dark Tophat", + "cost": 100, + "slot": "head", + "theme": "work", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/tophat_dark/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/tophat_dark/front.png" + }, + "sprites": "https://media.boxcritters.com/items/tophat_dark/sprites.png" + }, + { + "itemId": "tophat_gold", + "name": "Gold Tophat", + "cost": 1000000, + "slot": "head", + "theme": "work", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/tophat_gold/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/tophat_gold/front.png" + }, + "sprites": "https://media.boxcritters.com/items/tophat_gold/sprites.png" + }, + { + "itemId": "tophat_black", + "name": "Black Tophat", + "cost": 100, + "slot": "head", + "theme": "work", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/tophat_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/tophat_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/tophat_black/sprites.png" + }, + { + "itemId": "snorkel_blue", + "name": "Blue Snorkel", + "cost": 100, + "slot": "eyes", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/snorkel_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/snorkel_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/snorkel_blue/sprites.png" + }, + { + "itemId": "keytar_red", + "name": "Red Keytar", + "cost": 100, + "slot": "hand", + "theme": "music", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/keytar_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/keytar_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/keytar_red/sprites.png" + }, + { + "itemId": "aviator_hat_brown", + "name": "Aviator Hat", + "cost": 100, + "slot": "head", + "theme": "history", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/aviator_hat_brown/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/aviator_hat_brown/front.png" + }, + "sprites": "https://media.boxcritters.com/items/aviator_hat_brown/sprites.png" + }, + { + "itemId": "aviator_goggles_brown", + "name": "Aviator Goggles", + "cost": 100, + "slot": "eyes", + "theme": "history", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/aviator_goggles_brown/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/aviator_goggles_brown/front.png" + }, + "sprites": "https://media.boxcritters.com/items/aviator_goggles_brown/sprites.png" + }, + { + "itemId": "watergun_yellow", + "name": "Watergun", + "cost": 100, + "slot": "hand", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/watergun_yellow/icon.png", + "bits": {}, + "sprites": "https://media.boxcritters.com/items/watergun_yellow/sprites.png" + }, + { + "itemId": "pot_black", + "name": "Black Pot", + "cost": 100, + "slot": "head", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pot_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pot_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pot_black/sprites.png" + }, + { + "itemId": "ballcap_orange", + "name": "Orange Ballcap", + "cost": 40, + "slot": "head", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ballcap_orange/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ballcap_orange/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ballcap_orange/sprites.png" + }, + { + "itemId": "hoodie_orange", + "name": "Orange Hoodie", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hoodie_orange/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hoodie_orange/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hoodie_orange/sprites.png" + }, + { + "itemId": "school_pack_orange", + "name": "Orange Backpack", + "cost": 100, + "slot": "pack", + "theme": "school", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/school_pack_orange/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/school_pack_orange/front.png", + "back": "https://media.boxcritters.com/items/school_pack_orange/back.png" + }, + "sprites": "https://media.boxcritters.com/items/school_pack_orange/sprites.png" + }, + { + "itemId": "toque_orange", + "name": "Orange Toque", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/toque_orange/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/toque_orange/front.png" + }, + "sprites": "https://media.boxcritters.com/items/toque_orange/sprites.png" + }, + { + "itemId": "kit_yellow", + "name": "Yellow and Green Kit", + "cost": 100, + "slot": "body", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/kit_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/kit_yellow/front.png" + }, + "sprites": "https://media.boxcritters.com/items/kit_yellow/sprites.png" + }, + { + "itemId": "plaid_black", + "name": "Black Plaid Shirt", + "cost": 400, + "slot": "body", + "theme": "explore", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/plaid_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/plaid_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/plaid_black/sprites.png" + }, + { + "itemId": "propeller_silver", + "name": "Silver Propeller Cap", + "cost": 100, + "slot": "head", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/propeller_silver/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/propeller_silver/front.png" + }, + "sprites": "https://media.boxcritters.com/items/propeller_silver/sprites.png" + }, + { + "itemId": "school_pack_pink", + "name": "School Backpack with Rainbows", + "cost": 100, + "slot": "pack", + "theme": "school", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/school_pack_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/school_pack_pink/front.png", + "back": "https://media.boxcritters.com/items/school_pack_pink/back.png" + }, + "sprites": "https://media.boxcritters.com/items/school_pack_pink/sprites.png" + }, + { + "itemId": "school_pack_blue", + "name": "School Backpack with Stars", + "cost": 100, + "slot": "pack", + "theme": "school", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/school_pack_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/school_pack_blue/front.png", + "back": "https://media.boxcritters.com/items/school_pack_blue/back.png" + }, + "sprites": "https://media.boxcritters.com/items/school_pack_blue/sprites.png" + }, + { + "itemId": "tshirt_orange", + "name": "Orange T-Shirt", + "cost": 50, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/tshirt_orange/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/tshirt_orange/front.png" + }, + "sprites": "https://media.boxcritters.com/items/tshirt_orange/sprites.png" + }, + { + "itemId": "tinfoil_hat", + "name": "Tinfoil Hat", + "cost": 100, + "slot": "head", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/tinfoil_hat/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/tinfoil_hat/front.png" + }, + "sprites": "https://media.boxcritters.com/items/tinfoil_hat/sprites.png" + }, + { + "itemId": "sombrero_yellow", + "name": "Yellow Sombrero", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/sombrero_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/sombrero_yellow/front.png", + "back": "https://media.boxcritters.com/items/sombrero_yellow/back.png" + }, + "sprites": "https://media.boxcritters.com/items/sombrero_yellow/sprites.png" + }, + { + "itemId": "box_brown", + "name": "Cardboard Box", + "cost": 100, + "slot": "ride", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/box_brown/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/box_brown/front.png", + "back": "https://media.boxcritters.com/items/box_brown/back.png" + }, + "sprites": "https://media.boxcritters.com/items/box_brown/sprites.png" + }, + { + "itemId": "ghost_white", + "name": "Ghost", + "cost": 100, + "slot": "body", + "theme": "halloween", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/ghost_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ghost_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ghost_white/sprites.png" + }, + { + "itemId": "army_helmet_green", + "name": "Army Helmet", + "cost": 400, + "slot": "head", + "theme": "army", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/army_helmet_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/army_helmet_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/army_helmet_green/sprites.png" + }, + { + "itemId": "super_cape_pink", + "name": "Pink Superhero Cape", + "cost": 50, + "slot": "pack", + "theme": "super", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/super_cape_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/super_cape_pink/front.png", + "back": "https://media.boxcritters.com/items/super_cape_pink/back.png" + }, + "sprites": "https://media.boxcritters.com/items/super_cape_pink/sprites.png" + }, + { + "itemId": "super_cape_blue", + "name": "Blue Superhero Cape", + "cost": 50, + "slot": "pack", + "theme": "super", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/super_cape_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/super_cape_blue/front.png", + "back": "https://media.boxcritters.com/items/super_cape_blue/back.png" + }, + "sprites": "https://media.boxcritters.com/items/super_cape_blue/sprites.png" + }, + { + "itemId": "super_cape_white", + "name": "White Superhero Cape", + "cost": 100, + "slot": "pack", + "theme": "super", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/super_cape_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/super_cape_white/front.png", + "back": "https://media.boxcritters.com/items/super_cape_white/back.png" + }, + "sprites": "https://media.boxcritters.com/items/super_cape_white/sprites.png" + }, + { + "itemId": "school_navy_a", + "name": "School Navy Uniform", + "cost": 100, + "slot": "body", + "theme": "school", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/school_navy_a/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/school_navy_a/front.png" + }, + "sprites": "https://media.boxcritters.com/items/school_navy_a/sprites.png" + }, + { + "itemId": "school_navy_b", + "name": "School Navy Uniform", + "cost": 100, + "slot": "body", + "theme": "school", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/school_navy_b/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/school_navy_b/front.png" + }, + "sprites": "https://media.boxcritters.com/items/school_navy_b/sprites.png" + }, + { + "itemId": "ball_blue", + "name": "Running Ball", + "cost": 100, + "slot": "ride", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ball_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ball_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ball_blue/sprites.png" + }, + { + "itemId": "scarf_red", + "name": "Red Scarf", + "cost": 100, + "slot": "neck", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/scarf_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/scarf_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/scarf_red/sprites.png" + }, + { + "itemId": "fairy_wings", + "name": "Fairy Wings", + "cost": 100, + "slot": "pack", + "theme": "fantasy", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/fairy_wings/icon.png", + "bits": { + "back": "https://media.boxcritters.com/items/fairy_wings/back.png" + }, + "sprites": "https://media.boxcritters.com/items/fairy_wings/sprites.png" + }, + { + "itemId": "rocket_red", + "name": "Rocket", + "cost": 100, + "slot": "pack", + "theme": "mascot", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/rocket_red/icon.png", + "bits": { + "back": "https://media.boxcritters.com/items/rocket_red/back.png" + }, + "sprites": "https://media.boxcritters.com/items/rocket_red/sprites.png" + }, + { + "itemId": "roman_helmet", + "name": "Roman Helmet", + "cost": 100, + "slot": "head", + "theme": "history", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/roman_helmet/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/roman_helmet/front.png" + }, + "sprites": "https://media.boxcritters.com/items/roman_helmet/sprites.png" + }, + { + "itemId": "bandana_black", + "name": "Black Bandana", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bandana_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bandana_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bandana_black/sprites.png" + }, + { + "itemId": "bandana_pink", + "name": "Pink Bandana", + "cost": 20, + "slot": "head", + "theme": "pirate", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bandana_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bandana_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bandana_pink/sprites.png" + }, + { + "itemId": "clown_nose", + "name": "Clown Nose", + "cost": 100, + "slot": "mask", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/clown_nose/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/clown_nose/front.png" + }, + "sprites": "https://media.boxcritters.com/items/clown_nose/sprites.png" + }, + { + "itemId": "frank", + "name": "Frank", + "cost": 100, + "slot": "head", + "theme": "halloween", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/frank/icon.png", + "bits": { "front": "https://media.boxcritters.com/items/frank/front.png" }, + "sprites": "https://media.boxcritters.com/items/frank/sprites.png" + }, + { + "itemId": "hotdog", + "name": "Hotdog", + "cost": 100, + "slot": "body", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hotdog/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hotdog/front.png", + "back": "https://media.boxcritters.com/items/hotdog/back.png" + }, + "sprites": "https://media.boxcritters.com/items/hotdog/sprites.png" + }, + { + "itemId": "mummy_head", + "name": "Mummy Head", + "cost": 20, + "slot": "head", + "theme": "halloween", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/mummy_head/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/mummy_head/front.png" + }, + "sprites": "https://media.boxcritters.com/items/mummy_head/sprites.png" + }, + { + "itemId": "pirate_capt_pink", + "name": "Pink Pirate Captian", + "cost": 100, + "slot": "body", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_capt_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_capt_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_capt_pink/sprites.png" + }, + { + "itemId": "pirate_hat_pink", + "name": "Pink Pirate Hat", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_hat_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_hat_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_hat_pink/sprites.png" + }, + { + "itemId": "pumpkin", + "name": "Pumpkin", + "cost": 100, + "slot": "head", + "theme": "halloween", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/pumpkin/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pumpkin/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pumpkin/sprites.png" + }, + { + "itemId": "shark_blue", + "name": "Blue Shark", + "cost": 400, + "slot": "head", + "theme": "silly", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/shark_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/shark_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/shark_blue/sprites.png" + }, + { + "itemId": "viking_pink", + "name": "Pink Viking Helmet", + "cost": 100, + "slot": "head", + "theme": "viking", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/viking_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/viking_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/viking_pink/sprites.png" + }, + { + "itemId": "witch", + "name": "Witch Hat", + "cost": 100, + "slot": "head", + "theme": "halloween", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/witch/icon.png", + "bits": { "front": "https://media.boxcritters.com/items/witch/front.png" }, + "sprites": "https://media.boxcritters.com/items/witch/sprites.png" + }, + { + "itemId": "messenger_brown", + "name": "Messenger Bag", + "cost": 100, + "slot": "belt", + "theme": "school", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/messenger_brown/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/messenger_brown/front.png" + }, + "sprites": "https://media.boxcritters.com/items/messenger_brown/sprites.png" + }, + { + "itemId": "princess_dress_pink", + "name": "Pink Princess Dress", + "cost": 100, + "slot": "body", + "theme": "fantasy", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/princess_dress_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/princess_dress_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/princess_dress_pink/sprites.png" + }, + { + "itemId": "scarf_black", + "name": "Black Scarf", + "cost": 100, + "slot": "neck", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/scarf_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/scarf_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/scarf_black/sprites.png" + }, + { + "itemId": "scarf_blue", + "name": "Blue Scarf", + "cost": 100, + "slot": "neck", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/scarf_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/scarf_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/scarf_blue/sprites.png" + }, + { + "itemId": "scarf_pink", + "name": "Pink Scarf", + "cost": 100, + "slot": "neck", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/scarf_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/scarf_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/scarf_pink/sprites.png" + }, + { + "itemId": "scarf_purple", + "name": "Purple Scarf", + "cost": 100, + "slot": "neck", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/scarf_purple/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/scarf_purple/front.png" + }, + "sprites": "https://media.boxcritters.com/items/scarf_purple/sprites.png" + }, + { + "itemId": "scarf_white", + "name": "White Scarf", + "cost": 100, + "slot": "neck", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/scarf_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/scarf_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/scarf_white/sprites.png" + }, + { + "itemId": "ballerina_pink", + "name": "Pink Ballerina", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ballerina_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ballerina_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ballerina_pink/sprites.png" + }, + { + "itemId": "headphones_pink", + "name": "Pink Headphones", + "cost": 100, + "slot": "ears", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/headphones_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/headphones_pink/front.png", + "back": "https://media.boxcritters.com/items/headphones_pink/back.png" + }, + "sprites": "https://media.boxcritters.com/items/headphones_pink/sprites.png" + }, + { + "itemId": "goggles_orange", + "name": "Orange Goggles", + "cost": 50, + "slot": "eyes", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/goggles_orange/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/goggles_orange/front.png" + }, + "sprites": "https://media.boxcritters.com/items/goggles_orange/sprites.png" + }, + { + "itemId": "goggles_blue", + "name": "Blue Goggles", + "cost": 20, + "slot": "eyes", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/goggles_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/goggles_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/goggles_blue/sprites.png" + }, + { + "itemId": "dracula_cloak", + "name": "Dracula Cloak", + "cost": 100, + "slot": "pack", + "theme": "halloween", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/dracula_cloak/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/dracula_cloak/front.png", + "back": "https://media.boxcritters.com/items/dracula_cloak/back.png" + }, + "sprites": "https://media.boxcritters.com/items/dracula_cloak/sprites.png" + }, + { + "itemId": "plaid_green", + "name": "Green Plaid", + "cost": 400, + "slot": "body", + "theme": "explore", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/plaid_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/plaid_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/plaid_green/sprites.png" + }, + { + "itemId": "plaid_pink", + "name": "Pink Plaid", + "cost": 400, + "slot": "body", + "theme": "explore", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/plaid_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/plaid_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/plaid_pink/sprites.png" + }, + { + "itemId": "stripe_red_white", + "name": "Red and White Striped Shirt", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/stripe_red_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/stripe_red_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/stripe_red_white/sprites.png" + }, + { + "itemId": "princess_hat_pink", + "name": "Pink Princess Hat", + "cost": 100, + "slot": "head", + "theme": "fantasy", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/princess_hat_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/princess_hat_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/princess_hat_pink/sprites.png" + }, + { + "itemId": "bandana_orange", + "name": "Orange Bandana", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bandana_orange/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bandana_orange/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bandana_orange/sprites.png" + }, + { + "itemId": "bandana_purple", + "name": "Purple Bandana", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bandana_purple/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bandana_purple/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bandana_purple/sprites.png" + }, + { + "itemId": "propeller_black", + "name": "Black Propeller Cap", + "cost": 100, + "slot": "head", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/propeller_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/propeller_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/propeller_black/sprites.png" + }, + { + "itemId": "super_cape_black", + "name": "Black Super Cape", + "cost": 100, + "slot": "pack", + "theme": "super", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/super_cape_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/super_cape_black/front.png", + "back": "https://media.boxcritters.com/items/super_cape_black/back.png" + }, + "sprites": "https://media.boxcritters.com/items/super_cape_black/sprites.png" + }, + { + "itemId": "skeleton_body", + "name": "Skeleton Body", + "cost": 100, + "slot": "body", + "theme": "halloween", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/skeleton_body/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/skeleton_body/front.png" + }, + "sprites": "https://media.boxcritters.com/items/skeleton_body/sprites.png" + }, + { + "itemId": "skeleton_head", + "name": "Skeleton Head", + "cost": 100, + "slot": "mask", + "theme": "halloween", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/skeleton_head/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/skeleton_head/front.png" + }, + "sprites": "https://media.boxcritters.com/items/skeleton_head/sprites.png" + }, + { + "itemId": "mummy_body", + "name": "Mummy", + "cost": 40, + "slot": "body", + "theme": "halloween", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/mummy_body/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/mummy_body/front.png" + }, + "sprites": "https://media.boxcritters.com/items/mummy_body/sprites.png" + }, + { + "itemId": "party_hat", + "name": "The Party Hat", + "cost": 100, + "slot": "head", + "theme": "party", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/party_hat/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/party_hat/front.png" + }, + "sprites": "https://media.boxcritters.com/items/party_hat/sprites.png" + }, + { + "itemId": "moustache", + "name": "Movember Moustache", + "cost": 100, + "slot": "fuzz", + "theme": "charity", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/moustache/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/moustache/front.png" + }, + "sprites": "https://media.boxcritters.com/items/moustache/sprites.png" + }, + { + "itemId": "bb_headband", + "name": "Wil's Headband", + "cost": 100, + "slot": "head", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bb_headband/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bb_headband/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bb_headband/sprites.png" + }, + { + "itemId": "bb_will", + "name": "Wil's Outfit", + "cost": 100, + "slot": "body", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bb_will/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bb_will/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bb_will/sprites.png" + }, + { + "itemId": "bb_huggable", + "name": "Huggable Head", + "cost": 100, + "slot": "head", + "theme": "event", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/bb_huggable/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bb_huggable/front.png", + "back": "https://media.boxcritters.com/items/bb_huggable/back.png" + }, + "sprites": "https://media.boxcritters.com/items/bb_huggable/sprites.png" + }, + { + "itemId": "bb_oliver", + "name": "Oliver's Outfit", + "cost": 100, + "slot": "body", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bb_oliver/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bb_oliver/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bb_oliver/sprites.png" + }, + { + "itemId": "bb_astoria", + "name": "Astoria's Outfit", + "cost": 100, + "slot": "body", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bb_astoria/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bb_astoria/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bb_astoria/sprites.png" + }, + { + "itemId": "bb_ballcap", + "name": "Battle Bears Ballcap", + "cost": 100, + "slot": "head", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bb_ballcap/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bb_ballcap/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bb_ballcap/sprites.png" + }, + { + "itemId": "bb_riggs", + "name": "Rigg's Outfit", + "cost": 100, + "slot": "body", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bb_riggs/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bb_riggs/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bb_riggs/sprites.png" + }, + { + "itemId": "bb_backpack", + "name": "Battle Bears Backpack", + "cost": 100, + "slot": "pack", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bb_backpack/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bb_backpack/front.png", + "back": "https://media.boxcritters.com/items/bb_backpack/back.png" + }, + "sprites": "https://media.boxcritters.com/items/bb_backpack/sprites.png" + }, + { + "itemId": "headband_blue", + "name": "Blue Headband", + "cost": 100, + "slot": "head", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/headband_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/headband_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/headband_blue/sprites.png" + }, + { + "itemId": "bb_beebee", + "name": "Bee Bee", + "cost": 100, + "slot": "hand", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bb_beebee/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bb_beebee/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bb_beebee/sprites.png" + }, + { + "itemId": "candy_corn", + "name": "Candy Corn", + "cost": 100, + "slot": "body", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/candy_corn/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/candy_corn/front.png" + }, + "sprites": "https://media.boxcritters.com/items/candy_corn/sprites.png" + }, + { + "itemId": "turkey", + "name": "Turkey Hat", + "cost": 100, + "slot": "head", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/turkey/icon.png", + "bits": { "front": "https://media.boxcritters.com/items/turkey/front.png" }, + "sprites": "https://media.boxcritters.com/items/turkey/sprites.png" + }, + { + "itemId": "bonnet_white", + "name": "Bonnet", + "cost": 100, + "slot": "head", + "theme": "history", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bonnet_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bonnet_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bonnet_white/sprites.png" + }, + { + "itemId": "pilgram_suit", + "name": "Pilgrim Suit", + "cost": 100, + "slot": "body", + "theme": "history", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pilgram_suit/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pilgram_suit/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pilgram_suit/sprites.png" + }, + { + "itemId": "pilgram_dress", + "name": "Pilgrim Dress", + "cost": 100, + "slot": "body", + "theme": "history", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pilgram_dress/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pilgram_dress/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pilgram_dress/sprites.png" + }, + { + "itemId": "pilgram_hat", + "name": "Pilgrim Hat", + "cost": 100, + "slot": "head", + "theme": "history", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pilgram_hat/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pilgram_hat/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pilgram_hat/sprites.png" + }, + { + "itemId": "bb_tillman", + "name": "Tillman", + "cost": 100, + "slot": "head", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bb_tillman/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bb_tillman/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bb_tillman/sprites.png" + }, + { + "itemId": "jetpack", + "name": "Jetpack", + "cost": 100, + "slot": "pack", + "theme": "space", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/jetpack/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/jetpack/front.png", + "back": "https://media.boxcritters.com/items/jetpack/back.png" + }, + "sprites": "https://media.boxcritters.com/items/jetpack/sprites.png" + }, + { + "itemId": "santa_hat", + "name": "Santa Hat", + "cost": 100, + "slot": "head", + "theme": "holiday", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/santa_hat/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/santa_hat/front.png" + }, + "sprites": "https://media.boxcritters.com/items/santa_hat/sprites.png" + }, + { + "itemId": "santa_beard", + "name": "Santa Beard", + "cost": 100, + "slot": "fuzz", + "theme": "holiday", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/santa_beard/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/santa_beard/front.png" + }, + "sprites": "https://media.boxcritters.com/items/santa_beard/sprites.png" + }, + { + "itemId": "santa_suit", + "name": "Santa Suit", + "cost": 100, + "slot": "body", + "theme": "holiday", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/santa_suit/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/santa_suit/front.png" + }, + "sprites": "https://media.boxcritters.com/items/santa_suit/sprites.png" + }, + { + "itemId": "elf_suit_green", + "name": "Green Elf", + "cost": 100, + "slot": "body", + "theme": "holiday", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/elf_suit_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/elf_suit_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/elf_suit_green/sprites.png" + }, + { + "itemId": "elf_hat_green", + "name": "Green Elf Hat", + "cost": 100, + "slot": "head", + "theme": "holiday", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/elf_hat_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/elf_hat_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/elf_hat_green/sprites.png" + }, + { + "itemId": "winter_dress", + "name": "Winter Dress", + "cost": 100, + "slot": "body", + "theme": "holiday", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/winter_dress/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/winter_dress/front.png" + }, + "sprites": "https://media.boxcritters.com/items/winter_dress/sprites.png" + }, + { + "itemId": "bow_white", + "name": "White Bow", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bow_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bow_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bow_white/sprites.png" + }, + { + "itemId": "jumpsuit_red", + "name": "Red Jumpsuit", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/jumpsuit_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/jumpsuit_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/jumpsuit_red/sprites.png" + }, + { + "itemId": "gelatinous_green", + "name": "Gelatinous Cube", + "cost": 100, + "slot": "ride", + "theme": "holiday", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/gelatinous_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/gelatinous_green/front.png", + "back": "https://media.boxcritters.com/items/gelatinous_green/back.png" + }, + "sprites": "https://media.boxcritters.com/items/gelatinous_green/sprites.png" + }, + { + "itemId": "bulb_blue", + "name": "Blue Bulb", + "cost": 100, + "slot": "head", + "theme": "holiday", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/bulb_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bulb_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bulb_blue/sprites.png" + }, + { + "itemId": "bulb_green", + "name": "Green Bulb", + "cost": 100, + "slot": "head", + "theme": "holiday", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/bulb_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bulb_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bulb_green/sprites.png" + }, + { + "itemId": "bulb_pink", + "name": "Pink Bulb", + "cost": 100, + "slot": "head", + "theme": "holiday", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/bulb_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bulb_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bulb_pink/sprites.png" + }, + { + "itemId": "bulb_red", + "name": "Red Bulb", + "cost": 100, + "slot": "head", + "theme": "holiday", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/bulb_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bulb_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bulb_red/sprites.png" + }, + { + "itemId": "bulb_white", + "name": "White Bulb", + "cost": 100, + "slot": "head", + "theme": "holiday", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/bulb_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bulb_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bulb_white/sprites.png" + }, + { + "itemId": "bulb_yellow", + "name": "Yellow Bulb", + "cost": 100, + "slot": "head", + "theme": "holiday", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/bulb_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bulb_yellow/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bulb_yellow/sprites.png" + }, + { + "itemId": "train_blue", + "name": "Train Conductor", + "cost": 100, + "slot": "body", + "theme": "work", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/train_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/train_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/train_blue/sprites.png" + }, + { + "itemId": "box_hat_red", + "name": "Red Cardboard Box Hat", + "cost": 100, + "slot": "head", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/box_hat_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/box_hat_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/box_hat_red/sprites.png" + }, + { + "itemId": "train_hat_blue", + "name": "Train Conductor Hat", + "cost": 100, + "slot": "head", + "theme": "work", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/train_hat_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/train_hat_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/train_hat_blue/sprites.png" + }, + { + "itemId": "reindeer_body", + "name": "Reindeer", + "cost": 100, + "slot": "body", + "theme": "holiday", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/reindeer_body/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/reindeer_body/front.png" + }, + "sprites": "https://media.boxcritters.com/items/reindeer_body/sprites.png" + }, + { + "itemId": "reindeer_head", + "name": "Reindeer Head", + "cost": 100, + "slot": "head", + "theme": "holiday", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/reindeer_head/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/reindeer_head/front.png" + }, + "sprites": "https://media.boxcritters.com/items/reindeer_head/sprites.png" + }, + { + "itemId": "gift_hat_green", + "name": "Green Gift", + "cost": 100, + "slot": "head", + "theme": "charity", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/gift_hat_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/gift_hat_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/gift_hat_green/sprites.png" + }, + { + "itemId": "gift_hat_red", + "name": "Red Gift", + "cost": 100, + "slot": "head", + "theme": "charity", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/gift_hat_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/gift_hat_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/gift_hat_red/sprites.png" + }, + { + "itemId": "angel_halo", + "name": "Angel Halo", + "cost": 100, + "slot": "head", + "theme": "holiday", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/angel_halo/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/angel_halo/front.png" + }, + "sprites": "https://media.boxcritters.com/items/angel_halo/sprites.png" + }, + { + "itemId": "angel_wings", + "name": "Angel Wings", + "cost": 100, + "slot": "body", + "theme": "holiday", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/angel_wings/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/angel_wings/front.png", + "back": "https://media.boxcritters.com/items/angel_wings/back.png" + }, + "sprites": "https://media.boxcritters.com/items/angel_wings/sprites.png" + }, + { + "itemId": "ushanka", + "name": "Ushanka", + "cost": 100, + "slot": "head", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ushanka/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ushanka/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ushanka/sprites.png" + }, + { + "itemId": "bandana_yellow", + "name": "Yellow Bandana", + "cost": 40, + "slot": "head", + "theme": "pirate", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bandana_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bandana_yellow/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bandana_yellow/sprites.png" + }, + { + "itemId": "puffy_white", + "name": "White Puffy Jacket", + "cost": 100, + "slot": "body", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/puffy_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/puffy_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/puffy_white/sprites.png" + }, + { + "itemId": "puffy_red", + "name": "Red Puffy Jacket", + "cost": 100, + "slot": "body", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/puffy_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/puffy_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/puffy_red/sprites.png" + }, + { + "itemId": "puffy_pink", + "name": "Pink Puffy Jacket", + "cost": 100, + "slot": "body", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/puffy_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/puffy_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/puffy_pink/sprites.png" + }, + { + "itemId": "puffy_blue", + "name": "Blue Puffy Jacket", + "cost": 100, + "slot": "body", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/puffy_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/puffy_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/puffy_blue/sprites.png" + }, + { + "itemId": "puffy_black", + "name": "Black Puffy Jacket", + "cost": 100, + "slot": "body", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/puffy_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/puffy_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/puffy_black/sprites.png" + }, + { + "itemId": "winter_dress_red", + "name": "Red Winter Dress", + "cost": 100, + "slot": "body", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/winter_dress_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/winter_dress_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/winter_dress_red/sprites.png" + }, + { + "itemId": "tacky_green", + "name": "Tacky Green Sweater", + "cost": 100, + "slot": "body", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/tacky_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/tacky_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/tacky_green/sprites.png" + }, + { + "itemId": "tacky_red", + "name": "Tacky Red Sweater", + "cost": 100, + "slot": "body", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/tacky_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/tacky_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/tacky_red/sprites.png" + }, + { + "itemId": "ornament_blue", + "name": "Blue Ornament", + "cost": 100, + "slot": "body", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ornament_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ornament_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ornament_blue/sprites.png" + }, + { + "itemId": "ornament_gold", + "name": "Gold Ornament", + "cost": 100, + "slot": "body", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ornament_gold/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ornament_gold/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ornament_gold/sprites.png" + }, + { + "itemId": "ornament_green", + "name": "Green Ornament", + "cost": 100, + "slot": "body", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ornament_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ornament_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ornament_green/sprites.png" + }, + { + "itemId": "ornament_pink", + "name": "Pink Ornament", + "cost": 100, + "slot": "body", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ornament_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ornament_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ornament_pink/sprites.png" + }, + { + "itemId": "ornament_red", + "name": "Red Ornament", + "cost": 100, + "slot": "body", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ornament_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ornament_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ornament_red/sprites.png" + }, + { + "itemId": "ski_suit_blue", + "name": "Blue Ski Suit", + "cost": 100, + "slot": "body", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ski_suit_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ski_suit_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ski_suit_blue/sprites.png" + }, + { + "itemId": "ski_poles", + "name": "Ski Poles", + "cost": 100, + "slot": "hand", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ski_poles/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ski_poles/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ski_poles/sprites.png" + }, + { + "itemId": "toque_black", + "name": "Black Toque", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/toque_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/toque_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/toque_black/sprites.png" + }, + { + "itemId": "onesie_plaid_red", + "name": "Onesie Red Plaid", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/onesie_plaid_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/onesie_plaid_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/onesie_plaid_red/sprites.png" + }, + { + "itemId": "sleeping_red", + "name": "Red Sleeping Cap", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/sleeping_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/sleeping_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/sleeping_red/sprites.png" + }, + { + "itemId": "sweater_black", + "name": "Black Sweater", + "cost": 100, + "slot": "body", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/sweater_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/sweater_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/sweater_black/sprites.png" + }, + { + "itemId": "sweater_blue", + "name": "Blue Sweater", + "cost": 100, + "slot": "body", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/sweater_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/sweater_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/sweater_blue/sprites.png" + }, + { + "itemId": "sweater_green", + "name": "Green Sweater", + "cost": 100, + "slot": "body", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/sweater_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/sweater_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/sweater_green/sprites.png" + }, + { + "itemId": "sweater_orange", + "name": "Orange Sweater", + "cost": 100, + "slot": "body", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/sweater_orange/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/sweater_orange/front.png" + }, + "sprites": "https://media.boxcritters.com/items/sweater_orange/sprites.png" + }, + { + "itemId": "sweater_pink", + "name": "Pink Sweater", + "cost": 20, + "slot": "body", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/sweater_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/sweater_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/sweater_pink/sprites.png" + }, + { + "itemId": "sweater_red", + "name": "Red Sweater", + "cost": 100, + "slot": "body", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/sweater_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/sweater_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/sweater_red/sprites.png" + }, + { + "itemId": "blockhead", + "name": "Blockhead Hat", + "cost": 100, + "slot": "head", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/blockhead/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/blockhead/front.png" + }, + "sprites": "https://media.boxcritters.com/items/blockhead/sprites.png" + }, + { + "itemId": "tuxedo_black", + "name": "Tuxedo", + "cost": 100, + "slot": "body", + "theme": "party", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/tuxedo_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/tuxedo_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/tuxedo_black/sprites.png" + }, + { + "itemId": "australian_hat", + "name": "Australian Hat", + "cost": 100, + "slot": "head", + "theme": "charity", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/australian_hat/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/australian_hat/front.png" + }, + "sprites": "https://media.boxcritters.com/items/australian_hat/sprites.png" + }, + { + "itemId": "headphones_blue", + "name": "Blue Headphones", + "cost": 100, + "slot": "ears", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/headphones_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/headphones_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/headphones_blue/sprites.png" + }, + { + "itemId": "ski_helmet_blue", + "name": "Blue Ski Helmet", + "cost": 100, + "slot": "head", + "theme": "winter", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/ski_helmet_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ski_helmet_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ski_helmet_blue/sprites.png" + }, + { + "itemId": "hockey_jersey_red", + "name": "Red Hockey Jersey", + "cost": 100, + "slot": "body", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hockey_jersey_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hockey_jersey_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hockey_jersey_red/sprites.png" + }, + { + "itemId": "hockey_helmet_blue", + "name": "Blue Hockey Helmet", + "cost": 100, + "slot": "head", + "theme": "sports", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/hockey_helmet_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hockey_helmet_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hockey_helmet_blue/sprites.png" + }, + { + "itemId": "hockey_helmet_red", + "name": "Red Hockey Helmet", + "cost": 100, + "slot": "head", + "theme": "sports", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/hockey_helmet_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hockey_helmet_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hockey_helmet_red/sprites.png" + }, + { + "itemId": "hockey_jersey_blue", + "name": "Blue Hockey Jersey", + "cost": 100, + "slot": "body", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hockey_jersey_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hockey_jersey_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hockey_jersey_blue/sprites.png" + }, + { + "itemId": "traffic_cone", + "name": "Traffic Cone", + "cost": 100, + "slot": "head", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/traffic_cone/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/traffic_cone/front.png" + }, + "sprites": "https://media.boxcritters.com/items/traffic_cone/sprites.png" + }, + { + "itemId": "ringmaster_suit_red", + "name": "Ringmaster Suit", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ringmaster_suit_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ringmaster_suit_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ringmaster_suit_red/sprites.png" + }, + { + "itemId": "ringmaster_hat_black", + "name": "Ringmaster Hat", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ringmaster_hat_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ringmaster_hat_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ringmaster_hat_black/sprites.png" + }, + { + "itemId": "football_jersey_red", + "name": "Red Football Jersey", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/football_jersey_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/football_jersey_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/football_jersey_red/sprites.png" + }, + { + "itemId": "clown_suit_red", + "name": "Clown Suit", + "cost": 200, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/clown_suit_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/clown_suit_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/clown_suit_red/sprites.png" + }, + { + "itemId": "clown_wig", + "name": "Clown Wig", + "cost": 200, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/clown_wig/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/clown_wig/front.png" + }, + "sprites": "https://media.boxcritters.com/items/clown_wig/sprites.png" + }, + { + "itemId": "clown_face_white", + "name": "Clown Face Paint", + "cost": 100, + "slot": "face", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/clown_face_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/clown_face_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/clown_face_white/sprites.png" + }, + { + "itemId": "potato_brown", + "name": "Potato Sack", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/potato_brown/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/potato_brown/front.png" + }, + "sprites": "https://media.boxcritters.com/items/potato_brown/sprites.png" + }, + { + "itemId": "football_face_black", + "name": "Football Face Paint", + "cost": 100, + "slot": "face", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/football_face_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/football_face_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/football_face_black/sprites.png" + }, + { + "itemId": "float_pink", + "name": "Pink Duck Floatie", + "cost": 100, + "slot": "hand", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/float_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/float_pink/front.png", + "back": "https://media.boxcritters.com/items/float_pink/back.png" + }, + "sprites": "https://media.boxcritters.com/items/float_pink/sprites.png" + }, + { + "itemId": "cake_suit_pink", + "name": "1 Year Anniversary Suit", + "cost": 100, + "slot": "body", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/cake_suit_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/cake_suit_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/cake_suit_pink/sprites.png" + }, + { + "itemId": "cake_hat_pink", + "name": "1 Year Anniversary Hat", + "cost": 100, + "slot": "head", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/cake_hat_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/cake_hat_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/cake_hat_pink/sprites.png" + }, + { + "itemId": "headphones_green", + "name": "Green Headphones", + "cost": 100, + "slot": "ears", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/headphones_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/headphones_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/headphones_green/sprites.png" + }, + { + "itemId": "tactical_headset", + "name": "Tactical Headset", + "cost": 100, + "slot": "ears", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/tactical_headset/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/tactical_headset/front.png" + }, + "sprites": "https://media.boxcritters.com/items/tactical_headset/sprites.png" + }, + { + "itemId": "night_vision", + "name": "Night Vision", + "cost": 100, + "slot": "eyes", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/night_vision/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/night_vision/front.png" + }, + "sprites": "https://media.boxcritters.com/items/night_vision/sprites.png" + }, + { + "itemId": "tactical_vest", + "name": "Tactical Vest", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/tactical_vest/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/tactical_vest/front.png" + }, + "sprites": "https://media.boxcritters.com/items/tactical_vest/sprites.png" + }, + { + "itemId": "wings_black", + "name": "Raven Wings", + "cost": 100, + "slot": "pack", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/wings_black/icon.png", + "bits": { + "back": "https://media.boxcritters.com/items/wings_black/back.png" + }, + "sprites": "https://media.boxcritters.com/items/wings_black/sprites.png" + }, + { + "itemId": "school_pack_black", + "name": "Black School Backpack", + "cost": 100, + "slot": "pack", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/school_pack_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/school_pack_black/front.png", + "back": "https://media.boxcritters.com/items/school_pack_black/back.png" + }, + "sprites": "https://media.boxcritters.com/items/school_pack_black/sprites.png" + }, + { + "itemId": "toque_green", + "name": "Green Toque", + "cost": 100, + "slot": "head", + "theme": "winter", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/toque_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/toque_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/toque_green/sprites.png" + }, + { + "itemId": "wings_yellow", + "name": "Angel Wings", + "cost": 100, + "slot": "pack", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/wings_yellow/icon.png", + "bits": { + "back": "https://media.boxcritters.com/items/wings_yellow/back.png" + }, + "sprites": "https://media.boxcritters.com/items/wings_yellow/sprites.png" + }, + { + "itemId": "tomb_fedora", + "name": "Movie Fedora", + "cost": 100, + "slot": "head", + "theme": "movie", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/tomb_fedora/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/tomb_fedora/front.png" + }, + "sprites": "https://media.boxcritters.com/items/tomb_fedora/sprites.png" + }, + { + "itemId": "tomb_jacket", + "name": "Movie Jacket", + "cost": 100, + "slot": "body", + "theme": "movie", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/tomb_jacket/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/tomb_jacket/front.png" + }, + "sprites": "https://media.boxcritters.com/items/tomb_jacket/sprites.png" + }, + { + "itemId": "leprechaun_hat", + "name": "Leprechaun Hat", + "cost": 100, + "slot": "head", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/leprechaun_hat/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/leprechaun_hat/front.png" + }, + "sprites": "https://media.boxcritters.com/items/leprechaun_hat/sprites.png" + }, + { + "itemId": "leprechaun_suit", + "name": "Leprechaun Suit", + "cost": 100, + "slot": "body", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/leprechaun_suit/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/leprechaun_suit/front.png" + }, + "sprites": "https://media.boxcritters.com/items/leprechaun_suit/sprites.png" + }, + { + "itemId": "leprechaun_dress", + "name": "Leprechaun Lady", + "cost": 100, + "slot": "body", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/leprechaun_dress/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/leprechaun_dress/front.png" + }, + "sprites": "https://media.boxcritters.com/items/leprechaun_dress/sprites.png" + }, + { + "itemId": "cardboard_sword", + "name": "Cardboard Sword", + "cost": 100, + "slot": "hand", + "theme": "fantasy", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/cardboard_sword/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/cardboard_sword/front.png" + }, + "sprites": "https://media.boxcritters.com/items/cardboard_sword/sprites.png" + }, + { + "itemId": "buster_pack", + "name": "Buster Pack", + "cost": 100, + "slot": "pack", + "theme": "movie", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/buster_pack/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/buster_pack/front.png", + "back": "https://media.boxcritters.com/items/buster_pack/back.png" + }, + "sprites": "https://media.boxcritters.com/items/buster_pack/sprites.png" + }, + { + "itemId": "buster_suit", + "name": "Buster Suit", + "cost": 100, + "slot": "body", + "theme": "movie", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/buster_suit/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/buster_suit/front.png" + }, + "sprites": "https://media.boxcritters.com/items/buster_suit/sprites.png" + }, + { + "itemId": "scout_scarf_blue", + "name": "Blue Scout Scarf", + "cost": 100, + "slot": "neck", + "theme": "explore", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/scout_scarf_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/scout_scarf_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/scout_scarf_blue/sprites.png" + }, + { + "itemId": "scout_uniform", + "name": "Scout Uniform", + "cost": 100, + "slot": "body", + "theme": "explore", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/scout_uniform/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/scout_uniform/front.png" + }, + "sprites": "https://media.boxcritters.com/items/scout_uniform/sprites.png" + }, + { + "itemId": "scuba_suit_blue", + "name": "Blue Scuba Suit", + "cost": 100, + "slot": "body", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/scuba_suit_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/scuba_suit_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/scuba_suit_blue/sprites.png" + }, + { + "itemId": "scuba_tank_yellow", + "name": "Yellow Scuba Tank", + "cost": 100, + "slot": "pack", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/scuba_tank_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/scuba_tank_yellow/front.png", + "back": "https://media.boxcritters.com/items/scuba_tank_yellow/back.png" + }, + "sprites": "https://media.boxcritters.com/items/scuba_tank_yellow/sprites.png" + }, + { + "itemId": "scuba_tank_green", + "name": "Green Scuba Tank", + "cost": 100, + "slot": "pack", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/scuba_tank_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/scuba_tank_green/front.png", + "back": "https://media.boxcritters.com/items/scuba_tank_green/back.png" + }, + "sprites": "https://media.boxcritters.com/items/scuba_tank_green/sprites.png" + }, + { + "itemId": "scarecrow", + "name": "Scarecrow", + "cost": 100, + "slot": "body", + "theme": "halloween", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/scarecrow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/scarecrow/front.png" + }, + "sprites": "https://media.boxcritters.com/items/scarecrow/sprites.png" + }, + { + "itemId": "scarecrow_hat", + "name": "Scarecrow Hat", + "cost": 100, + "slot": "head", + "theme": "halloween", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/scarecrow_hat/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/scarecrow_hat/front.png" + }, + "sprites": "https://media.boxcritters.com/items/scarecrow_hat/sprites.png" + }, + { + "itemId": "leprechaun_hat2", + "name": "Leprechaun Hat with Hair", + "cost": 100, + "slot": "head", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/leprechaun_hat2/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/leprechaun_hat2/front.png", + "back": "https://media.boxcritters.com/items/leprechaun_hat2/back.png" + }, + "sprites": "https://media.boxcritters.com/items/leprechaun_hat2/sprites.png" + }, + { + "itemId": "potofgold", + "name": "Pot of Gold", + "cost": 100, + "slot": "hand", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/potofgold/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/potofgold/front.png" + }, + "sprites": "https://media.boxcritters.com/items/potofgold/sprites.png" + }, + { + "itemId": "fiddle", + "name": "Fiddle", + "cost": 100, + "slot": "hand", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/fiddle/icon.png", + "bits": { "front": "https://media.boxcritters.com/items/fiddle/front.png" }, + "sprites": "https://media.boxcritters.com/items/fiddle/sprites.png" + }, + { + "itemId": "chef_hat_white", + "name": "White Chef Hat", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/chef_hat_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/chef_hat_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/chef_hat_white/sprites.png" + }, + { + "itemId": "rainhat_yellow", + "name": "Rain Hat", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/rainhat_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/rainhat_yellow/front.png", + "back": "https://media.boxcritters.com/items/rainhat_yellow/back.png" + }, + "sprites": "https://media.boxcritters.com/items/rainhat_yellow/sprites.png" + }, + { + "itemId": "raincoat_yellow", + "name": "Raincoat", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/raincoat_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/raincoat_yellow/front.png" + }, + "sprites": "https://media.boxcritters.com/items/raincoat_yellow/sprites.png" + }, + { + "itemId": "gift_hat_blue", + "name": "Blue Gift Hat", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/gift_hat_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/gift_hat_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/gift_hat_blue/sprites.png" + }, + { + "itemId": "doctor_cap_blue", + "name": "Doctor Cap", + "cost": 100, + "slot": "head", + "theme": "work", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/doctor_cap_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/doctor_cap_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/doctor_cap_blue/sprites.png" + }, + { + "itemId": "doctor_coat_white", + "name": "Doctor Coat", + "cost": 200, + "slot": "body", + "theme": "work", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/doctor_coat_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/doctor_coat_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/doctor_coat_white/sprites.png" + }, + { + "itemId": "doctor_mask_blue", + "name": "Doctor Mask", + "cost": 100, + "slot": "mask", + "theme": "work", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/doctor_mask_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/doctor_mask_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/doctor_mask_blue/sprites.png" + }, + { + "itemId": "stethoscope", + "name": "Stethoscope", + "cost": 100, + "slot": "neck", + "theme": "work", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/stethoscope/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/stethoscope/front.png" + }, + "sprites": "https://media.boxcritters.com/items/stethoscope/sprites.png" + }, + { + "itemId": "paperhat_colour", + "name": "Coloured Paper Hat", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/paperhat_colour/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/paperhat_colour/front.png" + }, + "sprites": "https://media.boxcritters.com/items/paperhat_colour/sprites.png" + }, + { + "itemId": "jester_hat", + "name": "Jester Hat", + "cost": 100, + "slot": "head", + "theme": "fantasy", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/jester_hat/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/jester_hat/front.png" + }, + "sprites": "https://media.boxcritters.com/items/jester_hat/sprites.png" + }, + { + "itemId": "peacoat_red", + "name": "Red Peacoat", + "cost": 50, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/peacoat_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/peacoat_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/peacoat_red/sprites.png" + }, + { + "itemId": "beret_red", + "name": "Beret RED", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/beret_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/beret_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/beret_red/sprites.png" + }, + { + "itemId": "flight_suit_red", + "name": "Flight Suit", + "cost": 100, + "slot": "body", + "theme": "movie", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/flight_suit_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/flight_suit_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/flight_suit_red/sprites.png" + }, + { + "itemId": "flight_helmet_red", + "name": "Flight Helmet", + "cost": 100, + "slot": "head", + "theme": "movie", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/flight_helmet_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/flight_helmet_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/flight_helmet_red/sprites.png" + }, + { + "itemId": "waistcoat_red", + "name": "Red Waistcoat", + "cost": 100, + "slot": "body", + "theme": "movie", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/waistcoat_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/waistcoat_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/waistcoat_red/sprites.png" + }, + { + "itemId": "peacoat_pink", + "name": "Pink Peacoat", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/peacoat_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/peacoat_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/peacoat_pink/sprites.png" + }, + { + "itemId": "peacoat_yellow", + "name": "Yellow Peacoat", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/peacoat_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/peacoat_yellow/front.png" + }, + "sprites": "https://media.boxcritters.com/items/peacoat_yellow/sprites.png" + }, + { + "itemId": "beret_pink", + "name": "Pink Beret", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/beret_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/beret_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/beret_pink/sprites.png" + }, + { + "itemId": "beret_blue", + "name": "Blue Beret", + "cost": 50, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/beret_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/beret_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/beret_blue/sprites.png" + }, + { + "itemId": "beret_yellow", + "name": "Yellow Beret", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/beret_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/beret_yellow/front.png" + }, + "sprites": "https://media.boxcritters.com/items/beret_yellow/sprites.png" + }, + { + "itemId": "peacoat_blue", + "name": "Blue Peacoat", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/peacoat_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/peacoat_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/peacoat_blue/sprites.png" + }, + { + "itemId": "raincoat_green", + "name": "Green Raincoat", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/raincoat_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/raincoat_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/raincoat_green/sprites.png" + }, + { + "itemId": "rainhat_green", + "name": "Green Rainhat", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/rainhat_green/icon.png", + "bits": {}, + "sprites": "https://media.boxcritters.com/items/rainhat_green/sprites.png" + }, + { + "itemId": "raincoat_blue", + "name": "Blue Raincoat", + "cost": 50, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/raincoat_blue/icon.png", + "bits": {}, + "sprites": "https://media.boxcritters.com/items/raincoat_blue/sprites.png" + }, + { + "itemId": "rainhat_blue", + "name": "Blue Rainhat", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/rainhat_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/rainhat_blue/front.png", + "back": "https://media.boxcritters.com/items/rainhat_blue/back.png" + }, + "sprites": "https://media.boxcritters.com/items/rainhat_blue/sprites.png" + }, + { + "itemId": "raincoat_red", + "name": "Red Raincoat", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/raincoat_red/icon.png", + "bits": {}, + "sprites": "https://media.boxcritters.com/items/raincoat_red/sprites.png" + }, + { + "itemId": "rainhat_red", + "name": "Red Rainhat", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/rainhat_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/rainhat_red/front.png", + "back": "https://media.boxcritters.com/items/rainhat_red/back.png" + }, + "sprites": "https://media.boxcritters.com/items/rainhat_red/sprites.png" + }, + { + "itemId": "chef_jacket_white", + "name": "White Chef Jacket", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/chef_jacket_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/chef_jacket_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/chef_jacket_white/sprites.png" + }, + { + "itemId": "chef_jacket_black", + "name": "Black Chef Jacket", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/chef_jacket_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/chef_jacket_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/chef_jacket_black/sprites.png" + }, + { + "itemId": "chef_hat_black", + "name": "Black Chef Hat", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/chef_hat_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/chef_hat_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/chef_hat_black/sprites.png" + }, + { + "itemId": "easteregg_d", + "name": "Easter Egg", + "cost": 100, + "slot": "head", + "theme": "event", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/easteregg_d/icon.png", + "bits": {}, + "sprites": "https://media.boxcritters.com/items/easteregg_d/sprites.png" + }, + { + "itemId": "easteregg_e", + "name": "Easter Egg", + "cost": 100, + "slot": "head", + "theme": "event", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/easteregg_e/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/easteregg_e/front.png" + }, + "sprites": "https://media.boxcritters.com/items/easteregg_e/sprites.png" + }, + { + "itemId": "easteregg_f", + "name": "Easter Egg", + "cost": 100, + "slot": "head", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/easteregg_f/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/easteregg_f/front.png" + }, + "sprites": "https://media.boxcritters.com/items/easteregg_f/sprites.png" + }, + { + "itemId": "fuzzy_head_yellow", + "name": "Yellow Fuzzy Bunny Ears", + "cost": 100, + "slot": "head", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/fuzzy_head_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/fuzzy_head_yellow/front.png" + }, + "sprites": "https://media.boxcritters.com/items/fuzzy_head_yellow/sprites.png" + }, + { + "itemId": "fuzzy_body_yellow", + "name": "Yellow Fuzzy Bunny Suit", + "cost": 100, + "slot": "body", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/fuzzy_body_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/fuzzy_body_yellow/front.png" + }, + "sprites": "https://media.boxcritters.com/items/fuzzy_body_yellow/sprites.png" + }, + { + "itemId": "fuzzy_feet_yellow", + "name": "Yellow Fuzzy Bunny Feet", + "cost": 100, + "slot": "feet", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/fuzzy_feet_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/fuzzy_feet_yellow/front.png" + }, + "sprites": "https://media.boxcritters.com/items/fuzzy_feet_yellow/sprites.png" + }, + { + "itemId": "bunny_black", + "name": "Black Bunny", + "cost": 100, + "slot": "head", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bunny_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bunny_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bunny_black/sprites.png" + }, + { + "itemId": "bunny_robot", + "name": "Robot Bunny", + "cost": 100, + "slot": "head", + "theme": "event", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/bunny_robot/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/bunny_robot/front.png" + }, + "sprites": "https://media.boxcritters.com/items/bunny_robot/sprites.png" + }, + { + "itemId": "brain_green", + "name": "Green Brain", + "cost": 100, + "slot": "head", + "theme": "holiday", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/brain_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/brain_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/brain_green/sprites.png" + }, + { + "itemId": "pirate_dress_blue", + "name": "Blue Pirate Dress", + "cost": 100, + "slot": "body", + "theme": "holiday", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_dress_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_dress_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_dress_blue/sprites.png" + }, + { + "itemId": "pirate_dress_green", + "name": "Green Pirate Dress", + "cost": 100, + "slot": "body", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_dress_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_dress_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_dress_green/sprites.png" + }, + { + "itemId": "pirate_dress_pink", + "name": "Pink Pirate Dress", + "cost": 100, + "slot": "body", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_dress_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_dress_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_dress_pink/sprites.png" + }, + { + "itemId": "pirate_dress_tan", + "name": "Tan Pirate Dress", + "cost": 100, + "slot": "body", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_dress_tan/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_dress_tan/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_dress_tan/sprites.png" + }, + { + "itemId": "belt_black", + "name": "Black belt", + "cost": 100, + "slot": "belt", + "theme": "ninja", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/belt_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/belt_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/belt_black/sprites.png" + }, + { + "itemId": "pirate_hair_red", + "name": "Red Pirate Hat with Hair", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_hair_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_hair_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_hair_red/sprites.png" + }, + { + "itemId": "pirate_hair_blue", + "name": "Blue Pirate Hat with Hair", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_hair_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_hair_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_hair_blue/sprites.png" + }, + { + "itemId": "pirate_hair_pink", + "name": "Pink Pirate Hat with Hair", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_hair_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_hair_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_hair_pink/sprites.png" + }, + { + "itemId": "pirate_hair_purple", + "name": "Purple Pirate Hat with Hair", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_hair_purple/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_hair_purple/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_hair_purple/sprites.png" + }, + { + "itemId": "doll_hat_white", + "name": "White Doll Hat", + "cost": 100, + "slot": "head", + "theme": "movie", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/doll_hat_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/doll_hat_white/front.png", + "back": "https://media.boxcritters.com/items/doll_hat_white/back.png" + }, + "sprites": "https://media.boxcritters.com/items/doll_hat_white/sprites.png" + }, + { + "itemId": "doll_dress_white", + "name": "White Doll Dress", + "cost": 100, + "slot": "body", + "theme": "movie", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/doll_dress_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/doll_dress_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/doll_dress_white/sprites.png" + }, + { + "itemId": "pirate_bandana_blue", + "name": "Blue Pirate Bandana ", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_bandana_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_bandana_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_bandana_blue/sprites.png" + }, + { + "itemId": "pirate_bandana_red", + "name": "Red Pirate Bandana", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_bandana_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_bandana_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_bandana_red/sprites.png" + }, + { + "itemId": "pirate_bandana_purple", + "name": "Purple Pirate Bandana", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_bandana_purple/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_bandana_purple/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_bandana_purple/sprites.png" + }, + { + "itemId": "pirate_bandana_pink", + "name": "Pink Pirate Bandana", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_bandana_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_bandana_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_bandana_pink/sprites.png" + }, + { + "itemId": "pirate_bandana_darkblack", + "name": "Dark Mode Pirate Bandana", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_bandana_darkblack/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_bandana_darkblack/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_bandana_darkblack/sprites.png" + }, + { + "itemId": "pirate_bandana_tan", + "name": "Tan Pirate Bandana", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_bandana_tan/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_bandana_tan/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_bandana_tan/sprites.png" + }, + { + "itemId": "pirate_bandana_black", + "name": "Black Bandana", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_bandana_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_bandana_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_bandana_black/sprites.png" + }, + { + "itemId": "pirate_vest_white", + "name": "Pirate Vest", + "cost": 100, + "slot": "body", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_vest_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_vest_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_vest_white/sprites.png" + }, + { + "itemId": "pirate_crew_pink", + "name": "Pink Pirate Crew", + "cost": 200, + "slot": "body", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_crew_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_crew_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_crew_pink/sprites.png" + }, + { + "itemId": "pirate_crew_dark", + "name": "Dark Pirate Crew", + "cost": 200, + "slot": "body", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_crew_dark/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_crew_dark/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_crew_dark/sprites.png" + }, + { + "itemId": "pirate_crew_green", + "name": "Green Pirate Crew", + "cost": 200, + "slot": "body", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_crew_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_crew_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_crew_green/sprites.png" + }, + { + "itemId": "pirate_crew_red", + "name": "Red Pirate Crew", + "cost": 200, + "slot": "body", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_crew_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_crew_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_crew_red/sprites.png" + }, + { + "itemId": "pirate_crew_grey", + "name": "Grey Pirate Crew", + "cost": 200, + "slot": "body", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_crew_grey/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_crew_grey/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_crew_grey/sprites.png" + }, + { + "itemId": "beard1_black", + "name": "Black Circle Beard", + "cost": 20, + "slot": "fuzz", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/beard1_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/beard1_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/beard1_black/sprites.png" + }, + { + "itemId": "beard1_red", + "name": "Red Circle Beard", + "cost": 20, + "slot": "fuzz", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/beard1_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/beard1_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/beard1_red/sprites.png" + }, + { + "itemId": "beard1_brown", + "name": "Brown Circle Beard", + "cost": 20, + "slot": "fuzz", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/beard1_brown/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/beard1_brown/front.png" + }, + "sprites": "https://media.boxcritters.com/items/beard1_brown/sprites.png" + }, + { + "itemId": "beard2_black", + "name": "Black Dutch Beard", + "cost": 20, + "slot": "fuzz", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/beard2_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/beard2_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/beard2_black/sprites.png" + }, + { + "itemId": "beard2_red", + "name": "Red Dutch Beard", + "cost": 20, + "slot": "fuzz", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/beard2_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/beard2_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/beard2_red/sprites.png" + }, + { + "itemId": "beard2_brown", + "name": "Brown Dutch Beard", + "cost": 20, + "slot": "fuzz", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/beard2_brown/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/beard2_brown/front.png" + }, + "sprites": "https://media.boxcritters.com/items/beard2_brown/sprites.png" + }, + { + "itemId": "beard3_black", + "name": "Black Full Beard", + "cost": 20, + "slot": "fuzz", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/beard3_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/beard3_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/beard3_black/sprites.png" + }, + { + "itemId": "beard3_red", + "name": "Red Full Beard", + "cost": 20, + "slot": "fuzz", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/beard3_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/beard3_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/beard3_red/sprites.png" + }, + { + "itemId": "beard3_brown", + "name": "Brown Full Beard", + "cost": 20, + "slot": "fuzz", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/beard3_brown/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/beard3_brown/front.png" + }, + "sprites": "https://media.boxcritters.com/items/beard3_brown/sprites.png" + }, + { + "itemId": "goatee_black", + "name": "Black Goatee", + "cost": 20, + "slot": "fuzz", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/goatee_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/goatee_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/goatee_black/sprites.png" + }, + { + "itemId": "goatee_red", + "name": "Red Goatee", + "cost": 20, + "slot": "fuzz", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/goatee_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/goatee_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/goatee_red/sprites.png" + }, + { + "itemId": "goatee_brown", + "name": "Brown Goatee", + "cost": 20, + "slot": "fuzz", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/goatee_brown/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/goatee_brown/front.png" + }, + "sprites": "https://media.boxcritters.com/items/goatee_brown/sprites.png" + }, + { + "itemId": "moustache_black", + "name": "Black Moustache", + "cost": 20, + "slot": "fuzz", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/moustache_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/moustache_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/moustache_black/sprites.png" + }, + { + "itemId": "moustache_red", + "name": "Red Moustache", + "cost": 20, + "slot": "fuzz", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/moustache_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/moustache_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/moustache_red/sprites.png" + }, + { + "itemId": "moustache_brown", + "name": " Brown Moustache", + "cost": 20, + "slot": "fuzz", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/moustache_brown/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/moustache_brown/front.png" + }, + "sprites": "https://media.boxcritters.com/items/moustache_brown/sprites.png" + }, + { + "itemId": "stubble_black", + "name": "Face Stubble", + "cost": 20, + "slot": "fuzz", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/stubble_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/stubble_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/stubble_black/sprites.png" + }, + { + "itemId": "pirate_hat_hook", + "name": "Pirate Hook Hat", + "cost": 100, + "slot": "head", + "theme": "pirate", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_hat_hook/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_hat_hook/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_hat_hook/sprites.png" + }, + { + "itemId": "fedora_black", + "name": "Black Fedora Hat", + "cost": 50, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/fedora_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/fedora_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/fedora_black/sprites.png" + }, + { + "itemId": "fedora_white", + "name": "White Fedora Hat", + "cost": 50, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/fedora_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/fedora_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/fedora_white/sprites.png" + }, + { + "itemId": "grad_hat", + "name": "Grad Hat", + "cost": 100, + "slot": "head", + "theme": "school", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/grad_hat/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/grad_hat/front.png" + }, + "sprites": "https://media.boxcritters.com/items/grad_hat/sprites.png" + }, + { + "itemId": "grad_robe", + "name": "Grad Robe", + "cost": 100, + "slot": "body", + "theme": "school", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/grad_robe/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/grad_robe/front.png" + }, + "sprites": "https://media.boxcritters.com/items/grad_robe/sprites.png" + }, + { + "itemId": "cardboard_sword_gold", + "name": "Golden Cardboard Sword", + "cost": 100, + "slot": "hand", + "theme": "fantasy", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/cardboard_sword_gold/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/cardboard_sword_gold/front.png" + }, + "sprites": "https://media.boxcritters.com/items/cardboard_sword_gold/sprites.png" + }, + { + "itemId": "cardboard_sword_silver", + "name": "Silver Cardboard Sword", + "cost": 100, + "slot": "hand", + "theme": "fantasy", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/cardboard_sword_silver/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/cardboard_sword_silver/front.png" + }, + "sprites": "https://media.boxcritters.com/items/cardboard_sword_silver/sprites.png" + }, + { + "itemId": "ninja_black", + "name": "Black Ninja", + "cost": 200, + "slot": "body", + "theme": "ninja", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ninja_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ninja_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ninja_black/sprites.png" + }, + { + "itemId": "ninja_gi_gray", + "name": "Gray Ninja Gi", + "cost": 100, + "slot": "body", + "theme": "ninja", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ninja_gi_gray/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ninja_gi_gray/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ninja_gi_gray/sprites.png" + }, + { + "itemId": "ninja_orange", + "name": "Orange Ninja Trainer", + "cost": 200, + "slot": "body", + "theme": "ninja", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ninja_orange/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ninja_orange/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ninja_orange/sprites.png" + }, + { + "itemId": "ninja_gi_pink", + "name": "Pink Ninja Gi", + "cost": 100, + "slot": "body", + "theme": "ninja", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ninja_gi_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ninja_gi_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ninja_gi_pink/sprites.png" + }, + { + "itemId": "water_wings_blue", + "name": "Blue Water Wings", + "cost": 20, + "slot": "hand", + "theme": "sports", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/water_wings_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/water_wings_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/water_wings_blue/sprites.png" + }, + { + "itemId": "pie_purple", + "name": "Purple Pie", + "cost": 100, + "slot": "head", + "theme": "silly", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pie_purple/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pie_purple/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pie_purple/sprites.png" + }, + { + "itemId": "ninja_gi_red", + "name": "Red Ninja Gi", + "cost": 100, + "slot": "body", + "theme": "ninja", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ninja_gi_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ninja_gi_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ninja_gi_red/sprites.png" + }, + { + "itemId": "ninja_rogue_black", + "name": "Rogue Ninja Gi", + "cost": 100, + "slot": "body", + "theme": "ninja", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ninja_rogue_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ninja_rogue_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ninja_rogue_black/sprites.png" + }, + { + "itemId": "hachimaki_black", + "name": "Black Hachimaki", + "cost": 100, + "slot": "head", + "theme": "ninja", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hachimaki_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hachimaki_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hachimaki_black/sprites.png" + }, + { + "itemId": "ninja_hood_pink", + "name": "Pink Ninja Hood", + "cost": 100, + "slot": "head", + "theme": "ninja", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ninja_hood_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ninja_hood_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ninja_hood_pink/sprites.png" + }, + { + "itemId": "ninja_hood_gray", + "name": "Gray Ninja Hood", + "cost": 100, + "slot": "head", + "theme": "ninja", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ninja_hood_gray/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ninja_hood_gray/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ninja_hood_gray/sprites.png" + }, + { + "itemId": "ninja", + "name": "Fullbody Ninja", + "cost": 100, + "slot": "body", + "theme": "ninja", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ninja/icon.png", + "bits": { "front": "https://media.boxcritters.com/items/ninja/front.png" }, + "sprites": "https://media.boxcritters.com/items/ninja/sprites.png" + }, + { + "itemId": "mermaid_blue", + "name": "Mermaid Body Blue", + "cost": 100, + "slot": "body", + "theme": "fantasy", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/mermaid_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/mermaid_blue/front.png", + "back": "https://media.boxcritters.com/items/mermaid_blue/back.png" + }, + "sprites": "https://media.boxcritters.com/items/mermaid_blue/sprites.png" + }, + { + "itemId": "mermaid_pink", + "name": "Mermaid Body Pink", + "cost": 100, + "slot": "body", + "theme": "fantasy", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/mermaid_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/mermaid_pink/front.png", + "back": "https://media.boxcritters.com/items/mermaid_pink/back.png" + }, + "sprites": "https://media.boxcritters.com/items/mermaid_pink/sprites.png" + }, + { + "itemId": "mermaid_black", + "name": "Mermaid Body Black", + "cost": 100, + "slot": "body", + "theme": "fantasy", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/mermaid_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/mermaid_black/front.png", + "back": "https://media.boxcritters.com/items/mermaid_black/back.png" + }, + "sprites": "https://media.boxcritters.com/items/mermaid_black/sprites.png" + }, + { + "itemId": "mermaid_hair_yellow", + "name": "Mermaid Hair Yellow", + "cost": 100, + "slot": "head", + "theme": "fantasy", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/mermaid_hair_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/mermaid_hair_yellow/front.png", + "back": "https://media.boxcritters.com/items/mermaid_hair_yellow/back.png" + }, + "sprites": "https://media.boxcritters.com/items/mermaid_hair_yellow/sprites.png" + }, + { + "itemId": "mermaid_hair_blue", + "name": "Mermaid Hair Blue", + "cost": 100, + "slot": "head", + "theme": "fantasy", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/mermaid_hair_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/mermaid_hair_blue/front.png", + "back": "https://media.boxcritters.com/items/mermaid_hair_blue/back.png" + }, + "sprites": "https://media.boxcritters.com/items/mermaid_hair_blue/sprites.png" + }, + { + "itemId": "mermaid_hair_red", + "name": "Mermaid Hair Red", + "cost": 100, + "slot": "head", + "theme": "fantasy", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/mermaid_hair_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/mermaid_hair_red/front.png", + "back": "https://media.boxcritters.com/items/mermaid_hair_red/back.png" + }, + "sprites": "https://media.boxcritters.com/items/mermaid_hair_red/sprites.png" + }, + { + "itemId": "mermaid_hair_pink", + "name": "Mermaid Hair Pink", + "cost": 20, + "slot": "head", + "theme": "fantasy", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/mermaid_hair_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/mermaid_hair_pink/front.png", + "back": "https://media.boxcritters.com/items/mermaid_hair_pink/back.png" + }, + "sprites": "https://media.boxcritters.com/items/mermaid_hair_pink/sprites.png" + }, + { + "itemId": "mermaid_hair_black", + "name": "Mermaid Hair Black", + "cost": 100, + "slot": "head", + "theme": "fantasy", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/mermaid_hair_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/mermaid_hair_black/front.png", + "back": "https://media.boxcritters.com/items/mermaid_hair_black/back.png" + }, + "sprites": "https://media.boxcritters.com/items/mermaid_hair_black/sprites.png" + }, + { + "itemId": "lashes_black", + "name": "Black Eyelashes", + "cost": 100, + "slot": "fuzz", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/lashes_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/lashes_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/lashes_black/sprites.png" + }, + { + "itemId": "pirate_parrot", + "name": "Red Pirate Parrot", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pirate_parrot/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pirate_parrot/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pirate_parrot/sprites.png" + }, + { + "itemId": "robot_head", + "name": "Robot Head", + "cost": 150, + "slot": "head", + "theme": "space", + "hideEars": true, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/robot_head/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/robot_head/front.png" + }, + "sprites": "https://media.boxcritters.com/items/robot_head/sprites.png" + }, + { + "itemId": "robot_body", + "name": "Robot Body", + "cost": 100, + "slot": "body", + "theme": "space", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/robot_body/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/robot_body/front.png" + }, + "sprites": "https://media.boxcritters.com/items/robot_body/sprites.png" + }, + { + "itemId": "sun_green", + "name": "Green Rectangle Sunglasses", + "cost": 20, + "slot": "eyes", + "theme": "summer", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/sun_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/sun_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/sun_green/sprites.png" + }, + { + "itemId": "trunks_yellow", + "name": "Neon Yellow Swimming Trunks", + "cost": 20, + "slot": "body", + "theme": "summer", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/trunks_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/trunks_yellow/front.png" + }, + "sprites": "https://media.boxcritters.com/items/trunks_yellow/sprites.png" + }, + { + "itemId": "swimsuit_blue", + "name": "Blue Swimsuit", + "cost": 20, + "slot": "body", + "theme": "summer", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/swimsuit_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/swimsuit_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/swimsuit_blue/sprites.png" + }, + { + "itemId": "trunks_red", + "name": "Red/Orange Wave Swimming Trunks", + "cost": 20, + "slot": "body", + "theme": "summer", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/trunks_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/trunks_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/trunks_red/sprites.png" + }, + { + "itemId": "trunks_blue", + "name": "Neon Blue Swimming Trunks", + "cost": 20, + "slot": "body", + "theme": "summer", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/trunks_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/trunks_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/trunks_blue/sprites.png" + }, + { + "itemId": "trunks_green", + "name": "Neon Green Swimming Trunks", + "cost": 20, + "slot": "body", + "theme": "summer", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/trunks_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/trunks_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/trunks_green/sprites.png" + }, + { + "itemId": "trunks_purple", + "name": "Neon Purple Swimming Trunks", + "cost": 20, + "slot": "body", + "theme": "summer", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/trunks_purple/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/trunks_purple/front.png" + }, + "sprites": "https://media.boxcritters.com/items/trunks_purple/sprites.png" + }, + { + "itemId": "lifeguard_trunks", + "name": "Red Lifeguard Swimming Trunks", + "cost": 100, + "slot": "body", + "theme": "summer", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/lifeguard_trunks/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/lifeguard_trunks/front.png" + }, + "sprites": "https://media.boxcritters.com/items/lifeguard_trunks/sprites.png" + }, + { + "itemId": "trunks_teal", + "name": "Blue White Teal Swimming Trunks", + "cost": 20, + "slot": "body", + "theme": "summer", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/trunks_teal/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/trunks_teal/front.png" + }, + "sprites": "https://media.boxcritters.com/items/trunks_teal/sprites.png" + }, + { + "itemId": "trunks_black", + "name": "Black Swimming Trunks", + "cost": 20, + "slot": "body", + "theme": "summer", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/trunks_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/trunks_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/trunks_black/sprites.png" + }, + { + "itemId": "lifeguard_suit", + "name": "Red Lifeguard Swimsuit", + "cost": 100, + "slot": "body", + "theme": "summer", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/lifeguard_suit/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/lifeguard_suit/front.png" + }, + "sprites": "https://media.boxcritters.com/items/lifeguard_suit/sprites.png" + }, + { + "itemId": "swimsuit_pink", + "name": "Pink Swimsuit", + "cost": 20, + "slot": "body", + "theme": "summer", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/swimsuit_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/swimsuit_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/swimsuit_pink/sprites.png" + }, + { + "itemId": "swimsuit_black", + "name": "Black Swimsuit", + "cost": 20, + "slot": "body", + "theme": "summer", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/swimsuit_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/swimsuit_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/swimsuit_black/sprites.png" + }, + { + "itemId": "swimsuit_white", + "name": "White Swimsuit", + "cost": 20, + "slot": "body", + "theme": "summer", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/swimsuit_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/swimsuit_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/swimsuit_white/sprites.png" + }, + { + "itemId": "swimsuit_green", + "name": "Neon Green Swimsuit", + "cost": 100, + "slot": "body", + "theme": "summer", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/swimsuit_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/swimsuit_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/swimsuit_green/sprites.png" + }, + { + "itemId": "swimsuit_yellow", + "name": "Neon Yellow Swimsuit", + "cost": 20, + "slot": "body", + "theme": "summer", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/swimsuit_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/swimsuit_yellow/front.png" + }, + "sprites": "https://media.boxcritters.com/items/swimsuit_yellow/sprites.png" + }, + { + "itemId": "swimsuit_purple", + "name": "Neon Purple Swimsuit", + "cost": 20, + "slot": "body", + "theme": "summer", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/swimsuit_purple/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/swimsuit_purple/front.png" + }, + "sprites": "https://media.boxcritters.com/items/swimsuit_purple/sprites.png" + }, + { + "itemId": "porkpie_grey", + "name": "Grey Porkpie Hat", + "cost": 20, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/porkpie_grey/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/porkpie_grey/front.png" + }, + "sprites": "https://media.boxcritters.com/items/porkpie_grey/sprites.png" + }, + { + "itemId": "porkpie_straw", + "name": "Straw Porkpie Hat", + "cost": 20, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/porkpie_straw/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/porkpie_straw/front.png" + }, + "sprites": "https://media.boxcritters.com/items/porkpie_straw/sprites.png" + }, + { + "itemId": "porkpie_black", + "name": "Black Porkpie Hat", + "cost": 20, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/porkpie_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/porkpie_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/porkpie_black/sprites.png" + }, + { + "itemId": "porkpie_pink", + "name": "Pink Porkpie Hat", + "cost": 20, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/porkpie_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/porkpie_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/porkpie_pink/sprites.png" + }, + { + "itemId": "straw_sun_hat", + "name": "Floppy Straw Sun Hat", + "cost": 40, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/straw_sun_hat/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/straw_sun_hat/front.png" + }, + "sprites": "https://media.boxcritters.com/items/straw_sun_hat/sprites.png" + }, + { + "itemId": "wooden_barrel", + "name": "Wooden Barrel", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/wooden_barrel/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/wooden_barrel/front.png" + }, + "sprites": "https://media.boxcritters.com/items/wooden_barrel/sprites.png" + }, + { + "itemId": "hero_cape_black", + "name": "Black Cape", + "cost": 50, + "slot": "neck", + "theme": "super", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hero_cape_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hero_cape_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hero_cape_black/sprites.png" + }, + { + "itemId": "hero_suit_black", + "name": "Black Super Suit", + "cost": 80, + "slot": "body", + "theme": "super", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hero_suit_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hero_suit_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hero_suit_black/sprites.png" + }, + { + "itemId": "hero_mask_black", + "name": "Black Comic Mask", + "cost": 20, + "slot": "mask", + "theme": "super", + "hideEars": true, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/hero_mask_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hero_mask_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hero_mask_black/sprites.png" + }, + { + "itemId": "hero_cape_blue", + "name": "Blue Cape", + "cost": 50, + "slot": "neck", + "theme": "super", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hero_cape_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hero_cape_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hero_cape_blue/sprites.png" + }, + { + "itemId": "hero_mask_blue", + "name": "Blue Comic Mask", + "cost": 20, + "slot": "mask", + "theme": "super", + "hideEars": true, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/hero_mask_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hero_mask_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hero_mask_blue/sprites.png" + }, + { + "itemId": "hero_suit_blue", + "name": "Blue Super Suit", + "cost": 80, + "slot": "body", + "theme": "super", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hero_suit_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hero_suit_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hero_suit_blue/sprites.png" + }, + { + "itemId": "hero_suit_pink", + "name": "Pink Super Suit", + "cost": 80, + "slot": "body", + "theme": "super", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hero_suit_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hero_suit_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hero_suit_pink/sprites.png" + }, + { + "itemId": "hero_mask_pink", + "name": "Pink Comic Mask", + "cost": 20, + "slot": "mask", + "theme": "super", + "hideEars": true, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/hero_mask_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hero_mask_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hero_mask_pink/sprites.png" + }, + { + "itemId": "hero_cape_pink", + "name": "Pink Cape", + "cost": 50, + "slot": "neck", + "theme": "super", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hero_cape_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hero_cape_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hero_cape_pink/sprites.png" + }, + { + "itemId": "space_shirt_red", + "name": "Red Space Shirt", + "cost": 50, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/space_shirt_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/space_shirt_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/space_shirt_red/sprites.png" + }, + { + "itemId": "box_helmet", + "name": "Box Helmet", + "cost": 20, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/box_helmet/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/box_helmet/front.png" + }, + "sprites": "https://media.boxcritters.com/items/box_helmet/sprites.png" + }, + { + "itemId": "ufo_green", + "name": "Green UFO", + "cost": 100, + "slot": "ride", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ufo_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ufo_green/front.png", + "back": "https://media.boxcritters.com/items/ufo_green/back.png" + }, + "sprites": "https://media.boxcritters.com/items/ufo_green/sprites.png" + }, + { + "itemId": "ufo_pink", + "name": "Pink UFO", + "cost": 100, + "slot": "ride", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ufo_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ufo_pink/front.png", + "back": "https://media.boxcritters.com/items/ufo_pink/back.png" + }, + "sprites": "https://media.boxcritters.com/items/ufo_pink/sprites.png" + }, + { + "itemId": "ufo_black", + "name": "Black UFO", + "cost": 100, + "slot": "ride", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ufo_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ufo_black/front.png", + "back": "https://media.boxcritters.com/items/ufo_black/back.png" + }, + "sprites": "https://media.boxcritters.com/items/ufo_black/sprites.png" + }, + { + "itemId": "ufo_white", + "name": "White UFO", + "cost": 100, + "slot": "ride", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ufo_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ufo_white/front.png", + "back": "https://media.boxcritters.com/items/ufo_white/back.png" + }, + "sprites": "https://media.boxcritters.com/items/ufo_white/sprites.png" + }, + { + "itemId": "ufo_grey", + "name": "Grey UFO", + "cost": 100, + "slot": "ride", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ufo_grey/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ufo_grey/front.png", + "back": "https://media.boxcritters.com/items/ufo_grey/back.png" + }, + "sprites": "https://media.boxcritters.com/items/ufo_grey/sprites.png" + }, + { + "itemId": "apron_green", + "name": "Green Bakery Apron", + "cost": 20, + "slot": "body", + "theme": "work", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/apron_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/apron_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/apron_green/sprites.png" + }, + { + "itemId": "space_suit", + "name": "NEW Space Suit", + "cost": 100, + "slot": "body", + "theme": "space", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/space_suit/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/space_suit/front.png" + }, + "sprites": "https://media.boxcritters.com/items/space_suit/sprites.png" + }, + { + "itemId": "space_helmet", + "name": "NEW Space Helmet", + "cost": 50, + "slot": "head", + "theme": "space", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/space_helmet/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/space_helmet/front.png" + }, + "sprites": "https://media.boxcritters.com/items/space_helmet/sprites.png" + }, + { + "itemId": "glasses_red", + "name": "Red Square Glasses", + "cost": 20, + "slot": "eyes", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/glasses_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/glasses_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/glasses_red/sprites.png" + }, + { + "itemId": "glasses_black", + "name": "Black Square Glasses", + "cost": 20, + "slot": "eyes", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/glasses_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/glasses_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/glasses_black/sprites.png" + }, + { + "itemId": "glasses_blue", + "name": "Blue Square Glasses", + "cost": 20, + "slot": "eyes", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/glasses_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/glasses_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/glasses_blue/sprites.png" + }, + { + "itemId": "glasses_brown", + "name": "Brown Square Glasses", + "cost": 20, + "slot": "eyes", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/glasses_brown/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/glasses_brown/front.png" + }, + "sprites": "https://media.boxcritters.com/items/glasses_brown/sprites.png" + }, + { + "itemId": "space_boots_white", + "name": "Space Boots", + "cost": 50, + "slot": "feet", + "theme": "space", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/space_boots_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/space_boots_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/space_boots_white/sprites.png" + }, + { + "itemId": "space_boots", + "name": "Dark Grey Space Boots", + "cost": 50, + "slot": "feet", + "theme": "space", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/space_boots/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/space_boots/front.png" + }, + "sprites": "https://media.boxcritters.com/items/space_boots/sprites.png" + }, + { + "itemId": "ringmaster_boots", + "name": "Black Ringmaster Boots", + "cost": 50, + "slot": "feet", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/ringmaster_boots/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/ringmaster_boots/front.png" + }, + "sprites": "https://media.boxcritters.com/items/ringmaster_boots/sprites.png" + }, + { + "itemId": "super_girl_suit", + "name": "Super Hero Girl", + "cost": 80, + "slot": "body", + "theme": "super", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/super_girl_suit/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/super_girl_suit/front.png" + }, + "sprites": "https://media.boxcritters.com/items/super_girl_suit/sprites.png" + }, + { + "itemId": "super_boy_suit", + "name": "Super Hero Boy", + "cost": 80, + "slot": "body", + "theme": "super", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/super_boy_suit/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/super_boy_suit/front.png" + }, + "sprites": "https://media.boxcritters.com/items/super_boy_suit/sprites.png" + }, + { + "itemId": "onsie_plaid_feet_red", + "name": "Red Plaid Onsie Feet", + "cost": 20, + "slot": "feet", + "theme": "plaid", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/onsie_plaid_feet_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/onsie_plaid_feet_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/onsie_plaid_feet_red/sprites.png" + }, + { + "itemId": "climb_rope_yellow", + "name": "Yellow Climbing Rope with Grappling Hook", + "cost": 20, + "slot": "belt", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/climb_rope_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/climb_rope_yellow/front.png" + }, + "sprites": "https://media.boxcritters.com/items/climb_rope_yellow/sprites.png" + }, + { + "itemId": "climb_rope_dark", + "name": "Dark Grey Climbing Rope with Grappling Hook", + "cost": 20, + "slot": "belt", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/climb_rope_dark/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/climb_rope_dark/front.png" + }, + "sprites": "https://media.boxcritters.com/items/climb_rope_dark/sprites.png" + }, + { + "itemId": "climb_rope_orange", + "name": "Orange Climbing Rope with Grappling Hook", + "cost": 20, + "slot": "belt", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/climb_rope_orange/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/climb_rope_orange/front.png" + }, + "sprites": "https://media.boxcritters.com/items/climb_rope_orange/sprites.png" + }, + { + "itemId": "climb_rope_green", + "name": "Green Climbing Rope with Grappling Hook", + "cost": 20, + "slot": "belt", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/climb_rope_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/climb_rope_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/climb_rope_green/sprites.png" + }, + { + "itemId": "climb_rope_blue", + "name": "Blue Climbing Rope with Grappling Hook", + "cost": 20, + "slot": "belt", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/climb_rope_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/climb_rope_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/climb_rope_blue/sprites.png" + }, + { + "itemId": "climb_rope_pink", + "name": "Pink Climbing Rope with Grappling Hook", + "cost": 20, + "slot": "belt", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/climb_rope_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/climb_rope_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/climb_rope_pink/sprites.png" + }, + { + "itemId": "climb_helmet_yellow", + "name": "Yellow Climbing Helmet", + "cost": 40, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/climb_helmet_yellow/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/climb_helmet_yellow/front.png" + }, + "sprites": "https://media.boxcritters.com/items/climb_helmet_yellow/sprites.png" + }, + { + "itemId": "climb_helmet_dark", + "name": " Dark Grey Climbing Helmet", + "cost": 40, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/climb_helmet_dark/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/climb_helmet_dark/front.png" + }, + "sprites": "https://media.boxcritters.com/items/climb_helmet_dark/sprites.png" + }, + { + "itemId": "climb_helmet_orange", + "name": "Orange Climbing Helmet", + "cost": 40, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/climb_helmet_orange/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/climb_helmet_orange/front.png" + }, + "sprites": "https://media.boxcritters.com/items/climb_helmet_orange/sprites.png" + }, + { + "itemId": "climb_helmet_green", + "name": "Green Climbing Helmet", + "cost": 40, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/climb_helmet_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/climb_helmet_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/climb_helmet_green/sprites.png" + }, + { + "itemId": "climb_helmet_blue", + "name": "Blue Climbing Helmet", + "cost": 40, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/climb_helmet_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/climb_helmet_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/climb_helmet_blue/sprites.png" + }, + { + "itemId": "climb_helmet_pink", + "name": "Pink Climbing Helmet", + "cost": 40, + "slot": "head", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/climb_helmet_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/climb_helmet_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/climb_helmet_pink/sprites.png" + }, + { + "itemId": "hazmat_suit", + "name": "Hazmat Suit", + "cost": 100, + "slot": "body", + "theme": "work", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hazmat_suit/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hazmat_suit/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hazmat_suit/sprites.png" + }, + { + "itemId": "hazmat_hood", + "name": "Hazmat Hood", + "cost": 100, + "slot": "head", + "theme": "work", + "hideEars": null, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/hazmat_hood/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hazmat_hood/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hazmat_hood/sprites.png" + }, + { + "itemId": "hazmat_boots", + "name": "Hazmat Boots", + "cost": 100, + "slot": "feet", + "theme": "work", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hazmat_boots/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hazmat_boots/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hazmat_boots/sprites.png" + }, + { + "itemId": "pantomime_face", + "name": "Pantomime Face", + "cost": 100, + "slot": "face", + "theme": "halloween", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pantomime_face/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pantomime_face/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pantomime_face/sprites.png" + }, + { + "itemId": "spider", + "name": "Spider Costume", + "cost": 100, + "slot": "body", + "theme": "halloween", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/spider/icon.png", + "bits": { "front": "https://media.boxcritters.com/items/spider/front.png" }, + "sprites": "https://media.boxcritters.com/items/spider/sprites.png" + }, + { + "itemId": "pantomime_suit", + "name": "Pantomime Suit", + "cost": 100, + "slot": "body", + "theme": "halloween", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pantomime_suit/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pantomime_suit/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pantomime_suit/sprites.png" + }, + { + "itemId": "pantomime_hat", + "name": "Pantomime Hat", + "cost": 100, + "slot": "head", + "theme": "halloween", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/pantomime_hat/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/pantomime_hat/front.png" + }, + "sprites": "https://media.boxcritters.com/items/pantomime_hat/sprites.png" + }, + { + "itemId": "witch_dress_white", + "name": "White Witch Dress", + "cost": 100, + "slot": "body", + "theme": "halloween", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/witch_dress_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/witch_dress_white/front.png" + }, + "sprites": "https://media.boxcritters.com/items/witch_dress_white/sprites.png" + }, + { + "itemId": "witch_hat_black", + "name": "Black Witch Hat with Red Hair", + "cost": 100, + "slot": "head", + "theme": "halloween", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/witch_hat_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/witch_hat_black/front.png", + "back": "https://media.boxcritters.com/items/witch_hat_black/back.png" + }, + "sprites": "https://media.boxcritters.com/items/witch_hat_black/sprites.png" + }, + { + "itemId": "witch_hat_burgundy", + "name": "Burgundy Witch Hat with Blue Hair", + "cost": 100, + "slot": "head", + "theme": "halloween", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/witch_hat_burgundy/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/witch_hat_burgundy/front.png", + "back": "https://media.boxcritters.com/items/witch_hat_burgundy/back.png" + }, + "sprites": "https://media.boxcritters.com/items/witch_hat_burgundy/sprites.png" + }, + { + "itemId": "witch_hat_white", + "name": "White Witch Hat with Pink Hair", + "cost": 100, + "slot": "head", + "theme": "halloween", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/witch_hat_white/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/witch_hat_white/front.png", + "back": "https://media.boxcritters.com/items/witch_hat_white/back.png" + }, + "sprites": "https://media.boxcritters.com/items/witch_hat_white/sprites.png" + }, + { + "itemId": "witch_dress_black", + "name": "Black Witch Dress", + "cost": 100, + "slot": "body", + "theme": "halloween", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/witch_dress_black/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/witch_dress_black/front.png" + }, + "sprites": "https://media.boxcritters.com/items/witch_dress_black/sprites.png" + }, + { + "itemId": "witch_dress_burgundy", + "name": "Burgundy Witch Dress", + "cost": 100, + "slot": "body", + "theme": "halloween", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/witch_dress_burgundy/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/witch_dress_burgundy/front.png" + }, + "sprites": "https://media.boxcritters.com/items/witch_dress_burgundy/sprites.png" + }, + { + "itemId": "knight_armour", + "name": "Knight Armor", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/knight_armour/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/knight_armour/front.png" + }, + "sprites": "https://media.boxcritters.com/items/knight_armour/sprites.png" + }, + { + "itemId": "robot_head_pink", + "name": "Pink Robot Head", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": true, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/robot_head_pink/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/robot_head_pink/front.png" + }, + "sprites": "https://media.boxcritters.com/items/robot_head_pink/sprites.png" + }, + { + "itemId": "chocolate_bar", + "name": "Chocolate Costume", + "cost": 100, + "slot": "body", + "theme": "", + "hideEars": true, + "hideNose": true, + "icon": "https://media.boxcritters.com/items/chocolate_bar/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/chocolate_bar/front.png" + }, + "sprites": "https://media.boxcritters.com/items/chocolate_bar/sprites.png" + }, + { + "itemId": "paint_green", + "name": "Green Face Paint with Warts", + "cost": 100, + "slot": "face", + "theme": "halloween", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/paint_green/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/paint_green/front.png" + }, + "sprites": "https://media.boxcritters.com/items/paint_green/sprites.png" + }, + { + "itemId": "wizard_blizzard", + "name": "Blizzard Wizard Hat", + "cost": 100, + "slot": "head", + "theme": "", + "hideEars": true, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/wizard_blizzard/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/wizard_blizzard/front.png", + "back": "https://media.boxcritters.com/items/wizard_blizzard/back.png" + }, + "sprites": "https://media.boxcritters.com/items/wizard_blizzard/sprites.png" + }, + { + "itemId": "knight_shield_blue", + "name": "Blue Shield", + "cost": 100, + "slot": "hand", + "theme": "fantasy", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/knight_shield_blue/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/knight_shield_blue/front.png" + }, + "sprites": "https://media.boxcritters.com/items/knight_shield_blue/sprites.png" + }, + { + "itemId": "hero_cape_red", + "name": "Red Super Cape", + "cost": 100, + "slot": "neck", + "theme": "super", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/hero_cape_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/hero_cape_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/hero_cape_red/sprites.png" + }, + { + "itemId": "knight_shield_red", + "name": "Red Shield", + "cost": 100, + "slot": "hand", + "theme": "fantasy", + "hideEars": null, + "hideNose": null, + "icon": "https://media.boxcritters.com/items/knight_shield_red/icon.png", + "bits": { + "front": "https://media.boxcritters.com/items/knight_shield_red/front.png" + }, + "sprites": "https://media.boxcritters.com/items/knight_shield_red/sprites.png" + } +] diff --git a/src/constants/items.ts b/src/constants/items.ts new file mode 100644 index 0000000..6e8f280 --- /dev/null +++ b/src/constants/items.ts @@ -0,0 +1,140 @@ +export const shop = { + lastItem: { itemId: "beard2_brown", cost: 20 }, + freeItem: { itemId: "goggles_pink", cost: 0 }, + nextItem: { itemId: "scout_uniform", cost: 0 }, + collection: [ + { itemId: "santa_hat", cost: 100 }, + ], +}; + +export const codes = { + rocketsnail: ["viking", "rocket_red"], + andybulletin: "propeller", + cute: "toque_pink", + oommgames: "space_red", + boxcritters3d: ["3d_white", "3d_black"], + goodnight: "sleeping", + madeincanada: "toque_white", + thekeeper: "party_green", + bunnyhug: "hoodie_blue", + greenplumber: "ballcap_green", + duckhunter: "float_pink", + piratepack: "pirate_patch", + pickle: "pickle", + oscarproductions: "guitar_blue", + livestream: "headphones_black", + creative: "headphones_black", + fun: "propeller_pink", + marco: "keytar_red", + snowball: "hoodie_white", + critbits: "ballcap_pink", + esporte: "kit_yellow", + squeeze: "hoodie_orange", + imagination: "box_brown", + sparkle: "propeller_silver", + adventure: "snorkel_blue", + tamago: "sun_square", + redcross: "australian_hat", + discordcritterspt: "headphones_green", + scarletraven: "wings_black", + boxcritterswiki: "paperhat_colour", + wikicritters: "brain_green", + boxcrittersguild: "cardboard_sword_silver", + staysafe: "doctor_mask_blue", + glitter: "pirate_capt_pink", +}; + +export const throwback = [ + "goggles_black", + "pot", + "sombrero_yellow", + "cone", + "toque_purple", + "sun_orange", + "pirate_capt_black", + "lifejacket_red", + "ballcap_black", + "super_cape_red", + "tshirt_white", + "lei_red", + "ballcap_blue", + "viking_blue", + "overalls_orange", + "bunny_blue", + "messenger_brown", + "plaid_black", + "tinfoil_hat", + "monk", + "pirate_hat_black", + "hawaii_orange", + "space_black", + "traffic_cone", + "grass_yellow", + "ushanka", + "bandana_purple", + "ski_suit_blue", + "hotdog", + "space_blue", + "sweater_orange", + "tactical_headset", + "ballcap_yellow", + "ringmaster_suit_red", + "flight_helmet_red", + "rainhat_yellow", + "raincoat_yellow", + "ballcap_red", + "ballerina_pink", + "hawaii_blue", + "stripe_red_white", + "grass_green", + "plaid_blue", + "toque_orange", + "school_pack_orange", + "pirate_crew_blue", + "ringmaster_hat_black", + "super_mask_black", + "pirate_hat_pink", + "rainhat_red", + "tophat_black", + "scarf_red", + "skeleton_body", + "dracula_cloak", + "pumpkin", + "hotdog", + "beard3_black", + "scarf_purple", + "puffy_red", + "blockhead", + "hoodie_purple", + "winter_dress_red", + "bulb_blue", + "tacky_red", + "pirate_bandana_red", +]; + +export const eventCodes = { + christmas2019: { + jinglebells: "elf_hat_green", + winter: "winter_dress", + joy: "bulb_yellow", + rudolph: "reindeer_head", + elf: "elf_suit_green", + cheer: "bulb_green", + glow: "bulb_red", + rednose: "reindeer_body", + blizzard: "wizard_blizzard", + family: "ornament_red", + shine: "angel_halo", + peace: "angel_wings", + jolly: "santa_beard", + merry: "santa_hat", + christmas: "santa_suit", + boxingday: "onsie_plaid_red", + warm: "sleeping_red", + tacky: "tacky_green", + snow: "goggles_white", + beautiful: "winter_dress_red", + newyear: "tuxedo_black", + "2020": "tophat_black", + }, +}; diff --git a/src/constants/parties.json b/src/constants/parties.json new file mode 100644 index 0000000..f6840ca --- /dev/null +++ b/src/constants/parties.json @@ -0,0 +1,50 @@ +{ + "default": { + "start": null, + "end": null + }, + "easter2019": { + "start": "04-18-2019", + "end": "04-28-2019" + }, + "halloween2019": { + "start": "10-20-2019", + "end": "11-06-2019" + }, + "christmas2019": { + "start": "12-05-2019", + "end": "01-05-2020" + }, + "lucky2020": { + "start": "03-11-2020", + "end": "04-01-2020" + }, + "easter2020": { + "start": "04-10-2020", + "end": "04-19-2020" + }, + "grad2020": { + "start": "06-03-2020", + "end": "06-20-2020" + }, + "summer2020": { + "start": "07-15-2020", + "end": "08-16-2020" + }, + "space": { + "start": "08-16-2020", + "end": "09-04-2020" + }, + "halloween2020": { + "start": "10-07-2020", + "end": "11-08-2020" + }, + "christmas2020": { + "start": "12-02-2020", + "end": "01-01-2021" + }, + "fools2021": { + "start": "03-30-2021", + "end": "04-02-2021" + } +} diff --git a/src/constants/world.ts b/src/constants/world.ts new file mode 100644 index 0000000..04aef3f --- /dev/null +++ b/src/constants/world.ts @@ -0,0 +1,91 @@ +import { PlayerCrumb, Room } from "@/types.ts"; +import { indexRoomData } from "@/utils.ts"; + +export const rooms: Record> = + await indexRoomData(); +export const spawnRoom = "tavern"; + +export const players: Record = { + "0": { + "i": "0", + "n": "Huggable", + "c": "huggable", + "x": 1670, + "y": 323, + "r": 180, + "g": [], + "m": "", + "e": "", + "_roomId": "crash_site", + }, +}; +export const queue: Array = []; + +export const roomExits = { + "cellar->tavern": { x: 360, y: 410, r: 0 }, + "crash_site->cellar": { x: 615, y: 400, r: 0 }, + "shack->port": { x: 550, y: 235, r: 0 }, + "jungle->port": { x: 650, y: 230, r: 0 }, + "snowman_village->tavern": { x: 563, y: 368, r: 0 }, +}; + +// deno-lint-ignore no-explicit-any +export const npcs: { [key: string]: any } = { + snowman_village: [ + { + "i": "NPC0", + "n": "Snow Girl", + "c": "snowgirl", + "x": 1289, + "y": 228, + "r": 180, + "g": [], + "m": "", + "e": "", + }, + { + "i": "NPC1", + "n": "Snow Patrol", + "c": "snow_patrol", + "x": 1644, + "y": 221, + "r": 180, + "g": [], + "m": "", + "e": "", + }, + { + "i": "NPC2", + "n": "Snow Greeter", + "c": "snow_greeter", + "x": 443, + "y": 317, + "r": 180, + "g": [], + "m": "", + "e": "", + }, + { + "i": "NPC3", + "n": "Snow Grandma", + "c": "snowgrandma", + "x": 1938, + "y": 251, + "r": 180, + "g": [], + "m": "", + "e": "", + }, + { + "i": "NPC4", + "n": "Snow Keeper", + "c": "snowkeeper", + "x": 893, + "y": 216, + "r": 180, + "g": [], + "m": "", + "e": "", + }, + ], +}; diff --git a/src/io.ts b/src/io.ts deleted file mode 100644 index 1749cc9..0000000 --- a/src/io.ts +++ /dev/null @@ -1,546 +0,0 @@ -// deno-lint-ignore-file no-explicit-any -import { Server } from "https://deno.land/x/socket_io@0.2.0/mod.ts"; -import { z } from "zod"; - -import * as world from "../constants/world.ts"; -import * as items from "../constants/items.ts"; -import * as utils from "../src/utils.ts"; -import { CritterId, LocalPlayer, PlayerCrumb, ShopData } from "../src/types.ts"; - -import parties from "../constants/parties.json" with { type: "json" }; -import itemsJSON from "../public/base/items.json" with { type: "json" }; - -export const io = new Server(); -io.on("connection", (socket) => { - let localPlayer: LocalPlayer; - - /** Condensed player data that is sufficient enough for other clients */ - let localCrumb: PlayerCrumb; - - // TODO: implement checking PlayFab API with ticket - socket.once("login", async (ticket: string) => { - if ( - z.object({ - ticket: z.string(), - }).safeParse({ ticket: ticket }).success == false - ) return; - - let playerData; - try { - playerData = await utils.verifyJWT(ticket); - } catch (_e) { - socket.disconnect(true); - return; - } - - // TODO: make this just an inline function instead of having an onPropertyChange function, I'm just really lazy right now lol -index - function onPropertyChange(property: string, value: any) { - utils.updateAccount(localPlayer.nickname, property, value); - } - - const createArrayHandler = (propertyName: string) => ({ - get(target: any, property: string) { - if (typeof target[property] === "function") { - return function (...args: any[]) { - const result = target[property].apply(target, args); - onPropertyChange(propertyName, target); - return result; - }; - } - return target[property]; - }, - }); - - const handler = { - set(target: any, property: string, value: any) { - if (Array.isArray(value)) { - target[property] = new Proxy(value, createArrayHandler(property)); - onPropertyChange(property, target[property]); - } else { - target[property] = value; - onPropertyChange(property, value); - } - return true; - }, - get(target: any, property: string) { - if (Array.isArray(target[property])) { - return new Proxy(target[property], createArrayHandler(property)); - } - return target[property]; - }, - }; - - //@ts-ignore: I will fix the type errors with using a different JWT library eventually - const sub = playerData as { - playerId: string; - nickname: string; - critterId: CritterId; - partyId: string; - persistent: boolean; - mods: Array; - }; - - if ([ - "today2019", - "today2020", - "today2021" - ].includes(sub.partyId)) { - console.log('target year:', parseInt(sub.partyId.replace('today', ''))); - sub.partyId = utils.getCurrentEvent(parseInt(sub.partyId.replace('today', ''))) - }; - - const persistentAccount = await utils.getAccount(sub.nickname); - if (!sub.persistent || persistentAccount.individual == null) { - localPlayer = { - playerId: sub.playerId, - nickname: sub.nickname, - critterId: sub.critterId, - ignore: [], - friends: [], - inventory: [], - gear: [], - eggs: [], - coins: 150, - isMember: false, - isGuest: false, - isTeam: false, - x: 0, - y: 0, - rotation: 0, - mutes: [], - - _partyId: sub.partyId, // This key is replaced down the line anyway - _mods: [], - }; - - if (sub.persistent) { - utils.createAccount(localPlayer); - localPlayer = new Proxy( - utils.expandAccount(localPlayer), - handler, - ); - } - } else { - persistentAccount.individual.critterId = sub.critterId || "hamster"; - persistentAccount.individual._partyId = sub.partyId || "default"; - persistentAccount.individual._mods = sub.mods || []; - - localPlayer = new Proxy( - utils.expandAccount(persistentAccount.individual), - handler, - ); - } - - localPlayer._partyId = socket.handshake.query.get("partyId") || "default"; - world.queue.splice(world.queue.indexOf(localPlayer.nickname), 1); - - localCrumb = utils.makeCrumb(localPlayer, world.spawnRoom); - socket.join(world.spawnRoom); - - world.players[localPlayer.playerId] = localCrumb; - socket.emit("login", { - player: localPlayer, - spawnRoom: world.spawnRoom, - }); - }); - - socket.on("joinRoom", (roomId: string) => { - if ( - z.object({ - roomId: z.enum(Object.keys(world.rooms) as any), - }).safeParse({ roomId: roomId }).success == false - ) return; - - const _room = (world.rooms[roomId] || { default: null }).default; - if (!_room) return; - - socket.leave(localCrumb._roomId); - socket.broadcast.in(localCrumb._roomId).emit("R", localCrumb); - - const modEnabled = (localPlayer._mods || []).includes("roomExits"); - //@ts-ignore: Index type is correct - const correctExit = world.roomExits[localCrumb._roomId + "->" + roomId]; - if (modEnabled && correctExit) { - localPlayer.x = correctExit.x; - localPlayer.y = correctExit.y; - localPlayer.rotation = correctExit.r; - } - - if (!modEnabled || !correctExit) { - localPlayer.x = _room.startX; - localPlayer.y = _room.startY; - localPlayer.rotation = _room.startR | 180; - } - - localCrumb = utils.makeCrumb(localPlayer, roomId); - world.players[localPlayer.playerId] = localCrumb; - - console.log("> " + localPlayer.nickname + ' joined "' + roomId + '"!'); - socket.join(roomId); - - let playerCrumbs = Object.values(world.players).filter((crumb) => - crumb._roomId == roomId - ); - if (world.npcs[roomId]) { - playerCrumbs = [ - ...playerCrumbs, - ...world.npcs[roomId], - ]; - } - socket.emit("joinRoom", { - name: _room.name, - roomId: roomId, - playerCrumbs: playerCrumbs, - }); - - socket.broadcast.in(localCrumb._roomId).emit("A", localCrumb); - }); - - socket.on("moveTo", (x: number, y: number) => { - const roomData = world.rooms[localCrumb._roomId][localPlayer._partyId] || - world.rooms[localCrumb._roomId].default; - if ( - z.object({ - x: z.number().min(0).max(roomData.width), - y: z.number().min(0).max(roomData.height), - }).safeParse({ x: x, y: y }).success == false - ) return; - - const newDirection = utils.getDirection(localPlayer.x, localPlayer.y, x, y); - - localPlayer.x = x; - localPlayer.y = y; - localPlayer.rotation = newDirection; - - localCrumb.x = x; - localCrumb.y = y; - localCrumb.r = newDirection; - - io.in(localCrumb._roomId).volatile.emit("X", { - i: localPlayer.playerId, - x: x, - y: y, - r: newDirection, - }); - }); - - socket.on("message", (text: string) => { - if ( - z.object({ - text: z.string().nonempty(), - }).safeParse({ text: text }).success == false - ) return; - - console.log(`> ${localPlayer.nickname} sent message:`, text); - localCrumb.m = text; - - socket.broadcast.in(localCrumb._roomId).emit("M", { - i: localPlayer.playerId, - m: text, - }); - - setTimeout(() => { - if (localCrumb.m != text) return; - localCrumb.m = ""; - }, 5e3); - }); - - socket.on("emote", (emote: string) => { - if ( - z.object({ - emote: z.string().nonempty(), // TODO: make this an enum - }).safeParse({ emote: emote }).success == false - ) return; - - console.log(`> ${localPlayer.nickname} sent emote:`, emote); - localCrumb.e = emote; - - socket.broadcast.in(localCrumb._roomId).emit("E", { - i: localPlayer.playerId, - e: emote, - }); - - setTimeout(() => { - if (localCrumb.e != emote) return; - localCrumb.e = ""; - }, 5e3); - }); - - // ? Options is specified just because sometimes it is sent, but its always an empty string - socket.on("code", (code: string, _options?: string) => { - if ( - z.object({ - command: z.enum([ - "pop", - "freeitem", - "tbt", - "darkmode", - "spydar", - "allitems", - ]), - }).safeParse({ - command: code, - }).success == false - ) return; - - console.log(`> ${localPlayer.nickname} sent code:`, code); - - const addItem = function (id: string, showGUI: boolean = false) { - if (!localPlayer.inventory.includes(id)) { - socket.emit("addItem", { itemId: id, showGUI: showGUI }); - localPlayer.inventory.push(id); - } - }; - - // Misc. Codes - switch (code) { - case "pop": { - socket.emit( - "pop", - Object.values(world.players).filter((critter) => - critter.c != "huggable" - ).length, - ); - break; - } - case "freeitem": { - addItem(items.shop.freeItem.itemId, true); - break; - } - case "tbt": { - const _throwbackItem = utils.getNewCodeItem( - localPlayer, - items.throwback, - ); - if (_throwbackItem) addItem(_throwbackItem, true); - break; - } - case "darkmode": { - addItem("3d_black", true); - break; - } - case "spydar": { - localPlayer.gear = [ - "sun_orange", - "super_mask_black", - "toque_blue", - "dracula_cloak", - "headphones_black", - "hoodie_black", - ]; - - if (localCrumb._roomId == "tavern") { - localPlayer.x = 216; - localPlayer.y = 118; - - localCrumb.x = 216; - localCrumb.y = 118; - - io.in(localCrumb._roomId).volatile.emit("X", { - i: localPlayer.playerId, - x: 216, - y: 118, - }); - } - - io.in(localCrumb._roomId).emit("G", { - i: localPlayer.playerId, - g: localPlayer.gear, - }); - - socket.emit("updateGear", localPlayer.gear); - break; - } - case "allitems": { - for (const item of itemsJSON) { - addItem(item.itemId, false); - } - break; - } - } - - // Item Codes - const _itemCodes = items.codes as Record>; - const item = _itemCodes[code]; - - if (typeof item == "string") { - addItem(item, true); - } else if (typeof item == "object") { - for (const _ of item) { - addItem(_, true); - } - } - - // Event Codes (eg. Christmas 2019) - const _eventItemCodes = items.eventCodes as Record< - string, - Record - >; - const eventItem = (_eventItemCodes[localPlayer._partyId] || {})[code]; - if (eventItem) addItem(eventItem); - }); - - socket.on("updateGear", (gear: Array) => { - if ( - z.object({ - gear: z.array(z.string().nonempty()).default([]), - }).strict().safeParse({ gear: gear }).success == false - ) return; - - const _gear = []; - for (const itemId of gear) { - if (localPlayer.inventory.includes(itemId)) { - _gear.push(itemId); - } - } - localPlayer.gear = _gear; - - io.in(localCrumb._roomId).emit("G", { - i: localPlayer.playerId, - g: localPlayer.gear, - }); - - socket.emit("updateGear", localPlayer.gear); - }); - - socket.on("getShop", () => { - const _shopItems = items.shop as unknown as ShopData; - socket.emit("getShop", { - lastItem: _shopItems.lastItem.itemId, - freeItem: _shopItems.freeItem.itemId, - nextItem: _shopItems.nextItem.itemId, - collection: _shopItems.collection.map((item) => item.itemId), - }); - }); - - socket.on("buyItem", (itemId: string) => { - if ( - z.object({ - itemId: z.string().nonempty(), - }).strict().safeParse({ itemId: itemId }).success == false - ) return; - - // ? Free item is excluded from this list because the game just sends the "/freeitem" code - const currentShop = items.shop; - const _shopItems = [ - currentShop.lastItem, - currentShop.nextItem, - ...currentShop.collection, - ]; - - const target = _shopItems.find((item) => item.itemId == itemId)!; - if (!target) { - console.log( - "> There is no item in this week's shop with itemId:", - itemId, - ); - return; - } - - if ( - localPlayer.coins >= target.cost && - !localPlayer.inventory.includes(itemId) - ) { - console.log( - "[+] Bought item: " + itemId + " for " + target.cost + " coins", - ); - localPlayer.coins -= target.cost; - localPlayer.inventory.push(itemId); - - socket.emit("buyItem", { itemId: itemId }); - socket.emit("updateCoins", { balance: localPlayer.coins }); - } - }); - - socket.on("trigger", async () => { - const activatedTrigger = await utils.getTrigger( - localPlayer, - localCrumb._roomId, - localPlayer._partyId, - ); - if (!activatedTrigger) return; - - if (activatedTrigger.hasItems) { - for (const item of activatedTrigger.hasItems) { - if (!localPlayer.inventory.includes(item)) return; - } - } - - if (activatedTrigger.grantItem) { - let items = activatedTrigger.grantItem; - if (typeof items == "string") items = [items]; - - for (const item of items) { - if (!localPlayer.inventory.includes(item)) { - socket.emit("addItem", { itemId: item, showGUI: true }); - localPlayer.inventory.push(item); - } - } - } - - if (activatedTrigger.addEgg) { - const egg = activatedTrigger.addEgg; - socket.emit("addEgg", egg); - localPlayer.eggs.push(egg); - } - }); - - socket.on("addIgnore", (playerId: string) => { - if ( - z.object({ - playerId: z.enum(Object.keys(world.players) as any), - }).strict().safeParse({ playerId: playerId }).success == false - ) return; - - if ( - Object.keys(world.players).includes(playerId) && - !localPlayer.ignore.includes(playerId) - ) { - localPlayer.ignore.push(playerId); - } - }); - - socket.on("attack", (playerId: string) => { - if ( - z.object({ - playerId: z.enum(Object.keys(world.players) as any), - }).strict().safeParse({ playerId: playerId }).success == false - ) return; - - if (!localPlayer.gear.includes("bb_beebee")) return; - const monster = Object.values(world.players).find((player) => - player.i == playerId && player.c == "huggable" - ); - - if (monster) { - io.in(localCrumb._roomId).emit("R", monster); - - localPlayer.coins += 10; - socket.emit("updateCoins", { balance: localPlayer.coins }); - - delete world.players[playerId]; - } - }); - - socket.on("switchParty", (partyId: string) => { - if ( - z.object({ - partyId: z.enum(Object.keys(parties) as any), - }).strict().safeParse({ partyId: partyId }).success == false - ) return; - - localPlayer._partyId = partyId; - socket.emit("switchParty"); - }); - - socket.on("beep", () => socket.emit("beep")); - - socket.on("disconnect", (reason) => { - if (reason == "server namespace disconnect") return; - - if (localPlayer && localCrumb) { - io.in(localCrumb._roomId).emit("R", localCrumb); - delete world.players[localPlayer.playerId]; - } - }); -}); diff --git a/src/main.ts b/src/main.ts index 20a7ca8..fa71958 100644 --- a/src/main.ts +++ b/src/main.ts @@ -8,12 +8,12 @@ import { } from "https://deno.land/std@0.224.0/path/mod.ts"; import { exists } from "jsr:@std/fs/exists"; -import { io } from "./io.ts"; -import * as world from "../constants/world.ts"; -import { getAccount } from "./utils.ts"; -import * as schemas from "./schema.ts"; -import * as utils from "./utils.ts"; -import parties from "../constants/parties.json" with { type: "json" }; +import { io } from "@/socket/index.ts"; +import * as world from "@/constants/world.ts"; +import { getAccount } from "@/utils.ts"; +import * as schemas from "@/schema.ts"; +import * as utils from "@/utils.ts"; +import parties from "@/constants/parties.json" with { type: "json" }; import { extname } from "https://deno.land/std@0.212.0/path/extname.ts"; import { parseArgs } from "jsr:@std/cli/parse-args"; @@ -33,6 +33,7 @@ if (!EXECUTABLE) { async function serveStatic(req: Request): Promise { const url = new URL(req.url); let pathname = url.pathname; + pathname = decodeURIComponent(pathname); pathname = pathname.endsWith("/") ? pathname + "index.html" : pathname; const fsPath = normalize(join(PUBLIC_DIR, pathname)); @@ -139,13 +140,17 @@ async function handler( let partyId = url.searchParams.get("partyId") || "default"; const debug = url.searchParams.has("debug"); - if ([ - "today2019", - "today2020", - "today2021" - ].includes(partyId)) { - partyId = utils.getCurrentEvent(parseInt(partyId.replace('today', ''))) - }; + if ( + [ + "today2019", + "today2020", + "today2021", + ].includes(partyId) + ) { + partyId = utils.getCurrentEvent( + parseInt(partyId.replace("today", "")), + ); + } if (!Object.keys(parties).includes(partyId)) { return Response.json({ @@ -219,14 +224,14 @@ async function handler( const args = parseArgs(Deno.args, { string: ["port"], default: { - port: "3257" - } + port: "3257", + }, }); if (isNaN(Number(args.port))) { - console.log('Port provided is not valid.') + console.log("Port provided is not valid."); Deno.exit(); -}; +} //@ts-ignore: Type issues occuring from upgrading websocket requests to Socket.io await serve(handler, { port: args.port }); diff --git a/src/schema.ts b/src/schema.ts index 549a34f..45f19bb 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -1,11 +1,17 @@ import { z } from "zod"; -import parties from "../constants/parties.json" with { type: "json" }; +import parties from "@/constants/parties.json" with { type: "json" }; /* LOGIN API */ export const login = z.object({ - nickname: z.string().nonempty().max(25), + nickname: z.string() + .transform((s) => s.trim()) + .pipe( + z.string() + .min(3, "The nickname must be at least 3 characters long.") + .max(25, "The nickname must be less than 25 characters long."), + ), critterId: z.enum([ "hamster", "beaver", @@ -18,12 +24,13 @@ export const login = z.object({ "snowgirl", "snow_patrol", "snowgrandma", + "alpha_hamster", ]).default("hamster"), partyId: z.enum([ ...Object.keys(parties) as [string, ...string[]], "today2019", "today2020", - "today2021" + "today2021", ]).default("default"), persistent: z.boolean().default(false), mods: z.array(z.enum(["roomExits"])).default([]), diff --git a/src/socket/handlers/connection.ts b/src/socket/handlers/connection.ts new file mode 100644 index 0000000..a7d51f2 --- /dev/null +++ b/src/socket/handlers/connection.ts @@ -0,0 +1,155 @@ +// deno-lint-ignore-file no-explicit-any +import { Server, Socket } from "https://deno.land/x/socket_io@0.2.0/mod.ts"; +import z from "zod"; + +import * as world from "@/constants/world.ts"; +import * as utils from "@/utils.ts"; +import * as types from "@/types.ts"; + +export function listen( + io: Server, + socket: Socket, + ctx: types.SocketHandlerContext, +) { + socket.once("login", async (ticket: string) => { + if ( + z.object({ + ticket: z.string(), + }).safeParse({ ticket: ticket }).success == false + ) return; + + let playerData; + try { + playerData = await utils.verifyJWT(ticket); + } catch (_e) { + socket.disconnect(true); + return; + } + + // TODO: make this just an inline function instead of having an onPropertyChange function, I'm just really lazy right now lol -index + function onPropertyChange(property: string, value: any) { + utils.updateAccount(ctx.localPlayer!.nickname, property, value); + } + + const createArrayHandler = (propertyName: string) => ({ + get(target: any, property: string) { + if (typeof target[property] === "function") { + return function (...args: any[]) { + const result = target[property].apply(target, args); + onPropertyChange(propertyName, target); + return result; + }; + } + return target[property]; + }, + }); + + const handler = { + set(target: any, property: string, value: any) { + if (Array.isArray(value)) { + target[property] = new Proxy(value, createArrayHandler(property)); + onPropertyChange(property, target[property]); + } else { + target[property] = value; + onPropertyChange(property, value); + } + return true; + }, + get(target: any, property: string) { + if (Array.isArray(target[property])) { + return new Proxy(target[property], createArrayHandler(property)); + } + return target[property]; + }, + }; + + //@ts-ignore: I will fix the type errors with using a different JWT library eventually + const sub = playerData as { + playerId: string; + nickname: string; + critterId: types.CritterId; + partyId: string; + persistent: boolean; + mods: Array; + }; + + if ( + [ + "today2019", + "today2020", + "today2021", + ].includes(sub.partyId) + ) { + console.log("target year:", parseInt(sub.partyId.replace("today", ""))); + sub.partyId = utils.getCurrentEvent( + parseInt(sub.partyId.replace("today", "")), + ); + } + + const persistentAccount = await utils.getAccount(sub.nickname); + if (!sub.persistent || persistentAccount.individual == null) { + ctx.localPlayer = { + playerId: sub.playerId, + nickname: sub.nickname, + critterId: sub.critterId, + ignore: [], + friends: [], + inventory: [], + gear: [], + eggs: [], + coins: 150, + isMember: false, + isGuest: false, + isTeam: false, + x: 0, + y: 0, + rotation: 0, + mutes: [], + + _partyId: sub.partyId, // This key is replaced down the line anyway + _mods: sub.mods, + }; + + if (sub.persistent) { + utils.createAccount(ctx.localPlayer); + ctx.localPlayer = new Proxy( + utils.expandAccount(ctx.localPlayer), + handler, + ); + } + } else { + persistentAccount.individual.critterId = sub.critterId || "hamster"; + persistentAccount.individual._partyId = sub.partyId || "default"; + persistentAccount.individual._mods = sub.mods || []; + + ctx.localPlayer = new Proxy( + utils.expandAccount(persistentAccount.individual), + handler, + ); + } + + ctx.localPlayer._partyId = socket.handshake.query.get("partyId") || + "default"; + world.queue.splice(world.queue.indexOf(ctx.localPlayer.nickname), 1); + + ctx.localCrumb = utils.makeCrumb(ctx.localPlayer, world.spawnRoom); + socket.join(world.spawnRoom); + + world.players[ctx.localPlayer.playerId] = ctx.localCrumb; + socket.emit("login", { + player: ctx.localPlayer, + spawnRoom: world.spawnRoom, + }); + }); + + socket.on("beep", () => socket.emit("beep")); + + socket.on("disconnect", (reason) => { + if (reason == "server namespace disconnect") return; + + if (ctx.localPlayer && ctx.localCrumb) { + io.in(ctx.localCrumb._roomId).emit("R", ctx.localCrumb); + delete world.players[ctx.localPlayer.playerId]; + } + }); +} diff --git a/src/socket/handlers/economy.ts b/src/socket/handlers/economy.ts new file mode 100644 index 0000000..aa8a793 --- /dev/null +++ b/src/socket/handlers/economy.ts @@ -0,0 +1,62 @@ +import { Server, Socket } from "https://deno.land/x/socket_io@0.2.0/mod.ts"; +import z from "zod"; + +import * as items from "@/constants/items.ts"; +import * as types from "@/types.ts"; + +export function listen( + _io: Server, + socket: Socket, + ctx: types.SocketHandlerContext, +) { + socket.on("getShop", () => { + const _shopItems = items.shop as unknown as types.ShopData; + socket.emit("getShop", { + lastItem: _shopItems.lastItem.itemId, + freeItem: _shopItems.freeItem.itemId, + nextItem: _shopItems.nextItem.itemId, + collection: _shopItems.collection.map((item) => item.itemId), + }); + }); + + socket.on("buyItem", (itemId: string) => { + if (!ctx.localPlayer || !ctx.localCrumb) return; + + if ( + z.object({ + itemId: z.string().nonempty(), + }).strict().safeParse({ itemId: itemId }).success == false + ) return; + + // ? Free item is excluded from this list because the game just sends the "/freeitem" code + const currentShop = items.shop; + const _shopItems = [ + currentShop.lastItem, + currentShop.nextItem, + ...currentShop.collection, + ]; + + const target = _shopItems.find((item) => item.itemId == itemId)!; + if (!target) { + console.log( + "> There is no item in this week's shop with itemId:", + itemId, + ); + return; + } + + if ( + ctx.localPlayer.coins >= target.cost && + !ctx.localPlayer.inventory.includes(itemId) + ) { + console.log( + "[+] Bought item: " + itemId + " for " + target.cost + " coins", + ); + ctx.localPlayer.coins -= target.cost; + ctx.localPlayer.inventory.push(itemId); + + socket.emit("buyItem", { itemId: itemId }); + socket.emit("updateCoins", { balance: ctx.localPlayer.coins }); + } + }); +} diff --git a/src/socket/handlers/player.ts b/src/socket/handlers/player.ts new file mode 100644 index 0000000..91619b4 --- /dev/null +++ b/src/socket/handlers/player.ts @@ -0,0 +1,73 @@ +import { Server, Socket } from "https://deno.land/x/socket_io@0.2.0/mod.ts"; +import z from "zod"; + +import * as world from "@/constants/world.ts"; +import * as utils from "@/utils.ts"; +import * as types from "@/types.ts"; + +export function listen( + io: Server, + socket: Socket, + ctx: types.SocketHandlerContext, +) { + socket.on("moveTo", (x: number, y: number) => { + if (!ctx.localPlayer || !ctx.localCrumb) return; + + const roomData = + world.rooms[ctx.localCrumb._roomId][ctx.localPlayer._partyId] || + world.rooms[ctx.localCrumb._roomId].default; + if ( + z.object({ + x: z.number().min(0).max(roomData.width), + y: z.number().min(0).max(roomData.height), + }).safeParse({ x: x, y: y }).success == false + ) return; + + const newDirection = utils.getDirection( + ctx.localPlayer.x, + ctx.localPlayer.y, + x, + y, + ); + + ctx.localPlayer.x = x; + ctx.localPlayer.y = y; + ctx.localPlayer.rotation = newDirection; + + ctx.localCrumb.x = x; + ctx.localCrumb.y = y; + ctx.localCrumb.r = newDirection; + + io.in(ctx.localCrumb._roomId).volatile.emit("X", { + i: ctx.localPlayer.playerId, + x: x, + y: y, + r: newDirection, + }); + }); + + socket.on("updateGear", (gear: Array) => { + if (!ctx.localPlayer || !ctx.localCrumb) return; + + if ( + z.object({ + gear: z.array(z.string().nonempty()).default([]), + }).strict().safeParse({ gear: gear }).success == false + ) return; + + const _gear = []; + for (const itemId of gear) { + if (ctx.localPlayer.inventory.includes(itemId)) { + _gear.push(itemId); + } + } + ctx.localPlayer.gear = _gear; + + io.in(ctx.localCrumb._roomId).emit("G", { + i: ctx.localPlayer.playerId, + g: ctx.localPlayer.gear, + }); + + socket.emit("updateGear", ctx.localPlayer.gear); + }); +} diff --git a/src/socket/handlers/social.ts b/src/socket/handlers/social.ts new file mode 100644 index 0000000..3eadc77 --- /dev/null +++ b/src/socket/handlers/social.ts @@ -0,0 +1,219 @@ +// deno-lint-ignore-file no-explicit-any +import { Server, Socket } from "https://deno.land/x/socket_io@0.2.0/mod.ts"; +import z from "zod"; + +import * as world from "@/constants/world.ts"; +import * as items from "@/constants/items.ts"; +import * as utils from "@/utils.ts"; +import * as types from "@/types.ts"; + +import itemsJSON from "@/constants/items.json" with { type: "json" }; + +export function listen( + io: Server, + socket: Socket, + ctx: types.SocketHandlerContext, +) { + socket.on("message", (text: string) => { + if (!ctx.localPlayer || !ctx.localCrumb) return; + + if ( + z.object({ + text: z.string().nonempty(), + }).safeParse({ text: text }).success == false + ) return; + + console.log(`> ${ctx.localPlayer.nickname} sent message:`, text); + ctx.localCrumb.m = text; + + socket.broadcast.in(ctx.localCrumb._roomId).emit("M", { + i: ctx.localPlayer.playerId, + m: text, + }); + + setTimeout(() => { + if (ctx.localCrumb!.m != text) return; + ctx.localCrumb!.m = ""; + }, 5e3); + }); + + socket.on("emote", (emote: string) => { + if (!ctx.localPlayer || !ctx.localCrumb) return; + + if ( + z.object({ + emote: z.string().nonempty(), // TODO: make this an enum + }).safeParse({ emote: emote }).success == false + ) return; + + console.log(`> ${ctx.localPlayer.nickname} sent emote:`, emote); + ctx.localCrumb.e = emote; + + socket.broadcast.in(ctx.localCrumb._roomId).emit("E", { + i: ctx.localPlayer.playerId, + e: emote, + }); + + setTimeout(() => { + if (ctx.localCrumb!.e != emote) return; + ctx.localCrumb!.e = ""; + }, 5e3); + }); + + // ? Options is specified just because sometimes it is sent, but its always an empty string + socket.on("code", (code: string, _options?: string) => { + if (!ctx.localPlayer || !ctx.localCrumb) return; + + if ( + z.object({ + command: z.enum([ + "pop", + "freeitem", + "tbt", + "darkmode", + "spydar", + "allitems", + ]), + }).safeParse({ + command: code, + }).success == false + ) return; + + console.log(`> ${ctx.localPlayer.nickname} sent code:`, code); + + const addItem = function (id: string, showGUI: boolean = false) { + if (!ctx.localPlayer!.inventory.includes(id)) { + socket.emit("addItem", { itemId: id, showGUI: showGUI }); + ctx.localPlayer!.inventory.push(id); + } + }; + + // Misc. Codes + switch (code) { + case "pop": { + socket.emit( + "pop", + Object.values(world.players).filter((critter) => + critter.c != "huggable" + ).length, + ); + break; + } + case "freeitem": { + addItem(items.shop.freeItem.itemId, true); + break; + } + case "tbt": { + const _throwbackItem = utils.getNewCodeItem( + ctx.localPlayer, + items.throwback, + ); + if (_throwbackItem) addItem(_throwbackItem, true); + break; + } + case "darkmode": { + addItem("3d_black", true); + break; + } + case "spydar": { + ctx.localPlayer.gear = [ + "sun_orange", + "super_mask_black", + "toque_blue", + "dracula_cloak", + "headphones_black", + "hoodie_black", + ]; + + if (ctx.localCrumb._roomId == "tavern") { + ctx.localPlayer.x = 216; + ctx.localPlayer.y = 118; + + ctx.localCrumb.x = 216; + ctx.localCrumb.y = 118; + + io.in(ctx.localCrumb._roomId).volatile.emit("X", { + i: ctx.localPlayer.playerId, + x: 216, + y: 118, + }); + } + + io.in(ctx.localCrumb._roomId).emit("G", { + i: ctx.localPlayer.playerId, + g: ctx.localPlayer.gear, + }); + + socket.emit("updateGear", ctx.localPlayer.gear); + break; + } + case "allitems": { + for (const item of itemsJSON) { + addItem(item.itemId, false); + } + break; + } + } + + // Item Codes + const _itemCodes = items.codes as Record>; + const item = _itemCodes[code]; + + if (typeof item == "string") { + addItem(item, true); + } else if (typeof item == "object") { + for (const _ of item) { + addItem(_, true); + } + } + + // Event Codes (eg. Christmas 2019) + const _eventItemCodes = items.eventCodes as Record< + string, + Record + >; + const eventItem = (_eventItemCodes[ctx.localPlayer._partyId] || {})[code]; + if (eventItem) addItem(eventItem); + }); + + socket.on("addIgnore", (playerId: string) => { + if (!ctx.localPlayer || !ctx.localCrumb) return; + + if ( + z.object({ + playerId: z.enum(Object.keys(world.players) as any), + }).strict().safeParse({ playerId: playerId }).success == false + ) return; + + if ( + Object.keys(world.players).includes(playerId) && + !ctx.localPlayer.ignore.includes(playerId) + ) { + ctx.localPlayer.ignore.push(playerId); + } + }); + + socket.on("attack", (playerId: string) => { + if (!ctx.localPlayer || !ctx.localCrumb) return; + + if ( + z.object({ + playerId: z.enum(Object.keys(world.players) as any), + }).strict().safeParse({ playerId: playerId }).success == false + ) return; + + if (!ctx.localPlayer.gear.includes("bb_beebee")) return; + const monster = Object.values(world.players).find((player) => + player.i == playerId && player.c == "huggable" + ); + + if (monster) { + io.in(ctx.localCrumb._roomId).emit("R", monster); + + ctx.localPlayer.coins += 10; + socket.emit("updateCoins", { balance: ctx.localPlayer.coins }); + + delete world.players[playerId]; + } + }); +} diff --git a/src/socket/handlers/world.ts b/src/socket/handlers/world.ts new file mode 100644 index 0000000..dcb5d81 --- /dev/null +++ b/src/socket/handlers/world.ts @@ -0,0 +1,116 @@ +import { Server, Socket } from "https://deno.land/x/socket_io@0.2.0/mod.ts"; +import z from "zod"; + +import * as world from "@/constants/world.ts"; +import * as utils from "@/utils.ts"; +import * as types from "@/types.ts"; + +import parties from "@/constants/parties.json" with { type: "json" }; + +export function listen( + _io: Server, + socket: Socket, + ctx: types.SocketHandlerContext, +) { + socket.on("joinRoom", (roomId: string) => { + if (!ctx.localPlayer || !ctx.localCrumb) return; + + if ( + z.object({ + roomId: z.enum(Object.keys(world.rooms) as [string, ...string[]]), + }).safeParse({ roomId: roomId }).success == false + ) return; + + const _room = (world.rooms[roomId] || { default: null }).default; + if (!_room) return; + + socket.leave(ctx.localCrumb._roomId); + socket.broadcast.in(ctx.localCrumb._roomId).emit("R", ctx.localCrumb); + + const modEnabled = (ctx.localPlayer._mods || []).includes("roomExits"); + //@ts-ignore: Index type is correct + const correctExit = world.roomExits[ctx.localCrumb._roomId + "->" + roomId]; + if (modEnabled && correctExit) { + ctx.localPlayer.x = correctExit.x; + ctx.localPlayer.y = correctExit.y; + ctx.localPlayer.rotation = correctExit.r; + } + + if (!modEnabled || !correctExit) { + ctx.localPlayer.x = _room.startX; + ctx.localPlayer.y = _room.startY; + ctx.localPlayer.rotation = _room.startR | 180; + } + + ctx.localCrumb = utils.makeCrumb(ctx.localPlayer, roomId); + world.players[ctx.localPlayer.playerId] = ctx.localCrumb; + + console.log("> " + ctx.localPlayer.nickname + ' joined "' + roomId + '"!'); + socket.join(roomId); + + let playerCrumbs = Object.values(world.players).filter((crumb) => + crumb._roomId == roomId + ); + if (world.npcs[roomId]) { + playerCrumbs = [ + ...playerCrumbs, + ...world.npcs[roomId], + ]; + } + socket.emit("joinRoom", { + name: _room.name, + roomId: roomId, + playerCrumbs: playerCrumbs, + }); + + socket.broadcast.in(ctx.localCrumb._roomId).emit("A", ctx.localCrumb); + }); + + socket.on("switchParty", (partyId: string) => { + if (!ctx.localPlayer || !ctx.localCrumb) return; + + if ( + z.object({ + partyId: z.enum(Object.keys(parties) as [string, ...string[]]), + }).strict().safeParse({ partyId: partyId }).success == false + ) return; + + ctx.localPlayer._partyId = partyId; + socket.emit("switchParty"); + }); + + socket.on("trigger", async () => { + if (!ctx.localPlayer || !ctx.localCrumb) return; + + const activatedTrigger = await utils.getTrigger( + ctx.localPlayer, + ctx.localCrumb._roomId, + ctx.localPlayer._partyId, + ); + if (!activatedTrigger) return; + + if (activatedTrigger.hasItems) { + for (const item of activatedTrigger.hasItems) { + if (!ctx.localPlayer.inventory.includes(item)) return; + } + } + + if (activatedTrigger.grantItem) { + let items = activatedTrigger.grantItem; + if (typeof items == "string") items = [items]; + + for (const item of items) { + if (!ctx.localPlayer.inventory.includes(item)) { + socket.emit("addItem", { itemId: item, showGUI: true }); + ctx.localPlayer.inventory.push(item); + } + } + } + + if (activatedTrigger.addEgg) { + const egg = activatedTrigger.addEgg; + socket.emit("addEgg", egg); + ctx.localPlayer.eggs.push(egg); + } + }); +} diff --git a/src/socket/index.ts b/src/socket/index.ts new file mode 100644 index 0000000..abad212 --- /dev/null +++ b/src/socket/index.ts @@ -0,0 +1,22 @@ +import { Server } from "https://deno.land/x/socket_io@0.2.0/mod.ts"; + +import * as connection from "./handlers/connection.ts"; +import * as player from "./handlers/player.ts"; +import * as world from "./handlers/world.ts"; +import * as social from "./handlers/social.ts"; +import * as economy from "./handlers/economy.ts"; + +export const io = new Server(); + +io.on("connection", (socket) => { + const context = { + localPlayer: null, + localCrumb: null, + }; + + connection.listen(io, socket, context); + player.listen(io, socket, context); + world.listen(io, socket, context); + social.listen(io, socket, context); + economy.listen(io, socket, context); +}); diff --git a/src/types.ts b/src/types.ts index a7e78ac..1196acd 100644 --- a/src/types.ts +++ b/src/types.ts @@ -96,45 +96,14 @@ export type ShopData = { collection: Array<{ itemId: string; cost: number }>; }; -/* - Socket.io -*/ -export interface ServerToClientEvents { - login: () => { player: LocalPlayer }; - updateGear: () => { i: number; g: Array }; - updateCoins: () => { balance: number }; - addItem: () => { itemId: string }; - addEgg: () => string; - A: () => PlayerCrumb; - R: () => PlayerCrumb; - X: () => { i: number; x: number; y: number }; - M: () => { i: number; m: string }; - E: () => { i: number; e: string }; - G: () => { i: number; g: Array }; -} - -export interface ClientToServerEvents { - login: (ticket: string) => void; - joinLobby: () => unknown; // Unsure what this is for, I don't think the game had several servers - joinRoom: ( - roomId: string, - ) => { name: string; roomId: string; playerCrumbs: Array }; - message: (text: string) => void; - emote: (emote: string) => void; - code: (code: string, options?: string) => void; - addIgnore: (id: number) => void; - addFriend: (id: number) => void; - moveTo: (x: number, y: number) => void; - updateCritter: () => unknown; // Unsure of what this is, maybe settings? - updateGear: (gear: Array) => void; - getShop: () => ShopData; - buyItem: (itemId: string) => void; - trigger: () => void; -} - export type PartySchedule = { [key: string]: { start: string | null; end: string | null; }; }; + +export type SocketHandlerContext = { + localPlayer: null | LocalPlayer; + localCrumb: null | PlayerCrumb; +}; diff --git a/src/utils.ts b/src/utils.ts index e78ab2c..b8bff31 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -6,9 +6,9 @@ import { } from "https://deno.land/std@0.224.0/path/mod.ts"; import { jwtVerify, SignJWT } from "npm:jose@5.9.6"; -import { rooms, spawnRoom } from "../constants/world.ts"; -import { LocalPlayer, PlayerCrumb, Room } from "./types.ts"; -import parties from "../constants/parties.json" with { type: "json" }; +import { rooms, spawnRoom } from "@/constants/world.ts"; +import { LocalPlayer, PlayerCrumb, Room } from "@/types.ts"; +import parties from "@/constants/parties.json" with { type: "json" }; const EXECUTABLE = Deno.env.get("EXECUTABLE") == "true"; const BASE_DIR = EXECUTABLE @@ -183,7 +183,7 @@ export async function updateAccount( property: string, value: unknown, ) { - if (["x", "y", "rotation", "_partyId"].includes(property)) return; + if (["x", "y", "rotation", "_partyId", "_mods"].includes(property)) return; const accounts = await getAccount(nickname); accounts.individual[property] = value; @@ -245,12 +245,16 @@ export function getCurrentEvent(year: number): string { const originalStart = new Date(start); const originalEnd = new Date(end); - const adjustedStart = new Date(year, originalStart.getMonth(), originalStart.getDate()); + const adjustedStart = new Date( + year, + originalStart.getMonth(), + originalStart.getDate(), + ); const adjustedEnd = new Date( // Handle roll over originalEnd.getFullYear() > originalStart.getFullYear() ? year + 1 : year, originalEnd.getMonth(), - originalEnd.getDate() + originalEnd.getDate(), ); if (testDate >= adjustedStart && testDate <= adjustedEnd) { @@ -259,4 +263,4 @@ export function getCurrentEvent(year: number): string { } return "default"; -} \ No newline at end of file +}