diff --git a/economy_config.txt b/economy_config.txt new file mode 100644 index 00000000..f3eb9813 --- /dev/null +++ b/economy_config.txt @@ -0,0 +1 @@ +{"cycling_levels": [{"level": 1, "xp": 0, "drops": 0, "entitlement_1": "ENTITLEMENT_KIT_ZWIFT"}, {"level": 2, "xp": 750, "drops": 50000, "f4": 1, "entitlement_1": "ENTITLEMENT_KIT_BASIC", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 3, "xp": 1500, "drops": 100000, "f4": 1, "entitlement_1": "ENTITLEMENT_HELMET_BLACK", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 4, "xp": 2500, "drops": 150000, "f4": 2, "entitlement_1": "ENTITLEMENT_GLASSES_BASIC", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 5, "xp": 3500, "drops": 200000, "f4": 1, "entitlement_1": "ENTITLEMENT_SHOES_BLACK", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 6, "xp": 5000, "drops": 250000, "f4": 2, "entitlement_1": "ENTITLEMENT_GLOVES_ZWIFT_WHITE", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 7, "xp": 6500, "drops": 300000, "f4": 3, "entitlement_1": "ENTITLEMENT_SOCKS_SOLID", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 8, "xp": 8000, "drops": 350000, "f4": 2, "entitlement_1": "ENTITLEMENT_KIT_VINTAGE01", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 9, "xp": 9500, "drops": 400000, "f4": 1, "entitlement_1": "ENTITLEMENT_KIT_CAMOJERSEYS", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 10, "xp": 11000, "drops": 450000, "f4": 2, "entitlement_1": "ENTITLEMENT_GLASSES_OAKLEY", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 11, "xp": 13000, "drops": 500000, "f4": 1, "entitlement_1": "ENTITLEMENT_KIT_CAMOJERSEYSDIGITAL", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 12, "xp": 15000, "drops": 550000, "f4": 1, "entitlement_1": "ENTITLEMENT_KIT_BASIC2", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 13, "xp": 17000, "drops": 600000, "f4": 3, "entitlement_1": "ENTITLEMENT_SOCKS_DOT", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 14, "xp": 19000, "drops": 650000, "f4": 2, "entitlement_1": "ENTITLEMENT_GLOVES_PATTERN", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 15, "xp": 21000, "drops": 700000, "f4": 1, "entitlement_1": "ENTITLEMENT_15_JERSEY", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 16, "xp": 23500, "drops": 750000, "f4": 1, "entitlement_1": "ENTITLEMENT_GLASSES_COOL01", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 17, "xp": 26000, "drops": 800000, "f4": 2, "entitlement_1": "ENTITLEMENT_SOCKS_STRIPPED", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 18, "xp": 28500, "drops": 850000, "f4": 1, "entitlement_1": "ENTITLEMENT_KIT_ZWIFTCLASSY", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 19, "xp": 31000, "drops": 900000, "f4": 2, "entitlement_1": "ENTITLEMENT_GLASSES_COOL02", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 20, "xp": 33500, "drops": 950000, "f4": 3, "entitlement_1": "ENTITLEMENT_KIT_LEVEL_20", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 21, "xp": 36500, "drops": 1000000, "f4": 2, "entitlement_1": "ENTITLEMENT_KIT_ZWIFTNEON", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 22, "xp": 39500, "drops": 1050000, "f4": 3, "entitlement_1": "ENTITLEMENT_SOCKS_PATTERNED", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 23, "xp": 42500, "drops": 1100000, "f4": 2, "entitlement_1": "ENTITLEMENT_GLOVES_ZWIFT_BLACK", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 24, "xp": 45500, "drops": 1150000, "f4": 3, "entitlement_1": "ENTITLEMENT_HELMET_SKATER_BOWL", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 25, "xp": 48500, "drops": 1200000, "f4": 1, "entitlement_1": "ENTITLEMENT_KIT_LEVEL_25", "entitlement_2": "ENTITLEMENT_HEADWEAR_CYCLINGCAP"}, {"level": 26, "xp": 52000, "drops": 1250000, "f4": 1, "entitlement_1": "ENTITLEMENT_GLASSES_POC", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 27, "xp": 55500, "drops": 1300000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_SHOES_SWORKS", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 28, "xp": 59000, "drops": 1350000, "f4": 1, "entitlement_1": "ENTITLEMENT_SOCKS_DOTS", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 29, "xp": 62500, "drops": 1400000, "f4": 1, "entitlement_1": "ENTITLEMENT_HELMET_SWORK", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 30, "xp": 66000, "drops": 1450000, "f4": 3, "entitlement_1": "ENTITLEMENT_KIT_LEVEL_30", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 31, "xp": 70000, "drops": 1500000, "f4": 1, "entitlement_1": "ENTITLEMENT_GLASSES_OAKLEY_80S", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 32, "xp": 74000, "drops": 1550000, "f4": 1, "entitlement_1": "ENTITLEMENT_HEADGEAR_NEWSY", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 33, "xp": 78000, "drops": 1600000, "f4": 1, "entitlement_1": "ENTITLEMENT_GLOVES_PACK_FLUORO", "entitlement_2": "ENTITLEMENT_HELMET_LIMAR_AIR_SPEED_WHITE"}, {"level": 34, "xp": 82000, "drops": 1650000, "f4": 1, "entitlement_1": "ENTITLEMENT_KIT_MONOCHROME", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 35, "xp": 86000, "drops": 1700000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_SHOES_MAVIC", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 36, "xp": 90500, "drops": 1750000, "f4": 1, "entitlement_1": "ENTITLEMENT_SOCKS_FOOD", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 37, "xp": 95000, "drops": 1800000, "f4": 1, "entitlement_1": "ENTITLEMENT_HELMET_BELL_JAVELIN_LONG_TAIL", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 38, "xp": 99500, "drops": 1850000, "f4": 1, "entitlement_1": "ENTITLEMENT_GLOVES_PACK_VINTAGE", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 39, "xp": 104000, "drops": 1900000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_SHOES_LEATHER", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 40, "xp": 108500, "drops": 1950000, "f4": 3, "entitlement_1": "ENTITLEMENT_KIT_LEVEL_40", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 41, "xp": 113500, "drops": 2000000, "f4": 1, "entitlement_1": "ENTITLEMENT_GLASSES_U2", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 42, "xp": 118500, "drops": 2050000, "f4": 1, "entitlement_1": "ENTITLEMENT_KIT_LAZ_CLAIRE", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 43, "xp": 123500, "drops": 2100000, "f4": 1, "entitlement_1": "ENTITLEMENT_HELMET_80S_HAIRNET", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 44, "xp": 128500, "drops": 2150000, "f4": 1, "entitlement_1": "ENTITLEMENT_KIT_SKI", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 45, "xp": 133500, "drops": 2200000, "f4": 1, "entitlement_1": "ENTITLEMENT_HELMET_GIRO_SYNTHE", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 46, "xp": 139000, "drops": 2250000, "f4": 1, "entitlement_1": "ENTITLEMENT_KIT_COLOR_PAC", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 47, "xp": 144500, "drops": 2300000, "f4": 1, "entitlement_1": "ENTITLEMENT_GLASSES_OLD_SCHOOL_RIDING_GOGGLES", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 48, "xp": 150000, "drops": 2350000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_SHOES_BONT", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 49, "xp": 155500, "drops": 2400000, "f4": 1, "entitlement_1": "ENTITLEMENT_HELMET_GIRO_VANQUISH_AERO", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 50, "xp": 161000, "drops": 2450000, "f4": 3, "entitlement_1": "ENTITLEMENT_KIT_LEVEL_50", "entitlement_2": "ENTITLEMENT_SOCKS_SOCKS_FLAMETRAILS"}, {"level": 51, "xp": 167000, "drops": 2500000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_ZWIFTFOOD", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 52, "xp": 173000, "drops": 2550000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_EVENTS_TEALPINK2020", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 53, "xp": 179000, "drops": 2600000, "f4": 1, "entitlement_1": "ENTITLEMENT_GLASSES_TEALPINK2020GLASSES01", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 54, "xp": 185000, "drops": 2650000, "f4": 1, "entitlement_1": "ENTITLEMENT_PAINTJOB_TEALPINKD", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 55, "xp": 191000, "drops": 2700000, "f4": 1, "entitlement_1": "ENTITLEMENT_GLASSES_REARVIEW", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 56, "xp": 197500, "drops": 2750000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_ZWIFTANIMALS", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 57, "xp": 204000, "drops": 2800000, "f4": 1, "entitlement_1": "ENTITLEMENT_SOCKS_SOCKS_ZWIFTCUTE01", "entitlement_2": "ENTITLEMENT_SOCKS_SOCKS_ZWIFTCUTE02"}, {"level": 58, "xp": 210500, "drops": 2850000, "f4": 1, "entitlement_1": "ENTITLEMENT_SOCKS_SOCKS_TEALPINK2020", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 59, "xp": 217000, "drops": 2900000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_HEADGEAR_BACKWARDSCAPFLUORO01", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 60, "xp": 223500, "drops": 2950000, "f4": 3, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_ZWIFT_LVL60", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 61, "xp": 230500, "drops": 3000000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_GLOVES_COOLTONEGLOVES", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 62, "xp": 237500, "drops": 3050000, "f4": 1, "entitlement_1": "ENTITLEMENT_SOCKS_SOCKS_BIKEPACKER", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 63, "xp": 244500, "drops": 3100000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_LONDONTUBE", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 64, "xp": 251500, "drops": 3150000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_SHOES_POPARTL", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 65, "xp": 258500, "drops": 3200000, "f4": 1, "entitlement_1": "ENTITLEMENT_SOCKS_SOCKS_TORTOISEHARE", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 66, "xp": 266000, "drops": 3250000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_BIKEPACKER", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 67, "xp": 273500, "drops": 3300000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_HEADGEAR_GIROARIESSPHERICAL", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 68, "xp": 281000, "drops": 3350000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_ALPEDUKNIT", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 69, "xp": 288500, "drops": 3400000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_HEADGEAR_RUNNINGCAPBIKEPACKER", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 70, "xp": 296000, "drops": 3450000, "f4": 3, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_ZWIFT_LVL70", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 71, "xp": 304000, "drops": 3500000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_HEADGEAR_SCOTTYTHESQUIRREL", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 72, "xp": 312000, "drops": 3550000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_MAKURIBLOSSOMS", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 73, "xp": 320000, "drops": 3600000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_HEADGEAR_SOCKS_DINOPOWER", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 74, "xp": 328000, "drops": 3650000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_OUTFIELD", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 75, "xp": 336000, "drops": 3700000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_SHOES_RAPHAPROTEAML", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 76, "xp": 345000, "drops": 3750000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_DINOPOWER", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 77, "xp": 354000, "drops": 3800000, "f4": 1, "entitlement_1": "ENTITLEMENT_SOCKS_SOCKS_SCOTTYTHESQUIRREL", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 78, "xp": 363000, "drops": 3850000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_HAWAIIAN", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 79, "xp": 372000, "drops": 3900000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_SHOES_DINOPOWERL", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 80, "xp": 381000, "drops": 3950000, "f4": 3, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_ZWIFT_LVL80", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 81, "xp": 391000, "drops": 4000000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_HEADGEAR_LIGHTAERO", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 82, "xp": 401000, "drops": 4050000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_WOLFPOWER", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 83, "xp": 411000, "drops": 4100000, "f4": 1, "entitlement_1": "ENTITLEMENT_GLASSES_RAPHAPROTEAM", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 84, "xp": 421000, "drops": 4150000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_SOLIDCOLORS", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 85, "xp": 431000, "drops": 4200000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_SHOES_NIMBLFEATULTIMATEL", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 86, "xp": 441000, "drops": 4250000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_HEADGEAR_KASKELEMENTO", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 87, "xp": 451000, "drops": 4300000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_GRAVELPARTY", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 88, "xp": 461000, "drops": 4350000, "f4": 1, "entitlement_1": "ENTITLEMENT_SOCKS_SOCKS_PARTY", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 89, "xp": 471000, "drops": 4400000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_SHOES_GIROIMPERIALL", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 90, "xp": 481000, "drops": 4450000, "f4": 3, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_ZWIFT_LVL90", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 91, "xp": 492000, "drops": 4500000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_MODERN01", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 92, "xp": 503000, "drops": 4550000, "f4": 1, "entitlement_1": "ENTITLEMENT_SOCKS_SOCKS_MIRAGE", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 93, "xp": 514000, "drops": 4600000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_OUTOFTHISWORLD", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 94, "xp": 525000, "drops": 4650000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_HEADGEAR_CYCLINGCAPMIRAGE", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 95, "xp": 536000, "drops": 4700000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_MIRAGE", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 96, "xp": 547000, "drops": 4750000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_HEADGEAR_SWORKSEVADE3", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 97, "xp": 558000, "drops": 4800000, "f4": 1, "entitlement_1": "ENTITLEMENT_SOCKS_SOCKS_OUTOFTHISWORLD", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 98, "xp": 569000, "drops": 4850000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_SHOES_MIRAGEL", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 99, "xp": 580000, "drops": 4900000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_HEADGEAR_MIRAGE", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 100, "xp": 591000, "drops": 4950000, "f4": 1, "entitlement_1": "ENTITLEMENT_CYCLING_JERSEY_ORIGINALS_ZWIFT_LVL100", "entitlement_2": "ENTITLEMENT_NONE"}], "running_levels": [{"level": 1, "xp": 0, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_KIT_ZWIFT_2019", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 2, "xp": 1000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_RUNNING_OUTFIT03", "entitlement_2": "ENTITLEMENT_GLASSES_BASIC"}, {"level": 3, "xp": 2000, "drops": 0, "f4": 3, "entitlement_1": "ENTITLEMENT_HEADWEAR_SWEATBAND", "entitlement_2": "ENTITLEMENT_RUNNING_SHOES_01"}, {"level": 4, "xp": 3000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_RUNNING_OUTFIT04", "entitlement_2": "ENTITLEMENT_GLASSES_OAKLEY"}, {"level": 5, "xp": 6000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_RUNNING_OUTFIT05", "entitlement_2": "ENTITLEMENT_RUNNING_SHOES_ZWIFT_02_MAGENTA"}, {"level": 6, "xp": 8000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_RUNNING_OUTFIT06", "entitlement_2": "ENTITLEMENT_GLASSES_COOL01"}, {"level": 7, "xp": 10000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_HEADWEAR_VISOR", "entitlement_2": "ENTITLEMENT_SOCKS_STRIPPED"}, {"level": 8, "xp": 13000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_RUNNING_OUTFIT07", "entitlement_2": "ENTITLEMENT_GLASSES_COOL02"}, {"level": 9, "xp": 16000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_RUNNING_OUTFIT08", "entitlement_2": "ENTITLEMENT_SOCKS_PATTERNED"}, {"level": 10, "xp": 20000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_RUNNING_OUTFIT09", "entitlement_2": "ENTITLEMENT_GLASSES_POC"}, {"level": 11, "xp": 24000, "drops": 0, "f4": 3, "entitlement_1": "ENTITLEMENT_RUNNING_SHOES_UNDERARMOUR_HOVR", "entitlement_2": "ENTITLEMENT_SOCKS_DOTS"}, {"level": 12, "xp": 28000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_RUNNING_OUTFIT13", "entitlement_2": "ENTITLEMENT_GLASSES_OAKLEY_80S"}, {"level": 13, "xp": 32000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_RUNNING_OUTFIT12", "entitlement_2": "ENTITLEMENT_SOCKS_SOLID"}, {"level": 14, "xp": 37000, "drops": 0, "f4": 3, "entitlement_1": "ENTITLEMENT_RUNNING_SHOES_ZWIFT_02_BLUE", "entitlement_2": "ENTITLEMENT_SOCKS_FOOD"}, {"level": 15, "xp": 42000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_RUNNING_OUTFIT11", "entitlement_2": "ENTITLEMENT_SOCKS_DOT"}, {"level": 16, "xp": 48000, "drops": 0, "f4": 3, "entitlement_1": "ENTITLEMENT_RUNNING_SHOES_HOKA_CLIFTON", "entitlement_2": "ENTITLEMENT_GLASSES_U2"}, {"level": 17, "xp": 54000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_RUNNING_OUTFIT14", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 18, "xp": 60000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_RUNNING_OUTFIT15", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 19, "xp": 67000, "drops": 0, "f4": 3, "entitlement_1": "ENTITLEMENT_RUNNING_SHOES_ZWIFT_02_GREEN", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 20, "xp": 74000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_RUNNING_OUTFIT10", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 21, "xp": 81000, "drops": 0, "f4": 3, "entitlement_1": "ENTITLEMENT_RUNNING_SHOES_NEWBALANCE_ZANTEV4", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 22, "xp": 88000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_RUNNING_SHIRT_ZWIFT_MALETANKTOP1", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 23, "xp": 95000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_SOCKS_SOCKS_ANIMALS01", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 24, "xp": 102000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_RUNNING_SHIRT_ZWIFT_MALETANKTOP2", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 25, "xp": 109000, "drops": 0, "f4": 3, "entitlement_1": "ENTITLEMENT_RUNNING_SHOES_SAUCONY_ENDORPHIN_2021", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 26, "xp": 117000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_RUNNING_HEADGEAR_VISORBOLD01", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 27, "xp": 125000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_RUNNING_SHIRT_MONOCHROMEMALETANKTOP01", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 28, "xp": 133000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_SOCKS_SOCKS_FRUITS01", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 29, "xp": 141000, "drops": 0, "f4": 1, "entitlement_1": "ENTITLEMENT_RUNNING_SHIRT_FLUOROMALETANKTOP01", "entitlement_2": "ENTITLEMENT_NONE"}, {"level": 30, "xp": 149000, "drops": 0, "f4": 3, "entitlement_1": "ENTITLEMENT_RUNNING_SHOES_ADIDAS_ADIOS_PRO_2020", "entitlement_2": "ENTITLEMENT_NONE"}], "f3": 60, "f4": 21, "f5": 12000} \ No newline at end of file diff --git a/protobuf/login.proto b/protobuf/login.proto index 8678722b..21a44688 100644 --- a/protobuf/login.proto +++ b/protobuf/login.proto @@ -7,6 +7,7 @@ message LoginResponse { required PerSessionInfo info = 2; optional uint32 relay_session_id = 3; optional uint32 expiration = 4; // minutes + optional EconomyConfig economy_config = 5; } message LoginRequest { @@ -27,3 +28,22 @@ message RelaySessionRefreshResponse { required uint32 relay_session_id = 1; required uint32 expiration = 2; // minutes } + +message EconomyConfig { + repeated Level cycling_levels = 1; + repeated Level running_levels = 2; + required uint32 f3 = 3; + required uint32 f4 = 4; + required uint32 f5 = 5; + optional uint32 transition_start = 6; + optional uint32 transition_end = 7; +} + +message Level { + required uint32 level = 1; + required uint32 xp = 2; + required uint32 drops = 3; + optional uint32 f4 = 4; + optional string entitlement_1 = 5; + optional string entitlement_2 = 6; +} diff --git a/protobuf/login_pb2.py b/protobuf/login_pb2.py index 7cf2f966..05a4d707 100644 --- a/protobuf/login_pb2.py +++ b/protobuf/login_pb2.py @@ -14,21 +14,25 @@ import per_session_info_pb2 as per__session__info__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0blogin.proto\x1a\x16per-session-info.proto\"s\n\rLoginResponse\x12\x15\n\rsession_state\x18\x01 \x02(\t\x12\x1d\n\x04info\x18\x02 \x02(\x0b\x32\x0f.PerSessionInfo\x12\x18\n\x10relay_session_id\x18\x03 \x01(\r\x12\x12\n\nexpiration\x18\x04 \x01(\r\"J\n\x0cLoginRequest\x12-\n\nproperties\x18\x01 \x02(\x0b\x32\x19.AnalyticsEventProperties\x12\x0b\n\x03key\x18\x02 \x02(\x0c\"0\n\x16\x41nalyticsEventProperty\x12\n\n\x02\x66\x31\x18\x01 \x02(\t\x12\n\n\x02\x66\x32\x18\x02 \x02(\t\"E\n\x18\x41nalyticsEventProperties\x12)\n\x08property\x18\x02 \x03(\x0b\x32\x17.AnalyticsEventProperty\"K\n\x1bRelaySessionRefreshResponse\x12\x18\n\x10relay_session_id\x18\x01 \x02(\r\x12\x12\n\nexpiration\x18\x02 \x02(\r') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0blogin.proto\x1a\x16per-session-info.proto\"\x9b\x01\n\rLoginResponse\x12\x15\n\rsession_state\x18\x01 \x02(\t\x12\x1d\n\x04info\x18\x02 \x02(\x0b\x32\x0f.PerSessionInfo\x12\x18\n\x10relay_session_id\x18\x03 \x01(\r\x12\x12\n\nexpiration\x18\x04 \x01(\r\x12&\n\x0e\x65\x63onomy_config\x18\x05 \x01(\x0b\x32\x0e.EconomyConfig\"J\n\x0cLoginRequest\x12-\n\nproperties\x18\x01 \x02(\x0b\x32\x19.AnalyticsEventProperties\x12\x0b\n\x03key\x18\x02 \x02(\x0c\"0\n\x16\x41nalyticsEventProperty\x12\n\n\x02\x66\x31\x18\x01 \x02(\t\x12\n\n\x02\x66\x32\x18\x02 \x02(\t\"E\n\x18\x41nalyticsEventProperties\x12)\n\x08property\x18\x02 \x03(\x0b\x32\x17.AnalyticsEventProperty\"K\n\x1bRelaySessionRefreshResponse\x12\x18\n\x10relay_session_id\x18\x01 \x02(\r\x12\x12\n\nexpiration\x18\x02 \x02(\r\"\xa5\x01\n\rEconomyConfig\x12\x1e\n\x0e\x63ycling_levels\x18\x01 \x03(\x0b\x32\x06.Level\x12\x1e\n\x0erunning_levels\x18\x02 \x03(\x0b\x32\x06.Level\x12\n\n\x02\x66\x33\x18\x03 \x02(\r\x12\n\n\x02\x66\x34\x18\x04 \x02(\r\x12\n\n\x02\x66\x35\x18\x05 \x02(\r\x12\x18\n\x10transition_start\x18\x06 \x01(\r\x12\x16\n\x0etransition_end\x18\x07 \x01(\r\"k\n\x05Level\x12\r\n\x05level\x18\x01 \x02(\r\x12\n\n\x02xp\x18\x02 \x02(\r\x12\r\n\x05\x64rops\x18\x03 \x02(\r\x12\n\n\x02\x66\x34\x18\x04 \x01(\r\x12\x15\n\rentitlement_1\x18\x05 \x01(\t\x12\x15\n\rentitlement_2\x18\x06 \x01(\t') _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'login_pb2', globals()) if _descriptor._USE_C_DESCRIPTORS == False: DESCRIPTOR._options = None - _LOGINRESPONSE._serialized_start=39 - _LOGINRESPONSE._serialized_end=154 - _LOGINREQUEST._serialized_start=156 - _LOGINREQUEST._serialized_end=230 - _ANALYTICSEVENTPROPERTY._serialized_start=232 - _ANALYTICSEVENTPROPERTY._serialized_end=280 - _ANALYTICSEVENTPROPERTIES._serialized_start=282 - _ANALYTICSEVENTPROPERTIES._serialized_end=351 - _RELAYSESSIONREFRESHRESPONSE._serialized_start=353 - _RELAYSESSIONREFRESHRESPONSE._serialized_end=428 + _LOGINRESPONSE._serialized_start=40 + _LOGINRESPONSE._serialized_end=195 + _LOGINREQUEST._serialized_start=197 + _LOGINREQUEST._serialized_end=271 + _ANALYTICSEVENTPROPERTY._serialized_start=273 + _ANALYTICSEVENTPROPERTY._serialized_end=321 + _ANALYTICSEVENTPROPERTIES._serialized_start=323 + _ANALYTICSEVENTPROPERTIES._serialized_end=392 + _RELAYSESSIONREFRESHRESPONSE._serialized_start=394 + _RELAYSESSIONREFRESHRESPONSE._serialized_end=469 + _ECONOMYCONFIG._serialized_start=472 + _ECONOMYCONFIG._serialized_end=637 + _LEVEL._serialized_start=639 + _LEVEL._serialized_end=746 # @@protoc_insertion_point(module_scope) diff --git a/scripts/login_to_json.py b/scripts/login_to_json.py new file mode 100644 index 00000000..eb11472b --- /dev/null +++ b/scripts/login_to_json.py @@ -0,0 +1,12 @@ +import json +import sys +sys.path.insert(0, '../protobuf') +import login_pb2 +from google.protobuf.json_format import MessageToDict + +with open("login", "rb") as f: + login = login_pb2.LoginResponse() + login.ParseFromString(f.read()) + +with open('../economy_config.txt', 'w') as f: + json.dump(MessageToDict(login, preserving_proto_field_name=True)['economy_config'], f) diff --git a/standalone.spec b/standalone.spec index ff76e2d8..b391f54e 100644 --- a/standalone.spec +++ b/standalone.spec @@ -10,7 +10,7 @@ version = ET.parse('cdn/gameassets/Zwift_Updates_Root/Zwift_ver_cur.xml').getroo a = Analysis(['standalone.py'], pathex=['protobuf'], binaries=[], - datas=[('ssl/*', 'ssl'), ('start_lines.csv', '.'), ('game_info.txt', '.'), ('variants.txt', '.'), ('bot.txt', '.')], + datas=[('ssl/*', 'ssl'), ('start_lines.csv', '.'), ('game_info.txt', '.'), ('variants.txt', '.'), ('economy_config.txt', '.'), ('bot.txt', '.')], hiddenimports=[], hookspath=[], runtime_hooks=[], diff --git a/variants.txt b/variants.txt index f2fff174..27430cc1 100644 --- a/variants.txt +++ b/variants.txt @@ -1036,7 +1036,7 @@ "boolValue": false }, "ServerConfigXP": { - "varintValue": "0" + "varintValue": "2" }, "ShowRideStreaksScreen": { "boolValue": true diff --git a/zwift_offline.py b/zwift_offline.py index 2f86b739..9e13da27 100644 --- a/zwift_offline.py +++ b/zwift_offline.py @@ -1269,6 +1269,31 @@ def api_users_login(): udp_node.port = 3023 response.relay_session_id = player_id response.expiration = 70 + profile_dir = os.path.join(STORAGE_DIR, str(current_user.player_id)) + config_file = os.path.join(profile_dir, 'economy_config.txt') + if not os.path.isfile(config_file): + with open(os.path.join(SCRIPT_DIR, 'economy_config.txt')) as f: + economy_config = json.load(f) + profile_file = os.path.join(profile_dir, 'profile.bin') + if os.path.isfile(profile_file): + profile = profile_pb2.PlayerProfile() + with open(profile_file, 'rb') as f: + profile.ParseFromString(f.read()) + current_level = profile.achievement_level // 100 + levels = [x for x in economy_config['cycling_levels'] if x['level'] >= current_level] + if len(levels) > 1 and profile.total_xp > levels[1]['xp']: + offset = profile.total_xp - levels[0]['xp'] + transition_end = [x for x in levels if x['xp'] <= profile.total_xp][-1]['level'] + for level in economy_config['cycling_levels']: + if level['level'] >= current_level: + level['xp'] += offset + if transition_end > current_level: + economy_config['transition_start'] = current_level + economy_config['transition_end'] = transition_end + with open(config_file, 'w') as f: + json.dump(economy_config, f, indent=2) + with open(config_file) as f: + Parse(f.read(), response.economy_config) return response.SerializeToString(), 200