From 0efc13fc8a2b8b8a3bfd391a9f8ef5be804337ab Mon Sep 17 00:00:00 2001 From: JaredWeakStrike <96694163+JaredWeakStrike@users.noreply.github.com> Date: Tue, 16 Jan 2024 07:12:33 -0500 Subject: [PATCH] KH2: Location Groups and Subclasses (#2700) --- worlds/kh2/Client.py | 3 +- worlds/kh2/Items.py | 21 +----- worlds/kh2/Locations.py | 145 +++++++++++++++++++-------------------- worlds/kh2/Regions.py | 11 +-- worlds/kh2/Rules.py | 2 +- worlds/kh2/Subclasses.py | 29 ++++++++ worlds/kh2/__init__.py | 10 +-- 7 files changed, 118 insertions(+), 103 deletions(-) create mode 100644 worlds/kh2/Subclasses.py diff --git a/worlds/kh2/Client.py b/worlds/kh2/Client.py index 544e7107..513d8525 100644 --- a/worlds/kh2/Client.py +++ b/worlds/kh2/Client.py @@ -821,7 +821,8 @@ class KH2Context(CommonContext): def finishedGame(ctx: KH2Context, message): if ctx.kh2slotdata['FinalXemnas'] == 1: - if not ctx.final_xemnas and ctx.kh2_loc_name_to_id[LocationName.FinalXemnas] in ctx.locations_checked: + if not ctx.final_xemnas and ctx.kh2_read_byte(ctx.Save + all_world_locations[LocationName.FinalXemnas].addrObtained) \ + & 0x1 << all_world_locations[LocationName.FinalXemnas].bitIndex > 0: ctx.final_xemnas = True # three proofs if ctx.kh2slotdata['Goal'] == 0: diff --git a/worlds/kh2/Items.py b/worlds/kh2/Items.py index 3e656b41..cb3d7c8d 100644 --- a/worlds/kh2/Items.py +++ b/worlds/kh2/Items.py @@ -2,22 +2,7 @@ import typing from BaseClasses import Item from .Names import ItemName - - -class KH2Item(Item): - game: str = "Kingdom Hearts 2" - - -class ItemData(typing.NamedTuple): - quantity: int = 0 - kh2id: int = 0 - # Save+ mem addr - memaddr: int = 0 - # some items have bitmasks. if bitmask>0 bitor to give item else - bitmask: int = 0 - # if ability then - ability: bool = False - +from .Subclasses import ItemData # 0x130000 Reports_Table = { @@ -209,7 +194,7 @@ Armor_Table = { ItemName.GrandRibbon: ItemData(1, 157, 0x35D4), } Usefull_Table = { - ItemName.MickeyMunnyPouch: ItemData(1, 535, 0x3695), # 5000 munny per + ItemName.MickeyMunnyPouch: ItemData(1, 535, 0x3695), # 5000 munny per ItemName.OletteMunnyPouch: ItemData(2, 362, 0x363C), # 2500 munny per ItemName.HadesCupTrophy: ItemData(1, 537, 0x3696), ItemName.UnknownDisk: ItemData(1, 462, 0x365F), @@ -349,7 +334,7 @@ GoofyAbility_Table = { Wincon_Table = { ItemName.LuckyEmblem: ItemData(kh2id=367, memaddr=0x3641), # letter item - ItemName.Victory: ItemData(kh2id=263, memaddr=0x111), + # ItemName.Victory: ItemData(kh2id=263, memaddr=0x111), ItemName.Bounty: ItemData(kh2id=461, memaddr=0x365E), # Dummy 14 # ItemName.UniversalKey:ItemData(,365,0x363F,0)#Tournament Poster } diff --git a/worlds/kh2/Locations.py b/worlds/kh2/Locations.py index 9d7d9484..61fafe90 100644 --- a/worlds/kh2/Locations.py +++ b/worlds/kh2/Locations.py @@ -1,19 +1,9 @@ import typing from BaseClasses import Location -from .Names import LocationName, ItemName - - -class KH2Location(Location): - game: str = "Kingdom Hearts 2" - - -class LocationData(typing.NamedTuple): - locid: int - yml: str - charName: str = "Sora" - charNumber: int = 1 - +from .Names import LocationName, ItemName, RegionName +from .Subclasses import LocationData +from .Regions import KH2REGIONS # data's addrcheck sys3 addr obtained roomid bit index is eventid LoD_Checks = { @@ -541,7 +531,7 @@ TWTNW_Checks = { LocationName.Xemnas1: LocationData(26, "Double Get Bonus"), LocationName.Xemnas1GetBonus: LocationData(26, "Second Get Bonus"), LocationName.Xemnas1SecretAnsemReport13: LocationData(537, "Chest"), - LocationName.FinalXemnas: LocationData(71, "Get Bonus"), + # LocationName.FinalXemnas: LocationData(71, "Get Bonus"), LocationName.XemnasDataPowerBoost: LocationData(554, "Chest"), } @@ -806,74 +796,75 @@ Atlantica_Checks = { } event_location_to_item = { - LocationName.HostileProgramEventLocation: ItemName.HostileProgramEvent, - LocationName.McpEventLocation: ItemName.McpEvent, + LocationName.HostileProgramEventLocation: ItemName.HostileProgramEvent, + LocationName.McpEventLocation: ItemName.McpEvent, # LocationName.ASLarxeneEventLocation: ItemName.ASLarxeneEvent, - LocationName.DataLarxeneEventLocation: ItemName.DataLarxeneEvent, - LocationName.BarbosaEventLocation: ItemName.BarbosaEvent, - LocationName.GrimReaper1EventLocation: ItemName.GrimReaper1Event, - LocationName.GrimReaper2EventLocation: ItemName.GrimReaper2Event, - LocationName.DataLuxordEventLocation: ItemName.DataLuxordEvent, - LocationName.DataAxelEventLocation: ItemName.DataAxelEvent, - LocationName.CerberusEventLocation: ItemName.CerberusEvent, - LocationName.OlympusPeteEventLocation: ItemName.OlympusPeteEvent, - LocationName.HydraEventLocation: ItemName.HydraEvent, + LocationName.DataLarxeneEventLocation: ItemName.DataLarxeneEvent, + LocationName.BarbosaEventLocation: ItemName.BarbosaEvent, + LocationName.GrimReaper1EventLocation: ItemName.GrimReaper1Event, + LocationName.GrimReaper2EventLocation: ItemName.GrimReaper2Event, + LocationName.DataLuxordEventLocation: ItemName.DataLuxordEvent, + LocationName.DataAxelEventLocation: ItemName.DataAxelEvent, + LocationName.CerberusEventLocation: ItemName.CerberusEvent, + LocationName.OlympusPeteEventLocation: ItemName.OlympusPeteEvent, + LocationName.HydraEventLocation: ItemName.HydraEvent, LocationName.OcPainAndPanicCupEventLocation: ItemName.OcPainAndPanicCupEvent, - LocationName.OcCerberusCupEventLocation: ItemName.OcCerberusCupEvent, - LocationName.HadesEventLocation: ItemName.HadesEvent, + LocationName.OcCerberusCupEventLocation: ItemName.OcCerberusCupEvent, + LocationName.HadesEventLocation: ItemName.HadesEvent, # LocationName.ASZexionEventLocation: ItemName.ASZexionEvent, - LocationName.DataZexionEventLocation: ItemName.DataZexionEvent, - LocationName.Oc2TitanCupEventLocation: ItemName.Oc2TitanCupEvent, - LocationName.Oc2GofCupEventLocation: ItemName.Oc2GofCupEvent, + LocationName.DataZexionEventLocation: ItemName.DataZexionEvent, + LocationName.Oc2TitanCupEventLocation: ItemName.Oc2TitanCupEvent, + LocationName.Oc2GofCupEventLocation: ItemName.Oc2GofCupEvent, # LocationName.Oc2CupsEventLocation: ItemName.Oc2CupsEventLocation, - LocationName.HadesCupEventLocations: ItemName.HadesCupEvents, - LocationName.PrisonKeeperEventLocation: ItemName.PrisonKeeperEvent, - LocationName.OogieBoogieEventLocation: ItemName.OogieBoogieEvent, - LocationName.ExperimentEventLocation: ItemName.ExperimentEvent, + LocationName.HadesCupEventLocations: ItemName.HadesCupEvents, + LocationName.PrisonKeeperEventLocation: ItemName.PrisonKeeperEvent, + LocationName.OogieBoogieEventLocation: ItemName.OogieBoogieEvent, + LocationName.ExperimentEventLocation: ItemName.ExperimentEvent, # LocationName.ASVexenEventLocation: ItemName.ASVexenEvent, - LocationName.DataVexenEventLocation: ItemName.DataVexenEvent, - LocationName.ShanYuEventLocation: ItemName.ShanYuEvent, - LocationName.AnsemRikuEventLocation: ItemName.AnsemRikuEvent, - LocationName.StormRiderEventLocation: ItemName.StormRiderEvent, - LocationName.DataXigbarEventLocation: ItemName.DataXigbarEvent, - LocationName.RoxasEventLocation: ItemName.RoxasEvent, - LocationName.XigbarEventLocation: ItemName.XigbarEvent, - LocationName.LuxordEventLocation: ItemName.LuxordEvent, - LocationName.SaixEventLocation: ItemName.SaixEvent, - LocationName.XemnasEventLocation: ItemName.XemnasEvent, - LocationName.ArmoredXemnasEventLocation: ItemName.ArmoredXemnasEvent, - LocationName.ArmoredXemnas2EventLocation: ItemName.ArmoredXemnas2Event, + LocationName.DataVexenEventLocation: ItemName.DataVexenEvent, + LocationName.ShanYuEventLocation: ItemName.ShanYuEvent, + LocationName.AnsemRikuEventLocation: ItemName.AnsemRikuEvent, + LocationName.StormRiderEventLocation: ItemName.StormRiderEvent, + LocationName.DataXigbarEventLocation: ItemName.DataXigbarEvent, + LocationName.RoxasEventLocation: ItemName.RoxasEvent, + LocationName.XigbarEventLocation: ItemName.XigbarEvent, + LocationName.LuxordEventLocation: ItemName.LuxordEvent, + LocationName.SaixEventLocation: ItemName.SaixEvent, + LocationName.XemnasEventLocation: ItemName.XemnasEvent, + LocationName.ArmoredXemnasEventLocation: ItemName.ArmoredXemnasEvent, + LocationName.ArmoredXemnas2EventLocation: ItemName.ArmoredXemnas2Event, # LocationName.FinalXemnasEventLocation: ItemName.FinalXemnasEvent, - LocationName.DataXemnasEventLocation: ItemName.DataXemnasEvent, - LocationName.ThresholderEventLocation: ItemName.ThresholderEvent, - LocationName.BeastEventLocation: ItemName.BeastEvent, - LocationName.DarkThornEventLocation: ItemName.DarkThornEvent, - LocationName.XaldinEventLocation: ItemName.XaldinEvent, - LocationName.DataXaldinEventLocation: ItemName.DataXaldinEvent, - LocationName.TwinLordsEventLocation: ItemName.TwinLordsEvent, - LocationName.GenieJafarEventLocation: ItemName.GenieJafarEvent, + LocationName.DataXemnasEventLocation: ItemName.DataXemnasEvent, + LocationName.ThresholderEventLocation: ItemName.ThresholderEvent, + LocationName.BeastEventLocation: ItemName.BeastEvent, + LocationName.DarkThornEventLocation: ItemName.DarkThornEvent, + LocationName.XaldinEventLocation: ItemName.XaldinEvent, + LocationName.DataXaldinEventLocation: ItemName.DataXaldinEvent, + LocationName.TwinLordsEventLocation: ItemName.TwinLordsEvent, + LocationName.GenieJafarEventLocation: ItemName.GenieJafarEvent, # LocationName.ASLexaeusEventLocation: ItemName.ASLexaeusEvent, - LocationName.DataLexaeusEventLocation: ItemName.DataLexaeusEvent, - LocationName.ScarEventLocation: ItemName.ScarEvent, - LocationName.GroundShakerEventLocation: ItemName.GroundShakerEvent, - LocationName.DataSaixEventLocation: ItemName.DataSaixEvent, - LocationName.HBDemyxEventLocation: ItemName.HBDemyxEvent, - LocationName.ThousandHeartlessEventLocation: ItemName.ThousandHeartlessEvent, - LocationName.Mushroom13EventLocation: ItemName.Mushroom13Event, - LocationName.SephiEventLocation: ItemName.SephiEvent, - LocationName.DataDemyxEventLocation: ItemName.DataDemyxEvent, - LocationName.CorFirstFightEventLocation: ItemName.CorFirstFightEvent, - LocationName.CorSecondFightEventLocation: ItemName.CorSecondFightEvent, - LocationName.TransportEventLocation: ItemName.TransportEvent, - LocationName.OldPeteEventLocation: ItemName.OldPeteEvent, - LocationName.FuturePeteEventLocation: ItemName.FuturePeteEvent, + LocationName.DataLexaeusEventLocation: ItemName.DataLexaeusEvent, + LocationName.ScarEventLocation: ItemName.ScarEvent, + LocationName.GroundShakerEventLocation: ItemName.GroundShakerEvent, + LocationName.DataSaixEventLocation: ItemName.DataSaixEvent, + LocationName.HBDemyxEventLocation: ItemName.HBDemyxEvent, + LocationName.ThousandHeartlessEventLocation: ItemName.ThousandHeartlessEvent, + LocationName.Mushroom13EventLocation: ItemName.Mushroom13Event, + LocationName.SephiEventLocation: ItemName.SephiEvent, + LocationName.DataDemyxEventLocation: ItemName.DataDemyxEvent, + LocationName.CorFirstFightEventLocation: ItemName.CorFirstFightEvent, + LocationName.CorSecondFightEventLocation: ItemName.CorSecondFightEvent, + LocationName.TransportEventLocation: ItemName.TransportEvent, + LocationName.OldPeteEventLocation: ItemName.OldPeteEvent, + LocationName.FuturePeteEventLocation: ItemName.FuturePeteEvent, # LocationName.ASMarluxiaEventLocation: ItemName.ASMarluxiaEvent, - LocationName.DataMarluxiaEventLocation: ItemName.DataMarluxiaEvent, - LocationName.TerraEventLocation: ItemName.TerraEvent, - LocationName.TwilightThornEventLocation: ItemName.TwilightThornEvent, - LocationName.Axel1EventLocation: ItemName.Axel1Event, - LocationName.Axel2EventLocation: ItemName.Axel2Event, - LocationName.DataRoxasEventLocation: ItemName.DataRoxasEvent, + LocationName.DataMarluxiaEventLocation: ItemName.DataMarluxiaEvent, + LocationName.TerraEventLocation: ItemName.TerraEvent, + LocationName.TwilightThornEventLocation: ItemName.TwilightThornEvent, + LocationName.Axel1EventLocation: ItemName.Axel1Event, + LocationName.Axel2EventLocation: ItemName.Axel2Event, + LocationName.DataRoxasEventLocation: ItemName.DataRoxasEvent, + LocationName.FinalXemnasEventLocation: ItemName.Victory, } all_weapon_slot = { LocationName.FAKESlot, @@ -1361,3 +1352,9 @@ exclusion_table = { location for location, data in all_locations.items() if location not in event_location_to_item.keys() and location not in popups_set and location != LocationName.StationofSerenityPotion and data.yml == "Chest" } } + +location_groups: typing.Dict[str, list] +location_groups = { + Region_Name: [loc for loc in Region_Locs if "Event" not in loc] + for Region_Name, Region_Locs in KH2REGIONS.items() if Region_Locs +} diff --git a/worlds/kh2/Regions.py b/worlds/kh2/Regions.py index 6dd83131..235500ec 100644 --- a/worlds/kh2/Regions.py +++ b/worlds/kh2/Regions.py @@ -1,9 +1,11 @@ import typing from BaseClasses import MultiWorld, Region +from . import Locations -from .Locations import KH2Location, event_location_to_item -from . import LocationName, RegionName, Events_Table +from .Subclasses import KH2Location +from .Names import LocationName, RegionName +from .Items import Events_Table KH2REGIONS: typing.Dict[str, typing.List[str]] = { "Menu": [], @@ -788,7 +790,7 @@ KH2REGIONS: typing.Dict[str, typing.List[str]] = { LocationName.ArmoredXemnas2EventLocation ], RegionName.FinalXemnas: [ - LocationName.FinalXemnas + LocationName.FinalXemnasEventLocation ], RegionName.DataXemnas: [ LocationName.XemnasDataPowerBoost, @@ -1020,7 +1022,8 @@ def create_regions(self): multiworld.regions += [create_region(multiworld, player, active_locations, region, locations) for region, locations in KH2REGIONS.items()] # fill the event locations with events - for location, item in event_location_to_item.items(): + + for location, item in Locations.event_location_to_item.items(): multiworld.get_location(location, player).place_locked_item( multiworld.worlds[player].create_event_item(item)) diff --git a/worlds/kh2/Rules.py b/worlds/kh2/Rules.py index 111d12d0..65f690fd 100644 --- a/worlds/kh2/Rules.py +++ b/worlds/kh2/Rules.py @@ -270,7 +270,7 @@ class KH2WorldRules(KH2Rules): add_item_rule(location, lambda item: item.player == self.player and item.name in SupportAbility_Table.keys()) def set_kh2_goal(self): - final_xemnas_location = self.multiworld.get_location(LocationName.FinalXemnas, self.player) + final_xemnas_location = self.multiworld.get_location(LocationName.FinalXemnasEventLocation, self.player) if self.multiworld.Goal[self.player] == "three_proofs": final_xemnas_location.access_rule = lambda state: self.kh2_has_all(three_proofs, state) if self.multiworld.FinalXemnas[self.player]: diff --git a/worlds/kh2/Subclasses.py b/worlds/kh2/Subclasses.py new file mode 100644 index 00000000..79f52c41 --- /dev/null +++ b/worlds/kh2/Subclasses.py @@ -0,0 +1,29 @@ +import typing + +from BaseClasses import Location, Item + + +class KH2Location(Location): + game: str = "Kingdom Hearts 2" + + +class LocationData(typing.NamedTuple): + locid: int + yml: str + charName: str = "Sora" + charNumber: int = 1 + + +class KH2Item(Item): + game: str = "Kingdom Hearts 2" + + +class ItemData(typing.NamedTuple): + quantity: int = 0 + kh2id: int = 0 + # Save+ mem addr + memaddr: int = 0 + # some items have bitmasks. if bitmask>0 bitor to give item else + bitmask: int = 0 + # if ability then + ability: bool = False diff --git a/worlds/kh2/__init__.py b/worlds/kh2/__init__.py index 2bddbd5e..d02614d3 100644 --- a/worlds/kh2/__init__.py +++ b/worlds/kh2/__init__.py @@ -12,6 +12,7 @@ from .OpenKH import patch_kh2 from .Options import KingdomHearts2Options from .Regions import create_regions, connect_regions from .Rules import * +from .Subclasses import KH2Item def launch_client(): @@ -49,7 +50,9 @@ class KH2World(World): for item_id, item in enumerate(item_dictionary_table.keys(), 0x130000)} location_name_to_id = {item: location for location, item in enumerate(all_locations.keys(), 0x130000)} + item_name_groups = item_groups + location_name_groups = location_groups visitlocking_dict: Dict[str, int] plando_locations: Dict[str, str] @@ -253,11 +256,8 @@ class KH2World(World): self.goofy_gen_early() self.keyblade_gen_early() - if self.multiworld.FinalXemnas[self.player]: - self.plando_locations[LocationName.FinalXemnas] = ItemName.Victory - else: - self.plando_locations[LocationName.FinalXemnas] = self.create_filler().name - self.total_locations -= 1 + # final xemnas isn't a location anymore + # self.total_locations -= 1 if self.options.WeaponSlotStartHint: for location in all_weapon_slot: