Skip to content

Commit

Permalink
Add location type tracking to client UI
Browse files Browse the repository at this point in the history
  • Loading branch information
Salzkorn committed Oct 9, 2023
1 parent b7394df commit 377d512
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 12 deletions.
14 changes: 12 additions & 2 deletions worlds/sc2/Client.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
from CommonClient import CommonContext, server_loop, ClientCommandProcessor, gui_enabled, get_base_parser
from Utils import init_logging, is_windows
from worlds.sc2.Options import MissionOrder, KerriganPrimalStatus, kerrigan_unit_available, Kerriganless, GameSpeed, \
GenericUpgradeItems, GenericUpgradeResearch, ColorChoice, GenericUpgradeMissions, KerriganCheckLevelPackSize, KerriganChecksPerLevelPack
GenericUpgradeItems, GenericUpgradeResearch, ColorChoice, GenericUpgradeMissions, KerriganCheckLevelPackSize, KerriganChecksPerLevelPack, \
LocationInclusion, MissionProgressLocations, OptionalBossLocations, ChallengeLocations, BonusLocations

if __name__ == "__main__":
init_logging("SC2Client", exception_logger="Client")
Expand All @@ -33,7 +34,7 @@
from worlds._sc2common.bot.main import run_game
from worlds._sc2common.bot.player import Bot
from worlds.sc2.Items import lookup_id_to_name, get_full_item_list, ItemData, type_flaggroups, upgrade_numbers, upgrade_numbers_all
from worlds.sc2.Locations import SC2WOL_LOC_ID_OFFSET
from worlds.sc2.Locations import SC2WOL_LOC_ID_OFFSET, LocationType
from worlds.sc2.MissionTables import lookup_id_to_mission, SC2Campaign, lookup_name_to_mission, \
lookup_id_to_campaign, MissionConnection, SC2Mission, campaign_mission_table, SC2Race, get_no_build_missions
from worlds.sc2.Regions import MissionInfo
Expand Down Expand Up @@ -276,6 +277,7 @@ class SC2Context(CommonContext):
generic_upgrade_missions = 0
generic_upgrade_research = 0
generic_upgrade_items = 0
location_inclusions: typing.Dict[LocationType, LocationInclusion] = {}
current_tooltip = None
last_loc_list = None
difficulty_override = -1
Expand Down Expand Up @@ -331,6 +333,14 @@ def on_package(self, cmd: str, args: dict) -> None:
self.levels_per_check = args["slot_data"].get("kerrigan_check_level_pack_size", KerriganCheckLevelPackSize.default)
self.checks_per_level = args["slot_data"].get("kerrigan_checks_per_level_pack", KerriganChecksPerLevelPack.default)

self.location_inclusions = {
LocationType.VICTORY: LocationInclusion.option_enabled, # Victory checks are always enabled
LocationType.MISSION_PROGRESS: args["slot_data"].get("mission_progress_locations", MissionProgressLocations.default),
LocationType.BONUS: args["slot_data"].get("bonus_locations", BonusLocations.default),
LocationType.CHALLENGE: args["slot_data"].get("challenge_locations", ChallengeLocations.default),
LocationType.OPTIONAL_BOSS: args["slot_data"].get("optional_boss_locations", OptionalBossLocations.default),
}

self.build_location_to_mission_mapping()

# Looks for the required maps and mods for SC2. Runs check_game_install_path.
Expand Down
56 changes: 46 additions & 10 deletions worlds/sc2/ClientGui.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@

from CommonClient import CommonContext
from worlds.sc2.Client import SC2Context, calc_unfinished_missions, parse_unlock
from worlds.sc2.MissionTables import lookup_id_to_mission, lookup_name_to_mission
from worlds.sc2.MissionTables import lookup_id_to_mission, lookup_name_to_mission, SC2Mission
from worlds.sc2.Locations import LocationType, lookup_location_id_to_type
from worlds.sc2.Options import LocationInclusion
from worlds.sc2 import SC2World


Expand All @@ -30,6 +32,7 @@ def __init__(self, *args, **kwargs):
super(HoverableButton, self).__init__(*args, **kwargs)
self.layout = FloatLayout()
self.popuplabel = ServerToolTip(text=self.text)
self.popuplabel.padding = [5, 2, 5, 2]
self.layout.add_widget(self.popuplabel)

def on_enter(self):
Expand Down Expand Up @@ -153,11 +156,16 @@ def build_mission_table(self, dt) -> None:
for mission in categories[category]:
text: str = mission
tooltip: str = ""
mission_id: int = lookup_name_to_mission[mission].id
mission_obj: SC2Mission = lookup_name_to_mission[mission]
mission_id: int = mission_obj.id
mission_data = self.ctx.mission_req_table[campaign][mission]
remaining_locations, remaining_count = self.sort_unfinished_locations(mission)
# Map has uncollected locations
if mission in unfinished_missions:
text = f"[color=6495ED]{text}[/color]"
if self.any_valuable_locations(remaining_locations):
text = f"[color=6495ED]{text}[/color]"
else:
text = f"[color=A0BEF4]{text}[/color]"
elif mission in available_missions:
text = f"[color=FFFFFF]{text}[/color]"
# Map requirements not met
Expand All @@ -173,9 +181,6 @@ def build_mission_table(self, dt) -> None:
tooltip += " and "
if mission_data.number:
tooltip += f"{self.ctx.mission_req_table[campaign][mission].number} missions completed"
remaining_location_names: List[str] = [
self.ctx.location_names[loc] for loc in self.ctx.locations_for_mission(mission)
if loc in self.ctx.missing_locations]

if mission_id == self.ctx.final_mission:
if mission in available_missions:
Expand All @@ -186,11 +191,17 @@ def build_mission_table(self, dt) -> None:
tooltip += "\n"
tooltip += "Final Mission"

if remaining_location_names:
if remaining_count > 0:
if tooltip:
tooltip += "\n"
tooltip += f"Uncollected locations:\n"
tooltip += "\n".join(remaining_location_names)
tooltip += "\n\n"
tooltip += f"-- Uncollected locations --"
for loctype in LocationType:
if len(remaining_locations[loctype]) > 0:
if loctype == LocationType.VICTORY:
tooltip += f"\n- {remaining_locations[loctype][0]}"
else:
tooltip += f"\n{self.get_location_type_title(loctype)}:\n- "
tooltip += "\n- ".join(remaining_locations[loctype])

mission_button = MissionButton(text=text, size_hint_y=None, height=50)
mission_button.tooltip_text = tooltip
Expand Down Expand Up @@ -223,6 +234,31 @@ def mission_callback(self, button: MissionButton) -> None:

def finish_launching(self, dt):
self.launching = False

def sort_unfinished_locations(self, mission_name: str) -> (Dict[LocationType, List[str]], int):
locations: Dict[LocationType, List[str]] = {loctype: [] for loctype in LocationType}
count = 0
for loc in self.ctx.locations_for_mission(mission_name):
if loc in self.ctx.missing_locations:
count += 1
locations[lookup_location_id_to_type[loc]].append(self.ctx.location_names[loc])
return locations, count

def any_valuable_locations(self, locations: Dict[LocationType, List[str]]) -> bool:
for loctype in LocationType:
if len(locations[loctype]) > 0 and self.ctx.location_inclusions[loctype] == LocationInclusion.option_enabled:
return True
return False

def get_location_type_title(self, location_type: LocationType) -> str:
title = location_type.name.title().replace("_", " ")
if self.ctx.location_inclusions[location_type] == LocationInclusion.option_nothing:
title += " (Nothing)"
elif self.ctx.location_inclusions[location_type] == LocationInclusion.option_trash:
title += " (Trash)"
else:
title += ""
return title

def start_gui(context: SC2Context):
context.ui = SC2Manager(context)
Expand Down
2 changes: 2 additions & 0 deletions worlds/sc2/Locations.py
Original file line number Diff line number Diff line change
Expand Up @@ -726,3 +726,5 @@ def get_locations(multiworld: Optional[MultiWorld], player: Optional[int]) -> Tu
location_data._replace(name="Beat " + location_data.name.rsplit(": ", 1)[0], code=None)
)
return tuple(location_table + beat_events)

lookup_location_id_to_type = {loc.code: loc.type for loc in get_locations(None, None) if loc.code is not None}

0 comments on commit 377d512

Please sign in to comment.