overhaul filler generation

This commit is contained in:
Silvris
2024-05-18 03:38:11 -05:00
parent 139f222b92
commit 3b192c5407
4 changed files with 48 additions and 27 deletions

View File

@@ -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)])

View File

@@ -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 = {

View File

@@ -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,

View File

@@ -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))