Skip to content

Commit

Permalink
Merge pull request #9 from wcolding/plando
Browse files Browse the repository at this point in the history
Plando
  • Loading branch information
wcolding authored Oct 8, 2024
2 parents 789d127 + 9613278 commit 0c2e2c6
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 20 deletions.
33 changes: 32 additions & 1 deletion Locations.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,4 +273,35 @@ def get_location_name_to_id():
location_name_to_id = dict()
for item in full_location_table:
location_name_to_id[item] = full_location_table[item].id
return location_name_to_id
return location_name_to_id

def get_masked_course_id(course_name) -> int:
mask = 0
temp_name = course_name
if " (Mirrored)" in course_name:
mask = 0x80
temp_name = course_name.replace(" (Mirrored)", "")
if temp_name in courses_table:
return courses_table[temp_name] | mask
return -1

def get_course_name_from_id(id) -> str | None:
mirrored = (id & 0x80 != 0)
masked_id = id | 0x80
masked_id = masked_id ^ 0x80
names = {v:k for k,v in courses_table.items()}
if masked_id in names:
name = names[masked_id]
if mirrored:
name = f"{name} (Mirrored)"
return name
else:
print(f"Couldn't match id {id}")
return None

def get_course_entrance_index(entrance_name) -> int:
if entrance_name in course_clears_table:
entry = course_clears_table[entrance_name]
return entry.id - SWR_LOC_OFFSET - 45
else:
return -1
16 changes: 15 additions & 1 deletion Options.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from Options import Choice, Range, Toggle, DefaultOnToggle, DeathLink, dataclass, PerGameCommonOptions
from Options import Choice, Range, Toggle, DefaultOnToggle, OptionSet, OptionDict, DeathLink, dataclass, PerGameCommonOptions

class ProgressiveParts(Toggle):
"""Pod racer parts will always be the next level upgrade"""
Expand Down Expand Up @@ -39,6 +39,12 @@ class StartingRacersCount(Range):
range_end = 23
default = 6

class StartingRacersPlando(OptionSet):
"""List of specific racers with which to start
This option is only used if Starting Racers is set to 'random_range'
"""
display_name = "Starting Racers Plando"

class MaxAdditionalRacers(Range):
"""How many racers can be added to the pool (excluding the starting racers)"""
display_name = "Max Additional Racers"
Expand Down Expand Up @@ -116,6 +122,12 @@ class ShopCostMultiplier(Range):
range_end = 10
default = 1

class CoursePlando(OptionDict):
"""Sets specific courses
For mirrored, append ' (Mirrored)' to any course name
Repeated courses will cause errors"""
display_name = "Course Plando"

@dataclass
class SWROptions(PerGameCommonOptions):
progressive_parts: ProgressiveParts
Expand All @@ -124,6 +136,7 @@ class SWROptions(PerGameCommonOptions):
progressive_circuits: ProgressiveCircuits
starting_racers: StartingRacers
starting_racers_count: StartingRacersCount
starting_racers_plando: StartingRacersPlando
max_additional_racers: MaxAdditionalRacers
mirrored_tracks: MirroredTracks
disable_part_damage: DisablePartDamage
Expand All @@ -134,5 +147,6 @@ class SWROptions(PerGameCommonOptions):
auto_hint_shop: AutoHintShop
shop_costs: ShopCosts
shop_cost_multiplier: ShopCostMultiplier
course_plando: CoursePlando
deathlink_amnesty: DeathLinkAmnesty
deathlink: DeathLink
88 changes: 70 additions & 18 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ class SWRWorld(World):
"invitational": {"Invitational Circuit Pass", "Invitational Course Unlock"}
}

racers_pool = dict(racers_table)
starting_racers_flag = 0
randomized_courses = Dict[int, int]
randomized_course_data = list()
Expand All @@ -69,50 +68,103 @@ def set_shop_costs(self):
if i % 5 == 0:
index_offset += 1
self.shop_costs_data.update({int(i + index_offset): int(temp_costs[i] * self.options.shop_cost_multiplier.value)})



def set_starting_racers(self):
self.racers_pool = dict(racers_table)

if self.options.starting_racers == 0:
# Vanilla
for racer in vanilla_racers_list:
self.starting_racers_flag |= self.racers_pool.pop(racer).bitflag
else:
# Random Range
rand_range = self.options.starting_racers_count
racer_names = list(racers_table.keys())
racer_names = [*racers_table]

# Handle plando first
if rand_range < len(self.options.starting_racers_plando.value):
print("Unable to plando starting racers; list size exceeds Starting Racers Count value")
else:
for plando_racer in self.options.starting_racers_plando.value:
if plando_racer in racer_names:
racer_names.remove(plando_racer)
rand_range -= 1
self.starting_racers_flag |= self.racers_pool.pop(plando_racer).bitflag
print(f"Plando'd starting racer: {plando_racer}")
else:
print(f"Unable to plando racer: {plando_racer}\nNo matching racer name found")

# Shuffle the remaining racers and pick from them
random.shuffle(racer_names)

for i in range(0, rand_range):
selected_racer = racer_names.pop()
self.starting_racers_flag |= self.racers_pool.pop(selected_racer).bitflag

def randomize_courses(self):
self.randomized_courses = Dict[int, int]
self.randomized_courses = dict()
self.randomized_course_data = list()
self.randomized_course_names = list()
self.randomized_courses = {}
course_clears = [*course_clears_table]

course_entrances = [*course_clears_table]
course_names = [*courses_table]
for i in range(0, len(course_names)):
self.randomized_course_data += [SWRCourseData(course_names[i], courses_table[course_names[i]])]
mirrored_tracks = self.options.mirrored_tracks.value

temp_courses = dict()

# Handle plando first
for plando_entry in self.options.course_plando.value.items():
if plando_entry[0] in course_entrances:
plando_course_name = plando_entry[1].replace(" (Mirrored)", "")
if plando_course_name in course_names:
# Remove this entramce and course from the pool
course_names.remove(plando_course_name)
course_entrances.remove(plando_entry[0])

# Add this entry to the dict
index = get_course_entrance_index(plando_entry[0])
id = get_masked_course_id(plando_entry[1])
if (id & 0x80) != 0:
mirrored_tracks -= 1
temp_courses.update({index: id})
else:
print(f"Could not plando course '{plando_entry[1]}'; no matching entry found")
else:
print(f"Could not plando course on location '{plando_entry[0]}'; no matching entry found")

# Build course data of remaining courses
for course in course_names:
self.randomized_course_data += [SWRCourseData(course, courses_table[course])]

random.shuffle(self.randomized_course_data)

if self.options.mirrored_tracks.value > 0:
for i in range(0, self.options.mirrored_tracks.value):
# Mirror any tracks not covered in plando
if mirrored_tracks > 0:
for i in range(0, mirrored_tracks):
self.randomized_course_data[i].mirrored = True
random.shuffle(self.randomized_course_data)

# Set course data and spoiler log info
for i in range(0, len(self.randomized_course_data)):
current_course = self.randomized_course_data[i]
self.randomized_course_names += [current_course.name]
# Fill in temp courses table with remaining course data
index_offset = 0
for current_course in self.randomized_course_data:
if current_course.mirrored:
current_course.id |= 0x80
current_course.name += " (Mirrored)"
self.randomized_courses.update({int(i): int(current_course.id)})
self.multiworld.spoiler.set_entrance(f"{course_clears[i]} ({course_names[i]})", current_course.name, 'entrance', self.player)
while index_offset in temp_courses.keys():
index_offset += 1
temp_courses.update({index_offset: current_course.id})
index_offset += 1

# Sort temp courses into the actual order
for entry in sorted(temp_courses):
self.randomized_courses.update({entry: temp_courses[entry]})

# Populate course names list and spoiler log
original_entrances = [*course_clears_table]
course_keys = [*self.randomized_courses]
for i in range(0, len(course_keys)):
course_name = get_course_name_from_id(self.randomized_courses[course_keys[i]])
self.randomized_course_names += [course_name]
self.multiworld.spoiler.set_entrance(f"{original_entrances[i]}", course_name, 'entrance', self.player)

def generate_early(self):
self.set_starting_racers()
Expand Down

0 comments on commit 0c2e2c6

Please sign in to comment.