Widescreen & data: apply widescreen GUI fixes, add spellbook config and building data, unified win32 launcher

This commit is contained in:
Toontown Super 2026-08-02 16:42:34 -04:00
parent d1a7d29b15
commit 21b87b6dcf
56 changed files with 5178 additions and 113 deletions

14
.gitignore vendored
View File

@ -69,4 +69,16 @@ htmlcov/
*.tar.bz2
*.tar.xz
*.tar.zst
```
# 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

View File

@ -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).

13
config/spellbook.json Normal file
View File

@ -0,0 +1,13 @@
{
"words":
[
{
"name": "SetPos",
"access": "MODERATOR"
},
{
"name": "GetPos",
"access": "MODERATOR"
}
]
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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)

View File

@ -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):

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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():

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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')

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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):

View File

@ -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)

View File

@ -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()

View File

@ -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()

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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):

View File

@ -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):

View File

@ -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):

View File

@ -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

View File

@ -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),

View File

@ -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:

View File

@ -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"
}
]
}
'''

View File

@ -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)

View File

@ -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

View File

@ -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()

View File

@ -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)

392
win32/launcher.py Normal file
View File

@ -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()

View File

@ -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=<PPYTHON_PATH
rem Launch the unified launcher (starts Astron, UberDOG, AI and the game client
rem from this single window). The individual start_*_server.bat scripts remain
rem available for advanced/manual use.
"%PPYTHON_PATH%" -u win32\launcher.py

11
win32/startall.bat Normal file
View File

@ -0,0 +1,11 @@
@echo off
title Open Toontown - Unified Launcher
cd /d %~dp0..
rem Read the contents of PPYTHON_PATH into %PPYTHON_PATH%:
set /P PPYTHON_PATH=<PPYTHON_PATH
rem Launch the unified launcher (starts Astron, UberDOG, AI and the game client
rem from this single window). The individual start_*_server.bat scripts remain
rem available for advanced/manual use.
"%PPYTHON_PATH%" -u win32\launcher.py