Landstalker: Fix issues on generation (#4345)

This commit is contained in:
Dinopony 2024-12-24 20:08:03 +01:00 committed by GitHub
parent 78637c96a7
commit 5578ccd578
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 131 additions and 22 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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": [

View File

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

View File

@ -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"
]
},
{

View File

@ -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"
}
]
]