Files
dockipelago/worlds/hades/Locations.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

481 lines
18 KiB
Python

from BaseClasses import Location
hades_base_location_id = 1
max_number_room_checks = 1700 + hades_base_location_id
# Making global tables that can be used for unit testing.
global location_table_tartarus
location_table_tartarus = {
"Beat Meg": None,
}
global location_table_asphodel
location_table_asphodel = {
"Beat Lernie": None,
}
global location_table_elysium
location_table_elysium = {
"Beat Bros": None,
}
global location_table_styx
location_table_styx = {
"Beat Hades": None,
}
global location_table_styx_late
location_table_styx_late = {
}
location_keepsakes = {
"Cerberus Keepsake": max_number_room_checks + 1,
"Achilles Keepsake": max_number_room_checks + 2,
"Nyx Keepsake": max_number_room_checks + 3,
"Thanatos Keepsake": max_number_room_checks + 4,
"Charon Keepsake": max_number_room_checks + 5,
"Hypnos Keepsake": max_number_room_checks + 6,
"Megaera Keepsake": max_number_room_checks + 7,
"Orpheus Keepsake": max_number_room_checks + 8,
"Dusa Keepsake": max_number_room_checks + 9,
"Skelly Keepsake": max_number_room_checks + 10,
"Zeus Keepsake": max_number_room_checks + 11,
"Poseidon Keepsake": max_number_room_checks + 12,
"Athena Keepsake": max_number_room_checks + 13,
"Aphrodite Keepsake": max_number_room_checks + 14,
"Ares Keepsake": max_number_room_checks + 15,
"Artemis Keepsake": max_number_room_checks + 16,
"Dionysus Keepsake": max_number_room_checks + 17,
"Hermes Keepsake": max_number_room_checks + 18,
"Demeter Keepsake": max_number_room_checks + 19,
"Chaos Keepsake": max_number_room_checks + 20,
"Sisyphus Keepsake": max_number_room_checks + 21,
"Eurydice Keepsake": max_number_room_checks + 22,
"Patroclus Keepsake": max_number_room_checks + 23,
}
location_weapons = {
"Sword Weapon Unlock Location": max_number_room_checks + 25,
"Bow Weapon Unlock Location": max_number_room_checks + 26,
"Spear Weapon Unlock Location": max_number_room_checks + 27,
"Shield Weapon Unlock Location": max_number_room_checks + 28,
"Fist Weapon Unlock Location": max_number_room_checks + 29,
"Gun Weapon Unlock Location": max_number_room_checks + 30,
}
location_store_gemstones = {
"Fountain Upgrade1 Location": max_number_room_checks + 31,
"Fountain Upgrade2 Location": max_number_room_checks + 32,
"Fountain Tartarus Location": max_number_room_checks + 33,
"Fountain Asphodel Location": max_number_room_checks + 34,
"Fountain Elysium Location": max_number_room_checks + 35,
"Urns Of Wealth1 Location": max_number_room_checks + 36,
"Urns Of Wealth2 Location": max_number_room_checks + 37,
"Urns Of Wealth3 Location": max_number_room_checks + 38,
"Infernal Trove1 Location": max_number_room_checks + 39,
"Infernal Trove2 Location": max_number_room_checks + 40,
"Infernal Trove3 Location": max_number_room_checks + 41,
"Keepsake Collection Location": max_number_room_checks + 42,
}
location_store_diamonds = {
"Deluxe Contractor Desk Location": max_number_room_checks + 44,
"Vanquishers Keep Location": max_number_room_checks + 45,
"Fishing Rod Location": max_number_room_checks + 46,
"Court Musician Sentence Location": max_number_room_checks + 47,
"Court Musician Stand Location": max_number_room_checks + 48,
"Pitch Black Darkness Location": max_number_room_checks + 49,
"Fated Keys Location": max_number_room_checks + 50,
"Brilliant Gemstones Location": max_number_room_checks + 51,
"Vintage Nectar Location": max_number_room_checks + 52,
"Darker Thirst Location": max_number_room_checks + 53,
}
location_table_fates = {
"Is There No Escape?": max_number_room_checks + 54,
"Distant Relatives": max_number_room_checks + 55,
"Chthonic Colleagues": max_number_room_checks + 56,
"The Reluctant Musician": max_number_room_checks + 57,
"Goddess Of Wisdom": max_number_room_checks + 58,
"God Of The Heavens": max_number_room_checks + 59,
"God Of The Sea": max_number_room_checks + 60,
"Goddess Of Love": max_number_room_checks + 61,
"God Of War": max_number_room_checks + 62,
"Goddess Of The Hunt": max_number_room_checks + 63,
"God Of Wine": max_number_room_checks + 64,
"God Of Swiftness": max_number_room_checks + 65,
"Goddess Of Seasons": max_number_room_checks + 66,
"Power Without Equal": max_number_room_checks + 67,
"Divine Pairings": max_number_room_checks + 68,
"Primordial Boons": max_number_room_checks + 69,
"Primordial Banes": max_number_room_checks + 70,
"Infernal Arms": max_number_room_checks + 71,
"The Stygian Blade": max_number_room_checks + 72,
"The Heart Seeking Bow": max_number_room_checks + 73,
"The Shield Of Chaos": max_number_room_checks + 74,
"The Eternal Spear": max_number_room_checks + 75,
"The Twin Fists": max_number_room_checks + 76,
"The Adamant Rail": max_number_room_checks + 77,
"Master Of Arms": max_number_room_checks + 78,
"A Violent Past": max_number_room_checks + 79,
"Harsh Conditions": max_number_room_checks + 80,
"Slashed Benefits": max_number_room_checks + 81,
"Wanton Ransacking": max_number_room_checks + 82,
"A Simple Job": max_number_room_checks + 83,
"Chthonic Knowledge": max_number_room_checks + 84,
"Customer Loyalty": max_number_room_checks + 85,
"Dark Reflections": max_number_room_checks + 86,
"Close At Heart": max_number_room_checks + 87,
"Denizens Of The Deep": max_number_room_checks + 88,
"The Useless Trinket": max_number_room_checks + 89,
"Musician and Muse" : max_number_room_checks + 90,
"End to Torment" : max_number_room_checks + 91,
"Divided by Death" : max_number_room_checks + 92,
"Eternal Rest" : max_number_room_checks + 93,
"A Place of Revelry" : max_number_room_checks + 94,
"Amusing Chaos" : max_number_room_checks + 95,
"Sea-God's Spite" : max_number_room_checks + 96,
"War-God's Bloodlust" : max_number_room_checks + 97,
"A Friendly Wager" : max_number_room_checks + 98,
"The Holy Liege" : max_number_room_checks + 99,
"The Fated Saint of War" : max_number_room_checks + 100,
"The Preserver's Avatar" : max_number_room_checks + 101,
"The Dragon's Rival" : max_number_room_checks + 102,
"The God-like King" : max_number_room_checks + 103,
"The Dawn Bringer" : max_number_room_checks + 104,
"The Gift of Song" : max_number_room_checks + 105,
}
location_table_fates_events = {
"Is There No Escape? Event": None,
"Distant Relatives Event": None,
"Chthonic Colleagues Event": None,
"The Reluctant Musician Event": None,
"Goddess Of Wisdom Event": None,
"God Of The Heavens Event": None,
"God Of The Sea Event": None,
"Goddess Of Love Event": None,
"God Of War Event": None,
"Goddess Of The Hunt Event": None,
"God Of Wine Event": None,
"God Of Swiftness Event": None,
"Goddess Of Seasons Event": None,
"Power Without Equal Event": None,
"Divine Pairings Event": None,
"Primordial Boons Event": None,
"Primordial Banes Event": None,
"Infernal Arms Event": None,
"The Stygian Blade Event": None,
"The Heart Seeking Bow Event": None,
"The Shield Of Chaos Event": None,
"The Eternal Spear Event": None,
"The Twin Fists Event": None,
"The Adamant Rail Event": None,
"Master Of Arms Event": None,
"A Violent Past Event": None,
"Harsh Conditions Event": None,
"Slashed Benefits Event": None,
"Wanton Ransacking Event": None,
"A Simple Job Event": None,
"Chthonic Knowledge Event": None,
"Customer Loyalty Event": None,
"Dark Reflections Event": None,
"Close At Heart Event": None,
"Denizens Of The Deep Event": None,
"The Useless Trinket Event": None,
"Musician and Muse Event" : None,
"End to Torment Event" : None,
"Divided by Death Event" : None,
"Eternal Rest Event" : None,
"A Place of Revelry Event" : None,
"Amusing Chaos Event" : None,
"Sea-God's Spite Event" : None,
"War-God's Bloodlust Event" : None,
"A Friendly Wager Event" : None,
"The Holy Liege Event" : None,
"The Fated Saint of War Event" : None,
"The Preserver's Avatar Event" : None,
"The Dragon's Rival Event" : None,
"The God-like King Event" : None,
"The Dawn Bringer Event" : None,
"The Gift of Song Event" : None,
}
# ----------------------
location_weapons_subfixes = [
"Sword Weapon",
"Spear Weapon",
"Shield Weapon",
"Bow Weapon",
"Fist Weapon",
"Gun Weapon",
]
# ---------------------
def give_all_locations_table() -> dict:
table_rooms = give_default_location_table(False)
table_score = give_score_location_table(1000)
table_weaponlocation = give_weapon_based_locations(False)
return {
**table_rooms,
**table_score,
**table_weaponlocation,
**location_keepsakes,
**location_weapons,
**location_store_gemstones,
**location_store_diamonds,
**location_table_fates,
**location_table_fates_events,
}
def clear_tables() -> None:
global location_table_tartarus
location_table_tartarus = {
"Beat Meg": None,
}
global location_table_asphodel
location_table_asphodel = {
"Beat Lernie": None,
}
global location_table_elysium
location_table_elysium = {
"Beat Bros": None,
}
global location_table_styx
location_table_styx = {
"Beat Hades": None,
}
global location_table_styx_late
location_table_styx_late = {
}
# Change parameters so they include the settings of the player
# Chose between old and new system. And for the new system we want to be able
# to choose how many "locations" we have.
def setup_location_table_with_settings(options) -> None:
clear_tables()
total_table = {}
total_table.update(location_table_fates_events)
if options.keepsakesanity.value == 1:
total_table.update(location_keepsakes)
if options.weaponsanity.value == 1:
for weaponLocation, weaponData in location_weapons.items():
if not should_ignore_weapon_location(weaponLocation, options):
total_table.update({weaponLocation: weaponData})
if options.storesanity.value == 1:
total_table.update(location_store_gemstones)
total_table.update(location_store_diamonds)
if options.location_system.value == 1:
result = give_default_location_table(options.disable_late_styx)
total_table.update(result)
elif options.location_system.value == 2:
levels = options.score_rewards_amount.value
total_table.update(give_score_location_table(levels))
elif options.location_system.value == 3:
total_table.update(give_weapon_based_locations(options.disable_late_styx))
if options.fatesanity == 1:
total_table.update(location_table_fates)
return total_table
# -----------------------------------------------
def should_ignore_weapon_location(weaponLocation : str, options) -> None:
if options.initial_weapon.value == 0 and weaponLocation == "Sword Weapon Unlock Location":
return True
if options.initial_weapon.value == 1 and weaponLocation == "Bow Weapon Unlock Location":
return True
if options.initial_weapon.value == 2 and weaponLocation == "Spear Weapon Unlock Location":
return True
if options.initial_weapon.value == 3 and weaponLocation == "Shield Weapon Unlock Location":
return True
if options.initial_weapon.value == 4 and weaponLocation == "Fist Weapon Unlock Location":
return True
if options.initial_weapon.value == 5 and weaponLocation == "Gun Weapon Unlock Location":
return True
return False
# -----------------------------------------------
def give_default_location_table(disable_late_styx : bool) -> dict:
#Repopulate tartarus table; rooms from 1 to 13.
global location_table_tartarus
for i in range(13):
stringInt = i + 1
if stringInt < 10:
stringInt = "0"+str(stringInt);
location_table_tartarus["Clear Room "+str(stringInt)] = hades_base_location_id + i
# Repopulate asphodel table, rooms from 14 to 23
global location_table_asphodel
for i in range(13, 23):
location_table_asphodel["Clear Room "+str(i + 1)] = hades_base_location_id + i
# Repopulate elysium table, rooms from 24 to 35
global location_table_elysium
for i in range(23, 35):
location_table_elysium["Clear Room "+str(i + 1)] = hades_base_location_id + i
# Repopulate styx table, rooms from 35 to 72. Split into early and late
global location_table_styx
for i in range(35, 55):
location_table_styx["Clear Room "+str(i + 1)] = hades_base_location_id + i
if (not disable_late_styx):
global location_table_styx_late
for i in range(55, 72):
location_table_styx_late["Clear Room "+str(i + 1)] = hades_base_location_id + i
location_table = {
**location_table_tartarus,
**location_table_asphodel,
**location_table_elysium,
**location_table_styx,
**location_table_styx_late,
}
return location_table
def give_score_location_table(locations : int) -> dict:
fraction_location = int(locations/8)
locations_first_region = locations - 7 * fraction_location
global location_table_tartarus
# Recall to add a offset for the location to avoid sharing ids if two players play with different settings
for i in range(locations_first_region):
stringInt = str(i + 1)
while len(stringInt) < 4:
stringInt = "0" + str(stringInt)
location_table_tartarus["Clear Score "+str(stringInt)] = hades_base_location_id + i + 72
global location_table_asphodel
for i in range(locations_first_region, locations_first_region + 2 * fraction_location):
stringInt = str(i + 1)
while len(stringInt) < 4:
stringInt = "0" + str(stringInt)
location_table_asphodel["Clear Score "+stringInt] = hades_base_location_id + i + 72
global location_table_elysium
for i in range(locations_first_region+2*fraction_location, locations_first_region + 4 * fraction_location):
stringInt = str(i + 1)
while len(stringInt) < 4:
stringInt = "0" + str(stringInt)
location_table_elysium["Clear Score "+stringInt] = hades_base_location_id + i + 72
global location_table_styx
for i in range(locations_first_region+4*fraction_location, locations_first_region + 6 * fraction_location):
stringInt = str(i + 1)
while len(stringInt) < 4:
stringInt = "0" + str(stringInt)
location_table_styx["Clear Score "+stringInt] = hades_base_location_id + i + 72
global location_table_styx_late
location_table_styx_late = {}
for i in range(locations_first_region+6*fraction_location, locations):
stringInt = str(i + 1)
while len(stringInt) < 4:
stringInt = "0" + str(stringInt)
location_table_styx_late["Clear Score "+stringInt] = hades_base_location_id + i + 72
location_table = {
**location_table_tartarus,
**location_table_asphodel,
**location_table_elysium,
**location_table_styx,
**location_table_styx_late,
}
return location_table
def give_weapon_based_locations(disable_late_styx : bool) -> dict:
subfixCounter = 0
weapon_locations = {}
for weaponSubfix in location_weapons_subfixes:
for i in range(13):
stringInt = i + 1
if stringInt < 10:
stringInt = "0" + str(stringInt)
weapon_locations["Clear Room " + str(stringInt) + " " + weaponSubfix] = hades_base_location_id + 1073 + i \
+ 73 * subfixCounter
weapon_locations["Beat Meg "+weaponSubfix] = None
for i in range(13, 23):
weapon_locations["Clear Room " + str(i + 1) + " " + weaponSubfix] = hades_base_location_id + 1073 + i \
+ 73 * subfixCounter
weapon_locations["Beat Lernie "+weaponSubfix] = None
for i in range(23, 35):
weapon_locations["Clear Room " + str(i + 1) + " " + weaponSubfix] = hades_base_location_id + 1073 + i \
+ 73 * subfixCounter
weapon_locations["Beat Bros "+weaponSubfix] = None
for i in range(35, 55):
weapon_locations["Clear Room " + str(i + 1) + " " + weaponSubfix] = hades_base_location_id + 1073 + i \
+ 73 * subfixCounter
weapon_locations["Beat Hades " + weaponSubfix] = None
if (not disable_late_styx):
for i in range(55, 72):
weapon_locations["Clear Room " + str(i + 1) + " " + weaponSubfix] = hades_base_location_id + 1073 + i \
+ 73 * subfixCounter
subfixCounter += 1
return weapon_locations
# -----------------------------------------------
group_fates = {"fates": location_table_fates.keys()}
group_keepsakes = {"keepsakes": location_keepsakes.keys()}
group_weapons = {"weapons": location_weapons.keys()}
group_contractor_gemstones = {"contractor_gems": location_store_gemstones.keys()}
group_contractor_diamonds = {"contractor_diamonds": location_store_diamonds.keys()}
location_name_groups = {
**group_fates,
**group_keepsakes,
**group_weapons,
**group_contractor_gemstones,
**group_contractor_diamonds,
}
# -----------------------------------------------
class HadesLocation(Location):
game: str = "Hades"
def __init__(self, player: int, name: str, address=None, parent=None):
super(HadesLocation, self).__init__(player, name, address, parent)
if address is None:
self.event = True
self.locked = True