Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
2026-05-21: New W7 sections: Zenith Market and Research
2026-04-28: Updates from patch v2.503
2026-04-16: Updates from patch v2.502
2026-03-29: Crash fixes + new St Patrick's event items
Expand Down
14 changes: 14 additions & 0 deletions mysite/consts/consts_w7.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,17 @@
for index, (name, max_level, base_value, _, bonus, description ) in enumerate(LegendTalents)
if name.lower() != "filler"
}

# Last updated in v2.505 May 18
ZenithMarket = ["TRUE_ZEN 1 1.14 250 2 1 }x_higher_bonuses_from_Zenith_Statues".split(" ", ),"KRUK_BUBBLES 2 6 5 1 1 Adds_a_new_bubble_for_Kattlekruk_to_boost!".split(" ", ),"LAMP_BOOST 5 1.09 200 1 1 }x_higher_bonuses_from_The_Lamp_in_Caverns".split(" ", ),"DOUBLE_CLUSTER 8 1.17 100 5 1 +{%_chance_for_a_Double_Zenith_Cluster_drop".split(" ", ),"BUBBLE_BOOST 15 1.5 25 2 1 +{_daily_LVs_for_all_Kattlekruk_bubbles".split(" ", ),"SUPER_DUPERS 50 1.7 25 1 1 Super_Talents_get_+{_more_LVs".split(" "),"MOST_GRANDIOSE 250 1.25 50 4 1 }x_Grand_Discovery_Chance_in_Spelunking".split(" ", ),"GIGA_SYMBOLS 1000 1.15 100 1 1 }x_Sneaking_Symbol_success_chance".split(" ", ),"WOOZLE_WUZZLE 5000 1.125 30 1 1 +{%_EXP_Gain_for_the_Research_skill!".split(" ", ),"CLASSY_GOGO 25000 1.115 100 1 1 }x_Class_EXP_gain,_for_now...".split(" ", ), ]
zenith_market_upgrade_data = []
for upgrade in ZenithMarket:
name, base_price, price_mult_per_level, max_level, bonus_per_level, _, description_template = upgrade
zenith_market_upgrade_data.append({
"Name": name.replace("_", " "),
"Base Price": parse_number(base_price),
"Price Mult per Level": parse_number(price_mult_per_level),
"Max Level": parse_number(max_level),
"Bonus per Level": parse_number(bonus_per_level),
"Description Template": description_template.replace("_", " "),
})
3 changes: 3 additions & 0 deletions mysite/consts/idleon/consts_idleon.py

Large diffs are not rendered by default.

38 changes: 38 additions & 0 deletions mysite/consts/idleon/w7/research.py

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions mysite/models/account_calcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2223,6 +2223,8 @@ def _calculate_w7(account):
_calculate_w7_coral_reef(account)
account.meritocracy.calculate_bonuses()
account.gallery.calculate_bonuses(account)
account.zenith_market.calculate_bonuses()
account.research.calculate_bonuses()


def _calculate_w7_coral_reef(account):
Expand Down
4 changes: 4 additions & 0 deletions mysite/models/general/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
from models.w6.emperor import Emperor
from models.w6.beanstalk import Beanstalk
from models.w6.sneaking import Sneaking
from models.w7.research import Research
from models.w7.spelunk import Spelunk
from models.w7.advice_fish import AdviceFish
from models.w7.clam_work import ClamWork
from models.w7.meritocracy import Meritocracy
from models.w7.gallery import Gallery
from models.w7.zenith_market import ZenithMarket
from utils.safer_data_handling import safe_loads, safer_get
from utils.text_formatting import InputType
from flask import g
Expand Down Expand Up @@ -99,6 +101,8 @@ def __init__(self, json_data, source_string: InputType):
self.clam_work = ClamWork(self.raw_data)
self.meritocracy = Meritocracy(self.raw_data)
self.gallery = Gallery(self.raw_data)
self.zenith_market = ZenithMarket(self.raw_data)
self.research = Research(self.raw_data)

def add_alert_list(
self, group_name: str, advice_list: list[Advice | None] | set[Advice | None]
Expand Down
153 changes: 153 additions & 0 deletions mysite/models/w7/research.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
from consts.consts_autoreview import ValueToMulti
from consts.idleon.consts_idleon import MapDispName
from consts.idleon.w7.research import research_grid_upgrade_data, research_grid_row_size, observation_data, \
posty_notes_descriptions
from models.advice.advice import Advice
from utils.logging import get_logger
from utils.number_formatting import round_and_trim
from utils.safer_data_handling import safe_loads, safer_index, safer_math_pow, safer_get

logger = get_logger(__name__)

class ResearchGridUpgrade:
def __init__(self, info: dict, level: int):
self.grid_index = info["Grid Index"]
self.level = level
self.name = info["Name"]
self.description_template = info["Description Template"]
self.max_level = info["Max Level"]
self.base_value_per_level = info["Base Value Per Level"]
self.value = 0
self.max_value = self.base_value_per_level * self.max_level
self._image = f"research-grid-{self.grid_index}"

def calculate_bonus(self):
# TODO: any mults that increase research bonuses
self.value = self.level * self.base_value_per_level

def get_bonus_advice(self, link_to_section: bool = True) -> Advice:
label = ""
if link_to_section:
label += "{{Research|#research}} - "
if "{" in self.description_template:
value = self.value
max_value = self.max_value
else:
value = ValueToMulti(self.value)
max_value = ValueToMulti(self.max_value)

# TODO: handle "^x" in description. The values are mostly based on other mechanics
# TODO: handle "$" in description. The values are mostly based on other mechanics

bonus = f"{round_and_trim(value)}/{round_and_trim(max_value)}"
bonus_description = self.description_template.replace("{", bonus).replace("}", bonus).replace("|", str(self.level))
if self.name == "Divine Design":
from utils.misc.has_companion import has_companion
divine_design_description = "You_are_now_permanently_linked_to_Arctis_on_all_characters".replace("_", " ")
if has_companion("King Doot"):
divine_design_description = "Arctis_nods_in_approval..._all_Research_Grid_bonuses_are_1.05x_higher".replace("_", " ")
bonus_description = bonus_description.replace("<", divine_design_description)

label += f"{self.name} ({self.grid_index}):<br>{bonus_description}"
return Advice(
label=label,
picture_class=self._image,
progression=self.level,
goal=self.max_level,
)


class ResearchGrid(dict[str, ResearchGridUpgrade]):
def __init__(self, raw_research_info: list):

research_levels: list[int] = safer_index(raw_research_info, 0, [])
research_levels: list[list[int]] = [research_levels[i:i + research_grid_row_size] for i in range(0, len(research_levels), research_grid_row_size)]
research_levels.reverse()
research_levels: list[int] = [level for row in research_levels for level in row]

for index, info in enumerate(research_grid_upgrade_data):
if info["Name"] == "Name":
continue
level = safer_index(research_levels, index, 0)
upgrade = ResearchGridUpgrade(info, level)
self[upgrade.name] = upgrade

def calculate_bonuses(self):
for upgrade in self.values():
upgrade.calculate_bonus()


class Observation:
def __init__(self,observation_raw_data: dict, index: int, unlocked: bool, level: int, xp:int):
self.name = observation_raw_data["Name"]
self.level_requirement = observation_raw_data["Level Requirement"]
self.description = observation_raw_data["Description"]
self.map = MapDispName[observation_raw_data["Map Index"]].replace("_", " ")
self.unlocked = bool(unlocked)
self.level = level
self.xp = round_and_trim(xp, 0)
self.xp_required = round_and_trim(
(2 + 0.7 * index)
* safer_math_pow(1.75 + index / 200, self.level, )
* (1 + safer_math_pow(index, 2) / 100)
+ self.level
, 0)
self.image = f"observation-{index}"

def get_advice(self) -> Advice:
label = f"{self.name}"
if not self.unlocked:
label += f" ({self.map})<br>{self.description}"
else:
label += f"<br>Level {self.level}: {self.xp}/{self.xp_required} XP"
return Advice(
label=label,
picture_class=self.image,
progression=int(self.unlocked),
goal=1
)

class Observations(dict[str, Observation]):
def __init__(self, raw_research_info: list):
observations_unlocked = safer_index(raw_research_info, 2, [])
observation_xp = safer_index(raw_research_info, 3, [])
observation_levels = safer_index(raw_research_info, 4, [])
for index, (unlocked, xp, level) in enumerate(zip(observations_unlocked, observation_xp, observation_levels)):
observation_raw_data = observation_data[index]
if observation_raw_data["Name"] == "Name":
continue
self[observation_raw_data["Name"]] = Observation(observation_raw_data, index, unlocked, level, xp)


class PostyNote:
def __init__(self, index: int, description: str, research_level: int):
self.description = description
self.unlocked = research_level // 10 >= index + 1
self.image = f"posty-note-{index}"

def get_advice(self):
return Advice(
label=f"{self.description}",
picture_class=self.image,
progression=int(self.unlocked),
goal=1
)

class PostyNotes(dict[str, PostyNote]):
def __init__(self, research_level: int):
for index, description in enumerate(posty_notes_descriptions):
self[str(index)] = PostyNote(index, description, research_level)


class Research:
def __init__(self, raw_data: dict):
research_level = safer_index(safer_get(raw_data, "Lv0_0", []), 20, 0)
raw_research_info = safe_loads(raw_data.get("Research", []))
if not raw_research_info:
logger.warning("Research data not present.")
self.grid = ResearchGrid(raw_research_info)
self.observations = Observations(raw_research_info)
self.posty_notes = PostyNotes(research_level)

def calculate_bonuses(self):
self.grid.calculate_bonuses()
57 changes: 57 additions & 0 deletions mysite/models/w7/zenith_market.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from locale import currency
from math import floor

from consts.consts_autoreview import ValueToMulti
from consts.consts_w7 import zenith_market_upgrade_data
from models.advice.advice import Advice
from utils.logging import get_logger
from utils.safer_data_handling import safe_loads, safer_index, safer_math_pow

logger = get_logger(__name__)


class ZenithMarketUpgrade:
def __init__(self, info: dict, level: int, index: int):
self.name = info["Name"]
self.description_template = info["Description Template"]
self.level = level
self.max_level = info["Max Level"]
self.base_price = info["Base Price"]
self.price_mult_per_level = info["Price Mult per Level"]
self.bonus_per_level = info["Bonus per Level"]
self.price = floor(self.level + self.base_price * safer_math_pow(self.price_mult_per_level, self.level))
self.value = 0

def calculate_bonus(self):
self.value = self.level * self.bonus_per_level

def get_advice(self):
description = self.description_template
if "}" in description:
description = description.replace("}", str(ValueToMulti(self.value)))
elif "{" in description:
description = description.replace("{", str(self.value))
return Advice(
label=f"{self.name}:<br>{description}",
picture_class="zenith-market",
resource="zenith-crystal",
progression=self.level,
goal=self.max_level,
)



class ZenithMarket(dict[str, ZenithMarketUpgrade]):
def __init__(self, raw_data: dict):
raw_spelunk_info = safe_loads(raw_data.get("Spelunk", []))
if not raw_spelunk_info:
logger.warning("Zenith Market data not present.")
market_upgrade_levels: list[int] = safer_index(raw_spelunk_info, 45, [])
for index, info in enumerate(zenith_market_upgrade_data):
level = safer_index(market_upgrade_levels, index, 0)
upgrade = ZenithMarketUpgrade(info, level, index)
self[upgrade.name] = upgrade

def calculate_bonuses(self):
for upgrade in self.values():
upgrade.calculate_bonus()
Loading
Loading