mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-28 04:23:23 -07:00
overhaul filler generation
This commit is contained in:
@@ -85,6 +85,12 @@ class KDL3World(World):
|
||||
|
||||
create_regions = create_levels
|
||||
|
||||
def generate_early(self) -> None:
|
||||
if self.options.total_heart_stars != -1:
|
||||
logger.warning(f"Kirby's Dream Land 3 ({self.player_name}): Use of \"total_heart_stars\" is deprecated. "
|
||||
f"Please use \"max_heart_stars\" instead.")
|
||||
self.options.max_heart_stars.value = self.options.total_heart_stars.value
|
||||
|
||||
def create_item(self, name: str, force_non_progression: bool = False) -> KDL3Item:
|
||||
item = item_table[name]
|
||||
classification = ItemClassification.filler
|
||||
@@ -245,21 +251,20 @@ class KDL3World(World):
|
||||
remaining_items = len(location_table) - len(itempool)
|
||||
if not self.options.consumables:
|
||||
remaining_items -= len(consumable_locations)
|
||||
remaining_items -= len(star_locations)
|
||||
if self.options.starsanity:
|
||||
# star fill, keep consumable pool locked to consumable and fill 767 stars specifically
|
||||
star_items = list(star_item_weights.keys())
|
||||
star_weights = list(star_item_weights.values())
|
||||
itempool.extend([self.create_item(item) for item in self.random.choices(star_items, weights=star_weights,
|
||||
k=767)])
|
||||
total_heart_stars = self.options.total_heart_stars
|
||||
if not self.options.starsanity:
|
||||
remaining_items -= len(star_locations)
|
||||
max_heart_stars = self.options.max_heart_stars.value
|
||||
if max_heart_stars > remaining_items:
|
||||
max_heart_stars = remaining_items
|
||||
# ensure at least 1 heart star required per world
|
||||
required_heart_stars = max(int(total_heart_stars * required_percentage), 5)
|
||||
filler_items = total_heart_stars - required_heart_stars
|
||||
filler_amount = math.floor(filler_items * (self.options.filler_percentage / 100.0))
|
||||
trap_amount = math.floor(filler_amount * (self.options.trap_percentage / 100.0))
|
||||
filler_amount -= trap_amount
|
||||
non_required_heart_stars = filler_items - filler_amount - trap_amount
|
||||
required_heart_stars = min(max(int(max_heart_stars * required_percentage), 5), 99)
|
||||
filler_items = remaining_items - required_heart_stars
|
||||
converted_heart_stars = math.floor((max_heart_stars - required_heart_stars) * (self.options.filler_percentage / 100.0))
|
||||
non_required_heart_stars = max_heart_stars - converted_heart_stars - required_heart_stars
|
||||
filler_items -= non_required_heart_stars
|
||||
trap_amount = math.floor(filler_items * (self.options.trap_percentage / 100.0))
|
||||
|
||||
filler_items -= trap_amount
|
||||
self.required_heart_stars = required_heart_stars
|
||||
# handle boss requirements here
|
||||
requirements = [required_heart_stars]
|
||||
@@ -281,8 +286,8 @@ class KDL3World(World):
|
||||
requirements.insert(i - 1, quotient * i)
|
||||
self.boss_requirements = requirements
|
||||
itempool.extend([self.create_item("Heart Star") for _ in range(required_heart_stars)])
|
||||
itempool.extend([self.create_item(self.get_filler_item_name(False))
|
||||
for _ in range(filler_amount + (remaining_items - total_heart_stars))])
|
||||
itempool.extend([self.create_item(self.get_filler_item_name(bool(self.options.starsanity.value)))
|
||||
for _ in range(filler_items)])
|
||||
itempool.extend([self.create_item(self.get_trap_item_name())
|
||||
for _ in range(trap_amount)])
|
||||
itempool.extend([self.create_item("Heart Star", True) for _ in range(non_required_heart_stars)])
|
||||
|
||||
@@ -77,9 +77,9 @@ filler_item_weights = {
|
||||
}
|
||||
|
||||
star_item_weights = {
|
||||
"Little Star": 4,
|
||||
"Medium Star": 2,
|
||||
"Big Star": 1
|
||||
"Little Star": 16,
|
||||
"Medium Star": 8,
|
||||
"Big Star": 4
|
||||
}
|
||||
|
||||
total_filler_weights = {
|
||||
|
||||
@@ -4,7 +4,7 @@ from typing import List
|
||||
|
||||
from BaseClasses import OptionGroup
|
||||
from Options import DeathLinkMixin, Choice, Toggle, OptionDict, Range, PlandoBosses, DefaultOnToggle, \
|
||||
PerGameCommonOptions
|
||||
PerGameCommonOptions, Visibility
|
||||
from .names import location_name
|
||||
|
||||
|
||||
@@ -46,13 +46,14 @@ class GoalSpeed(Choice):
|
||||
option_fast = 1
|
||||
|
||||
|
||||
class TotalHeartStars(Range):
|
||||
class MaxHeartStars(Range):
|
||||
"""
|
||||
Maximum number of heart stars to include in the pool of items.
|
||||
If fewer available locations exist in the pool than this number, the number of available locations will be used instead.
|
||||
"""
|
||||
display_name = "Max Heart Stars"
|
||||
range_start = 5 # set to 5 so strict bosses does not degrade
|
||||
range_end = 50 # 30 default locations + 30 stage clears + 5 bosses - 14 progression items = 51, so round down
|
||||
range_end = 99 # previously set to 50, set to highest it can be should there be less locations than heart stars
|
||||
default = 30
|
||||
|
||||
|
||||
@@ -320,6 +321,7 @@ class KirbyFlavor(OptionDict):
|
||||
"14": "F8F8F8",
|
||||
"15": "B03830",
|
||||
}
|
||||
visibility = Visibility.template | Visibility.spoiler # likely never supported on guis
|
||||
|
||||
|
||||
class GooeyFlavorPreset(Choice):
|
||||
@@ -371,6 +373,7 @@ class GooeyFlavor(OptionDict):
|
||||
"8": "D0C0C0",
|
||||
"9": "F8F8F8",
|
||||
}
|
||||
visibility = Visibility.template | Visibility.spoiler # likely never supported on guis
|
||||
|
||||
|
||||
class MusicShuffle(Choice):
|
||||
@@ -410,13 +413,23 @@ class Gifting(Toggle):
|
||||
display_name = "Gifting"
|
||||
|
||||
|
||||
class TotalHeartStars(Range):
|
||||
"""
|
||||
Deprecated. Use max_heart_stars instead. Supported for only one version.
|
||||
"""
|
||||
default = -1
|
||||
range_start = 5
|
||||
range_end = 99
|
||||
visibility = Visibility.none
|
||||
|
||||
|
||||
@dataclass
|
||||
class KDL3Options(PerGameCommonOptions, DeathLinkMixin):
|
||||
remote_items: RemoteItems
|
||||
game_language: GameLanguage
|
||||
goal: Goal
|
||||
goal_speed: GoalSpeed
|
||||
total_heart_stars: TotalHeartStars
|
||||
max_heart_stars: MaxHeartStars
|
||||
heart_stars_required: HeartStarsRequired
|
||||
filler_percentage: FillerPercentage
|
||||
trap_percentage: TrapPercentage
|
||||
@@ -443,9 +456,11 @@ class KDL3Options(PerGameCommonOptions, DeathLinkMixin):
|
||||
music_shuffle: MusicShuffle
|
||||
virtual_console: VirtualConsoleChanges
|
||||
|
||||
total_heart_stars: TotalHeartStars # remove in 2 versions
|
||||
|
||||
|
||||
kdl3_option_groups: List[OptionGroup] = [
|
||||
OptionGroup("Goal Options", [Goal, GoalSpeed, TotalHeartStars, HeartStarsRequired, JumpingTarget, ]),
|
||||
OptionGroup("Goal Options", [Goal, GoalSpeed, MaxHeartStars, HeartStarsRequired, JumpingTarget, ]),
|
||||
OptionGroup("World Options", [RemoteItems, StrictBosses, OpenWorld, OpenWorldBossRequirement, ConsumableChecks,
|
||||
StarChecks, FillerPercentage, TrapPercentage, GooeyTrapPercentage,
|
||||
SlowTrapPercentage, AbilityTrapPercentage, LevelShuffle, BossShuffle,
|
||||
|
||||
@@ -550,10 +550,11 @@ def patch_rom(world: "KDL3World", patch: KDL3ProcedurePatch) -> None:
|
||||
patch.write_token(APTokenTypes.WRITE, 0x944E, struct.pack("H", world.options.jumping_target))
|
||||
|
||||
from Utils import __version__
|
||||
patch.name = bytearray(
|
||||
patch_name = bytearray(
|
||||
f'KDL3{__version__.replace(".", "")[0:3]}_{world.player}_{world.multiworld.seed:11}\0', 'utf8')[:21]
|
||||
patch.name.extend([0] * (21 - len(patch.name)))
|
||||
patch.write_token(APTokenTypes.WRITE, 0x3C000, bytes(patch.name))
|
||||
patch_name.extend([0] * (21 - len(patch_name)))
|
||||
patch.name = bytes(patch_name)
|
||||
patch.write_token(APTokenTypes.WRITE, 0x3C000, patch.name)
|
||||
patch.write_token(APTokenTypes.WRITE, 0x3C020, world.options.game_language.value.to_bytes(1, "little"))
|
||||
|
||||
patch.write_token(APTokenTypes.COPY, 0x7FC0, (21, 0x3C000))
|
||||
|
||||
Reference in New Issue
Block a user