Files
Grinch-AP/worlds/cvcotm/__init__.py

223 lines
10 KiB
Python
Raw Normal View History

Castlevania: Circle of the Moon - Implement New Game (#3299) * Add the cotm package with working seed playthrough generation. * Add the proper event flag IDs for the Item codes. * Oooops. Put the world completion condition in! * Adjust the game name and abbreviations. * Implement more settings. * Account for too many start_inventory_from_pool cards with Halve DSS Cards Placed. * Working (albeit very sloooooooooooow) ROM patching. * Screw you, bsdiff! AP Procedure Patch for life! * Nuke stage_assert_generate as the ROM is no longer needed for that. * Working item writing and position adjusting. * Fix the magic item graphics in Locations wherein they can be fixed. * Enable sub-weapon shuffle * Get the seed display working. * Get the enemy item drop randomization working. Phew! * Enemy drop rando and seed display fixes. * Functional Countdown + Early Double setting * Working multiworld (yay!) * Fix item links and demo shenanigans. * Add Wii U VC hash and a docs section explaining the rereleases. * Change all client read/writes to EWRAM instead of Combined WRAM. * Custom text insertion foundations. * Working text converter and word wrap detector. * More refinements to the text wrap system. * Well and truly working sent/received messages. * Add DeathLink and Battle Arena goal options. * Add tracker stuff, unittests, all locations countdown, presets. * Add to README, CODEOWNERS, and inno_setup * Add to README, CODEOWNERS, and inno_setup * Address some suggestions/problems. * Switch the Items and Locations to using dataclasses. * Add note about the alternate classes to the Game Page. * Oooops, typo! * Touch up the Options descriptions. * Fix Battle Arena flag being detected incorrectly on connection and name the locked location/item pairs better. * Implement option groups * Swap the Lizard-man Locations into their correct Regions. * Local start inventory, better DeathLink message handling, handle receiving over 255 of an item. * Update the PopTracker pack links to no longer point to the Releases page. * Add Skip Dialogues option. * Update the presets for the accessibility rework. * Swap the choices in the accessibility preset options. * Uhhhhhhh...just see the apworld v4 changelog for this one. * Ooops, typo! * . * Bunch of small stuff * Correctly change "Fake" to "Breakable" in this comment. Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Make can_touch_water one line. Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Make broke_iron_maidens one line. Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Fix majors countdown and make can_open_ceremonial_door one line. * Make the Trap AP Item less obvious. * Add Progression + Useful stuff, patcher handling for incompatible versions, and fix some mypy stuff. * Better option groups. * Change Early Double to Early Escape Item. * Update DeathLink description and ditch the Menu region. * Fix the Start Broken choice for Iron Maiden Behavior * Remove the forced option change with Arena goal + required All Bosses and Arena. * Update the Game Page with the removal of the forced option combination change. * Fix client potential to send packets nonstop. * More review addressing. * Fix the new select_drop code. * Fix the new select_drop code for REAL this time. * Send another LocationScout if we send Location checks without having the Location info. --------- Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> Co-authored-by: Exempt-Medic <ExemptMedic@Gmail.com> Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-12-12 06:47:47 -07:00
import os
import typing
import settings
import base64
import logging
from BaseClasses import Item, Region, Tutorial, ItemClassification
from .items import CVCotMItem, FILLER_ITEM_NAMES, ACTION_CARDS, ATTRIBUTE_CARDS, cvcotm_item_info, \
get_item_names_to_ids, get_item_counts
from .locations import CVCotMLocation, get_location_names_to_ids, BASE_ID, get_named_locations_data, \
get_location_name_groups
from .options import cvcotm_option_groups, CVCotMOptions, SubWeaponShuffle, IronMaidenBehavior, RequiredSkirmishes, \
CompletionGoal, EarlyEscapeItem
from .regions import get_region_info, get_all_region_names
from .rules import CVCotMRules
from .data import iname, lname
from .presets import cvcotm_options_presets
from worlds.AutoWorld import WebWorld, World
from .aesthetics import shuffle_sub_weapons, get_location_data, get_countdown_flags, populate_enemy_drops, \
get_start_inventory_data
from .rom import RomData, patch_rom, get_base_rom_path, CVCotMProcedurePatch, CVCOTM_CT_US_HASH, CVCOTM_AC_US_HASH
# CVCOTM_VC_US_HASH
Castlevania: Circle of the Moon - Implement New Game (#3299) * Add the cotm package with working seed playthrough generation. * Add the proper event flag IDs for the Item codes. * Oooops. Put the world completion condition in! * Adjust the game name and abbreviations. * Implement more settings. * Account for too many start_inventory_from_pool cards with Halve DSS Cards Placed. * Working (albeit very sloooooooooooow) ROM patching. * Screw you, bsdiff! AP Procedure Patch for life! * Nuke stage_assert_generate as the ROM is no longer needed for that. * Working item writing and position adjusting. * Fix the magic item graphics in Locations wherein they can be fixed. * Enable sub-weapon shuffle * Get the seed display working. * Get the enemy item drop randomization working. Phew! * Enemy drop rando and seed display fixes. * Functional Countdown + Early Double setting * Working multiworld (yay!) * Fix item links and demo shenanigans. * Add Wii U VC hash and a docs section explaining the rereleases. * Change all client read/writes to EWRAM instead of Combined WRAM. * Custom text insertion foundations. * Working text converter and word wrap detector. * More refinements to the text wrap system. * Well and truly working sent/received messages. * Add DeathLink and Battle Arena goal options. * Add tracker stuff, unittests, all locations countdown, presets. * Add to README, CODEOWNERS, and inno_setup * Add to README, CODEOWNERS, and inno_setup * Address some suggestions/problems. * Switch the Items and Locations to using dataclasses. * Add note about the alternate classes to the Game Page. * Oooops, typo! * Touch up the Options descriptions. * Fix Battle Arena flag being detected incorrectly on connection and name the locked location/item pairs better. * Implement option groups * Swap the Lizard-man Locations into their correct Regions. * Local start inventory, better DeathLink message handling, handle receiving over 255 of an item. * Update the PopTracker pack links to no longer point to the Releases page. * Add Skip Dialogues option. * Update the presets for the accessibility rework. * Swap the choices in the accessibility preset options. * Uhhhhhhh...just see the apworld v4 changelog for this one. * Ooops, typo! * . * Bunch of small stuff * Correctly change "Fake" to "Breakable" in this comment. Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Make can_touch_water one line. Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Make broke_iron_maidens one line. Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Fix majors countdown and make can_open_ceremonial_door one line. * Make the Trap AP Item less obvious. * Add Progression + Useful stuff, patcher handling for incompatible versions, and fix some mypy stuff. * Better option groups. * Change Early Double to Early Escape Item. * Update DeathLink description and ditch the Menu region. * Fix the Start Broken choice for Iron Maiden Behavior * Remove the forced option change with Arena goal + required All Bosses and Arena. * Update the Game Page with the removal of the forced option combination change. * Fix client potential to send packets nonstop. * More review addressing. * Fix the new select_drop code. * Fix the new select_drop code for REAL this time. * Send another LocationScout if we send Location checks without having the Location info. --------- Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> Co-authored-by: Exempt-Medic <ExemptMedic@Gmail.com> Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-12-12 06:47:47 -07:00
from .client import CastlevaniaCotMClient
class CVCotMSettings(settings.Group):
class RomFile(settings.UserFilePath):
"""File name of the Castlevania CotM US rom"""
copy_to = "Castlevania - Circle of the Moon (USA).gba"
description = "Castlevania CotM (US) ROM File"
# md5s = [CVCOTM_CT_US_HASH, CVCOTM_AC_US_HASH, CVCOTM_VC_US_HASH]
md5s = [CVCOTM_CT_US_HASH, CVCOTM_AC_US_HASH]
Castlevania: Circle of the Moon - Implement New Game (#3299) * Add the cotm package with working seed playthrough generation. * Add the proper event flag IDs for the Item codes. * Oooops. Put the world completion condition in! * Adjust the game name and abbreviations. * Implement more settings. * Account for too many start_inventory_from_pool cards with Halve DSS Cards Placed. * Working (albeit very sloooooooooooow) ROM patching. * Screw you, bsdiff! AP Procedure Patch for life! * Nuke stage_assert_generate as the ROM is no longer needed for that. * Working item writing and position adjusting. * Fix the magic item graphics in Locations wherein they can be fixed. * Enable sub-weapon shuffle * Get the seed display working. * Get the enemy item drop randomization working. Phew! * Enemy drop rando and seed display fixes. * Functional Countdown + Early Double setting * Working multiworld (yay!) * Fix item links and demo shenanigans. * Add Wii U VC hash and a docs section explaining the rereleases. * Change all client read/writes to EWRAM instead of Combined WRAM. * Custom text insertion foundations. * Working text converter and word wrap detector. * More refinements to the text wrap system. * Well and truly working sent/received messages. * Add DeathLink and Battle Arena goal options. * Add tracker stuff, unittests, all locations countdown, presets. * Add to README, CODEOWNERS, and inno_setup * Add to README, CODEOWNERS, and inno_setup * Address some suggestions/problems. * Switch the Items and Locations to using dataclasses. * Add note about the alternate classes to the Game Page. * Oooops, typo! * Touch up the Options descriptions. * Fix Battle Arena flag being detected incorrectly on connection and name the locked location/item pairs better. * Implement option groups * Swap the Lizard-man Locations into their correct Regions. * Local start inventory, better DeathLink message handling, handle receiving over 255 of an item. * Update the PopTracker pack links to no longer point to the Releases page. * Add Skip Dialogues option. * Update the presets for the accessibility rework. * Swap the choices in the accessibility preset options. * Uhhhhhhh...just see the apworld v4 changelog for this one. * Ooops, typo! * . * Bunch of small stuff * Correctly change "Fake" to "Breakable" in this comment. Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Make can_touch_water one line. Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Make broke_iron_maidens one line. Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Fix majors countdown and make can_open_ceremonial_door one line. * Make the Trap AP Item less obvious. * Add Progression + Useful stuff, patcher handling for incompatible versions, and fix some mypy stuff. * Better option groups. * Change Early Double to Early Escape Item. * Update DeathLink description and ditch the Menu region. * Fix the Start Broken choice for Iron Maiden Behavior * Remove the forced option change with Arena goal + required All Bosses and Arena. * Update the Game Page with the removal of the forced option combination change. * Fix client potential to send packets nonstop. * More review addressing. * Fix the new select_drop code. * Fix the new select_drop code for REAL this time. * Send another LocationScout if we send Location checks without having the Location info. --------- Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> Co-authored-by: Exempt-Medic <ExemptMedic@Gmail.com> Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-12-12 06:47:47 -07:00
rom_file: RomFile = RomFile(RomFile.copy_to)
class CVCotMWeb(WebWorld):
theme = "stone"
options_presets = cvcotm_options_presets
tutorials = [Tutorial(
"Multiworld Setup Guide",
"A guide to setting up the Archipleago Castlevania: Circle of the Moon randomizer on your computer and "
"connecting it to a multiworld.",
"English",
"setup_en.md",
"setup/en",
["Liquid Cat"]
)]
option_groups = cvcotm_option_groups
class CVCotMWorld(World):
"""
Castlevania: Circle of the Moon is a launch title for the Game Boy Advance and the first of three Castlevania games
released for the handheld in the "Metroidvania" format. As Nathan Graves, wielding the Hunter Whip and utilizing the
Dual Set-Up System for new possibilities, you must battle your way through Camilla's castle and rescue your master
from a demonic ritual to restore the Count's power...
"""
game = "Castlevania - Circle of the Moon"
item_name_groups = {
"DSS": ACTION_CARDS.union(ATTRIBUTE_CARDS),
"Card": ACTION_CARDS.union(ATTRIBUTE_CARDS),
"Action": ACTION_CARDS,
"Action Card": ACTION_CARDS,
"Attribute": ATTRIBUTE_CARDS,
"Attribute Card": ATTRIBUTE_CARDS,
"Freeze": {iname.serpent, iname.cockatrice, iname.mercury, iname.mars},
"Freeze Action": {iname.mercury, iname.mars},
"Freeze Attribute": {iname.serpent, iname.cockatrice}
}
location_name_groups = get_location_name_groups()
options_dataclass = CVCotMOptions
options: CVCotMOptions
settings: typing.ClassVar[CVCotMSettings]
origin_region_name = "Catacomb"
hint_blacklist = frozenset({lname.ba24}) # The Battle Arena reward, if it's put in, will always be a Last Key.
item_name_to_id = {name: cvcotm_item_info[name].code + BASE_ID for name in cvcotm_item_info
if cvcotm_item_info[name].code is not None}
location_name_to_id = get_location_names_to_ids()
# Default values to possibly be updated in generate_early
total_last_keys: int = 0
required_last_keys: int = 0
auth: bytearray
web = CVCotMWeb()
def generate_early(self) -> None:
# Generate the player's unique authentication
self.auth = bytearray(self.random.getrandbits(8) for _ in range(16))
# If Required Skirmishes are on, force the Required and Available Last Keys to 8 or 9 depending on which option
# was chosen.
if self.options.required_skirmishes == RequiredSkirmishes.option_all_bosses:
self.options.required_last_keys.value = 8
self.options.available_last_keys.value = 8
elif self.options.required_skirmishes == RequiredSkirmishes.option_all_bosses_and_arena:
self.options.required_last_keys.value = 9
self.options.available_last_keys.value = 9
self.total_last_keys = self.options.available_last_keys.value
self.required_last_keys = self.options.required_last_keys.value
# If there are more Last Keys required than there are Last Keys in total, drop the required Last Keys to
# the total Last Keys.
if self.required_last_keys > self.total_last_keys:
self.required_last_keys = self.total_last_keys
logging.warning(f"[{self.player_name}] The Required Last Keys "
f"({self.options.required_last_keys.value}) is higher than the Available Last Keys "
f"({self.options.available_last_keys.value}). Lowering the required number to: "
f"{self.required_last_keys}")
self.options.required_last_keys.value = self.required_last_keys
# Place the Double or Roc Wing in local_early_items if the Early Escape option is being used.
if self.options.early_escape_item == EarlyEscapeItem.option_double:
self.multiworld.local_early_items[self.player][iname.double] = 1
elif self.options.early_escape_item == EarlyEscapeItem.option_roc_wing:
self.multiworld.local_early_items[self.player][iname.roc_wing] = 1
elif self.options.early_escape_item == EarlyEscapeItem.option_double_or_roc_wing:
self.multiworld.local_early_items[self.player][self.random.choice([iname.double, iname.roc_wing])] = 1
def create_regions(self) -> None:
# Create every Region object.
created_regions = [Region(name, self.player, self.multiworld) for name in get_all_region_names()]
# Attach the Regions to the Multiworld.
self.multiworld.regions.extend(created_regions)
for reg in created_regions:
# Add the Entrances to all the Regions.
ent_destinations_and_names = get_region_info(reg.name, "entrances")
if ent_destinations_and_names is not None:
reg.add_exits(ent_destinations_and_names)
# Add the Locations to all the Regions.
loc_names = get_region_info(reg.name, "locations")
if loc_names is None:
continue
locations_with_ids, locked_pairs = get_named_locations_data(loc_names, self.options)
reg.add_locations(locations_with_ids, CVCotMLocation)
# Place locked Items on all of their associated Locations.
for locked_loc, locked_item in locked_pairs.items():
self.get_location(locked_loc).place_locked_item(self.create_item(locked_item,
ItemClassification.progression))
def create_item(self, name: str, force_classification: typing.Optional[ItemClassification] = None) -> Item:
if force_classification is not None:
classification = force_classification
else:
classification = cvcotm_item_info[name].default_classification
code = cvcotm_item_info[name].code
if code is not None:
code += BASE_ID
created_item = CVCotMItem(name, classification, code, self.player)
return created_item
def create_items(self) -> None:
item_counts = get_item_counts(self)
# Set up the items correctly
self.multiworld.itempool += [self.create_item(item, classification) for classification in item_counts for item
in item_counts[classification] for _ in range(item_counts[classification][item])]
def set_rules(self) -> None:
# Set all the Entrance and Location rules properly.
CVCotMRules(self).set_cvcotm_rules()
def generate_output(self, output_directory: str) -> None:
# Get out all the Locations that are not Events. Only take the Iron Maiden switch if the Maiden Detonator is in
# the item pool.
active_locations = [loc for loc in self.multiworld.get_locations(self.player) if loc.address is not None and
(loc.name != lname.ct21 or self.options.iron_maiden_behavior ==
IronMaidenBehavior.option_detonator_in_pool)]
# Location data
offset_data = get_location_data(self, active_locations)
# Sub-weapons
if self.options.sub_weapon_shuffle:
offset_data.update(shuffle_sub_weapons(self))
# Item drop randomization
if self.options.item_drop_randomization:
offset_data.update(populate_enemy_drops(self))
# Countdown
if self.options.countdown:
offset_data.update(get_countdown_flags(self, active_locations))
# Start Inventory
start_inventory_data = get_start_inventory_data(self)
offset_data.update(start_inventory_data[0])
patch = CVCotMProcedurePatch(player=self.player, player_name=self.player_name)
patch_rom(self, patch, offset_data, start_inventory_data[1])
rom_path = os.path.join(output_directory, f"{self.multiworld.get_out_file_name_base(self.player)}"
f"{patch.patch_file_ending}")
patch.write(rom_path)
def fill_slot_data(self) -> dict:
return {"death_link": self.options.death_link.value,
"iron_maiden_behavior": self.options.iron_maiden_behavior.value,
"ignore_cleansing": self.options.ignore_cleansing.value,
"skip_tutorials": self.options.skip_tutorials.value,
"required_last_keys": self.required_last_keys,
"completion_goal": self.options.completion_goal.value}
def get_filler_item_name(self) -> str:
return self.random.choice(FILLER_ITEM_NAMES)
def modify_multidata(self, multidata: typing.Dict[str, typing.Any]):
# Put the player's unique authentication in connect_names.
multidata["connect_names"][base64.b64encode(self.auth).decode("ascii")] = \
multidata["connect_names"][self.player_name]