From 21b87b6dcf8decc0aacd823bea7bcb22472187dc Mon Sep 17 00:00:00 2001 From: Toontown Super <108632596+ToontownSuperForeverMVP@users.noreply.github.com> Date: Sun, 2 Aug 2026 16:42:34 -0400 Subject: [PATCH] Widescreen & data: apply widescreen GUI fixes, add spellbook config and building data, unified win32 launcher --- .gitignore | 14 +- README.md | 4 +- config/spellbook.json | 13 + data/401000001_1100_buildings.json | 173 ++++++++ data/401000001_1200_buildings.json | 230 ++++++++++ data/401000001_1300_buildings.json | 245 +++++++++++ data/401000001_2100_buildings.json | 371 +++++++++++++++++ data/401000001_2200_buildings.json | 254 ++++++++++++ data/401000001_2300_buildings.json | 191 +++++++++ data/401000001_3100_buildings.json | 335 +++++++++++++++ data/401000001_3200_buildings.json | 281 +++++++++++++ data/401000001_3300_buildings.json | 218 ++++++++++ data/401000001_4100_buildings.json | 362 ++++++++++++++++ data/401000001_4200_buildings.json | 281 +++++++++++++ data/401000001_4300_buildings.json | 326 +++++++++++++++ data/401000001_5100_buildings.json | 218 ++++++++++ data/401000001_5200_buildings.json | 218 ++++++++++ data/401000001_5300_buildings.json | 155 +++++++ data/401000001_9100_buildings.json | 299 +++++++++++++ data/401000001_9200_buildings.json | 299 +++++++++++++ otp/otpbase/OTPTimer.py | 20 +- toontown/battle/DistributedBattleBldg.py | 4 +- toontown/building/DistributedBuilding.py | 4 +- .../cogdominium/DistributedCogdoInterior.py | 2 +- toontown/golf/GolfScoreBoard.py | 8 +- toontown/login/AvatarChooser.py | 9 +- toontown/makeatoon/BodyShop.py | 3 +- toontown/makeatoon/ClothesGUI.py | 3 +- toontown/makeatoon/ColorShop.py | 3 +- toontown/minigame/DistributedDivingGame.py | 10 +- toontown/minigame/DistributedPatternGame.py | 4 +- toontown/minigame/DistributedRingGame.py | 4 +- toontown/minigame/DistributedTargetGame.py | 10 +- toontown/minigame/DistributedTugOfWarGame.py | 4 +- toontown/minigame/Purchase.py | 2 +- .../DistributedPartyTrampolineActivity.py | 13 +- toontown/quest/QuestMap.py | 6 +- toontown/quest/QuestParser.py | 4 +- toontown/racing/DistributedStartingBlock.py | 4 +- toontown/racing/DistributedVehicle.py | 4 +- toontown/racing/RaceEndPanels.py | 2 +- toontown/racing/RaceGUI.py | 13 +- toontown/safezone/DistributedCheckers.py | 12 +- .../safezone/DistributedChineseCheckers.py | 12 +- toontown/safezone/DistributedFindFour.py | 12 +- toontown/settings/Settings.py | 8 + toontown/shtiker/OptionsPage.py | 35 +- toontown/shtiker/ShtikerBook.py | 40 +- toontown/spellbook/MagicWordConfig.py | 17 + toontown/toonbase/ToonBase.py | 65 ++- toontown/toonbase/ToontownStart.py | 20 +- toontown/toontowngui/LoadingAssetPreview.py | 7 +- toontown/toontowngui/ToontownLoadingScreen.py | 19 + win32/launcher.py | 392 ++++++++++++++++++ win32/old/startall.bat | 18 +- win32/startall.bat | 11 + 56 files changed, 5178 insertions(+), 113 deletions(-) create mode 100644 config/spellbook.json create mode 100644 data/401000001_1100_buildings.json create mode 100644 data/401000001_1200_buildings.json create mode 100644 data/401000001_1300_buildings.json create mode 100644 data/401000001_2100_buildings.json create mode 100644 data/401000001_2200_buildings.json create mode 100644 data/401000001_2300_buildings.json create mode 100644 data/401000001_3100_buildings.json create mode 100644 data/401000001_3200_buildings.json create mode 100644 data/401000001_3300_buildings.json create mode 100644 data/401000001_4100_buildings.json create mode 100644 data/401000001_4200_buildings.json create mode 100644 data/401000001_4300_buildings.json create mode 100644 data/401000001_5100_buildings.json create mode 100644 data/401000001_5200_buildings.json create mode 100644 data/401000001_5300_buildings.json create mode 100644 data/401000001_9100_buildings.json create mode 100644 data/401000001_9200_buildings.json create mode 100644 win32/launcher.py create mode 100644 win32/startall.bat diff --git a/.gitignore b/.gitignore index 3d0673a..c243db8 100644 --- a/.gitignore +++ b/.gitignore @@ -69,4 +69,16 @@ htmlcov/ *.tar.bz2 *.tar.xz *.tar.zst -``` \ No newline at end of file + +# Gemini / Agent documentation +GEMINI.md + +``` + +# Local environment / large assets (not part of the repo) +Panda3D/ +resources/ +errorCode +useropt.json +toontown/launcher/useropt.json +astron/databases/accounts.json diff --git a/README.md b/README.md index 7e47063..5462838 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -Disclaimer and Disclosure: This is a joke source. Take nothing you see here seriously, any changes, additions, or new content is jokingly fabricated to make Toontown a very, very silly game. Yes, AI was used to create this, as the original goal of this source was to "outslop" Toontown: Frontlines. - # TOONTOWN SUPER PRESENTS: TOONTOWN THE BEST!!! ## THIS IS THE BEST EVER TOONTOWN, NEVER ANY OTHER WIN @@ -9,7 +7,7 @@ Disclaimer and Disclosure: This is a joke source. Take nothing you see here seri - THE BEST BUTTONS - MORE BEST COME TO!!!!!!!!! -SOON TO HAVE NEW SHADOW NEW CRANE NEW STREET NEW NEW NEW ENW ENW ! 1111!11 +- tbh its really just a challenge to see if i can outslop toontown frontlines lol this source is just a joke # Open Toontown This repository contains the code for Open Toontown, based on the latest version of Disney's Toontown Online (sv1.0.47.38). diff --git a/config/spellbook.json b/config/spellbook.json new file mode 100644 index 0000000..4d15f58 --- /dev/null +++ b/config/spellbook.json @@ -0,0 +1,13 @@ +{ + "words": + [ + { + "name": "SetPos", + "access": "MODERATOR" + }, + { + "name": "GetPos", + "access": "MODERATOR" + } + ] +} diff --git a/data/401000001_1100_buildings.json b/data/401000001_1100_buildings.json new file mode 100644 index 0000000..06682b9 --- /dev/null +++ b/data/401000001_1100_buildings.json @@ -0,0 +1,173 @@ +{ + "2": { + "state": "toon", + "block": "2", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "4": { + "state": "suit", + "block": "4", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407038.1934795 + }, + "6": { + "state": "suit", + "block": "6", + "track": "c", + "difficulty": "2", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776411273.1159532 + }, + "8": { + "state": "toon", + "block": "8", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "9": { + "state": "cogdo", + "block": "9", + "track": "s", + "difficulty": "4", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407111.0249455 + }, + "12": { + "state": "suit", + "block": "12", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407036.3265915 + }, + "13": { + "state": "toon", + "block": "13", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "14": { + "state": "toon", + "block": "14", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "15": { + "state": "cogdo", + "block": "15", + "track": "s", + "difficulty": "4", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776411789.2534516 + }, + "16": { + "state": "toon", + "block": "16", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "17": { + "state": "cogdo", + "block": "17", + "track": "s", + "difficulty": "4", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776401079.7629383 + }, + "19": { + "state": "toon", + "block": "19", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "20": { + "state": "toon", + "block": "20", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "21": { + "state": "cogdo", + "block": "21", + "track": "s", + "difficulty": "4", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407973.1377637 + }, + "22": { + "state": "toon", + "block": "22", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "24": { + "state": "toon", + "block": "24", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "26": { + "state": "cogdo", + "block": "26", + "track": "s", + "difficulty": "4", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407160.0253901 + }, + "27": { + "state": "suit", + "block": "27", + "track": "c", + "difficulty": "2", + "numFloors": "2", + "savedBy": [], + "becameSuitTime": 1776406998.899616 + }, + "28": { + "state": "suit", + "block": "28", + "track": "c", + "difficulty": "2", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 1776401125.6067028 + } +} \ No newline at end of file diff --git a/data/401000001_1200_buildings.json b/data/401000001_1200_buildings.json new file mode 100644 index 0000000..e5e8cb4 --- /dev/null +++ b/data/401000001_1200_buildings.json @@ -0,0 +1,230 @@ +{ + "1": { + "state": "toon", + "block": "1", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "3": { + "state": "toon", + "block": "3", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "5": { + "state": "cogdo", + "block": "5", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776406999.1331465 + }, + "6": { + "state": "suit", + "block": "6", + "track": "m", + "difficulty": "4", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 1776411250.1738942 + }, + "7": { + "state": "toon", + "block": "7", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "9": { + "state": "toon", + "block": "9", + "track": "m", + "difficulty": "3", + "numFloors": "2", + "savedBy": [], + "becameSuitTime": 0 + }, + "10": { + "state": "toon", + "block": "10", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "11": { + "state": "toon", + "block": "11", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "12": { + "state": "suit", + "block": "12", + "track": "m", + "difficulty": "5", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 1776660454.1140993 + }, + "13": { + "state": "toon", + "block": "13", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "14": { + "state": "cogdo", + "block": "14", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407135.1193488 + }, + "16": { + "state": "cogdo", + "block": "16", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776411867.88171 + }, + "17": { + "state": "toon", + "block": "17", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "18": { + "state": "suit", + "block": "18", + "track": "m", + "difficulty": "5", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 1776652099.9874463 + }, + "19": { + "state": "toon", + "block": "19", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "20": { + "state": "suit", + "block": "20", + "track": "m", + "difficulty": "3", + "numFloors": "2", + "savedBy": [], + "becameSuitTime": 1776594873.9986186 + }, + "21": { + "state": "toon", + "block": "21", + "track": "m", + "difficulty": "3", + "numFloors": "2", + "savedBy": [ + [ + 100000001, + "King Mizzenbumper", + [ + "rls", + "ms", + "s", + "m", + 9, + 0, + 9, + 9, + 0, + 7, + 0, + 7, + 1, + 13 + ] + ] + ], + "becameSuitTime": 0 + }, + "23": { + "state": "toon", + "block": "23", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "24": { + "state": "cogdo", + "block": "24", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776400957.0131931 + }, + "25": { + "state": "cogdo", + "block": "25", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776401001.45201 + }, + "26": { + "state": "cogdo", + "block": "26", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407803.0513244 + }, + "27": { + "state": "toon", + "block": "27", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "28": { + "state": "suit", + "block": "28", + "track": "m", + "difficulty": "4", + "numFloors": "2", + "savedBy": [], + "becameSuitTime": 1776407981.5209658 + } +} \ No newline at end of file diff --git a/data/401000001_1300_buildings.json b/data/401000001_1300_buildings.json new file mode 100644 index 0000000..2ffbcf6 --- /dev/null +++ b/data/401000001_1300_buildings.json @@ -0,0 +1,245 @@ +{ + "2": { + "state": "toon", + "block": "2", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "4": { + "state": "cogdo", + "block": "4", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776401038.3655844 + }, + "5": { + "state": "toon", + "block": "5", + "track": "l", + "difficulty": "4", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 0 + }, + "6": { + "state": "cogdo", + "block": "6", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407016.2131588 + }, + "7": { + "state": "toon", + "block": "7", + "track": "s", + "difficulty": "4", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 0 + }, + "8": { + "state": "cogdo", + "block": "8", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776410206.508166 + }, + "9": { + "state": "cogdo", + "block": "9", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407013.2574003 + }, + "10": { + "state": "toon", + "block": "10", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "11": { + "state": "toon", + "block": "11", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "13": { + "state": "toon", + "block": "13", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "14": { + "state": "suit", + "block": "14", + "track": "m", + "difficulty": "5", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 1776652362.155264 + }, + "15": { + "state": "cogdo", + "block": "15", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776401045.9829102 + }, + "18": { + "state": "suit", + "block": "18", + "track": "l", + "difficulty": "4", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 1776407046.3599896 + }, + "19": { + "state": "cogdo", + "block": "19", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776406043.3950603 + }, + "20": { + "state": "toon", + "block": "20", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "21": { + "state": "cogdo", + "block": "21", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776408564.8082345 + }, + "23": { + "state": "toon", + "block": "23", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "24": { + "state": "suit", + "block": "24", + "track": "l", + "difficulty": "2", + "numFloors": "2", + "savedBy": [], + "becameSuitTime": 1776667289.7308545 + }, + "25": { + "state": "suit", + "block": "25", + "track": "s", + "difficulty": "5", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 1776407146.2550125 + }, + "26": { + "state": "toon", + "block": "26", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "28": { + "state": "cogdo", + "block": "28", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776404327.7764344 + }, + "29": { + "state": "toon", + "block": "29", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "30": { + "state": "toon", + "block": "30", + "track": "c", + "difficulty": "2", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "31": { + "state": "toon", + "block": "31", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "32": { + "state": "toon", + "block": "32", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "33": { + "state": "toon", + "block": "33", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "34": { + "state": "suit", + "block": "34", + "track": "c", + "difficulty": "5", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 1776407005.3874943 + } +} \ No newline at end of file diff --git a/data/401000001_2100_buildings.json b/data/401000001_2100_buildings.json new file mode 100644 index 0000000..11e494d --- /dev/null +++ b/data/401000001_2100_buildings.json @@ -0,0 +1,371 @@ +{ + "1": { + "state": "toon", + "block": "1", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "2": { + "state": "toon", + "block": "2", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "3": { + "state": "toon", + "block": "3", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "4": { + "state": "toon", + "block": "4", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "6": { + "state": "toon", + "block": "6", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "7": { + "state": "toon", + "block": "7", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "10": { + "state": "toon", + "block": "10", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "11": { + "state": "toon", + "block": "11", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "16": { + "state": "toon", + "block": "16", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "17": { + "state": "suit", + "block": "17", + "track": "s", + "difficulty": "1", + "numFloors": "2", + "savedBy": [], + "becameSuitTime": 1776407168.7026908 + }, + "18": { + "state": "toon", + "block": "18", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "21": { + "state": "toon", + "block": "21", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "24": { + "state": "toon", + "block": "24", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "25": { + "state": "toon", + "block": "25", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "26": { + "state": "toon", + "block": "26", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "29": { + "state": "toon", + "block": "29", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "32": { + "state": "toon", + "block": "32", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "33": { + "state": "toon", + "block": "33", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "38": { + "state": "toon", + "block": "38", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "39": { + "state": "toon", + "block": "39", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "43": { + "state": "toon", + "block": "43", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "44": { + "state": "toon", + "block": "44", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "49": { + "state": "toon", + "block": "49", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "52": { + "state": "suit", + "block": "52", + "track": "m", + "difficulty": "2", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776401023.961993 + }, + "53": { + "state": "toon", + "block": "53", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "54": { + "state": "toon", + "block": "54", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "55": { + "state": "toon", + "block": "55", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "56": { + "state": "toon", + "block": "56", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "57": { + "state": "toon", + "block": "57", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "59": { + "state": "toon", + "block": "59", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "60": { + "state": "toon", + "block": "60", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "61": { + "state": "toon", + "block": "61", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "62": { + "state": "toon", + "block": "62", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "63": { + "state": "suit", + "block": "63", + "track": "l", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776401122.8183227 + }, + "64": { + "state": "toon", + "block": "64", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "65": { + "state": "toon", + "block": "65", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "66": { + "state": "toon", + "block": "66", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "67": { + "state": "toon", + "block": "67", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "69": { + "state": "toon", + "block": "69", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "70": { + "state": "toon", + "block": "70", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "5": { + "state": "toon", + "block": "5", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + } +} \ No newline at end of file diff --git a/data/401000001_2200_buildings.json b/data/401000001_2200_buildings.json new file mode 100644 index 0000000..e8465d7 --- /dev/null +++ b/data/401000001_2200_buildings.json @@ -0,0 +1,254 @@ +{ + "1": { + "state": "toon", + "block": "1", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "4": { + "state": "toon", + "block": "4", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "5": { + "state": "toon", + "block": "5", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "8": { + "state": "toon", + "block": "8", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "11": { + "state": "toon", + "block": "11", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "12": { + "state": "toon", + "block": "12", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "13": { + "state": "toon", + "block": "13", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "14": { + "state": "toon", + "block": "14", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "16": { + "state": "toon", + "block": "16", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "17": { + "state": "toon", + "block": "17", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "20": { + "state": "toon", + "block": "20", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "25": { + "state": "toon", + "block": "25", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "27": { + "state": "toon", + "block": "27", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "28": { + "state": "toon", + "block": "28", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "29": { + "state": "toon", + "block": "29", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "30": { + "state": "toon", + "block": "30", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "31": { + "state": "toon", + "block": "31", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "32": { + "state": "cogdo", + "block": "32", + "track": "s", + "difficulty": "3", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776406444.9440663 + }, + "33": { + "state": "toon", + "block": "33", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "34": { + "state": "toon", + "block": "34", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "35": { + "state": "toon", + "block": "35", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "39": { + "state": "toon", + "block": "39", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "40": { + "state": "toon", + "block": "40", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "41": { + "state": "toon", + "block": "41", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "43": { + "state": "toon", + "block": "43", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "44": { + "state": "toon", + "block": "44", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + }, + "47": { + "state": "cogdo", + "block": "47", + "track": "s", + "difficulty": "3", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776406479.6340756 + }, + "48": { + "state": "toon", + "block": "48", + "track": "c", + "difficulty": "1", + "numFloors": "0", + "savedBy": [], + "becameSuitTime": 0 + } +} \ No newline at end of file diff --git a/data/401000001_2300_buildings.json b/data/401000001_2300_buildings.json new file mode 100644 index 0000000..eff7049 --- /dev/null +++ b/data/401000001_2300_buildings.json @@ -0,0 +1,191 @@ +{ + "1": { + "state": "toon", + "block": "1", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "2": { + "state": "toon", + "block": "2", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "3": { + "state": "toon", + "block": "3", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "4": { + "state": "toon", + "block": "4", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "5": { + "state": "cogdo", + "block": "5", + "track": "s", + "difficulty": "3", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776411750.5660672 + }, + "9": { + "state": "toon", + "block": "9", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "14": { + "state": "cogdo", + "block": "14", + "track": "s", + "difficulty": "3", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776408741.9047232 + }, + "18": { + "state": "toon", + "block": "18", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "21": { + "state": "toon", + "block": "21", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "22": { + "state": "toon", + "block": "22", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "23": { + "state": "toon", + "block": "23", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "24": { + "state": "toon", + "block": "24", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "29": { + "state": "toon", + "block": "29", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "30": { + "state": "toon", + "block": "30", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "31": { + "state": "toon", + "block": "31", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "33": { + "state": "toon", + "block": "33", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "34": { + "state": "toon", + "block": "34", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "36": { + "state": "toon", + "block": "36", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "37": { + "state": "cogdo", + "block": "37", + "track": "s", + "difficulty": "3", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407401.1867948 + }, + "39": { + "state": "toon", + "block": "39", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "41": { + "state": "toon", + "block": "41", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + } +} \ No newline at end of file diff --git a/data/401000001_3100_buildings.json b/data/401000001_3100_buildings.json new file mode 100644 index 0000000..1781ee6 --- /dev/null +++ b/data/401000001_3100_buildings.json @@ -0,0 +1,335 @@ +{ + "1": { + "state": "toon", + "block": "1", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "2": { + "state": "suit", + "block": "2", + "track": "c", + "difficulty": "5", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 1776411796.159887 + }, + "5": { + "state": "toon", + "block": "5", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "7": { + "state": "toon", + "block": "7", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "8": { + "state": "toon", + "block": "8", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "10": { + "state": "toon", + "block": "10", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "11": { + "state": "toon", + "block": "11", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "12": { + "state": "toon", + "block": "12", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "13": { + "state": "toon", + "block": "13", + "track": "c", + "difficulty": "4", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 0 + }, + "14": { + "state": "cogdo", + "block": "14", + "track": "s", + "difficulty": "7", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776401101.6760328 + }, + "15": { + "state": "suit", + "block": "15", + "track": "c", + "difficulty": "4", + "numFloors": "2", + "savedBy": [], + "becameSuitTime": 1776407154.7029412 + }, + "17": { + "state": "toon", + "block": "17", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "18": { + "state": "suit", + "block": "18", + "track": "c", + "difficulty": "6", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 1776579966.965988 + }, + "20": { + "state": "toon", + "block": "20", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "21": { + "state": "toon", + "block": "21", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "22": { + "state": "suit", + "block": "22", + "track": "c", + "difficulty": "6", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 1776407090.1497698 + }, + "23": { + "state": "cogdo", + "block": "23", + "track": "s", + "difficulty": "7", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776410198.6535106 + }, + "24": { + "state": "toon", + "block": "24", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "25": { + "state": "toon", + "block": "25", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "27": { + "state": "toon", + "block": "27", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "29": { + "state": "toon", + "block": "29", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "30": { + "state": "toon", + "block": "30", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "34": { + "state": "toon", + "block": "34", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "35": { + "state": "toon", + "block": "35", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "36": { + "state": "toon", + "block": "36", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "37": { + "state": "suit", + "block": "37", + "track": "l", + "difficulty": "4", + "numFloors": "2", + "savedBy": [], + "becameSuitTime": 1776411803.1902273 + }, + "38": { + "state": "toon", + "block": "38", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "41": { + "state": "toon", + "block": "41", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "42": { + "state": "toon", + "block": "42", + "track": "c", + "difficulty": "6", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 0 + }, + "43": { + "state": "toon", + "block": "43", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "44": { + "state": "toon", + "block": "44", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "47": { + "state": "toon", + "block": "47", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "48": { + "state": "toon", + "block": "48", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "49": { + "state": "toon", + "block": "49", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "50": { + "state": "toon", + "block": "50", + "track": "c", + "difficulty": "6", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 0 + }, + "51": { + "state": "toon", + "block": "51", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "53": { + "state": "toon", + "block": "53", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + } +} \ No newline at end of file diff --git a/data/401000001_3200_buildings.json b/data/401000001_3200_buildings.json new file mode 100644 index 0000000..8064f18 --- /dev/null +++ b/data/401000001_3200_buildings.json @@ -0,0 +1,281 @@ +{ + "2": { + "state": "toon", + "block": "2", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "3": { + "state": "cogdo", + "block": "3", + "track": "s", + "difficulty": "7", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776406702.9646912 + }, + "5": { + "state": "cogdo", + "block": "5", + "track": "s", + "difficulty": "7", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776411790.0934026 + }, + "6": { + "state": "toon", + "block": "6", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "7": { + "state": "suit", + "block": "7", + "track": "c", + "difficulty": "5", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 1776408736.4910765 + }, + "8": { + "state": "toon", + "block": "8", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "10": { + "state": "suit", + "block": "10", + "track": "m", + "difficulty": "4", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 1776407099.108053 + }, + "11": { + "state": "toon", + "block": "11", + "track": "l", + "difficulty": "5", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 0 + }, + "12": { + "state": "toon", + "block": "12", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "13": { + "state": "toon", + "block": "13", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "15": { + "state": "toon", + "block": "15", + "track": "s", + "difficulty": "6", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 0 + }, + "16": { + "state": "toon", + "block": "16", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "17": { + "state": "toon", + "block": "17", + "track": "s", + "difficulty": "6", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 0 + }, + "18": { + "state": "cogdo", + "block": "18", + "track": "s", + "difficulty": "7", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776414118.6338015 + }, + "19": { + "state": "toon", + "block": "19", + "track": "m", + "difficulty": "4", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 0 + }, + "21": { + "state": "cogdo", + "block": "21", + "track": "s", + "difficulty": "7", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776410152.444562 + }, + "22": { + "state": "cogdo", + "block": "22", + "track": "s", + "difficulty": "7", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407813.2101953 + }, + "23": { + "state": "toon", + "block": "23", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "24": { + "state": "suit", + "block": "24", + "track": "s", + "difficulty": "6", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 1776411284.0836847 + }, + "25": { + "state": "suit", + "block": "25", + "track": "s", + "difficulty": "6", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 1776660303.1468217 + }, + "26": { + "state": "cogdo", + "block": "26", + "track": "s", + "difficulty": "7", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776400960.7453852 + }, + "28": { + "state": "toon", + "block": "28", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "29": { + "state": "toon", + "block": "29", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "30": { + "state": "toon", + "block": "30", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "31": { + "state": "toon", + "block": "31", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "32": { + "state": "toon", + "block": "32", + "track": "c", + "difficulty": "6", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 0 + }, + "34": { + "state": "cogdo", + "block": "34", + "track": "s", + "difficulty": "7", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776406724.7581935 + }, + "35": { + "state": "toon", + "block": "35", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "36": { + "state": "toon", + "block": "36", + "track": "s", + "difficulty": "4", + "numFloors": "2", + "savedBy": [], + "becameSuitTime": 0 + }, + "37": { + "state": "suit", + "block": "37", + "track": "l", + "difficulty": "6", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 1776581823.5394022 + }, + "38": { + "state": "toon", + "block": "38", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + } +} \ No newline at end of file diff --git a/data/401000001_3300_buildings.json b/data/401000001_3300_buildings.json new file mode 100644 index 0000000..b7ea5ce --- /dev/null +++ b/data/401000001_3300_buildings.json @@ -0,0 +1,218 @@ +{ + "6": { + "state": "suit", + "block": "6", + "track": "l", + "difficulty": "8", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 1776660975.4591558 + }, + "7": { + "state": "cogdo", + "block": "7", + "track": "s", + "difficulty": "9", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776410157.3457165 + }, + "8": { + "state": "toon", + "block": "8", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "9": { + "state": "cogdo", + "block": "9", + "track": "s", + "difficulty": "9", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776401060.8475585 + }, + "10": { + "state": "toon", + "block": "10", + "track": "m", + "difficulty": "6", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 0 + }, + "11": { + "state": "toon", + "block": "11", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "12": { + "state": "cogdo", + "block": "12", + "track": "s", + "difficulty": "9", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776400952.367675 + }, + "13": { + "state": "toon", + "block": "13", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "14": { + "state": "toon", + "block": "14", + "track": "l", + "difficulty": "6", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 0 + }, + "15": { + "state": "suit", + "block": "15", + "track": "l", + "difficulty": "7", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 1776410222.1726365 + }, + "16": { + "state": "cogdo", + "block": "16", + "track": "s", + "difficulty": "9", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776406707.3513057 + }, + "17": { + "state": "suit", + "block": "17", + "track": "s", + "difficulty": "6", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 1776667296.8419452 + }, + "18": { + "state": "cogdo", + "block": "18", + "track": "s", + "difficulty": "9", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407142.5207002 + }, + "19": { + "state": "cogdo", + "block": "19", + "track": "s", + "difficulty": "9", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776410218.3500104 + }, + "20": { + "state": "suit", + "block": "20", + "track": "l", + "difficulty": "7", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 1776651669.3624191 + }, + "21": { + "state": "toon", + "block": "21", + "track": "l", + "difficulty": "6", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 0 + }, + "23": { + "state": "suit", + "block": "23", + "track": "l", + "difficulty": "6", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 1776407391.901123 + }, + "24": { + "state": "toon", + "block": "24", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "25": { + "state": "toon", + "block": "25", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "26": { + "state": "cogdo", + "block": "26", + "track": "s", + "difficulty": "9", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407011.919608 + }, + "27": { + "state": "toon", + "block": "27", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "28": { + "state": "toon", + "block": "28", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "29": { + "state": "toon", + "block": "29", + "track": "l", + "difficulty": "6", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 0 + }, + "30": { + "state": "toon", + "block": "30", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + } +} \ No newline at end of file diff --git a/data/401000001_4100_buildings.json b/data/401000001_4100_buildings.json new file mode 100644 index 0000000..8e18ae5 --- /dev/null +++ b/data/401000001_4100_buildings.json @@ -0,0 +1,362 @@ +{ + "3": { + "state": "toon", + "block": "3", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "4": { + "state": "toon", + "block": "4", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "5": { + "state": "suit", + "block": "5", + "track": "s", + "difficulty": "3", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 1776410206.2747438 + }, + "6": { + "state": "toon", + "block": "6", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "7": { + "state": "toon", + "block": "7", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "9": { + "state": "cogdo", + "block": "9", + "track": "s", + "difficulty": "4", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776411448.3815963 + }, + "10": { + "state": "suit", + "block": "10", + "track": "m", + "difficulty": "2", + "numFloors": "2", + "savedBy": [], + "becameSuitTime": 1776666853.1069696 + }, + "11": { + "state": "toon", + "block": "11", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "12": { + "state": "toon", + "block": "12", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "14": { + "state": "cogdo", + "block": "14", + "track": "s", + "difficulty": "4", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776401142.6474926 + }, + "15": { + "state": "toon", + "block": "15", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "17": { + "state": "toon", + "block": "17", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "18": { + "state": "toon", + "block": "18", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "19": { + "state": "toon", + "block": "19", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "22": { + "state": "toon", + "block": "22", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "23": { + "state": "toon", + "block": "23", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "25": { + "state": "suit", + "block": "25", + "track": "s", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776411892.3356252 + }, + "26": { + "state": "toon", + "block": "26", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "28": { + "state": "toon", + "block": "28", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "29": { + "state": "toon", + "block": "29", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "30": { + "state": "toon", + "block": "30", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "31": { + "state": "toon", + "block": "31", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "32": { + "state": "toon", + "block": "32", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "35": { + "state": "cogdo", + "block": "35", + "track": "s", + "difficulty": "4", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407092.5744872 + }, + "37": { + "state": "toon", + "block": "37", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "38": { + "state": "toon", + "block": "38", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "39": { + "state": "toon", + "block": "39", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "41": { + "state": "toon", + "block": "41", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "42": { + "state": "toon", + "block": "42", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "45": { + "state": "toon", + "block": "45", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "46": { + "state": "suit", + "block": "46", + "track": "s", + "difficulty": "3", + "numFloors": "2", + "savedBy": [], + "becameSuitTime": 1776401087.8125484 + }, + "48": { + "state": "toon", + "block": "48", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "49": { + "state": "cogdo", + "block": "49", + "track": "s", + "difficulty": "4", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776411256.0677192 + }, + "52": { + "state": "toon", + "block": "52", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "53": { + "state": "toon", + "block": "53", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "54": { + "state": "toon", + "block": "54", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "55": { + "state": "suit", + "block": "55", + "track": "s", + "difficulty": "2", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776406521.9523387 + }, + "56": { + "state": "toon", + "block": "56", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "57": { + "state": "toon", + "block": "57", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "58": { + "state": "toon", + "block": "58", + "track": "m", + "difficulty": "3", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 0 + } +} \ No newline at end of file diff --git a/data/401000001_4200_buildings.json b/data/401000001_4200_buildings.json new file mode 100644 index 0000000..cae456e --- /dev/null +++ b/data/401000001_4200_buildings.json @@ -0,0 +1,281 @@ +{ + "1": { + "state": "toon", + "block": "1", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "2": { + "state": "toon", + "block": "2", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "3": { + "state": "suit", + "block": "3", + "track": "m", + "difficulty": "2", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407985.301502 + }, + "4": { + "state": "cogdo", + "block": "4", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407384.7930605 + }, + "5": { + "state": "toon", + "block": "5", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "7": { + "state": "toon", + "block": "7", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "9": { + "state": "cogdo", + "block": "9", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776401114.3302522 + }, + "10": { + "state": "toon", + "block": "10", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "12": { + "state": "toon", + "block": "12", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "13": { + "state": "toon", + "block": "13", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "16": { + "state": "toon", + "block": "16", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "17": { + "state": "toon", + "block": "17", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "18": { + "state": "toon", + "block": "18", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "19": { + "state": "toon", + "block": "19", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "20": { + "state": "suit", + "block": "20", + "track": "m", + "difficulty": "5", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 1776407072.3235095 + }, + "22": { + "state": "toon", + "block": "22", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "23": { + "state": "toon", + "block": "23", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "24": { + "state": "toon", + "block": "24", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "25": { + "state": "toon", + "block": "25", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "27": { + "state": "toon", + "block": "27", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "28": { + "state": "toon", + "block": "28", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "29": { + "state": "cogdo", + "block": "29", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776411983.3405118 + }, + "30": { + "state": "toon", + "block": "30", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "31": { + "state": "toon", + "block": "31", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "32": { + "state": "toon", + "block": "32", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "33": { + "state": "cogdo", + "block": "33", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776414220.6659482 + }, + "34": { + "state": "toon", + "block": "34", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "35": { + "state": "toon", + "block": "35", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "36": { + "state": "toon", + "block": "36", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "37": { + "state": "toon", + "block": "37", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "38": { + "state": "cogdo", + "block": "38", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407133.0194175 + } +} \ No newline at end of file diff --git a/data/401000001_4300_buildings.json b/data/401000001_4300_buildings.json new file mode 100644 index 0000000..90bd8c4 --- /dev/null +++ b/data/401000001_4300_buildings.json @@ -0,0 +1,326 @@ +{ + "1": { + "state": "toon", + "block": "1", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "3": { + "state": "toon", + "block": "3", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "4": { + "state": "toon", + "block": "4", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "7": { + "state": "toon", + "block": "7", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "9": { + "state": "suit", + "block": "9", + "track": "c", + "difficulty": "2", + "numFloors": "2", + "savedBy": [], + "becameSuitTime": 1776651926.282736 + }, + "12": { + "state": "toon", + "block": "12", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "17": { + "state": "toon", + "block": "17", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "19": { + "state": "toon", + "block": "19", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "20": { + "state": "toon", + "block": "20", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "21": { + "state": "toon", + "block": "21", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "27": { + "state": "toon", + "block": "27", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "28": { + "state": "toon", + "block": "28", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "29": { + "state": "toon", + "block": "29", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "35": { + "state": "toon", + "block": "35", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "36": { + "state": "toon", + "block": "36", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "38": { + "state": "toon", + "block": "38", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "40": { + "state": "toon", + "block": "40", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "41": { + "state": "cogdo", + "block": "41", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776406498.2564616 + }, + "42": { + "state": "toon", + "block": "42", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "43": { + "state": "toon", + "block": "43", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "44": { + "state": "toon", + "block": "44", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "45": { + "state": "toon", + "block": "45", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "48": { + "state": "suit", + "block": "48", + "track": "c", + "difficulty": "4", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 1776401097.2462523 + }, + "49": { + "state": "suit", + "block": "49", + "track": "l", + "difficulty": "2", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 1776407960.6767075 + }, + "50": { + "state": "suit", + "block": "50", + "track": "l", + "difficulty": "5", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 1776406470.5786207 + }, + "52": { + "state": "cogdo", + "block": "52", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776406533.7441206 + }, + "53": { + "state": "toon", + "block": "53", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "54": { + "state": "suit", + "block": "54", + "track": "c", + "difficulty": "3", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 1776579969.9569304 + }, + "55": { + "state": "toon", + "block": "55", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "56": { + "state": "toon", + "block": "56", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "62": { + "state": "toon", + "block": "62", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "67": { + "state": "toon", + "block": "67", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "68": { + "state": "toon", + "block": "68", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "70": { + "state": "toon", + "block": "70", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "71": { + "state": "toon", + "block": "71", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "72": { + "state": "toon", + "block": "72", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + } +} \ No newline at end of file diff --git a/data/401000001_5100_buildings.json b/data/401000001_5100_buildings.json new file mode 100644 index 0000000..515c5c7 --- /dev/null +++ b/data/401000001_5100_buildings.json @@ -0,0 +1,218 @@ +{ + "1": { + "state": "toon", + "block": "1", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "2": { + "state": "toon", + "block": "2", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "3": { + "state": "suit", + "block": "3", + "track": "l", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776400957.1380389 + }, + "4": { + "state": "suit", + "block": "4", + "track": "l", + "difficulty": "3", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 1776406699.2779305 + }, + "5": { + "state": "toon", + "block": "5", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "6": { + "state": "suit", + "block": "6", + "track": "m", + "difficulty": "3", + "numFloors": "2", + "savedBy": [], + "becameSuitTime": 1776410226.0914896 + }, + "7": { + "state": "cogdo", + "block": "7", + "track": "s", + "difficulty": "4", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776401091.9235585 + }, + "8": { + "state": "toon", + "block": "8", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "9": { + "state": "toon", + "block": "9", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "10": { + "state": "toon", + "block": "10", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "11": { + "state": "toon", + "block": "11", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "13": { + "state": "toon", + "block": "13", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "15": { + "state": "toon", + "block": "15", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "16": { + "state": "toon", + "block": "16", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "17": { + "state": "toon", + "block": "17", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "18": { + "state": "toon", + "block": "18", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "19": { + "state": "toon", + "block": "19", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "20": { + "state": "toon", + "block": "20", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "21": { + "state": "toon", + "block": "21", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "22": { + "state": "cogdo", + "block": "22", + "track": "s", + "difficulty": "4", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407045.753145 + }, + "23": { + "state": "toon", + "block": "23", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "24": { + "state": "suit", + "block": "24", + "track": "m", + "difficulty": "2", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776406495.7351432 + }, + "25": { + "state": "cogdo", + "block": "25", + "track": "s", + "difficulty": "4", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776406427.6263142 + }, + "26": { + "state": "toon", + "block": "26", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + } +} \ No newline at end of file diff --git a/data/401000001_5200_buildings.json b/data/401000001_5200_buildings.json new file mode 100644 index 0000000..7e2a303 --- /dev/null +++ b/data/401000001_5200_buildings.json @@ -0,0 +1,218 @@ +{ + "1": { + "state": "suit", + "block": "1", + "track": "l", + "difficulty": "3", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 1776411452.3805523 + }, + "2": { + "state": "toon", + "block": "2", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "3": { + "state": "cogdo", + "block": "3", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776408576.8037343 + }, + "4": { + "state": "cogdo", + "block": "4", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407017.2858732 + }, + "5": { + "state": "toon", + "block": "5", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "6": { + "state": "suit", + "block": "6", + "track": "l", + "difficulty": "2", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776652717.3697903 + }, + "7": { + "state": "suit", + "block": "7", + "track": "l", + "difficulty": "3", + "numFloors": "2", + "savedBy": [], + "becameSuitTime": 1776404335.8955424 + }, + "8": { + "state": "toon", + "block": "8", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "9": { + "state": "suit", + "block": "9", + "track": "l", + "difficulty": "4", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 1776496114.1771314 + }, + "10": { + "state": "toon", + "block": "10", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "11": { + "state": "cogdo", + "block": "11", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407798.041045 + }, + "12": { + "state": "toon", + "block": "12", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "13": { + "state": "toon", + "block": "13", + "track": "s", + "difficulty": "4", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 0 + }, + "14": { + "state": "toon", + "block": "14", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "15": { + "state": "suit", + "block": "15", + "track": "l", + "difficulty": "3", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 1776407407.875649 + }, + "16": { + "state": "toon", + "block": "16", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "17": { + "state": "toon", + "block": "17", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "18": { + "state": "cogdo", + "block": "18", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776411779.447126 + }, + "19": { + "state": "toon", + "block": "19", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "20": { + "state": "toon", + "block": "20", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "21": { + "state": "toon", + "block": "21", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "25": { + "state": "toon", + "block": "25", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "26": { + "state": "toon", + "block": "26", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "27": { + "state": "toon", + "block": "27", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + } +} \ No newline at end of file diff --git a/data/401000001_5300_buildings.json b/data/401000001_5300_buildings.json new file mode 100644 index 0000000..07b3bb2 --- /dev/null +++ b/data/401000001_5300_buildings.json @@ -0,0 +1,155 @@ +{ + "4": { + "state": "cogdo", + "block": "4", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776411270.1291585 + }, + "5": { + "state": "suit", + "block": "5", + "track": "s", + "difficulty": "5", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 1776407964.7990842 + }, + "9": { + "state": "toon", + "block": "9", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "10": { + "state": "cogdo", + "block": "10", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776410224.22525 + }, + "11": { + "state": "suit", + "block": "11", + "track": "s", + "difficulty": "2", + "numFloors": "2", + "savedBy": [], + "becameSuitTime": 1776406467.6855912 + }, + "15": { + "state": "toon", + "block": "15", + "track": "c", + "difficulty": "3", + "numFloors": "2", + "savedBy": [], + "becameSuitTime": 0 + }, + "17": { + "state": "suit", + "block": "17", + "track": "s", + "difficulty": "5", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 1776579670.4015367 + }, + "19": { + "state": "suit", + "block": "19", + "track": "s", + "difficulty": "2", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 1776406476.7417428 + }, + "21": { + "state": "toon", + "block": "21", + "track": "s", + "difficulty": "5", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 0 + }, + "26": { + "state": "cogdo", + "block": "26", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776414275.9934132 + }, + "27": { + "state": "toon", + "block": "27", + "track": "s", + "difficulty": "2", + "numFloors": "2", + "savedBy": [], + "becameSuitTime": 0 + }, + "28": { + "state": "suit", + "block": "28", + "track": "s", + "difficulty": "4", + "numFloors": "2", + "savedBy": [], + "becameSuitTime": 1776651749.715086 + }, + "30": { + "state": "cogdo", + "block": "30", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407069.9103181 + }, + "33": { + "state": "cogdo", + "block": "33", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776411988.241442 + }, + "35": { + "state": "cogdo", + "block": "35", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776406987.8563893 + }, + "36": { + "state": "cogdo", + "block": "36", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407420.8322682 + }, + "37": { + "state": "cogdo", + "block": "37", + "track": "s", + "difficulty": "6", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776411905.266459 + } +} \ No newline at end of file diff --git a/data/401000001_9100_buildings.json b/data/401000001_9100_buildings.json new file mode 100644 index 0000000..32f3437 --- /dev/null +++ b/data/401000001_9100_buildings.json @@ -0,0 +1,299 @@ +{ + "1": { + "state": "cogdo", + "block": "1", + "track": "s", + "difficulty": "9", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776401109.2239604 + }, + "2": { + "state": "toon", + "block": "2", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "4": { + "state": "suit", + "block": "4", + "track": "c", + "difficulty": "5", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 1776414193.0797713 + }, + "5": { + "state": "toon", + "block": "5", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "7": { + "state": "cogdo", + "block": "7", + "track": "s", + "difficulty": "9", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776406504.5424633 + }, + "8": { + "state": "toon", + "block": "8", + "track": "l", + "difficulty": "8", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 0 + }, + "9": { + "state": "suit", + "block": "9", + "track": "m", + "difficulty": "8", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 1776411810.7023568 + }, + "13": { + "state": "suit", + "block": "13", + "track": "c", + "difficulty": "8", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 1776651994.1404142 + }, + "16": { + "state": "cogdo", + "block": "16", + "track": "s", + "difficulty": "9", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776408582.3703592 + }, + "17": { + "state": "toon", + "block": "17", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "19": { + "state": "toon", + "block": "19", + "track": "m", + "difficulty": "5", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 0 + }, + "20": { + "state": "toon", + "block": "20", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "22": { + "state": "toon", + "block": "22", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "25": { + "state": "toon", + "block": "25", + "track": "s", + "difficulty": "8", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 0 + }, + "26": { + "state": "toon", + "block": "26", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "27": { + "state": "suit", + "block": "27", + "track": "c", + "difficulty": "7", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 1776411771.4690347 + }, + "28": { + "state": "toon", + "block": "28", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "29": { + "state": "toon", + "block": "29", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "30": { + "state": "toon", + "block": "30", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "31": { + "state": "toon", + "block": "31", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "33": { + "state": "toon", + "block": "33", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "34": { + "state": "toon", + "block": "34", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "36": { + "state": "cogdo", + "block": "36", + "track": "s", + "difficulty": "9", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407037.446429 + }, + "39": { + "state": "toon", + "block": "39", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "40": { + "state": "cogdo", + "block": "40", + "track": "s", + "difficulty": "9", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407414.034237 + }, + "42": { + "state": "toon", + "block": "42", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "43": { + "state": "toon", + "block": "43", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "44": { + "state": "toon", + "block": "44", + "track": "l", + "difficulty": "8", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 0 + }, + "45": { + "state": "suit", + "block": "45", + "track": "m", + "difficulty": "7", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 1776660591.4981713 + }, + "47": { + "state": "cogdo", + "block": "47", + "track": "s", + "difficulty": "9", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776412023.9540827 + }, + "49": { + "state": "toon", + "block": "49", + "track": "c", + "difficulty": "6", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 0 + }, + "50": { + "state": "toon", + "block": "50", + "track": "s", + "difficulty": "6", + "numFloors": "3", + "savedBy": [], + "becameSuitTime": 0 + }, + "51": { + "state": "toon", + "block": "51", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + } +} \ No newline at end of file diff --git a/data/401000001_9200_buildings.json b/data/401000001_9200_buildings.json new file mode 100644 index 0000000..cef81a4 --- /dev/null +++ b/data/401000001_9200_buildings.json @@ -0,0 +1,299 @@ +{ + "3": { + "state": "toon", + "block": "3", + "track": "s", + "difficulty": "7", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 0 + }, + "4": { + "state": "toon", + "block": "4", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "5": { + "state": "toon", + "block": "5", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "6": { + "state": "toon", + "block": "6", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "7": { + "state": "toon", + "block": "7", + "track": "m", + "difficulty": "6", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 0 + }, + "8": { + "state": "toon", + "block": "8", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "9": { + "state": "suit", + "block": "9", + "track": "c", + "difficulty": "5", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 1776652290.8167818 + }, + "10": { + "state": "toon", + "block": "10", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "11": { + "state": "toon", + "block": "11", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "12": { + "state": "toon", + "block": "12", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "13": { + "state": "toon", + "block": "13", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "14": { + "state": "toon", + "block": "14", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "15": { + "state": "suit", + "block": "15", + "track": "m", + "difficulty": "6", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 1776652016.09749 + }, + "16": { + "state": "becomingToon", + "block": "16", + "track": "s", + "difficulty": "6", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 1776585463.7174423 + }, + "17": { + "state": "toon", + "block": "17", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "18": { + "state": "toon", + "block": "18", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "19": { + "state": "toon", + "block": "19", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "20": { + "state": "toon", + "block": "20", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "21": { + "state": "toon", + "block": "21", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "22": { + "state": "cogdo", + "block": "22", + "track": "s", + "difficulty": "9", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776404335.3353655 + }, + "25": { + "state": "suit", + "block": "25", + "track": "m", + "difficulty": "6", + "numFloors": "5", + "savedBy": [], + "becameSuitTime": 1776661023.7236362 + }, + "27": { + "state": "toon", + "block": "27", + "track": "m", + "difficulty": "7", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 0 + }, + "36": { + "state": "toon", + "block": "36", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "37": { + "state": "cogdo", + "block": "37", + "track": "s", + "difficulty": "9", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776406538.753664 + }, + "38": { + "state": "toon", + "block": "38", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "40": { + "state": "toon", + "block": "40", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "41": { + "state": "cogdo", + "block": "41", + "track": "s", + "difficulty": "9", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776406505.8333917 + }, + "44": { + "state": "suit", + "block": "44", + "track": "m", + "difficulty": "5", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 1776651884.0433154 + }, + "52": { + "state": "cogdo", + "block": "52", + "track": "s", + "difficulty": "9", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776407615.175306 + }, + "53": { + "state": "toon", + "block": "53", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + }, + "54": { + "state": "cogdo", + "block": "54", + "track": "s", + "difficulty": "9", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 1776411233.7490227 + }, + "55": { + "state": "suit", + "block": "55", + "track": "s", + "difficulty": "5", + "numFloors": "4", + "savedBy": [], + "becameSuitTime": 1776660678.3059356 + }, + "59": { + "state": "toon", + "block": "59", + "track": "c", + "difficulty": "1", + "numFloors": "1", + "savedBy": [], + "becameSuitTime": 0 + } +} \ No newline at end of file diff --git a/otp/otpbase/OTPTimer.py b/otp/otpbase/OTPTimer.py index 6e2a607..90bb8ea 100644 --- a/otp/otpbase/OTPTimer.py +++ b/otp/otpbase/OTPTimer.py @@ -35,13 +35,27 @@ class OTPTimer(DirectFrame): return OTPTimer.ClockImage def posInTopRightCorner(self): - self.setPos(1.16, 0, 0.83) + # Widescreen-aware: keep the clock pinned to the top-right corner of the + # screen regardless of aspect ratio (1.16 was the 4:3 position). + try: + from toontown.toonbase.ToonBaseGlobal import base + self.setPos(base.a2dRight - 0.173, 0, 0.83) + except Exception: + self.setPos(1.16, 0, 0.83) def posBelowTopRightCorner(self): - self.setPos(1.16, 0, 0.58) + try: + from toontown.toonbase.ToonBaseGlobal import base + self.setPos(base.a2dRight - 0.173, 0, 0.58) + except Exception: + self.setPos(1.16, 0, 0.58) def posAboveShtikerBook(self): - self.setPos(1.16, 0, -.63) + try: + from toontown.toonbase.ToonBaseGlobal import base + self.setPos(base.a2dRight - 0.173, 0, -0.63) + except Exception: + self.setPos(1.16, 0, -.63) def setTime(self, time): time = bound(time, 0, 999) diff --git a/toontown/battle/DistributedBattleBldg.py b/toontown/battle/DistributedBattleBldg.py index 3033041..99c3e79 100644 --- a/toontown/battle/DistributedBattleBldg.py +++ b/toontown/battle/DistributedBattleBldg.py @@ -111,7 +111,7 @@ class DistributedBattleBldg(DistributedBattleBase.DistributedBattleBase): camTrack = Sequence() def setCamFov(fov): - base.camLens.setFov(fov) + base.camLens.setFov(base.getAdjustedFov(fov)) camTrack.append(Func(camera.wrtReparentTo, suitLeader)) camTrack.append(Func(setCamFov, self.camFOFov)) @@ -157,7 +157,7 @@ class DistributedBattleBldg(DistributedBattleBase.DistributedBattleBase): self.clearInterval(self.faceOffName) self._removeMembersKeep() camera.wrtReparentTo(self) - base.camLens.setFov(self.camFov) + base.camLens.setFov(base.getAdjustedFov(self.camFov) if hasattr(base, 'getAdjustedFov') else self.camFov) return None def __playReward(self, ts, callback): diff --git a/toontown/building/DistributedBuilding.py b/toontown/building/DistributedBuilding.py index bf24ddc..69caf40 100644 --- a/toontown/building/DistributedBuilding.py +++ b/toontown/building/DistributedBuilding.py @@ -154,7 +154,7 @@ class DistributedBuilding(DistributedObject.DistributedObject): self.acceptOnce('insideVictorElevator', self.handleInsideVictorElevator) camera.reparentTo(render) camera.setPosHpr(self.elevatorNodePath, 0, -32.5, 9.4, 0, 348, 0) - base.camLens.setFov(52.0) + base.camLens.setFov(base.getAdjustedFov(52.0)) anyOthers = 0 for v in self.victorList: if v != 0 and v != base.localAvatar.doId: @@ -192,7 +192,7 @@ class DistributedBuilding(DistributedObject.DistributedObject): self.acceptOnce('insideVictorElevator', self.handleInsideVictorElevatorFromCogdo) camera.reparentTo(render) camera.setPosHpr(self.elevatorNodePath, 0, -32.5, 9.4, 0, 348, 0) - base.camLens.setFov(52.0) + base.camLens.setFov(base.getAdjustedFov(52.0)) anyOthers = 0 for v in self.victorList: if v != 0 and v != base.localAvatar.doId: diff --git a/toontown/cogdominium/DistributedCogdoInterior.py b/toontown/cogdominium/DistributedCogdoInterior.py index e90b8a9..df427e8 100644 --- a/toontown/cogdominium/DistributedCogdoInterior.py +++ b/toontown/cogdominium/DistributedCogdoInterior.py @@ -761,6 +761,6 @@ class DistributedCogdoInterior(DistributedObject.DistributedObject): def __outroPenthouseChatDone(self, elapsed = None): self.shopOwnerNpc.setChatAbsolute(TTLocalizer.CogdoExecutiveSuiteToonBye, CFSpeech) self.ignore('doneChatPage') - track = Parallel(Sequence(ActorInterval(self.shopOwnerNpc, 'wave'), Func(self.shopOwnerNpc.loop, 'neutral')), Sequence(Wait(2.0), Func(self.exitCogdoBuilding), Func(base.camLens.setFov, ToontownGlobals.DefaultCameraFov))) + track = Parallel(Sequence(ActorInterval(self.shopOwnerNpc, 'wave'), Func(self.shopOwnerNpc.loop, 'neutral')), Sequence(Wait(2.0), Func(self.exitCogdoBuilding), Func(base.camLens.setFov, base.getAdjustedFov(ToontownGlobals.DefaultCameraFov)))) track.start() self.penthouseOutroChatDoneTrack = track diff --git a/toontown/golf/GolfScoreBoard.py b/toontown/golf/GolfScoreBoard.py index 684cb94..3e93557 100644 --- a/toontown/golf/GolfScoreBoard.py +++ b/toontown/golf/GolfScoreBoard.py @@ -33,7 +33,13 @@ class GolfScoreBoard: self.lines.setThickness(2) guiModel = loader.loadModel('phase_6/models/golf/golf_gui') highlight = loader.loadModel('phase_6/models/golf/headPanel') - self.maximizeB = DirectButton(parent=aspect2d, pos=(1.2, 0, -0.85), relief=None, state=DGG.NORMAL, image=(guiModel.find('**/score_card_icon'), guiModel.find('**/score_card_icon_rollover'), guiModel.find('**/score_card_icon_rollover')), image_scale=(0.2, 1, 0.2), command=self.showBoard) + # Widescreen-aware: keep the score-card icon pinned to the right edge of + # the screen (1.2 was the 4:3 position). + try: + maximizePos = (base.a2dRight - 0.133, 0, -0.85) + except Exception: + maximizePos = (1.2, 0, -0.85) + self.maximizeB = DirectButton(parent=aspect2d, pos=maximizePos, relief=None, state=DGG.NORMAL, image=(guiModel.find('**/score_card_icon'), guiModel.find('**/score_card_icon_rollover'), guiModel.find('**/score_card_icon_rollover')), image_scale=(0.2, 1, 0.2), command=self.showBoard) self.vertOffset = 0.13 self.playaTop = 0.12 horzOffset = 0.12 diff --git a/toontown/login/AvatarChooser.py b/toontown/login/AvatarChooser.py index 71c5fb6..18c307c 100644 --- a/toontown/login/AvatarChooser.py +++ b/toontown/login/AvatarChooser.py @@ -154,6 +154,7 @@ class AvatarChooser(StateData.StateData): elif failed or not haveBackdrop: chooser_notify.warning('pick_a_toon_gui failed to load; skipping legacy background image') self.title = OnscreenText(TTLocalizer.AvatarChooserPickAToon, scale=TTLocalizer.ACtitle, parent=hidden, font=ToontownGlobals.getSignFont(), fg=(1, 0.9, 0.1, 1), pos=(0.0, 0.82)) + # Some forks remove/rename assets; guard against missing models so we # don't trip Panda NodePath empty assertions. quitHover = None @@ -167,8 +168,12 @@ class AvatarChooser(StateData.StateData): if quitHover is None: # Safe fallback: DirectButton allows image=None. chooser_notify.warning('pick_a_toon_gui missing QuitBtn_RLVR; using fallback button visuals') - self.quitButton = DirectButton(image=(quitHover, quitHover, quitHover), relief=None, text=TTLocalizer.AvatarChooserQuit, text_font=ToontownGlobals.getSignFont(), text_fg=(0.977, 0.816, 0.133, 1), text_pos=TTLocalizer.ACquitButtonPos, text_scale=TTLocalizer.ACquitButton, image_scale=1, image1_scale=1.05, image2_scale=1.05, scale=1.05, pos=(1.08, 0, -0.907), command=self.__handleQuit) - self.logoutButton = DirectButton(relief=None, image=(quitHover, quitHover, quitHover), text=TTLocalizer.OptionsPageLogout, text_font=ToontownGlobals.getSignFont(), text_fg=(0.977, 0.816, 0.133, 1), text_scale=TTLocalizer.AClogoutButton, text_pos=(0, -0.035), pos=(-1.17, 0, -0.914), image_scale=1.15, image1_scale=1.15, image2_scale=1.18, scale=0.5, command=self.__handleLogoutWithoutConfirm) + # Widescreen-aware: pin the quit/logout buttons to the screen edges + quitButtonPos = (base.getWidescreenXOffset(1.08, 'right') if hasattr(base, 'getWidescreenXOffset') else 1.08, 0, -0.907) + self.quitButton = DirectButton(image=(quitHover, quitHover, quitHover), relief=None, text=TTLocalizer.AvatarChooserQuit, text_font=ToontownGlobals.getSignFont(), text_fg=(0.977, 0.816, 0.133, 1), text_pos=TTLocalizer.ACquitButtonPos, text_scale=TTLocalizer.ACquitButton, image_scale=1, image1_scale=1.05, image2_scale=1.05, scale=1.05, pos=quitButtonPos, command=self.__handleQuit) + logoutButtonPos = (base.getWidescreenXOffset(-1.17, 'left') if hasattr(base, 'getWidescreenXOffset') else -1.17, 0, -0.914) + self.logoutButton = DirectButton(relief=None, image=(quitHover, quitHover, quitHover), text=TTLocalizer.OptionsPageLogout, text_font=ToontownGlobals.getSignFont(), text_fg=(0.977, 0.816, 0.133, 1), text_scale=TTLocalizer.AClogoutButton, text_pos=(0, -0.035), pos=logoutButtonPos, image_scale=1.15, image1_scale=1.15, image2_scale=1.18, scale=0.5, command=self.__handleLogoutWithoutConfirm) + self.logoutButton.hide() try: if gui is not None and not gui.isEmpty(): diff --git a/toontown/makeatoon/BodyShop.py b/toontown/makeatoon/BodyShop.py index 4b404e9..1331897 100644 --- a/toontown/makeatoon/BodyShop.py +++ b/toontown/makeatoon/BodyShop.py @@ -95,7 +95,8 @@ class BodyShop(StateData.StateData): shuffleArrowDisabled = self.gui.find('**/tt_t_gui_mat_shuffleArrowDisabled') self.upsellModel = loader.loadModel('phase_3/models/gui/tt_m_gui_ups_mainGui') upsellTex = self.upsellModel.find('**/tt_t_gui_ups_banner') - self.parentFrame = DirectFrame(relief=DGG.RAISED, pos=(0.98, 0, 0.416), frameColor=(1, 0, 0, 0)) + # Widescreen-aware: pin the shop frame to the right edge of the screen + self.parentFrame = DirectFrame(relief=DGG.RAISED, pos=(base.getWidescreenXOffset(0.98, 'right') if hasattr(base, 'getWidescreenXOffset') else 0.98, 0, 0.416), frameColor=(1, 0, 0, 0)) self.speciesFrame = DirectFrame(parent=self.parentFrame, image=shuffleFrame, image_scale=halfButtonInvertScale, relief=None, pos=(0, 0, -0.073), hpr=(0, 0, 0), scale=1.3, frameColor=(1, 1, 1, 1), text='Species', text_scale=0.0625, text_pos=(-0.001, -0.015), text_fg=(1, 1, 1, 1)) self.speciesLButton = DirectButton(parent=self.speciesFrame, relief=None, image=(shuffleArrowUp, shuffleArrowDown, diff --git a/toontown/makeatoon/ClothesGUI.py b/toontown/makeatoon/ClothesGUI.py index 80e6d0b..033000b 100644 --- a/toontown/makeatoon/ClothesGUI.py +++ b/toontown/makeatoon/ClothesGUI.py @@ -36,7 +36,8 @@ class ClothesGUI(StateData.StateData): shuffleArrowDown = self.gui.find('**/tt_t_gui_mat_shuffleArrowDown') shuffleArrowRollover = self.gui.find('**/tt_t_gui_mat_shuffleArrowUp') shuffleArrowDisabled = self.gui.find('**/tt_t_gui_mat_shuffleArrowDisabled') - self.parentFrame = DirectFrame(relief=DGG.RAISED, pos=(0.98, 0, 0.416), frameColor=(1, 0, 0, 0)) + # Widescreen-aware: pin the shop frame to the right edge of the screen + self.parentFrame = DirectFrame(relief=DGG.RAISED, pos=(base.getWidescreenXOffset(0.98, 'right') if hasattr(base, 'getWidescreenXOffset') else 0.98, 0, 0.416), frameColor=(1, 0, 0, 0)) self.shirtFrame = DirectFrame(parent=self.parentFrame, image=shuffleFrame, image_scale=halfButtonInvertScale, relief=None, pos=(0, 0, -0.4), hpr=(0, 0, 3), scale=1.2, frameColor=(1, 1, 1, 1), text=TTLocalizer.ClothesShopShirt, text_scale=0.0575, text_pos=(-0.001, -0.015), text_fg=(1, 1, 1, 1)) self.topLButton = DirectButton(parent=self.shirtFrame, relief=None, image=(shuffleArrowUp, shuffleArrowDown, diff --git a/toontown/makeatoon/ColorShop.py b/toontown/makeatoon/ColorShop.py index a607f73..985fe30 100644 --- a/toontown/makeatoon/ColorShop.py +++ b/toontown/makeatoon/ColorShop.py @@ -78,7 +78,8 @@ class ColorShop(StateData.StateData): shuffleArrowDown = self.gui.find('**/tt_t_gui_mat_shuffleArrowDown') shuffleArrowRollover = self.gui.find('**/tt_t_gui_mat_shuffleArrowUp') shuffleArrowDisabled = self.gui.find('**/tt_t_gui_mat_shuffleArrowDisabled') - self.parentFrame = DirectFrame(relief=DGG.RAISED, pos=(0.98, 0, 0.416), frameColor=(1, 0, 0, 0)) + # Widescreen-aware: pin the shop frame to the right edge of the screen + self.parentFrame = DirectFrame(relief=DGG.RAISED, pos=(base.getWidescreenXOffset(0.98, 'right') if hasattr(base, 'getWidescreenXOffset') else 0.98, 0, 0.416), frameColor=(1, 0, 0, 0)) self.toonFrame = DirectFrame(parent=self.parentFrame, image=shuffleFrame, image_scale=halfButtonInvertScale, relief=None, pos=(0, 0, -0.073), hpr=(0, 0, 0), scale=1.3, frameColor=(1, 1, 1, 1), text=TTLocalizer.ColorShopToon, text_scale=TTLocalizer.CStoonFrame, text_pos=(-0.001, -0.015), text_fg=(1, 1, 1, 1)) self.allLButton = DirectButton(parent=self.toonFrame, relief=None, image=(shuffleArrowUp, shuffleArrowDown, diff --git a/toontown/minigame/DistributedDivingGame.py b/toontown/minigame/DistributedDivingGame.py index aaa9269..42275db 100644 --- a/toontown/minigame/DistributedDivingGame.py +++ b/toontown/minigame/DistributedDivingGame.py @@ -230,7 +230,7 @@ class DistributedDivingGame(DistributedMinigame): camera.setZ(36) camera.setH(0) camera.setX(0) - base.camLens.setFov(45) + base.camLens.setFov(base.getAdjustedFov(45)) camera.setY(-54) base.camLens.setFar(1500) self.introMovie = self.getIntroMovie() @@ -274,7 +274,8 @@ class DistributedDivingGame(DistributedMinigame): self.mapModel.reparentTo(aspect2d) self.mapModel.setScale(1.0 / self.mapScaleRatio) self.mapModel.setTransparency(1) - self.mapModel.setPos(1.15, -0.5, -0.125) + # Widescreen-aware: pin the map to the right edge of the screen + self.mapModel.setPos(base.getWidescreenXOffset(1.15, 'right') if hasattr(base, 'getWidescreenXOffset') else 1.15, -0.5, -0.125) self.mapModel.setColorScale(1, 1, 1, 0.7) self.mapModel.hide() if None != self.sndAmbience: @@ -294,7 +295,7 @@ class DistributedDivingGame(DistributedMinigame): self.toonSDs[avId].exit() base.camLens.setFar(ToontownGlobals.DefaultCameraFar) - base.camLens.setFov(ToontownGlobals.DefaultCameraFov) + base.camLens.setFov(base.getAdjustedFov(ToontownGlobals.DefaultCameraFov)) base.setBackgroundColor(ToontownGlobals.DefaultBackgroundColor) self.arrowKeys.destroy() del self.arrowKeys @@ -528,7 +529,8 @@ class DistributedDivingGame(DistributedMinigame): DistributedMinigame.setGameStart(self, timestamp) self.notify.debug('setGameStart') self.treasurePanel = TreasureScorePanel.TreasureScorePanel() - self.treasurePanel.setPos(-1.19, 0, 0.75) + # Widescreen-aware: pin the score panel to the left edge of the screen + self.treasurePanel.setPos(base.getWidescreenXOffset(-1.19, 'left') if hasattr(base, 'getWidescreenXOffset') else -1.19, 0, 0.75) self.treasurePanel.makeTransparent(0.7) self.introMovie.finish() self.gameFSM.request('swim') diff --git a/toontown/minigame/DistributedPatternGame.py b/toontown/minigame/DistributedPatternGame.py index 7e7420c..d6bc99c 100644 --- a/toontown/minigame/DistributedPatternGame.py +++ b/toontown/minigame/DistributedPatternGame.py @@ -214,7 +214,7 @@ class DistributedPatternGame(DistributedMinigame): self.lt = base.localAvatar base.camera.reparentTo(base.render) base.camera.setPosHpr(0.0, -14.59, 10.56, 0.0, -16.39, 0.0) - base.camLens.setFov(24.66) + base.camLens.setFov(base.getAdjustedFov(24.66)) NametagGlobals.setGlobalNametagScale(0.6) self.arrowKeys = ArrowKeys() self.room.reparentTo(base.render) @@ -288,7 +288,7 @@ class DistributedPatternGame(DistributedMinigame): self.notify.debug('offstage') DistributedMinigame.offstage(self) self.music.stop() - base.camLens.setFov(ToontownGlobals.DefaultCameraFov) + base.camLens.setFov(base.getAdjustedFov(ToontownGlobals.DefaultCameraFov)) NametagGlobals.setGlobalNametagScale(1.0) self.arrowKeys.destroy() del self.arrowKeys diff --git a/toontown/minigame/DistributedRingGame.py b/toontown/minigame/DistributedRingGame.py index f6e65be..eb8a19a 100644 --- a/toontown/minigame/DistributedRingGame.py +++ b/toontown/minigame/DistributedRingGame.py @@ -134,7 +134,7 @@ class DistributedRingGame(DistributedMinigame): camera.reparentTo(render) camera.reparentTo(base.localAvatar) camera.setPosHpr(0, self.CAMERA_Y + self.TOON_Y, 0, 0, 0, 0) - base.camLens.setFov(80) + base.camLens.setFov(base.getAdjustedFov(80)) base.camLens.setFar(self.FAR_PLANE_DIST) base.setBackgroundColor(self.WATER_COLOR) self.__fog = Fog('ringGameFog') @@ -192,7 +192,7 @@ class DistributedRingGame(DistributedMinigame): self.__removeAllToonDropShadows() render.clearFog() base.camLens.setFar(ToontownGlobals.DefaultCameraFar) - base.camLens.setFov(ToontownGlobals.DefaultCameraFov) + base.camLens.setFov(base.getAdjustedFov(ToontownGlobals.DefaultCameraFov)) base.setBackgroundColor(ToontownGlobals.DefaultBackgroundColor) self.arrowKeys.destroy() del self.arrowKeys diff --git a/toontown/minigame/DistributedTargetGame.py b/toontown/minigame/DistributedTargetGame.py index 335f3f8..947198e 100644 --- a/toontown/minigame/DistributedTargetGame.py +++ b/toontown/minigame/DistributedTargetGame.py @@ -576,7 +576,7 @@ class DistributedTargetGame(DistributedMinigame): camera.reparentTo(render) toonPos = self.getAvatar(self.localAvId).getPos() camera.setPosHpr(toonPos[0], toonPos[1] - 18, toonPos[2] + 10, 0, -15, 0) - base.camLens.setFov(80) + base.camLens.setFov(base.getAdjustedFov(80)) base.camLens.setFar(self.FOGDISTGROUND) base.setBackgroundColor(self.AMB_COLOR) self.__fog = Fog('ringGameFog') @@ -676,7 +676,7 @@ class DistributedTargetGame(DistributedMinigame): self.__spawnUpdateLocalToonTask() toonPos = base.localAvatar.getPos() camera.setPosHpr(toonPos[0], toonPos[1] - 26, toonPos[2] + 10, 0, -15, 0) - base.camLens.setFov(80) + base.camLens.setFov(base.getAdjustedFov(80)) self.resetNums() def resetNums(self): @@ -704,7 +704,7 @@ class DistributedTargetGame(DistributedMinigame): self.__removeAllToonDropShadows() render.clearFog() base.camLens.setFar(ToontownGlobals.DefaultCameraFar) - base.camLens.setFov(ToontownGlobals.DefaultCameraFov) + base.camLens.setFov(base.getAdjustedFov(ToontownGlobals.DefaultCameraFov)) camera.setHpr(0, 90, 0) base.setBackgroundColor(ToontownGlobals.DefaultBackgroundColor) self.arrowKeys.destroy() @@ -865,7 +865,7 @@ class DistributedTargetGame(DistributedMinigame): newHpr = Point3(0, -15, 0) self.cameraWork = camera.posHprInterval(2.5, newPos, newHpr, blendType='easeInOut') self.cameraWork.start() - base.camLens.setFov(80) + base.camLens.setFov(base.getAdjustedFov(80)) self.stretchY = self.startPower self.power = self.startPower self.scoreboard.hide() @@ -906,7 +906,7 @@ class DistributedTargetGame(DistributedMinigame): toon.dropShadow.hide() camera.reparentTo(base.localAvatar) camera.setPosHpr(0, self.CAMERA_Y + self.TOON_Y + 12, 5, 0, -15, 0) - base.camLens.setFov(80) + base.camLens.setFov(base.getAdjustedFov(80)) self.help.show() self.help['text'] = TTLocalizer.TargetGameFlyHelp self.rubberSound.setVolume(0.0) diff --git a/toontown/minigame/DistributedTugOfWarGame.py b/toontown/minigame/DistributedTugOfWarGame.py index 2dcae83..0b51f0c 100644 --- a/toontown/minigame/DistributedTugOfWarGame.py +++ b/toontown/minigame/DistributedTugOfWarGame.py @@ -311,7 +311,7 @@ class DistributedTugOfWarGame(DistributedMinigame): del self.setupTrack self.setupTrack = None - base.camLens.setFov(ToontownGlobals.DefaultCameraFov) + base.camLens.setFov(base.getAdjustedFov(ToontownGlobals.DefaultCameraFov)) base.camLens.setNearFar(ToontownGlobals.DefaultCameraNear, ToontownGlobals.DefaultCameraFar) NametagGlobals.setGlobalNametagScale(1.0) if self.arrowKeys: @@ -363,7 +363,7 @@ class DistributedTugOfWarGame(DistributedMinigame): lerpDur = 8 self.introTrack = LerpPosHprInterval(base.camera, lerpDur, pos=gameCamPos, hpr=gameCamHpr, blendType='easeInOut', name=self.uniqueName('introLerpCameraPos')) self.introTrack.start() - base.camLens.setFov(60 + 2 * self.numPlayers) + base.camLens.setFov(base.getAdjustedFov(60 + 2 * self.numPlayers)) base.camLens.setFar(450.0) def sendGameType(self, index, suit): diff --git a/toontown/minigame/Purchase.py b/toontown/minigame/Purchase.py index a8eb5c4..bc793da 100644 --- a/toontown/minigame/Purchase.py +++ b/toontown/minigame/Purchase.py @@ -278,7 +278,7 @@ class Purchase(PurchaseBase): self.counters = [] self.totalCounters = [] camera.reparentTo(render) - base.camLens.setFov(ToontownGlobals.DefaultCameraFov) + base.camLens.setFov(base.getAdjustedFov(ToontownGlobals.DefaultCameraFov)) camera.setPos(0, 16.0, 2.0) camera.lookAt(0, 0, 0.75) base.transitions.irisIn(0.4) diff --git a/toontown/parties/DistributedPartyTrampolineActivity.py b/toontown/parties/DistributedPartyTrampolineActivity.py index 964ad53..71c1417 100644 --- a/toontown/parties/DistributedPartyTrampolineActivity.py +++ b/toontown/parties/DistributedPartyTrampolineActivity.py @@ -144,7 +144,11 @@ class DistributedPartyTrampolineActivity(DistributedPartyActivity): def loadGUI(self): self.gui = loader.loadModel('phase_13/models/parties/trampolineGUI') - self.gui.setX(-1.15) + # Widescreen-aware: pin the GUI to the left edge of the screen + try: + self.gui.setX(base.a2dLeft + 0.183) + except Exception: + self.gui.setX(-1.15) self.gui.reparentTo(self.screenPlaneElements) self.toonIndicator = self.gui.find('**/trampolineGUI_MovingBar') jumpLineLocator = self.gui.find('**/jumpLine_locator') @@ -167,7 +171,12 @@ class DistributedPartyTrampolineActivity(DistributedPartyActivity): quitEarlyUp = self.quitEarlyButtonModels.find('**//InventoryButtonUp') quitEarlyDown = self.quitEarlyButtonModels.find('**/InventoryButtonDown') quitEarlyRollover = self.quitEarlyButtonModels.find('**/InventoryButtonRollover') - self.quitEarlyButton = DirectButton(parent=self.screenPlaneElements, relief=None, text=TTLocalizer.PartyTrampolineQuitEarlyButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -0.23), text_scale=0.7, image=(quitEarlyUp, quitEarlyDown, quitEarlyRollover), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(1.15, 0, 0.6), scale=0.09, command=self.leaveTrampoline) + # Widescreen-aware: pin the quit button to the right edge of the screen + try: + quitEarlyPos = (base.a2dRight - 0.183, 0, 0.6) + except Exception: + quitEarlyPos = (1.15, 0, 0.6) + self.quitEarlyButton = DirectButton(parent=self.screenPlaneElements, relief=None, text=TTLocalizer.PartyTrampolineQuitEarlyButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -0.23), text_scale=0.7, image=(quitEarlyUp, quitEarlyDown, quitEarlyRollover), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=quitEarlyPos, scale=0.09, command=self.leaveTrampoline) self.quitEarlyButton.stash() self.flashText = OnscreenText(text='', pos=(0.0, -0.45), scale=0.2, fg=(1.0, 1.0, 0.65, 1.0), align=TextNode.ACenter, font=ToontownGlobals.getSignFont(), mayChange=True) self.timer = PartyUtils.getNewToontownTimer() diff --git a/toontown/quest/QuestMap.py b/toontown/quest/QuestMap.py index 2441f92..ff30bae 100644 --- a/toontown/quest/QuestMap.py +++ b/toontown/quest/QuestMap.py @@ -57,8 +57,10 @@ class QuestMap(DirectFrame): self.marker['image'] = iconNP self.marker.setScale(0.05) iconNP.removeNode() - self.mapOpenButton = DirectButton(image=(gui.find('**/tt_t_gui_qst_mapClose'), gui.find('**/tt_t_gui_qst_mapClose'), gui.find('**/tt_t_gui_qst_mapTryToOpen')), relief=None, pos=(1.25, 0, -0.63), scale=0.205, command=self.show) - self.mapCloseButton = DirectButton(image=(gui.find('**/tt_t_gui_qst_mapOpen'), gui.find('**/tt_t_gui_qst_mapOpen'), gui.find('**/tt_t_gui_qst_mapTryToClose')), relief=None, pos=(1.25, 0, -0.63), scale=0.205, command=self.hide) + # Widescreen-aware: pin the quest-map buttons to the right edge of the screen + mapButtonX = base.getWidescreenXOffset(1.25, 'right') if hasattr(base, 'getWidescreenXOffset') else 1.25 + self.mapOpenButton = DirectButton(image=(gui.find('**/tt_t_gui_qst_mapClose'), gui.find('**/tt_t_gui_qst_mapClose'), gui.find('**/tt_t_gui_qst_mapTryToOpen')), relief=None, pos=(mapButtonX, 0, -0.63), scale=0.205, command=self.show) + self.mapCloseButton = DirectButton(image=(gui.find('**/tt_t_gui_qst_mapOpen'), gui.find('**/tt_t_gui_qst_mapOpen'), gui.find('**/tt_t_gui_qst_mapTryToClose')), relief=None, pos=(mapButtonX, 0, -0.63), scale=0.205, command=self.hide) self.mapOpenButton.hide() self.mapCloseButton.hide() gui.removeNode() diff --git a/toontown/quest/QuestParser.py b/toontown/quest/QuestParser.py index 7780608..15f8afa 100644 --- a/toontown/quest/QuestParser.py +++ b/toontown/quest/QuestParser.py @@ -1089,7 +1089,9 @@ class NPCMoviePlayer(DirectObject.DirectObject): vfs = VirtualFileSystem.getGlobalPtr() searchPath = DSearchPath() -searchPath.appendDirectory(Filename('/phase_3/etc')) +# Resources live under the 'resources/' folder on disk (model-path resources); +# they are not VFS-mounted at the root like in the original game. +searchPath.appendDirectory(Filename('resources/phase_3/etc')) scriptFile = Filename('QuestScripts.txt') found = vfs.resolveFilename(scriptFile, searchPath) if not found: diff --git a/toontown/racing/DistributedStartingBlock.py b/toontown/racing/DistributedStartingBlock.py index a0350ab..39920fd 100644 --- a/toontown/racing/DistributedStartingBlock.py +++ b/toontown/racing/DistributedStartingBlock.py @@ -326,7 +326,9 @@ class DistributedStartingBlock(DistributedObject.DistributedObject, FSM): if hasattr(self, 'cancelButton'): return fishGui = loader.loadModel('phase_4/models/gui/fishingGui') - self.cancelButton = DirectGui.DirectButton(relief=None, scale=0.67, pos=(1.16, 0, -0.9), text=('', TTLocalizer.FishingExit, TTLocalizer.FishingExit), text_align=TextNode.ACenter, text_fg=Vec4(1, 1, 1, 1), text_shadow=Vec4(0, 0, 0, 1), text_pos=(0.0, -0.12), textMayChange=0, text_scale=0.1, image=(fishGui.find('**/exit_buttonUp'), fishGui.find('**/exit_buttonDown'), fishGui.find('**/exit_buttonRollover')), text_font=ToontownGlobals.getInterfaceFont(), command=self.d_requestExit) + # Widescreen-aware: pin the exit button to the right edge of the screen + cancelButtonPos = (base.getWidescreenXOffset(1.16, 'right') if hasattr(base, 'getWidescreenXOffset') else 1.16, 0, -0.9) + self.cancelButton = DirectGui.DirectButton(relief=None, scale=0.67, pos=cancelButtonPos, text=('', TTLocalizer.FishingExit, TTLocalizer.FishingExit), text_align=TextNode.ACenter, text_fg=Vec4(1, 1, 1, 1), text_shadow=Vec4(0, 0, 0, 1), text_pos=(0.0, -0.12), textMayChange=0, text_scale=0.1, image=(fishGui.find('**/exit_buttonUp'), fishGui.find('**/exit_buttonDown'), fishGui.find('**/exit_buttonRollover')), text_font=ToontownGlobals.getInterfaceFont(), command=self.d_requestExit) self.cancelButton.hide() return diff --git a/toontown/racing/DistributedVehicle.py b/toontown/racing/DistributedVehicle.py index 26c6c4d..7d0d89e 100644 --- a/toontown/racing/DistributedVehicle.py +++ b/toontown/racing/DistributedVehicle.py @@ -686,7 +686,7 @@ class DistributedVehicle(DistributedSmoothNode.DistributedSmoothNode, Kart.Kart, if self.cameraTrack: self.cameraTrack.pause() cameraZoomIn = Parallel(LerpPosInterval(camera, 2, newCameraPos), LerpFunc(base.camLens.setFov, fromData=startFov, toData=newCameraFov, duration=2)) - cameraToNormal = Parallel(LerpPosInterval(camera, 1, Point3(0, -33, 16), newCameraPos), LerpFunc(base.camLens.setFov, fromData=newCameraFov, toData=ToontownGlobals.DefaultCameraFov, duration=1)) + cameraToNormal = Parallel(LerpPosInterval(camera, 1, Point3(0, -33, 16), newCameraPos), LerpFunc(base.camLens.setFov, fromData=newCameraFov, toData=base.getAdjustedFov(ToontownGlobals.DefaultCameraFov), duration=1)) self.cameraTrack = Sequence(Func(self.turboStartSfx.play), cameraZoomIn, Func(lambda : self.setTurbo(True)), Wait(turboDuration), Func(self.__stopTurbo), cameraToNormal) self.cameraTrack.start() @@ -1098,7 +1098,7 @@ class DistributedVehicle(DistributedSmoothNode.DistributedSmoothNode, Kart.Kart, self.imHitMult = level if hasattr(self, 'cameraTrack') and self.cameraTrack: self.cameraTrack.pause() - cameraToNormal = Parallel(LerpPosInterval(camera, 0.05, Point3(0, -33, 16), startPos=camera.getPos()), LerpFunc(base.camLens.setFov, fromData=base.camLens.getFov()[0], toData=ToontownGlobals.DefaultCameraFov, duration=0.05)) + cameraToNormal = Parallel(LerpPosInterval(camera, 0.05, Point3(0, -33, 16), startPos=camera.getPos()), LerpFunc(base.camLens.setFov, fromData=base.camLens.getFov()[0], toData=base.getAdjustedFov(ToontownGlobals.DefaultCameraFov), duration=0.05)) cameraToNormal.start() self.__stopTurbo() self.stopped = True diff --git a/toontown/racing/RaceEndPanels.py b/toontown/racing/RaceEndPanels.py index b3b5124..0a2a81d 100644 --- a/toontown/racing/RaceEndPanels.py +++ b/toontown/racing/RaceEndPanels.py @@ -339,7 +339,7 @@ class RaceEndPanel(DirectFrame): self.closeButton = DirectButton(parent=self, image=(gui.find('**/CloseBtn_UP'), gui.find('**/CloseBtn_DN'), gui.find('**/CloseBtn_Rllvr'), - gui.find('**/CloseBtn_UP')), relief=None, scale=2.0, text=exitText, text_scale=TTLocalizer.REPsmallLabel, text_pos=(0, -0.1), text_fg=VBase4(1, 1, 1, 1), pos=(1.1, 0, -0.5), command=self.closeButtonPressed) + gui.find('**/CloseBtn_UP')), relief=None, scale=2.0, text=exitText, text_scale=TTLocalizer.REPsmallLabel, text_pos=(0, -0.1), text_fg=VBase4(1, 1, 1, 1), pos=(base.getWidescreenXOffset(1.1, 'right') if hasattr(base, 'getWidescreenXOffset') else 1.1, 0, -0.5), command=self.closeButtonPressed) self.closeButton.hide() self.disable() return diff --git a/toontown/racing/RaceGUI.py b/toontown/racing/RaceGUI.py index 87dd55b..119a790 100644 --- a/toontown/racing/RaceGUI.py +++ b/toontown/racing/RaceGUI.py @@ -93,10 +93,12 @@ class RaceGUI: self.aspect2dRoot.setDepthWrite(1) self.raceModeRoot = self.aspect2dRoot.attachNewNode('RaceModeRoot') gui = loader.loadModel('phase_3.5/models/gui/avatar_panel_gui') + # Widescreen-aware: keep HUD buttons pinned to the screen edges + closeButtonPos = (base.a2dLeft + 0.343, 0, 0.925) if hasattr(base, 'a2dLeft') else (-0.99, 0, 0.925) self.closeButton = DirectButton(image=(gui.find('**/CloseBtn_UP'), gui.find('**/CloseBtn_DN'), gui.find('**/CloseBtn_Rllvr'), - gui.find('**/CloseBtn_UP')), relief=None, scale=1.05, text=TTLocalizer.KartRace_Leave, text_scale=0.04, text_pos=(0, -0.07), text_fg=VBase4(1, 1, 1, 1), pos=(-0.99, 0, 0.925), command=self.race.leaveRace) + gui.find('**/CloseBtn_UP')), relief=None, scale=1.05, text=TTLocalizer.KartRace_Leave, text_scale=0.04, text_pos=(0, -0.07), text_fg=VBase4(1, 1, 1, 1), pos=closeButtonPos, command=self.race.leaveRace) self.closeButton.reparentTo(self.aspect2dRoot) self.directObjList.append(self.closeButton) self.raceTimeDelta = 0 @@ -137,13 +139,15 @@ class RaceGUI: self.placeLabelStr = DirectLabel(relief=None, pos=TTLocalizer.RGUIplaceLabelStrPos, text=TTLocalizer.KartRace_FirstSuffix, text_scale=0.1, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont()) self.placeLabelStr.reparentTo(self.raceModeRoot) self.directObjList.append(self.placeLabelStr) - self.lapLabel = DirectLabel(relief=None, pos=(1.1, 0, 0.45), text='1/' + str(self.race.lapCount), text_scale=0.1, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont()) + lapLabelPos = (base.a2dRight - 0.233, 0, 0.45) if hasattr(base, 'a2dRight') else (1.1, 0, 0.45) + self.lapLabel = DirectLabel(relief=None, pos=lapLabelPos, text='1/' + str(self.race.lapCount), text_scale=0.1, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont()) self.lapLabel.reparentTo(self.raceModeRoot) self.directObjList.append(self.lapLabel) self.photoFinishLabel = DirectLabel(relief=None, pos=(0, 0, -0.1), text=TTLocalizer.KartRace_PhotoFinish, text_scale=TTLocalizer.RGUIphotoFinish, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont()) self.photoFinishLabel.hide() self.directObjList.append(self.photoFinishLabel) - self.wrongWayLabel = DirectLabel(relief=None, pos=(1.1, 0, 0.85), text=TTLocalizer.KartRace_WrongWay, text_scale=0.1, text_fg=(0.95, 0, 0, 1), text_font=ToontownGlobals.getSignFont()) + wrongWayLabelPos = (base.a2dRight - 0.233, 0, 0.85) if hasattr(base, 'a2dRight') else (1.1, 0, 0.85) + self.wrongWayLabel = DirectLabel(relief=None, pos=wrongWayLabelPos, text=TTLocalizer.KartRace_WrongWay, text_scale=0.1, text_fg=(0.95, 0, 0, 1), text_font=ToontownGlobals.getSignFont()) self.wrongWayLabel.reparentTo(self.raceModeRoot) self.directObjList.append(self.wrongWayLabel) self.wrongWayLabel.setColorScale(Vec4(1, 1, 1, 0)) @@ -166,7 +170,8 @@ class RaceGUI: self.cardMaker.setName('GagIndicator') self.cardMaker.setFrame(-0.5, 0.5, -0.5, 0.5) self.cardMaker.setColor(1, 1, 1, 1) - self.gagPanel = DirectFrame(parent=self.raceModeRoot, relief=None, image=loader.loadModel('phase_6/models/karting/gag_panel'), image_scale=0.25, pos=(-1.13, 0, -0.5)) + gagPanelPos = (base.a2dLeft + 0.203, 0, -0.5) if hasattr(base, 'a2dLeft') else (-1.13, 0, -0.5) + self.gagPanel = DirectFrame(parent=self.raceModeRoot, relief=None, image=loader.loadModel('phase_6/models/karting/gag_panel'), image_scale=0.25, pos=gagPanelPos) self.directObjList.append(self.gagPanel) self.gag = self.gagPanel.attachNewNode('gag') self.gag.setScale(0.2) diff --git a/toontown/safezone/DistributedCheckers.py b/toontown/safezone/DistributedCheckers.py index 5051f79..c90bb90 100644 --- a/toontown/safezone/DistributedCheckers.py +++ b/toontown/safezone/DistributedCheckers.py @@ -58,7 +58,7 @@ class DistributedCheckers(DistributedNode.DistributedNode): self.downButton = self.buttonModels.find('**/InventoryButtonDown') self.rolloverButton = self.buttonModels.find('**/InventoryButtonRollover') self.clockNode = ToontownTimer() - self.clockNode.setPos(1.16, 0, -0.83) + self.clockNode.setPos(base.getWidescreenXOffset(1.16, 'right') if hasattr(base, 'getWidescreenXOffset') else 1.16, 0, -0.83) self.clockNode.setScale(0.3) self.clockNode.hide() self.playerColors = [Vec4(0, 0, 1, 1), Vec4(0, 1, 0, 1)] @@ -181,7 +181,7 @@ class DistributedCheckers(DistributedNode.DistributedNode): if timeLeft > 0 and timerEnd != 0: if timeLeft > 60: timeLeft = 60 - self.clockNode.setPos(1.16, 0, -0.83) + self.clockNode.setPos(base.getWidescreenXOffset(1.16, 'right') if hasattr(base, 'getWidescreenXOffset') else 1.16, 0, -0.83) self.clockNode.countdown(timeLeft, self.startButtonPushed) self.clockNode.show() else: @@ -195,7 +195,7 @@ class DistributedCheckers(DistributedNode.DistributedNode): time = globalClockDelta.networkToLocalTime(turnEnd) timeLeft = int(time - globalClock.getRealTime()) if timeLeft > 0: - self.clockNode.setPos(-.74, 0, -0.2) + self.clockNode.setPos(base.getWidescreenXOffset(-.74, 'left') if hasattr(base, 'getWidescreenXOffset') else -.74, 0, -0.2) if self.isMyTurn: self.clockNode.countdown(timeLeft, self.doNothing) else: @@ -297,7 +297,7 @@ class DistributedCheckers(DistributedNode.DistributedNode): self.clockNode.reset() def enableExitButton(self): - self.exitButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersGetUpButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.8, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.4), scale=0.15, command=lambda self = self: self.exitButtonPushed()) + self.exitButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersGetUpButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.8, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(base.getWidescreenXOffset(0.92, 'right') if hasattr(base, 'getWidescreenXOffset') else 0.92, 0, 0.4), scale=0.15, command=lambda self = self: self.exitButtonPushed()) return def enableScreenText(self): @@ -315,11 +315,11 @@ class DistributedCheckers(DistributedNode.DistributedNode): self.screenText = OnscreenText(text=message, pos=defaultPos, scale=0.1, fg=color, align=TextNode.ACenter, mayChange=1) def enableStartButton(self): - self.startButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersStartButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.6, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.1), scale=0.15, command=lambda self = self: self.startButtonPushed()) + self.startButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersStartButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.6, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(base.getWidescreenXOffset(0.92, 'right') if hasattr(base, 'getWidescreenXOffset') else 0.92, 0, 0.1), scale=0.15, command=lambda self = self: self.startButtonPushed()) return def enableLeaveButton(self): - self.leaveButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersQuitButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.13), text_scale=0.5, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.4), scale=0.15, command=lambda self = self: self.exitButtonPushed()) + self.leaveButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersQuitButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.13), text_scale=0.5, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(base.getWidescreenXOffset(0.92, 'right') if hasattr(base, 'getWidescreenXOffset') else 0.92, 0, 0.4), scale=0.15, command=lambda self = self: self.exitButtonPushed()) return def enableTurnScreenText(self, player): diff --git a/toontown/safezone/DistributedChineseCheckers.py b/toontown/safezone/DistributedChineseCheckers.py index d7247fa..e99304d 100644 --- a/toontown/safezone/DistributedChineseCheckers.py +++ b/toontown/safezone/DistributedChineseCheckers.py @@ -62,7 +62,7 @@ class DistributedChineseCheckers(DistributedNode.DistributedNode): self.downButton = self.buttonModels.find('**/InventoryButtonDown') self.rolloverButton = self.buttonModels.find('**/InventoryButtonRollover') self.clockNode = ToontownTimer() - self.clockNode.setPos(1.16, 0, -0.83) + self.clockNode.setPos(base.getWidescreenXOffset(1.16, 'right') if hasattr(base, 'getWidescreenXOffset') else 1.16, 0, -0.83) self.clockNode.setScale(0.3) self.clockNode.hide() self.playerColors = [Vec4(0, 0.9, 0, 1), @@ -231,7 +231,7 @@ class DistributedChineseCheckers(DistributedNode.DistributedNode): if timeLeft > 0 and timerEnd != 0: if timeLeft > 60: timeLeft = 60 - self.clockNode.setPos(1.16, 0, -0.83) + self.clockNode.setPos(base.getWidescreenXOffset(1.16, 'right') if hasattr(base, 'getWidescreenXOffset') else 1.16, 0, -0.83) self.clockNode.countdown(timeLeft, self.startButtonPushed) self.clockNode.show() else: @@ -245,7 +245,7 @@ class DistributedChineseCheckers(DistributedNode.DistributedNode): time = globalClockDelta.networkToLocalTime(turnEnd) timeLeft = int(time - globalClock.getRealTime()) if timeLeft > 0: - self.clockNode.setPos(-.74, 0, -0.2) + self.clockNode.setPos(base.getWidescreenXOffset(-.74, 'left') if hasattr(base, 'getWidescreenXOffset') else -.74, 0, -0.2) if self.isMyTurn: self.clockNode.countdown(timeLeft, self.doRandomMove) else: @@ -416,7 +416,7 @@ class DistributedChineseCheckers(DistributedNode.DistributedNode): self.clockNode.reset() def enableExitButton(self): - self.exitButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersGetUpButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.8, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.4), scale=0.15, command=lambda self = self: self.exitButtonPushed()) + self.exitButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersGetUpButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.8, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(base.getWidescreenXOffset(0.92, 'right') if hasattr(base, 'getWidescreenXOffset') else 0.92, 0, 0.4), scale=0.15, command=lambda self = self: self.exitButtonPushed()) return def enableScreenText(self): @@ -446,11 +446,11 @@ class DistributedChineseCheckers(DistributedNode.DistributedNode): self.screenText = OnscreenText(text=message, pos=defaultPos, scale=0.1, fg=color, align=TextNode.ACenter, mayChange=1) def enableStartButton(self): - self.startButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersStartButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.6, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.1), scale=0.15, command=lambda self = self: self.startButtonPushed()) + self.startButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersStartButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.6, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(base.getWidescreenXOffset(0.92, 'right') if hasattr(base, 'getWidescreenXOffset') else 0.92, 0, 0.1), scale=0.15, command=lambda self = self: self.startButtonPushed()) return def enableLeaveButton(self): - self.leaveButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersQuitButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.13), text_scale=0.5, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.4), scale=0.15, command=lambda self = self: self.exitButtonPushed()) + self.leaveButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersQuitButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.13), text_scale=0.5, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(base.getWidescreenXOffset(0.92, 'right') if hasattr(base, 'getWidescreenXOffset') else 0.92, 0, 0.4), scale=0.15, command=lambda self = self: self.exitButtonPushed()) return def enableTurnScreenText(self, player): diff --git a/toontown/safezone/DistributedFindFour.py b/toontown/safezone/DistributedFindFour.py index c43ac09..5d904f3 100644 --- a/toontown/safezone/DistributedFindFour.py +++ b/toontown/safezone/DistributedFindFour.py @@ -106,7 +106,7 @@ class DistributedFindFour(DistributedNode.DistributedNode): self.downButton = self.buttonModels.find('**/InventoryButtonDown') self.rolloverButton = self.buttonModels.find('**/InventoryButtonRollover') self.clockNode = ToontownTimer() - self.clockNode.setPos(1.16, 0, -0.83) + self.clockNode.setPos(base.getWidescreenXOffset(1.16, 'right') if hasattr(base, 'getWidescreenXOffset') else 1.16, 0, -0.83) self.clockNode.setScale(0.3) self.clockNode.hide() self.tintConstant = Vec4(0.25, 0.25, 0.25, 0) @@ -250,7 +250,7 @@ class DistributedFindFour(DistributedNode.DistributedNode): if timeLeft > 0 and timerEnd != 0: if timeLeft > 60: timeLeft = 60 - self.clockNode.setPos(1.16, 0, -0.83) + self.clockNode.setPos(base.getWidescreenXOffset(1.16, 'right') if hasattr(base, 'getWidescreenXOffset') else 1.16, 0, -0.83) self.clockNode.countdown(timeLeft, self.startButtonPushed) self.clockNode.show() else: @@ -264,7 +264,7 @@ class DistributedFindFour(DistributedNode.DistributedNode): time = globalClockDelta.networkToLocalTime(turnEnd) timeLeft = int(time - globalClock.getRealTime()) if timeLeft > 0: - self.clockNode.setPos(0.64, 0, -0.27) + self.clockNode.setPos(base.getWidescreenXOffset(0.64, 'right') if hasattr(base, 'getWidescreenXOffset') else 0.64, 0, -0.27) self.clockNode.countdown(timeLeft, self.doRandomMove) self.clockNode.show() return @@ -356,7 +356,7 @@ class DistributedFindFour(DistributedNode.DistributedNode): self.clockNode.reset() def enableExitButton(self): - self.exitButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersGetUpButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.8, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.8), scale=0.15, command=lambda self = self: self.exitButtonPushed()) + self.exitButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersGetUpButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.8, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(base.getWidescreenXOffset(0.92, 'right') if hasattr(base, 'getWidescreenXOffset') else 0.92, 0, 0.8), scale=0.15, command=lambda self = self: self.exitButtonPushed()) return def enableScreenText(self): @@ -373,11 +373,11 @@ class DistributedFindFour(DistributedNode.DistributedNode): self.screenText = OnscreenText(text=message, pos=defaultPos, scale=0.1, fg=color, align=TextNode.ACenter, mayChange=1) def enableStartButton(self): - self.startButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersStartButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.6, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.57), scale=0.15, command=lambda self = self: self.startButtonPushed()) + self.startButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersStartButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.6, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(base.getWidescreenXOffset(0.92, 'right') if hasattr(base, 'getWidescreenXOffset') else 0.92, 0, 0.57), scale=0.15, command=lambda self = self: self.startButtonPushed()) return def enableLeaveButton(self): - self.leaveButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersQuitButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.13), text_scale=0.5, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.8), scale=0.15, command=lambda self = self: self.exitButtonPushed()) + self.leaveButton = DirectButton(relief=None, text=TTLocalizer.ChineseCheckersQuitButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.13), text_scale=0.5, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(base.getWidescreenXOffset(0.92, 'right') if hasattr(base, 'getWidescreenXOffset') else 0.92, 0, 0.8), scale=0.15, command=lambda self = self: self.exitButtonPushed()) return def enableTurnScreenText(self, player): diff --git a/toontown/settings/Settings.py b/toontown/settings/Settings.py index b4dbdd3..0f716cd 100644 --- a/toontown/settings/Settings.py +++ b/toontown/settings/Settings.py @@ -125,6 +125,14 @@ class Settings: def readSettings(self) -> None: pass + def doSavedSettingsExist(self) -> bool: + """Return True if a settings file exists on disk. + + Mirrors the legacy otp.settings.Settings method used by DisplayOptions + to decide whether saved settings (vs. defaults) should be honored. + """ + return self.settingsFile.exists() + def set(self, setting: str, value: Setting) -> None: if not isinstance(value, type(self.defaultSettings.get(setting))): return diff --git a/toontown/shtiker/OptionsPage.py b/toontown/shtiker/OptionsPage.py index bd3f314..6af149e 100644 --- a/toontown/shtiker/OptionsPage.py +++ b/toontown/shtiker/OptionsPage.py @@ -496,6 +496,39 @@ class DropdownScrolledFrame(ToontownScrolledFrame): super().destroy() +def _getPossibleScreenSizes(): + """Return the resolutions offered by the Video > Resolution dropdown. + + Uses the same standard list as DisplaySettingsDialog, plus any display modes + supported by the current graphics pipe. Values are [width, height] lists to + match the JSON 'resolution' setting format in Settings.py. + """ + sizes = [ + [640, 480], # 4:3 + [800, 600], # 4:3 + [1024, 768], # 4:3 + [1280, 720], # 16:9 HD + [1280, 800], # 16:10 + [1280, 1024], # 5:4 + [1366, 768], # 16:9 + [1600, 900], # 16:9 + [1600, 1200], # 4:3 + [1920, 1080], # 16:9 Full HD + [1920, 1200], # 16:10 + [2560, 1440], # 16:9 QHD + [3840, 2160], # 16:9 4K + ] + try: + displayInfo = base.pipe.getDisplayInformation() + for i in range(displayInfo.getTotalDisplayModes()): + size = [displayInfo.getDisplayModeWidth(i), displayInfo.getDisplayModeHeight(i)] + if size not in sizes: + sizes.append(size) + except Exception: + pass + return sorted(sizes) + + class OptionElement(DirectFrame): """ Option types: @@ -517,7 +550,7 @@ class OptionElement(DirectFrame): optionOptions[option] = ["Hold", "Toggle"] optionOptions.update({ - "resolution": base.possibleScreenSizes, + "resolution": _getPossibleScreenSizes(), "anisotropic-filter": list(TTLocalizer.OptionAnisotropic), "anti-aliasing": list(TTLocalizer.OptionAntiAlias), "fps-limit": list(TTLocalizer.OptionFPSLimit), diff --git a/toontown/shtiker/ShtikerBook.py b/toontown/shtiker/ShtikerBook.py index ecb6e5c..2f7c92c 100644 --- a/toontown/shtiker/ShtikerBook.py +++ b/toontown/shtiker/ShtikerBook.py @@ -30,13 +30,20 @@ class ShtikerBook(DirectFrame, StateData.StateData): self.__isOpen = 0 self.hide() self.setPos(0, 0, 0.1) + # Order of pages in the ShtikerBook - every page added via addPage() + # must be listed here or it will be rejected. Note that the old + # 'CheckPageTitle' / 'LocationPageTitle' pages were removed from the + # localizer, and the modern pages (Shard, Track, Photo, TIP) take + # their place. self.pageOrder = [TTLocalizer.OptionsPageTitle, - TTLocalizer.CheckPageTitle, - TTLocalizer.LocationPageTitle, + TTLocalizer.ShardPageTitle, TTLocalizer.MapPageTitle, TTLocalizer.InventoryPageTitle, TTLocalizer.QuestPageToonTasks, + TTLocalizer.TrackPageShortTitle, TTLocalizer.SuitPageTitle, + TTLocalizer.SpellbookPageTitle, + TTLocalizer.PhotoPageTitle, TTLocalizer.FishPageTitle, TTLocalizer.KartPageTitle, TTLocalizer.DisguisePageTitle, @@ -46,7 +53,7 @@ class ShtikerBook(DirectFrame, StateData.StateData): TTLocalizer.EventsPageName, TTLocalizer.AutoerPageTitle, TTLocalizer.NewsPageName, - TTLocalizer.SpellbookPageTitle] + TTLocalizer.TIPPageTitle] return def setSafeMode(self, setting): @@ -208,21 +215,12 @@ class ShtikerBook(DirectFrame, StateData.StateData): extraArgs = [] if pageName == TTLocalizer.OptionsPageTitle: iconModels = loader.loadModel('phase_3.5/models/gui/sos_textures') - iconGeom = iconModels.find('**/switch1') + iconGeom = iconModels.find('**/switch') iconModels.detachNode() elif pageName == TTLocalizer.ShardPageTitle: iconModels = loader.loadModel('phase_3.5/models/gui/sos_textures') iconGeom = iconModels.find('**/district') iconModels.detachNode() - elif pageName == TTLocalizer.CheckPageTitle: - iconModels = loader.loadModel('phase_4/models/parties/schtickerbookHostingGUI') - iconGeom = iconModels.find('**/checkmark') - iconScale = 25 - iconModels.detachNode() - elif pageName == TTLocalizer.LocationPageTitle: - iconModels = loader.loadModel('phase_3.5/models/gui/sos_textures') - iconGeom = iconModels.find('**/district') - iconModels.detachNode() elif pageName == TTLocalizer.MapPageTitle: iconModels = loader.loadModel('phase_3.5/models/gui/sos_textures') iconGeom = iconModels.find('**/teleportIcon') @@ -293,9 +291,21 @@ class ShtikerBook(DirectFrame, StateData.StateData): buttonPressedCommand = self.goToNewsPage extraArgs = [page] elif pageName == TTLocalizer.SpellbookPageTitle: - iconModels = loader.loadModel('phase_3.5/models/gui/sos_textures') - iconGeom = iconModels.find('**/spellbookIcon') + # The sos_textures model has no 'spellbookIcon' node; use the + # scroll/note icon from stickerbook_gui for the magic-words page. + iconModels = loader.loadModel('phase_3.5/models/gui/stickerbook_gui') + iconGeom = iconModels.find('**/paper_note') + iconScale = 0.9 iconModels.detachNode() + # Guard against missing icon nodes: an empty NodePath would crash + # DirectButton (AssertionError: !is_empty()), so fall back to a + # text-only tab if an icon can't be found in the model. + if iconGeom is not None and iconGeom.isEmpty(): + self.notify.warning('Icon node not found for page tab %s; using text-only tab.' % pageName) + iconGeom = None + if iconImage is not None and iconImage.isEmpty(): + self.notify.warning('Icon image not found for page tab %s; using text-only tab.' % pageName) + iconImage = None if pageName == TTLocalizer.OptionsPageTitle: pageName = TTLocalizer.OptionsTabTitle elif pageName == TTLocalizer.AutoerPageTitle: diff --git a/toontown/spellbook/MagicWordConfig.py b/toontown/spellbook/MagicWordConfig.py index 03de98d..144e237 100644 --- a/toontown/spellbook/MagicWordConfig.py +++ b/toontown/spellbook/MagicWordConfig.py @@ -48,3 +48,20 @@ ARGUMENT_NAME = 0 ARGUMENT_TYPE = 1 ARGUMENT_REQUIRED = 2 ARGUMENT_DEFAULT = 3 + +# The default values generated with config/spellbook.json to help server hosters get started. +# ToontownMagicWordManagerAI writes these to config/spellbook.json on first run. +CUSTOM_SPELLBOOK_DEFAULT = '''{ + "words": + [ + { + "name": "SetPos", + "access": "MODERATOR" + }, + { + "name": "GetPos", + "access": "MODERATOR" + } + ] +} +''' diff --git a/toontown/toonbase/ToonBase.py b/toontown/toonbase/ToonBase.py index e791727..b4b6368 100644 --- a/toontown/toonbase/ToonBase.py +++ b/toontown/toonbase/ToonBase.py @@ -202,27 +202,28 @@ class ToonBase(OTPBase.OTPBase): multiplier = max(0.5, min(2.0, multiplier)) self.mouseSensitivity = multiplier + def getAdjustedFov(self, baseFov): + """Return the horizontal FOV adjusted for the current aspect ratio. + + Widescreen displays show more of the world horizontally instead of + cropping vertically. At 4:3 (1.333) the base FOV is returned + unchanged; wider aspect ratios get a proportional horizontal FOV + increase (capped to prevent a fish-eye effect). + + This is the canonical helper - use it everywhere a FOV is set so the + game looks correct on widescreen monitors. + """ + aspectRatio = base.camLens.getAspectRatio() + baseAspectRatio = 4.0 / 3.0 + if aspectRatio > baseAspectRatio: + adjustedFov = baseFov * (aspectRatio / baseAspectRatio) + return min(adjustedFov, 90.0) + return baseFov + def updateFovForAspectRatio(self): """Update FOV dynamically based on aspect ratio for proper widescreen support.""" - aspectRatio = base.camLens.getAspectRatio() - - # Base FOV is for 4:3 aspect ratio (1.333...) - # For widescreen, we increase horizontal FOV to prevent stretching - baseAspectRatio = 4.0 / 3.0 - - if aspectRatio > baseAspectRatio: - # Widescreen - increase FOV proportionally - # Calculate the horizontal FOV adjustment - fovMultiplier = aspectRatio / baseAspectRatio - newFov = self.baseFov * fovMultiplier - # Cap maximum FOV to prevent fish-eye effect - newFov = min(newFov, 90.0) - else: - # Standard or narrower aspect ratio - newFov = self.baseFov - - self.camLens.setFov(newFov) - + self.camLens.setFov(self.getAdjustedFov(self.baseFov)) + def getWidescreenGUIXScale(self): """Get the X scaling factor for GUI elements in widescreen. @@ -232,7 +233,17 @@ class ToonBase(OTPBase.OTPBase): currentAspect = base.camLens.getAspectRatio() baseAspect = 4.0 / 3.0 # 1.333... return currentAspect / baseAspect - + + def getFullscreenGuiXScale(self): + """Return the X scale multiplier needed to make a 4:3 full-screen GUI + card cover the current aspect ratio. + + At 4:3 this returns 1.0 (no change); on widescreen displays it returns + >1.0 so backgrounds/overlays designed for a 4:3 screen stretch to fill + the extra horizontal space without leaving black bars at the sides. + """ + return self.getWidescreenGUIXScale() + def getWidescreenXOffset(self, baseX, alignment='left'): """Calculate proper X position for GUI elements in widescreen. @@ -344,6 +355,20 @@ class ToonBase(OTPBase.OTPBase): return Point3(x, 0, z) + def updateDisplay(self): + """Apply the saved display settings (resolution, windowed mode, etc.). + + Called by the OptionsPage when the player changes display options. + """ + try: + if not hasattr(self, 'displayOptions') or not self.displayOptions: + from toontown.toonbase.DisplayOptions import DisplayOptions + self.displayOptions = DisplayOptions() + self.displayOptions.loadFromSettings() + self.displayOptions.restrictToEmbedded(False) + except Exception: + self.notify.warning('updateDisplay: Failed to apply display settings.') + def windowEvent(self, win): OTPBase.OTPBase.windowEvent(self, win) diff --git a/toontown/toonbase/ToontownStart.py b/toontown/toonbase/ToontownStart.py index f198be0..e72ba89 100644 --- a/toontown/toonbase/ToontownStart.py +++ b/toontown/toonbase/ToontownStart.py @@ -71,6 +71,7 @@ ConfigVariableBool('garbage-collect-states').setValue(0) ConfigVariableBool('support-threads').setValue(1) # Texture and Model pools are managed automatically by Panda3D + # Modern launcher/loading overlay (best-effort). try: from toontown.toontowngui.ModernLoadingScreen import ModernLoadingScreen @@ -98,9 +99,16 @@ if not (_modern and _modern.enabled()): backgroundNode = tempLoader.loadSync(Filename('phase_3/models/gui/loading-background')) backgroundNodePath = aspect2d.attachNewNode(backgroundNode, 0) backgroundNodePath.setPos(0.0, 0.0, 0.0) - backgroundNodePath.setScale(render2d, VBase3(1)) + # Widescreen: stretch the 4:3 loading background to cover widescreen displays. + backgroundGuiXScale = 1.0 + try: + backgroundGuiXScale = base.getWidescreenGUIXScale() + except Exception: + pass + backgroundNodePath.setScale(render2d, VBase3(backgroundGuiXScale, 1.0, 1.0)) backgroundNodePath.find('**/fg').setBin('fixed', 20) backgroundNodePath.find('**/bg').setBin('fixed', 10) + base.graphicsEngine.renderFrame() # Optional: auto-start local servers (Astron/UberDOG/AI) before connecting. @@ -187,7 +195,14 @@ else: from direct.gui.DirectGui import OnscreenText serverVersion = ConfigVariableString('server-version', 'no_version_set').value print('ToontownStart: serverVersion: ', serverVersion) -version = OnscreenText(serverVersion, pos=(-1.3, -0.975), scale=0.06, fg=Vec4(0, 0, 1, 0.6), align=TextNode.ALeft) + +# Pin the version text to the left edge of the screen (works in any aspect ratio) +versionX = -1.3 +try: + versionX = base.a2dLeft + 0.033 # same distance from the left edge as -1.3 at 4:3 +except Exception: + pass +version = OnscreenText(serverVersion, pos=(versionX, -0.975), scale=0.06, fg=Vec4(0, 0, 1, 0.6), align=TextNode.ALeft) try: if getattr(base, 'modernLoading', None): base.modernLoading.set_status('Loading client repository…') @@ -197,6 +212,7 @@ except Exception: pass # Progress range: six `loader.loadModel` calls in initNametagGlobals (ToonBase). loader.beginBulkLoad('init', TTLocalizer.LoaderLabel, 6, 0, TTLocalizer.TIP_NONE) + from toontown.distributed.ToontownClientRepository import ToontownClientRepository cr = ToontownClientRepository(serverVersion, launcher) cr.music = music diff --git a/toontown/toontowngui/LoadingAssetPreview.py b/toontown/toontowngui/LoadingAssetPreview.py index aa899fe..814d4d1 100644 --- a/toontown/toontowngui/LoadingAssetPreview.py +++ b/toontown/toontowngui/LoadingAssetPreview.py @@ -9,7 +9,6 @@ import os from typing import Optional from direct.directnotify import DirectNotifyGlobal -from direct.showbase.ShowBaseGlobal import base from direct.task import Task from panda3d.core import ( AmbientLight, @@ -45,6 +44,9 @@ class LoadingAssetPreview: pos: (x, y, z) in aspect2d space frame: (left, right, bottom, top) CardMaker frame (relative scale) """ + # `base` may not exist yet at import time (this module is imported while + # ToonBase is still being constructed), so resolve it lazily at runtime. + from toontown.toonbase.ToonBaseGlobal import base self.detach_card() if not base.win: return @@ -118,6 +120,7 @@ class LoadingAssetPreview: self._clear_holder() def _teardown_buffer(self): + from toontown.toonbase.ToonBaseGlobal import base if self._buffer: try: base.graphicsEngine.removeWindow(self._buffer) @@ -135,6 +138,7 @@ class LoadingAssetPreview: pass def _stop_spin(self): + from toontown.toonbase.ToonBaseGlobal import base if self._spin_task: try: base.taskMgr.remove(self._spin_task) @@ -156,6 +160,7 @@ class LoadingAssetPreview: texture: Optional[Texture] = None, force: bool = False, ): + from toontown.toonbase.ToonBaseGlobal import base if not self._buffer or not self._card: return now = base.globalClock.getRealTime() diff --git a/toontown/toontowngui/ToontownLoadingScreen.py b/toontown/toontowngui/ToontownLoadingScreen.py index 6d1c89e..7082073 100644 --- a/toontown/toontowngui/ToontownLoadingScreen.py +++ b/toontown/toontowngui/ToontownLoadingScreen.py @@ -22,6 +22,17 @@ class ToontownLoadingScreen: self.banner = loader.loadModel('phase_3/models/gui/toon_council').find('**/scroll') self.banner.reparentTo(self.gui) self.banner.setScale(0.4, 0.4, 0.4) + # Widescreen support: stretch the 4:3 background to cover widescreen + # displays, then counter-scale the child elements so they keep their + # original proportions (no black bars, no distorted text). + self.wideScale = 1.0 + try: + self.wideScale = float(base.getWidescreenGUIXScale()) + except Exception: + self.wideScale = 1.0 + if self.wideScale != 1.0: + self.gui.setScale(self.wideScale, 1, 1) + self.banner.setScale(0.4 / self.wideScale, 0.4, 0.4) self.tip = DirectLabel(guiId='ToontownLoadingScreenTip', parent=self.banner, relief=None, text='', text_scale=TTLocalizer.TLStip, textMayChange=1, pos=(-1.2, 0.0, 0.1), text_fg=(0.4, 0.3, 0.2, 1), text_wordwrap=13, text_align=TextNode.ALeft) self.title = DirectLabel(guiId='ToontownLoadingScreenTitle', parent=self.gui, relief=None, pos=(-1.06, 0, -0.77), text='', textMayChange=1, text_scale=0.08, text_fg=(0, 0, 0.5, 1), text_align=TextNode.ALeft) self.waitBar = DirectWaitBar(guiId='ToontownLoadingScreenWaitBar', parent=self.gui, frameSize=(-1.06, @@ -68,6 +79,10 @@ class ToontownLoadingScreen: if gui: self.waitBar.reparentTo(self.gui) self.title.reparentTo(self.gui) + if self.wideScale != 1.0: + # Counter-scale so the bar/title keep 4:3 proportions on widescreen + self.waitBar.setScale(1.0 / self.wideScale, 1, 1) + self.title.setScale(1.0 / self.wideScale, 1, 1) self.gui.reparentTo(aspect2dp, DGG.NO_FADE_SORT_INDEX) else: self.waitBar.reparentTo(aspect2dp, DGG.NO_FADE_SORT_INDEX) @@ -83,6 +98,10 @@ class ToontownLoadingScreen: self.waitBar.finish() self.waitBar.reparentTo(self.gui) self.title.reparentTo(self.gui) + if self.wideScale != 1.0: + # Restore normal scale now that the screen is hidden + self.waitBar.setScale(1, 1, 1) + self.title.setScale(1, 1, 1) self.gui.reparentTo(hidden) return (self.__expectedCount, self.__count) diff --git a/win32/launcher.py b/win32/launcher.py new file mode 100644 index 0000000..4f3999d --- /dev/null +++ b/win32/launcher.py @@ -0,0 +1,392 @@ +#!/usr/bin/env python3 +""" +Unified launcher for Open Toontown (TTBTN). + +Starts the full local server stack (Astron -> UberDOG -> AI) and the game +client from a single console window, interleaving their logs with color +coding and offering a client relaunch loop. No more juggling four windows. + +Port of the "SUPER CFO UNIFIED LAUNCHER", adapted to this source's layout: + * Server entry points (AIStart / UDStart) are configured via command-line + arguments instead of environment variables (see win32/start_*.bat). + * The bundled Python interpreter is read from the PPYTHON_PATH file. + * Astron lives under astron/win32/ and must be launched from that folder + so the relative paths in astrond.yml resolve correctly. + * The client is started with toontown.launcher.QuickStartLauncher and the + LOGIN_TOKEN environment variable (tt-specific-login). +""" + +import ctypes +import json +import os +import socket +import subprocess +import sys +import threading +import time + +# Enable ANSI escape processing on the Windows console +COLOR_SYSTEM = "\033[97;1m" # Bold White +COLOR_ASTRON = "\033[96m" # Cyan +COLOR_UBERDOG = "\033[92m" # Green +COLOR_AI = "\033[93m" # Yellow +COLOR_CLIENT = "\033[95m" # Magenta +COLOR_RESET = "\033[0m" + +# Fixed infrastructure ports (must match astron/config/astrond.yml) +EVENTLOGGER_IP = "127.0.0.1:7197" +STATESERVER = "4002" +CLIENT_AGENT_PORT = 7198 + +# Thread-safe printer +print_lock = threading.Lock() + + +def enable_ansi(): + if os.name == 'nt': + try: + kernel32 = ctypes.windll.kernel32 + h_stdout = kernel32.GetStdHandle(-11) # STD_OUTPUT_HANDLE + mode = ctypes.c_ulong() + if kernel32.GetConsoleMode(h_stdout, ctypes.byref(mode)): + # ENABLE_VIRTUAL_TERMINAL_PROCESSING + kernel32.SetConsoleMode(h_stdout, mode.value | 0x0004) + except Exception: + pass + + +def safe_print(prefix, color_code, text): + with print_lock: + encoding = sys.stdout.encoding or 'utf-8' + for line in text.splitlines(): + cleaned = line.encode(encoding, errors='replace').decode(encoding) + sys.stdout.write("%s%-10s | %s%s\n" % (color_code, prefix, cleaned, COLOR_RESET)) + sys.stdout.flush() + + +# Stream reader for subprocess output +def stream_reader(pipe, prefix, color_code): + try: + for line in iter(pipe.readline, b''): + try: + line_str = line.decode('utf-8', errors='replace') + except Exception: + line_str = line.decode('cp1252', errors='replace') + safe_print(prefix, color_code, line_str.rstrip('\r\n')) + except Exception as e: + safe_print("[System]", COLOR_SYSTEM, "Error reading output from %s: %s" % (prefix, e)) + + +def find_python(root): + """Resolve the bundled interpreter via the PPYTHON_PATH file (sys.executable fallback).""" + pp = None + try: + with open(os.path.join(root, 'PPYTHON_PATH'), 'r', encoding='utf-8') as f: + pp = f.read().strip() + except Exception: + pass + if pp: + if not os.path.isabs(pp): + pp = os.path.join(root, pp) + pp = os.path.normpath(pp) + if os.path.isfile(pp): + return pp + safe_print("[System]", COLOR_SYSTEM, "PPYTHON_PATH points to a missing file (%s); falling back to %s" % (pp, sys.executable)) + return sys.executable + safe_print("[System]", COLOR_SYSTEM, "PPYTHON_PATH not found; falling back to %s" % sys.executable) + return sys.executable + + +def find_astrond(root): + candidates = [ + os.path.join(root, 'astron', 'win32', 'astrond.exe'), + os.path.join(root, 'astron', 'astrond.exe'), + os.path.join(root, 'astron', 'bin', 'astrond.exe'), + os.path.join(root, 'astron', 'astrond'), + ] + for c in candidates: + if os.path.isfile(c): + return c + return None + + +def split_host_port(value, default_port): + host = value + port = default_port + if ':' in value: + host, port = value.rsplit(':', 1) + try: + port = int(port) + except ValueError: + port = default_port + return host, port + + +def is_tcp_open(host, port, timeout_s=0.5): + try: + with socket.create_connection((host, port), timeout=timeout_s): + return True + except OSError: + return False + + +def wait_for_port(host, port, timeout_s, label): + deadline = time.time() + timeout_s + while time.time() < deadline: + if is_tcp_open(host, port): + return True + time.sleep(0.25) + safe_print("[System]", COLOR_SYSTEM, "Timed out waiting for %s (%s:%s)." % (label, host, port)) + return False + + +def configure_launcher(config, config_path, force_prompt=False): + if not force_prompt: + safe_print("[System]", COLOR_SYSTEM, "--------------------------------------------------------") + safe_print("[System]", COLOR_SYSTEM, "Current saved settings:") + safe_print("[System]", COLOR_SYSTEM, " Player Name: %s" % config['player_name']) + safe_print("[System]", COLOR_SYSTEM, " District Name: %s" % config['district_name']) + safe_print("[System]", COLOR_SYSTEM, " Astron (MD) IP: %s" % config['astron_ip']) + safe_print("[System]", COLOR_SYSTEM, "--------------------------------------------------------") + + try: + use_saved = input("Use these settings? [Y/n]: ").strip().lower() + except KeyboardInterrupt: + raise + except Exception: + use_saved = 'y' + if use_saved not in ('n', 'no'): + return config + + # Prompt for each value + new_config = {} + try: + val = input("Enter player name [%s]: " % config['player_name']).strip() + new_config['player_name'] = val if val else config['player_name'] + + val = input("Enter district name [%s]: " % config['district_name']).strip() + new_config['district_name'] = val if val else config['district_name'] + + val = input("Enter Astron IP (MessageDirector) [%s]: " % config['astron_ip']).strip() + new_config['astron_ip'] = val if val else config['astron_ip'] + except KeyboardInterrupt: + raise + except Exception as e: + safe_print("[System]", COLOR_SYSTEM, "Error reading input: %s. Using defaults." % e) + return config + + try: + with open(config_path, "w") as f: + json.dump(new_config, f, indent=4) + safe_print("[System]", COLOR_SYSTEM, "Settings saved to config file.") + except Exception as e: + safe_print("[System]", COLOR_SYSTEM, "Could not save config file: %s" % e) + + return new_config + + +def main(): + enable_ansi() + + # Compute directories + win32_dir = os.path.dirname(os.path.abspath(__file__)) + root_dir = os.path.dirname(win32_dir) + + # Load configuration + config_path = os.path.join(win32_dir, "launcher_config.json") + defaults = { + "player_name": "dev", + "district_name": "Toon Valley", + "astron_ip": "127.0.0.1:7199" + } + config = defaults.copy() + if os.path.exists(config_path): + try: + with open(config_path, "r") as f: + saved = json.load(f) + for k, v in saved.items(): + config[k] = v + except Exception as e: + safe_print("[System]", COLOR_SYSTEM, "Error loading config file: %s" % e) + check_dependencies = bool(config.get('check_dependencies', True)) + + # Locate the bundled interpreter and astron binary + ppython_path = find_python(root_dir) + astrond = find_astrond(root_dir) + if astrond is None: + safe_print("[System]", COLOR_SYSTEM, "ERROR: Astron binary not found under astron/ (expected astron/win32/astrond.exe)!") + sys.exit(1) + astron_win32_dir = os.path.join(root_dir, 'astron', 'win32') + + # Prompt user + safe_print("[System]", COLOR_SYSTEM, "========================================================") + safe_print("[System]", COLOR_SYSTEM, " OPEN TOONTOWN UNIFIED LAUNCHER ") + safe_print("[System]", COLOR_SYSTEM, "========================================================") + + try: + config = configure_launcher(config, config_path, force_prompt=False) + except KeyboardInterrupt: + safe_print("[System]", COLOR_SYSTEM, "Aborted.") + sys.exit(0) + + # Dependency verification (optional; set "check_dependencies": false in the + # config to skip. Non-fatal and bounded so it can never hang the launcher.) + req_file = os.path.join(root_dir, "requirements.txt") + if check_dependencies and os.path.exists(req_file): + safe_print("[System]", COLOR_SYSTEM, "Verifying dependency installation...") + try: + subprocess.run( + [ppython_path, "-m", "pip", "install", "-q", "-r", req_file], + timeout=90, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + except Exception as e: + safe_print("[System]", COLOR_SYSTEM, "Warning: Python dependency check returned error: %s" % e) + + # Build commands (this source configures servers via CLI args, see win32/start_*.bat) + md_host, md_port = split_host_port(config['astron_ip'], 7199) + + astron_cmd = [astrond, "--loglevel", "info", "../config/astrond.yml"] + + ud_cmd = [ + ppython_path, "-u", "-m", "toontown.uberdog.UDStart", + "--base-channel", "1000000", + "--max-channels", "999999", + "--stateserver", STATESERVER, + "--messagedirector-ip", config['astron_ip'], + "--eventlogger-ip", EVENTLOGGER_IP, + ] + + ai_cmd = [ + ppython_path, "-u", "-m", "toontown.ai.AIStart", + "--base-channel", "401000000", + "--max-channels", "999999", + "--stateserver", STATESERVER, + "--messagedirector-ip", config['astron_ip'], + "--eventlogger-ip", EVENTLOGGER_IP, + "--district-name", config['district_name'], + ] + + client_env = os.environ.copy() + client_env["LOGIN_TOKEN"] = config['player_name'] + client_cmd = [ppython_path, "-u", "-m", "toontown.launcher.QuickStartLauncher"] + + active_processes = {} + + def cleanup(): + safe_print("[System]", COLOR_SYSTEM, "Shutting down all background processes...") + # Terminate gently first (reverse startup order: AI, UberDOG, Astron) + for name in ["AI", "Uberdog", "Astron"]: + p = active_processes.get(name) + if p and p.poll() is None: + try: + p.terminate() + except Exception: + pass + time.sleep(1.0) + # Kill if still alive + for name in ["AI", "Uberdog", "Astron"]: + p = active_processes.get(name) + if p and p.poll() is None: + try: + p.kill() + except Exception: + pass + active_processes.clear() + + def servers_running(): + alive = True + for name in ["Astron", "Uberdog", "AI"]: + p = active_processes.get(name) + if p and p.poll() is not None: + safe_print("[System]", COLOR_SYSTEM, "WARNING: %s server is not running (exited early)." % name) + alive = False + return alive + + try: + # Start Astron + safe_print("[System]", COLOR_SYSTEM, "Starting Astron...") + p = subprocess.Popen(astron_cmd, cwd=astron_win32_dir, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + active_processes["Astron"] = p + threading.Thread(target=stream_reader, args=(p.stdout, "[Astron]", COLOR_ASTRON), daemon=True).start() + + if not wait_for_port(md_host, md_port, timeout_s=45, label="MessageDirector"): + safe_print("[System]", COLOR_SYSTEM, "Astron may not be ready; continuing anyway...") + + # Start Uberdog + safe_print("[System]", COLOR_SYSTEM, "Starting UberDOG...") + p = subprocess.Popen(ud_cmd, cwd=root_dir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + active_processes["Uberdog"] = p + threading.Thread(target=stream_reader, args=(p.stdout, "[Uberdog]", COLOR_UBERDOG), daemon=True).start() + time.sleep(1.0) + + # Start AI + safe_print("[System]", COLOR_SYSTEM, "Starting AI (district '%s')..." % config['district_name']) + p = subprocess.Popen(ai_cmd, cwd=root_dir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + active_processes["AI"] = p + threading.Thread(target=stream_reader, args=(p.stdout, "[AI]", COLOR_AI), daemon=True).start() + + # Give UberDOG/AI a moment to register with the cluster before the client + # tries to log in (the client-agent port opens as soon as Astron is up). + safe_print("[System]", COLOR_SYSTEM, "Waiting for UberDOG/AI to come online...") + time.sleep(5.0) + + # Client loop (allows restarting without restarting the servers) + while True: + servers_running() + + # Wait for the client agent (7198) so the client never races a cold start + if not is_tcp_open(md_host, CLIENT_AGENT_PORT, timeout_s=0.5): + wait_for_port(md_host, CLIENT_AGENT_PORT, timeout_s=30, label="Client Agent") + + safe_print("[System]", COLOR_SYSTEM, "Starting game client for '%s'..." % client_env["LOGIN_TOKEN"]) + p_client = subprocess.Popen(client_cmd, cwd=root_dir, env=client_env, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + active_processes["Client"] = p_client + threading.Thread(target=stream_reader, args=(p_client.stdout, "[Client]", COLOR_CLIENT), daemon=True).start() + + # Wait for client to exit + while p_client.poll() is None: + time.sleep(0.5) + for name in ["Astron", "Uberdog", "AI"]: + proc = active_processes.get(name) + if proc and proc.poll() is not None and name in active_processes: + safe_print("[System]", COLOR_SYSTEM, "WARNING: %s process has stopped running!" % name) + del active_processes[name] + + safe_print("[System]", COLOR_SYSTEM, "Client process has exited.") + active_processes.pop("Client", None) + + # Provide options to relaunch client or quit + safe_print("[System]", COLOR_SYSTEM, "Options: [R]elaunch Client | [C]hange Settings & Relaunch | [Enter] to exit all") + try: + choice = input("Enter choice: ").strip().lower() + except KeyboardInterrupt: + break + except Exception: + choice = '' + + if choice == 'r': + continue + elif choice == 'c': + # Force prompt for config (district name applies after a full restart) + try: + config = configure_launcher(config, config_path, force_prompt=True) + except KeyboardInterrupt: + break + client_env["LOGIN_TOKEN"] = config['player_name'] + continue + else: + break + + except KeyboardInterrupt: + safe_print("[System]", COLOR_SYSTEM, "Interrupted by user.") + finally: + cleanup() + safe_print("[System]", COLOR_SYSTEM, "Unified launcher finished.") + + +if __name__ == "__main__": + main() diff --git a/win32/old/startall.bat b/win32/old/startall.bat index dd272c3..0aea8f9 100644 --- a/win32/old/startall.bat +++ b/win32/old/startall.bat @@ -1,11 +1,11 @@ @echo off -start "Starting Astron..." "start_astron_server.bat" -timeout /t 1 >nul -start "Starting UberDOG..." "start_uberdog_server.bat" -timeout /t 3 >nul -start "Starting AI..." "start_ai_server.bat" -timeout /t 3 >nul -start "Starting the game..." "start_game.bat" +title Open Toontown - Unified Launcher +cd /d %~dp0.. -rem Tip: create a new test account/toon with: -rem ..\Panda3D\python\ppython.exe ..\tools\create_test_account.py --username test --toon-name "Test Toon" +rem Read the contents of PPYTHON_PATH into %PPYTHON_PATH%: +set /P PPYTHON_PATH=