Files
Archipelago/worlds/mm3/locations.py
2026-03-08 21:42:06 +01:00

313 lines
14 KiB
Python

from BaseClasses import Location, Region
from typing import NamedTuple
from . import names
class MM3Location(Location):
game = "Mega Man 3"
class MM3Region(Region):
game = "Mega Man 3"
class LocationData(NamedTuple):
location_id: int | None
energy: bool = False
oneup_tank: bool = False
class RegionData(NamedTuple):
locations: dict[str, LocationData]
required_items: list[str]
parent: str = ""
mm3_regions: dict[str, RegionData] = {
"Needle Man Stage": RegionData({
names.needle_man: LocationData(0x0001),
names.get_needle_cannon: LocationData(0x0101),
names.get_rush_jet: LocationData(0x0111),
names.needle_man_c1: LocationData(0x0200, energy=True),
names.needle_man_c2: LocationData(0x0201, oneup_tank=True),
}, [names.needle_man_stage]),
"Magnet Man Stage": RegionData({
names.magnet_man: LocationData(0x0002),
names.get_magnet_missile: LocationData(0x0102),
names.magnet_man_c1: LocationData(0x0202, energy=True),
names.magnet_man_c2: LocationData(0x0203, energy=True),
names.magnet_man_c3: LocationData(0x0204, energy=True),
names.magnet_man_c4: LocationData(0x0205, energy=True),
names.magnet_man_c5: LocationData(0x0206, energy=True),
names.magnet_man_c6: LocationData(0x0207, energy=True),
names.magnet_man_c7: LocationData(0x0208, energy=True),
names.magnet_man_c8: LocationData(0x0209, energy=True),
}, [names.magnet_man_stage]),
"Gemini Man Stage": RegionData({
names.gemini_man: LocationData(0x0003),
names.get_gemini_laser: LocationData(0x0103),
names.gemini_man_c1: LocationData(0x020A, oneup_tank=True),
names.gemini_man_c2: LocationData(0x020B, energy=True),
names.gemini_man_c3: LocationData(0x020C, oneup_tank=True),
names.gemini_man_c4: LocationData(0x020D, energy=True),
names.gemini_man_c5: LocationData(0x020E, energy=True),
names.gemini_man_c6: LocationData(0x020F, oneup_tank=True),
names.gemini_man_c7: LocationData(0x0210, oneup_tank=True),
names.gemini_man_c8: LocationData(0x0211, energy=True),
names.gemini_man_c9: LocationData(0x0212, energy=True),
names.gemini_man_c10: LocationData(0x0213, oneup_tank=True),
}, [names.gemini_man_stage]),
"Hard Man Stage": RegionData({
names.hard_man: LocationData(0x0004),
names.get_hard_knuckle: LocationData(0x0104),
names.hard_man_c1: LocationData(0x0214, energy=True),
names.hard_man_c2: LocationData(0x0215, energy=True),
names.hard_man_c3: LocationData(0x0216, oneup_tank=True),
names.hard_man_c4: LocationData(0x0217, energy=True),
names.hard_man_c5: LocationData(0x0218, energy=True),
names.hard_man_c6: LocationData(0x0219, energy=True),
names.hard_man_c7: LocationData(0x021A, energy=True),
}, [names.hard_man_stage]),
"Top Man Stage": RegionData({
names.top_man: LocationData(0x0005),
names.get_top_spin: LocationData(0x0105),
names.top_man_c1: LocationData(0x021B, energy=True),
names.top_man_c2: LocationData(0x021C, energy=True),
names.top_man_c3: LocationData(0x021D, energy=True),
names.top_man_c4: LocationData(0x021E, energy=True),
names.top_man_c5: LocationData(0x021F, energy=True),
names.top_man_c6: LocationData(0x0220, oneup_tank=True),
names.top_man_c7: LocationData(0x0221, energy=True),
names.top_man_c8: LocationData(0x0222, energy=True),
}, [names.top_man_stage]),
"Snake Man Stage": RegionData({
names.snake_man: LocationData(0x0006),
names.get_search_snake: LocationData(0x0106),
names.snake_man_c1: LocationData(0x0223, energy=True),
names.snake_man_c2: LocationData(0x0224, energy=True),
names.snake_man_c3: LocationData(0x0225, oneup_tank=True),
names.snake_man_c4: LocationData(0x0226, oneup_tank=True),
names.snake_man_c5: LocationData(0x0227, energy=True),
}, [names.snake_man_stage]),
"Spark Man Stage": RegionData({
names.spark_man: LocationData(0x0007),
names.get_spark_shock: LocationData(0x0107),
names.spark_man_c1: LocationData(0x0228, energy=True),
names.spark_man_c2: LocationData(0x0229, energy=True),
names.spark_man_c3: LocationData(0x022A, energy=True),
names.spark_man_c4: LocationData(0x022B, energy=True),
names.spark_man_c5: LocationData(0x022C, energy=True),
names.spark_man_c6: LocationData(0x022D, energy=True),
}, [names.spark_man_stage]),
"Shadow Man Stage": RegionData({
names.shadow_man: LocationData(0x0008),
names.get_shadow_blade: LocationData(0x0108),
names.get_rush_marine: LocationData(0x0112),
names.shadow_man_c1: LocationData(0x022E, energy=True),
names.shadow_man_c2: LocationData(0x022F, energy=True),
names.shadow_man_c3: LocationData(0x0230, energy=True),
names.shadow_man_c4: LocationData(0x0231, energy=True),
}, [names.shadow_man_stage]),
"Doc Robot (Needle) - Air": RegionData({
names.doc_air: LocationData(0x0010),
names.doc_needle_c1: LocationData(0x0232, energy=True),
names.doc_needle_c2: LocationData(0x0233, oneup_tank=True),
names.doc_needle_c3: LocationData(0x0234, oneup_tank=True),
}, [names.doc_needle_stage]),
"Doc Robot (Needle) - Crash": RegionData({
names.doc_crash: LocationData(0x0011),
names.doc_needle: LocationData(None),
names.doc_needle_c4: LocationData(0x0235, energy=True),
names.doc_needle_c5: LocationData(0x0236, energy=True),
names.doc_needle_c6: LocationData(0x0237, energy=True),
names.doc_needle_c7: LocationData(0x0238, energy=True),
names.doc_needle_c8: LocationData(0x0239, energy=True),
names.doc_needle_c9: LocationData(0x023A, energy=True),
names.doc_needle_c10: LocationData(0x023B, energy=True),
names.doc_needle_c11: LocationData(0x023C, energy=True),
}, [], parent="Doc Robot (Needle) - Air"),
"Doc Robot (Gemini) - Flash": RegionData({
names.doc_flash: LocationData(0x0012),
names.doc_gemini_c1: LocationData(0x023D, oneup_tank=True),
names.doc_gemini_c2: LocationData(0x023E, oneup_tank=True),
}, [names.doc_gemini_stage]),
"Doc Robot (Gemini) - Bubble": RegionData({
names.doc_bubble: LocationData(0x0013),
names.doc_gemini: LocationData(None),
names.doc_gemini_c3: LocationData(0x023F, energy=True),
names.doc_gemini_c4: LocationData(0x0240, energy=True),
}, [], parent="Doc Robot (Gemini) - Flash"),
"Doc Robot (Shadow) - Wood": RegionData({
names.doc_wood: LocationData(0x0014),
}, [names.doc_shadow_stage]),
"Doc Robot (Shadow) - Heat": RegionData({
names.doc_heat: LocationData(0x0015),
names.doc_shadow: LocationData(None),
names.doc_shadow_c1: LocationData(0x0243, energy=True),
names.doc_shadow_c2: LocationData(0x0244, energy=True),
names.doc_shadow_c3: LocationData(0x0245, energy=True),
names.doc_shadow_c4: LocationData(0x0246, energy=True),
names.doc_shadow_c5: LocationData(0x0247, energy=True),
}, [], parent="Doc Robot (Shadow) - Wood"),
"Doc Robot (Spark) - Metal": RegionData({
names.doc_metal: LocationData(0x0016),
names.doc_spark_c1: LocationData(0x0241, energy=True),
}, [names.doc_spark_stage]),
"Doc Robot (Spark) - Quick": RegionData({
names.doc_quick: LocationData(0x0017),
names.doc_spark: LocationData(None),
names.doc_spark_c2: LocationData(0x0242, energy=True),
}, [], parent="Doc Robot (Spark) - Metal"),
"Break Man": RegionData({
names.break_man: LocationData(0x000F),
names.break_stage: LocationData(None),
}, [names.doc_needle, names.doc_gemini, names.doc_spark, names.doc_shadow]),
"Wily Stage 1": RegionData({
names.wily_1_boss: LocationData(0x0009),
names.wily_stage_1: LocationData(None),
names.wily_1_c1: LocationData(0x0248, oneup_tank=True),
names.wily_1_c2: LocationData(0x0249, oneup_tank=True),
names.wily_1_c3: LocationData(0x024A, energy=True),
names.wily_1_c4: LocationData(0x024B, oneup_tank=True),
names.wily_1_c5: LocationData(0x024C, energy=True),
names.wily_1_c6: LocationData(0x024D, energy=True),
names.wily_1_c7: LocationData(0x024E, energy=True),
names.wily_1_c8: LocationData(0x024F, oneup_tank=True),
names.wily_1_c9: LocationData(0x0250, energy=True),
names.wily_1_c10: LocationData(0x0251, energy=True),
names.wily_1_c11: LocationData(0x0252, energy=True),
names.wily_1_c12: LocationData(0x0253, energy=True),
}, [names.break_stage], parent="Break Man"),
"Wily Stage 2": RegionData({
names.wily_2_boss: LocationData(0x000A),
names.wily_stage_2: LocationData(None),
names.wily_2_c1: LocationData(0x0254, energy=True),
names.wily_2_c2: LocationData(0x0255, energy=True),
names.wily_2_c3: LocationData(0x0256, oneup_tank=True),
names.wily_2_c4: LocationData(0x0257, energy=True),
names.wily_2_c5: LocationData(0x0258, energy=True),
names.wily_2_c6: LocationData(0x0259, energy=True),
names.wily_2_c7: LocationData(0x025A, energy=True),
names.wily_2_c8: LocationData(0x025B, energy=True),
names.wily_2_c9: LocationData(0x025C, oneup_tank=True),
names.wily_2_c10: LocationData(0x025D, energy=True),
names.wily_2_c11: LocationData(0x025E, oneup_tank=True),
names.wily_2_c12: LocationData(0x025F, energy=True),
names.wily_2_c13: LocationData(0x0260, energy=True),
}, [names.wily_stage_1], parent="Wily Stage 1"),
"Wily Stage 3": RegionData({
names.wily_3_boss: LocationData(0x000B),
names.wily_stage_3: LocationData(None),
names.wily_3_c1: LocationData(0x0261, energy=True),
names.wily_3_c2: LocationData(0x0262, energy=True),
names.wily_3_c3: LocationData(0x0263, oneup_tank=True),
names.wily_3_c4: LocationData(0x0264, oneup_tank=True),
names.wily_3_c5: LocationData(0x0265, energy=True),
names.wily_3_c6: LocationData(0x0266, energy=True),
names.wily_3_c7: LocationData(0x0267, energy=True),
names.wily_3_c8: LocationData(0x0268, energy=True),
names.wily_3_c9: LocationData(0x0269, energy=True),
names.wily_3_c10: LocationData(0x026A, oneup_tank=True),
names.wily_3_c11: LocationData(0x026B, oneup_tank=True)
}, [names.wily_stage_2], parent="Wily Stage 2"),
"Wily Stage 4": RegionData({
names.wily_stage_4: LocationData(None),
names.wily_4_c1: LocationData(0x026C, energy=True),
names.wily_4_c2: LocationData(0x026D, energy=True),
names.wily_4_c3: LocationData(0x026E, energy=True),
names.wily_4_c4: LocationData(0x026F, energy=True),
names.wily_4_c5: LocationData(0x0270, energy=True),
names.wily_4_c6: LocationData(0x0271, energy=True),
names.wily_4_c7: LocationData(0x0272, energy=True),
names.wily_4_c8: LocationData(0x0273, energy=True),
names.wily_4_c9: LocationData(0x0274, energy=True),
names.wily_4_c10: LocationData(0x0275, oneup_tank=True),
names.wily_4_c11: LocationData(0x0276, energy=True),
names.wily_4_c12: LocationData(0x0277, oneup_tank=True),
names.wily_4_c13: LocationData(0x0278, energy=True),
names.wily_4_c14: LocationData(0x0279, energy=True),
names.wily_4_c15: LocationData(0x027A, energy=True),
names.wily_4_c16: LocationData(0x027B, energy=True),
names.wily_4_c17: LocationData(0x027C, energy=True),
names.wily_4_c18: LocationData(0x027D, energy=True),
names.wily_4_c19: LocationData(0x027E, energy=True),
names.wily_4_c20: LocationData(0x027F, energy=True),
}, [names.wily_stage_3], parent="Wily Stage 3"),
"Wily Stage 5": RegionData({
names.wily_5_boss: LocationData(0x000D),
names.wily_stage_5: LocationData(None),
names.wily_5_c1: LocationData(0x0280, energy=True),
names.wily_5_c2: LocationData(0x0281, energy=True),
names.wily_5_c3: LocationData(0x0282, oneup_tank=True),
names.wily_5_c4: LocationData(0x0283, oneup_tank=True),
}, [names.wily_stage_4], parent="Wily Stage 4"),
"Wily Stage 6": RegionData({
names.gamma: LocationData(None),
names.wily_6_c1: LocationData(0x0284, oneup_tank=True),
names.wily_6_c2: LocationData(0x0285, oneup_tank=True),
names.wily_6_c3: LocationData(0x0286, energy=True),
names.wily_6_c4: LocationData(0x0287, energy=True),
names.wily_6_c5: LocationData(0x0288, oneup_tank=True),
names.wily_6_c6: LocationData(0x0289, oneup_tank=True),
names.wily_6_c7: LocationData(0x028A, energy=True),
}, [names.wily_stage_5], parent="Wily Stage 5"),
}
def get_boss_locations(region: str) -> list[str]:
return [location for location, data in mm3_regions[region].locations.items()
if not data.energy and not data.oneup_tank]
def get_energy_locations(region: str) -> list[str]:
return [location for location, data in mm3_regions[region].locations.items() if data.energy]
def get_oneup_locations(region: str) -> list[str]:
return [location for location, data in mm3_regions[region].locations.items() if data.oneup_tank]
location_table: dict[str, int | None] = {
location: data.location_id for region in mm3_regions.values() for location, data in region.locations.items()
}
location_groups = {
"Get Equipped": {
names.get_needle_cannon,
names.get_magnet_missile,
names.get_gemini_laser,
names.get_hard_knuckle,
names.get_top_spin,
names.get_search_snake,
names.get_spark_shock,
names.get_shadow_blade,
names.get_rush_marine,
names.get_rush_jet,
},
**{name: {location for location, data in region.locations.items() if data.location_id} for name, region in mm3_regions.items()}
}
lookup_location_to_id: dict[str, int] = {location: idx for location, idx in location_table.items() if idx is not None}