Files
dockipelago/worlds/glover/Hints.py
Jonathan Tinney 7971961166
Some checks failed
Analyze modified files / flake8 (push) Failing after 2m28s
Build / build-win (push) Has been cancelled
Build / build-ubuntu2204 (push) Has been cancelled
ctest / Test C++ ubuntu-latest (push) Has been cancelled
ctest / Test C++ windows-latest (push) Has been cancelled
Analyze modified files / mypy (push) Has been cancelled
Build and Publish Docker Images / Push Docker image to Docker Hub (push) Successful in 5m4s
Native Code Static Analysis / scan-build (push) Failing after 5m2s
type check / pyright (push) Successful in 1m7s
unittests / Test Python 3.11.2 ubuntu-latest (push) Failing after 16m23s
unittests / Test Python 3.12 ubuntu-latest (push) Failing after 28m19s
unittests / Test Python 3.13 ubuntu-latest (push) Failing after 14m49s
unittests / Test hosting with 3.13 on ubuntu-latest (push) Successful in 5m0s
unittests / Test Python 3.13 macos-latest (push) Has been cancelled
unittests / Test Python 3.11 windows-latest (push) Has been cancelled
unittests / Test Python 3.13 windows-latest (push) Has been cancelled
add schedule I, sonic 1/frontiers/heroes, spirit island
2026-04-02 23:46:36 -07:00

179 lines
7.8 KiB
Python

from types import NoneType
from .Options import MrHints, ChickenHints
from BaseClasses import Item, ItemClassification, Location
def create_hints(self):
#Mr. Hints
tip_catagories = get_catagories(self.options.mr_hints, MrHints)
valid_tip_items = get_valid_items(self, tip_catagories)
#Chicken Hints
chicken_catagories = get_catagories(self.options.chicken_hints, ChickenHints)
valid_chicken_items = get_valid_items(self, chicken_catagories)
#Get Mr. Tip Hints First
tips_pair = create_hint_lookup(self, list(self.tip_locations.keys()), valid_tip_items, tip_catagories, self.options.mr_hints == 2, "")
#Remove any items you've already gotten from being hints from the chicken
for each_item in tips_pair[0]:
if each_item in valid_chicken_items:
valid_chicken_items.remove(each_item)
#Chicken Hints
chicken_locations = []
for each_index in range(7):
chicken_locations.append("Chicken Hint " + str(each_index + 1))
chicken_hints = create_hint_lookup(self, chicken_locations, valid_chicken_items, chicken_catagories, self.options.chicken_hints == 2, "Cheat Chicken Says:\n")
#Apply the hints to the world
return [tips_pair[1], chicken_hints[1], tips_pair[2], chicken_hints[2]]
def create_hint_lookup(self, hint_locations : list[str], valid_items : list[Item], valid_catagories : list [ItemClassification], vague_hint : bool, vauge_prefix : str):
hint_lookup : dict[str, dict[str,int]] = {}
hint_text : dict[str, str] = {}
newly_chosen_items : list[Item] = []
#If nothing's valid, give an empty array
if valid_catagories == None:
return [[],{},{}]
#If there's multiple valid catagories, we're in balanced mode
if len(valid_catagories) > 1:
valid_item_catagories : dict[ItemClassification:list[Item]] = {}
grabbed_from_catagory : dict[ItemClassification:int] = {}
for each_classification in valid_catagories:
valid_item_catagories[each_classification] = get_valid_items(self, [each_classification])
grabbed_from_catagory[each_classification] = 0
current_catagory : ItemClassification
for each_tip_spot in hint_locations:
#Get the catagory with the lowest value
lowest_value = 999
for each_catagory, catagory_value in grabbed_from_catagory.items():
if catagory_value < lowest_value:
lowest_value = catagory_value
current_catagory = each_catagory
if len(valid_item_catagories[current_catagory]) > 0:
next_item : Item = self.random.choice(valid_item_catagories[current_catagory])
valid_item_catagories[current_catagory].remove(next_item)
newly_chosen_items.append(next_item)
to_scout : Location = next_item.location
address = location_name_to_address(self, each_tip_spot)
hint_lookup[address] = location_to_hint_info(self, to_scout)
hint_text[address] = generate_hint_text(self, vague_hint, to_scout, next_item, vauge_prefix)
grabbed_from_catagory[current_catagory] += 1
else:
#If this catagory has no more items, remove it
del grabbed_from_catagory[current_catagory]
#If no catagories have items, bail
if len(grabbed_from_catagory) == 0:
break
return [newly_chosen_items, hint_lookup, hint_text]
#Otherwise, just grab from the single catagory
for each_tip_spot in hint_locations:
if len(valid_items) > 0:
next_item : Item = self.random.choice(valid_items)
valid_items.remove(next_item)
newly_chosen_items.append(next_item)
to_scout : Location = next_item.location
address = location_name_to_address(self, each_tip_spot)
hint_lookup[address] = location_to_hint_info(self, to_scout)
hint_text[address] = generate_hint_text(self, vague_hint, to_scout, next_item, vauge_prefix)
else:
break
return [newly_chosen_items, hint_lookup, hint_text]
def generate_hint_text(self, vague_hint : bool, in_location : Location, in_item : Item, vauge_prefix : str) -> str:
hint_text = in_location.hint_text
locations_owner = self.multiworld.player_name[in_location.player] + "s"
if in_location.player == self.player:
locations_owner = "your"
item_owner = self.multiworld.player_name[in_item.player]
if in_item.player == self.player:
item_owner = "you"
if vague_hint:
hint_text = hint_text.removeprefix("at ")
item_class = " " + str(in_item.classification.value) + " "
if in_location.player == self.player:
locations_owner = locations_owner.title()
match in_item.classification.value:
#Filler
case 0:
item_class = " belongs to "
#Progression
case 1:
item_class = " is important for "
#Useful
case 2:
item_class = " would help "
#Useful Progression
case 3:
item_class = " is critical for "
#Trap
case 4:
item_class = " will hurt "
#
case 25:
item_class = " is good for "
case 9:
item_class = " is important for "
case 17:
item_class = " is good for "
return vauge_prefix + locations_owner + " " + hint_text + item_class + item_owner
item_owner += "s"
if in_item.player == self.player:
item_owner = "Your"
item_name = in_item.hint_text
world_specification = locations_owner + " "
if in_location.player == in_item.player:
world_specification = ""
return item_owner + " " + item_name + " is " + world_specification + hint_text
def location_to_hint_info(self, in_location : Location) -> dict[str:str]:
hint : dict[str:str] = {
"player_id" : in_location.player,
"location_id" : in_location.address
}
return hint
def location_name_to_address(self, location_name : str) -> str:
if location_name.startswith("Chicken Hint "):
return location_name.removeprefix("Chicken Hint ")
if not self.options.mr_tip_checks:
return self.tip_locations[location_name]
return str(self.multiworld.get_location(location_name, self.player).address)
def get_catagories(set_option, option_origin) -> list[ItemClassification] | None:
match set_option:
case option_origin.option_off:
#No Hints
return None
case option_origin.option_catagory_only:
#Vauge Hints
return []
case option_origin.option_chaos:
#Any items
return []
case option_origin.option_balanced:
#Tries to keep a bit of all types
return [ItemClassification.trap, ItemClassification.useful, ItemClassification.progression]
case option_origin.option_traps:
#Traps
return [ItemClassification.trap]
case option_origin.option_useful:
#Useful
return [ItemClassification.useful]
case option_origin.option_progression:
#Progression
return [ItemClassification.progression]
def get_valid_items(self, item_classes : list[ItemClassification] | None) -> list[Item]:
#No items
if item_classes == None:
return []
valid_items : list[Item] = []
for each_item in self.multiworld.itempool:
#Only items from the catagory are valid choices
if (not each_item.classification in item_classes) and item_classes != []:
continue
#No prefills
if each_item.location == None:
continue
valid_items.append(each_item)
return valid_items