Landstalker: Fix issues on generation (#4345)
This commit is contained in:
		
							parent
							
								
									78637c96a7
								
							
						
					
					
						commit
						5578ccd578
					
				| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
 | 
			
		||||
BASE_ITEM_ID = 4000
 | 
			
		||||
 | 
			
		||||
BASE_LOCATION_ID = 4000
 | 
			
		||||
BASE_GROUND_LOCATION_ID = BASE_LOCATION_ID + 256
 | 
			
		||||
BASE_SHOP_LOCATION_ID = BASE_GROUND_LOCATION_ID + 30
 | 
			
		||||
BASE_REWARD_LOCATION_ID = BASE_SHOP_LOCATION_ID + 50
 | 
			
		||||
 | 
			
		||||
ENDGAME_REGIONS = [
 | 
			
		||||
    "kazalt",
 | 
			
		||||
    "king_nole_labyrinth_pre_door",
 | 
			
		||||
    "king_nole_labyrinth_post_door",
 | 
			
		||||
    "king_nole_labyrinth_exterior",
 | 
			
		||||
    "king_nole_labyrinth_fall_from_exterior",
 | 
			
		||||
    "king_nole_labyrinth_path_to_palace",
 | 
			
		||||
    "king_nole_labyrinth_raft_entrance",
 | 
			
		||||
    "king_nole_labyrinth_raft",
 | 
			
		||||
    "king_nole_labyrinth_sacred_tree",
 | 
			
		||||
    "king_nole_palace"
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
ENDGAME_PROGRESSION_ITEMS = [
 | 
			
		||||
    "Gola's Nail",
 | 
			
		||||
    "Gola's Fang",
 | 
			
		||||
    "Gola's Horn",
 | 
			
		||||
    "Logs",
 | 
			
		||||
    "Snow Spikes"
 | 
			
		||||
]
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ def generate_lithograph_hint(world: "LandstalkerWorld"):
 | 
			
		|||
            words.append(item.name.split(" ")[0].upper())
 | 
			
		||||
        if item.location.player != world.player:
 | 
			
		||||
            # Add player name if it's not in our own world
 | 
			
		||||
            player_name = world.multiworld.get_player_name(world.player)
 | 
			
		||||
            player_name = world.multiworld.get_player_name(item.location.player)
 | 
			
		||||
            words.append(player_name.upper())
 | 
			
		||||
        world.random.shuffle(words)
 | 
			
		||||
        hint_text += " ".join(words) + "\n"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,7 @@
 | 
			
		|||
from typing import Dict, List, NamedTuple
 | 
			
		||||
 | 
			
		||||
from BaseClasses import Item, ItemClassification
 | 
			
		||||
 | 
			
		||||
BASE_ITEM_ID = 4000
 | 
			
		||||
from .Constants import BASE_ITEM_ID
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LandstalkerItem(Item):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,15 +1,11 @@
 | 
			
		|||
from typing import Dict, Optional
 | 
			
		||||
 | 
			
		||||
from BaseClasses import Location, ItemClassification, Item
 | 
			
		||||
from .Constants import *
 | 
			
		||||
from .Regions import LandstalkerRegion
 | 
			
		||||
from .data.item_source import ITEM_SOURCES_JSON
 | 
			
		||||
from .data.world_path import WORLD_PATHS_JSON
 | 
			
		||||
 | 
			
		||||
BASE_LOCATION_ID = 4000
 | 
			
		||||
BASE_GROUND_LOCATION_ID = BASE_LOCATION_ID + 256
 | 
			
		||||
BASE_SHOP_LOCATION_ID = BASE_GROUND_LOCATION_ID + 30
 | 
			
		||||
BASE_REWARD_LOCATION_ID = BASE_SHOP_LOCATION_ID + 50
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LandstalkerLocation(Location):
 | 
			
		||||
    game: str = "Landstalker - The Treasures of King Nole"
 | 
			
		||||
| 
						 | 
				
			
			@ -21,10 +17,14 @@ class LandstalkerLocation(Location):
 | 
			
		|||
        self.type_string = type_string
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def create_locations(player: int, regions_table: Dict[str, LandstalkerRegion], name_to_id_table: Dict[str, int]):
 | 
			
		||||
def create_locations(player: int, regions_table: Dict[str, LandstalkerRegion],
 | 
			
		||||
                     name_to_id_table: Dict[str, int], reach_kazalt_goal: bool):
 | 
			
		||||
    # Create real locations from the data inside the corresponding JSON file
 | 
			
		||||
    for data in ITEM_SOURCES_JSON:
 | 
			
		||||
        region_id = data["nodeId"]
 | 
			
		||||
        # If "Reach Kazalt" goal is enabled and location is beyond Kazalt, don't create it
 | 
			
		||||
        if reach_kazalt_goal and region_id in ENDGAME_REGIONS:
 | 
			
		||||
            continue
 | 
			
		||||
        region = regions_table[region_id]
 | 
			
		||||
        new_location = LandstalkerLocation(player, data["name"], name_to_id_table[data["name"]], region, data["type"])
 | 
			
		||||
        region.locations.append(new_location)
 | 
			
		||||
| 
						 | 
				
			
			@ -32,6 +32,10 @@ def create_locations(player: int, regions_table: Dict[str, LandstalkerRegion], n
 | 
			
		|||
    # Create fake event locations that will be used to determine if some key regions has been visited
 | 
			
		||||
    regions_with_entrance_checks = []
 | 
			
		||||
    for data in WORLD_PATHS_JSON:
 | 
			
		||||
        # If "Reach Kazalt" goal is enabled and region is beyond Kazalt, don't create any event for it since it would
 | 
			
		||||
        # be useless anyway
 | 
			
		||||
        if reach_kazalt_goal and data["fromId"] in ENDGAME_REGIONS:
 | 
			
		||||
            continue
 | 
			
		||||
        if "requiredNodes" in data:
 | 
			
		||||
            regions_with_entrance_checks.extend([region_id for region_id in data["requiredNodes"]])
 | 
			
		||||
    regions_with_entrance_checks = sorted(set(regions_with_entrance_checks))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@ from typing import ClassVar, Set
 | 
			
		|||
 | 
			
		||||
from BaseClasses import LocationProgressType, Tutorial
 | 
			
		||||
from worlds.AutoWorld import WebWorld, World
 | 
			
		||||
from .Constants import *
 | 
			
		||||
from .Hints import *
 | 
			
		||||
from .Items import *
 | 
			
		||||
from .Locations import *
 | 
			
		||||
| 
						 | 
				
			
			@ -87,7 +88,8 @@ class LandstalkerWorld(World):
 | 
			
		|||
 | 
			
		||||
    def create_regions(self):
 | 
			
		||||
        self.regions_table = Regions.create_regions(self)
 | 
			
		||||
        Locations.create_locations(self.player, self.regions_table, self.location_name_to_id)
 | 
			
		||||
        Locations.create_locations(self.player, self.regions_table, self.location_name_to_id,
 | 
			
		||||
                                   self.options.goal == "reach_kazalt")
 | 
			
		||||
        self.create_teleportation_trees()
 | 
			
		||||
 | 
			
		||||
    def create_item(self, name: str, classification_override: Optional[ItemClassification] = None) -> LandstalkerItem:
 | 
			
		||||
| 
						 | 
				
			
			@ -109,7 +111,16 @@ class LandstalkerWorld(World):
 | 
			
		|||
            # If item is an armor and progressive armors are enabled, transform it into a progressive armor item
 | 
			
		||||
            if self.options.progressive_armors and "Breast" in name:
 | 
			
		||||
                name = "Progressive Armor"
 | 
			
		||||
            item_pool += [self.create_item(name) for _ in range(data.quantity)]
 | 
			
		||||
 | 
			
		||||
            qty = data.quantity
 | 
			
		||||
            if self.options.goal == "reach_kazalt":
 | 
			
		||||
                # In "Reach Kazalt" goal, remove all endgame progression items that would be useless anyway
 | 
			
		||||
                if name in ENDGAME_PROGRESSION_ITEMS:
 | 
			
		||||
                    continue
 | 
			
		||||
                # Also reduce quantities for most filler items to let space for more EkeEke (see end of function)
 | 
			
		||||
                if data.classification == ItemClassification.filler:
 | 
			
		||||
                    qty = int(qty * 0.8)
 | 
			
		||||
            item_pool += [self.create_item(name) for _ in range(qty)]
 | 
			
		||||
 | 
			
		||||
        # If the appropriate setting is on, place one EkeEke in one shop in every town in the game
 | 
			
		||||
        if self.options.ensure_ekeeke_in_shops:
 | 
			
		||||
| 
						 | 
				
			
			@ -120,9 +131,10 @@ class LandstalkerWorld(World):
 | 
			
		|||
                "Mercator: Shop item #1",
 | 
			
		||||
                "Verla: Shop item #1",
 | 
			
		||||
                "Destel: Inn item",
 | 
			
		||||
                "Route to Lake Shrine: Greedly's shop item #1",
 | 
			
		||||
                "Kazalt: Shop item #1"
 | 
			
		||||
                "Route to Lake Shrine: Greedly's shop item #1"
 | 
			
		||||
            ]
 | 
			
		||||
            if self.options.goal != "reach_kazalt":
 | 
			
		||||
                shops_to_fill.append("Kazalt: Shop item #1")
 | 
			
		||||
            for location_name in shops_to_fill:
 | 
			
		||||
                self.multiworld.get_location(location_name, self.player).place_locked_item(self.create_item("EkeEke"))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -73,6 +73,22 @@ WORLD_NODES_JSON = {
 | 
			
		|||
            "between Gumi and Ryuma"
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    "tibor_tree": {
 | 
			
		||||
        "name": "Route from Gumi to Ryuma (Tibor tree)",
 | 
			
		||||
        "hints": [
 | 
			
		||||
            "on a route",
 | 
			
		||||
            "in a region inhabited by bears",
 | 
			
		||||
            "between Gumi and Ryuma"
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    "mercator_gate_tree": {
 | 
			
		||||
        "name": "Route from Gumi to Ryuma (Mercator gate tree)",
 | 
			
		||||
        "hints": [
 | 
			
		||||
            "on a route",
 | 
			
		||||
            "in a region inhabited by bears",
 | 
			
		||||
            "between Gumi and Ryuma"
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    "tibor": {
 | 
			
		||||
        "name": "Tibor",
 | 
			
		||||
        "hints": [
 | 
			
		||||
| 
						 | 
				
			
			@ -223,6 +239,13 @@ WORLD_NODES_JSON = {
 | 
			
		|||
            "in the infamous Greenmaze"
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    "greenmaze_post_whistle_tree": {
 | 
			
		||||
        "name": "Greenmaze (post-whistle tree)",
 | 
			
		||||
        "hints": [
 | 
			
		||||
            "among the trees",
 | 
			
		||||
            "in the infamous Greenmaze"
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    "verla_shore": {
 | 
			
		||||
        "name": "Verla shore",
 | 
			
		||||
        "hints": [
 | 
			
		||||
| 
						 | 
				
			
			@ -230,6 +253,13 @@ WORLD_NODES_JSON = {
 | 
			
		|||
            "near the town of Verla"
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    "verla_shore_tree": {
 | 
			
		||||
        "name": "Verla shore tree",
 | 
			
		||||
        "hints": [
 | 
			
		||||
            "on a route",
 | 
			
		||||
            "near the town of Verla"
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    "verla_shore_cliff": {
 | 
			
		||||
        "name": "Verla shore cliff (accessible from Verla Mines)",
 | 
			
		||||
        "hints": [
 | 
			
		||||
| 
						 | 
				
			
			@ -326,6 +356,12 @@ WORLD_NODES_JSON = {
 | 
			
		|||
            "in a mountainous area"
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    "mountainous_area_tree": {
 | 
			
		||||
        "name": "Mountainous Area tree",
 | 
			
		||||
        "hints": [
 | 
			
		||||
            "in a mountainous area"
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    "king_nole_cave": {
 | 
			
		||||
        "name": "King Nole's Cave",
 | 
			
		||||
        "hints": [
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,6 +54,16 @@ WORLD_PATHS_JSON = [
 | 
			
		|||
        "toId": "ryuma",
 | 
			
		||||
        "twoWay": True
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "fromId": "route_gumi_ryuma",
 | 
			
		||||
        "toId": "tibor_tree",
 | 
			
		||||
        "twoWay": True
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "fromId": "route_gumi_ryuma",
 | 
			
		||||
        "toId": "mercator_gate_tree",
 | 
			
		||||
        "twoWay": True
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "fromId": "ryuma",
 | 
			
		||||
        "toId": "ryuma_after_thieves_hideout",
 | 
			
		||||
| 
						 | 
				
			
			@ -211,6 +221,11 @@ WORLD_PATHS_JSON = [
 | 
			
		|||
        ],
 | 
			
		||||
        "twoWay": True
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "fromId": "greenmaze_post_whistle",
 | 
			
		||||
        "toId": "greenmaze_post_whistle_tree",
 | 
			
		||||
        "twoWay": True
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "fromId": "greenmaze_post_whistle",
 | 
			
		||||
        "toId": "route_massan_gumi"
 | 
			
		||||
| 
						 | 
				
			
			@ -253,6 +268,11 @@ WORLD_PATHS_JSON = [
 | 
			
		|||
        "fromId": "verla_shore_cliff",
 | 
			
		||||
        "toId": "verla_shore"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "fromId": "verla_shore",
 | 
			
		||||
        "toId": "verla_shore_tree",
 | 
			
		||||
        "twoWay": True
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "fromId": "verla_shore",
 | 
			
		||||
        "toId": "mir_tower_sector",
 | 
			
		||||
| 
						 | 
				
			
			@ -316,6 +336,11 @@ WORLD_PATHS_JSON = [
 | 
			
		|||
            "Axe Magic"
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "fromId": "mountainous_area",
 | 
			
		||||
        "toId": "mountainous_area_tree",
 | 
			
		||||
        "twoWay": True
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "fromId": "mountainous_area",
 | 
			
		||||
        "toId": "route_lake_shrine_cliff",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,7 +57,9 @@ WORLD_REGIONS_JSON = [
 | 
			
		|||
        "name": "Route between Gumi and Ryuma",
 | 
			
		||||
        "canBeHintedAsRequired": False,
 | 
			
		||||
        "nodeIds": [
 | 
			
		||||
            "route_gumi_ryuma"
 | 
			
		||||
            "route_gumi_ryuma",
 | 
			
		||||
            "tibor_tree",
 | 
			
		||||
            "mercator_gate_tree"
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -157,7 +159,8 @@ WORLD_REGIONS_JSON = [
 | 
			
		|||
        "hintName": "in Greenmaze",
 | 
			
		||||
        "nodeIds": [
 | 
			
		||||
            "greenmaze_pre_whistle",
 | 
			
		||||
            "greenmaze_post_whistle"
 | 
			
		||||
            "greenmaze_post_whistle",
 | 
			
		||||
            "greenmaze_post_whistle_tree"
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -165,7 +168,8 @@ WORLD_REGIONS_JSON = [
 | 
			
		|||
        "canBeHintedAsRequired": False,
 | 
			
		||||
        "nodeIds": [
 | 
			
		||||
            "verla_shore",
 | 
			
		||||
            "verla_shore_cliff"
 | 
			
		||||
            "verla_shore_cliff",
 | 
			
		||||
            "verla_shore_tree"
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -244,7 +248,8 @@ WORLD_REGIONS_JSON = [
 | 
			
		|||
        "name": "Mountainous Area",
 | 
			
		||||
        "hintName": "in the mountainous area",
 | 
			
		||||
        "nodeIds": [
 | 
			
		||||
            "mountainous_area"
 | 
			
		||||
            "mountainous_area",
 | 
			
		||||
            "mountainous_area_tree"
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,19 +8,19 @@ WORLD_TELEPORT_TREES_JSON = [
 | 
			
		|||
        {
 | 
			
		||||
            "name": "Tibor tree",
 | 
			
		||||
            "treeMapId": 534,
 | 
			
		||||
            "nodeId": "route_gumi_ryuma"
 | 
			
		||||
            "nodeId": "tibor_tree"
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    [
 | 
			
		||||
        {
 | 
			
		||||
            "name": "Mercator front gate tree",
 | 
			
		||||
            "treeMapId": 539,
 | 
			
		||||
            "nodeId": "route_gumi_ryuma"
 | 
			
		||||
            "nodeId": "mercator_gate_tree"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "Verla shore tree",
 | 
			
		||||
            "treeMapId": 537,
 | 
			
		||||
            "nodeId": "verla_shore"
 | 
			
		||||
            "nodeId": "verla_shore_tree"
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    [
 | 
			
		||||
| 
						 | 
				
			
			@ -44,7 +44,7 @@ WORLD_TELEPORT_TREES_JSON = [
 | 
			
		|||
        {
 | 
			
		||||
            "name": "Mountainous area tree",
 | 
			
		||||
            "treeMapId": 535,
 | 
			
		||||
            "nodeId": "mountainous_area"
 | 
			
		||||
            "nodeId": "mountainous_area_tree"
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    [
 | 
			
		||||
| 
						 | 
				
			
			@ -56,7 +56,7 @@ WORLD_TELEPORT_TREES_JSON = [
 | 
			
		|||
        {
 | 
			
		||||
            "name": "Greenmaze end tree",
 | 
			
		||||
            "treeMapId": 511,
 | 
			
		||||
            "nodeId": "greenmaze_post_whistle"
 | 
			
		||||
            "nodeId": "greenmaze_post_whistle_tree"
 | 
			
		||||
        }
 | 
			
		||||
    ]
 | 
			
		||||
]
 | 
			
		||||
		Loading…
	
		Reference in New Issue