Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Landstalker: Fix issues on generation #4345

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions worlds/landstalker/Constants.py
Original file line number Diff line number Diff line change
@@ -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"
]
2 changes: 1 addition & 1 deletion worlds/landstalker/Hints.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
3 changes: 1 addition & 2 deletions worlds/landstalker/Items.py
Original file line number Diff line number Diff line change
@@ -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):
Expand Down
16 changes: 10 additions & 6 deletions worlds/landstalker/Locations.py
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -21,17 +17,25 @@ def __init__(self, player: int, name: str, location_id: Optional[int], region: L
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)

# 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))
Expand Down
20 changes: 16 additions & 4 deletions worlds/landstalker/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from BaseClasses import LocationProgressType, Tutorial
from worlds.AutoWorld import WebWorld, World
from .Constants import *
from .Hints import *
from .Items import *
from .Locations import *
Expand Down Expand Up @@ -87,7 +88,8 @@ def generate_early(self):

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:
Expand All @@ -109,7 +111,16 @@ def create_items(self):
# 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:
Expand All @@ -120,9 +131,10 @@ def create_items(self):
"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"))

Expand Down
36 changes: 36 additions & 0 deletions worlds/landstalker/data/world_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,22 @@
"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": [
Expand Down Expand Up @@ -223,13 +239,27 @@
"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": [
"on a route",
"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": [
Expand Down Expand Up @@ -326,6 +356,12 @@
"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": [
Expand Down
25 changes: 25 additions & 0 deletions worlds/landstalker/data/world_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@
"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",
Expand Down Expand Up @@ -211,6 +221,11 @@
],
"twoWay": True
},
{
"fromId": "greenmaze_post_whistle",
"toId": "greenmaze_post_whistle_tree",
"twoWay": True
},
{
"fromId": "greenmaze_post_whistle",
"toId": "route_massan_gumi"
Expand Down Expand Up @@ -253,6 +268,11 @@
"fromId": "verla_shore_cliff",
"toId": "verla_shore"
},
{
"fromId": "verla_shore",
"toId": "verla_shore_tree",
"twoWay": True
},
{
"fromId": "verla_shore",
"toId": "mir_tower_sector",
Expand Down Expand Up @@ -316,6 +336,11 @@
"Axe Magic"
]
},
{
"fromId": "mountainous_area",
"toId": "mountainous_area_tree",
"twoWay": True
},
{
"fromId": "mountainous_area",
"toId": "route_lake_shrine_cliff",
Expand Down
13 changes: 9 additions & 4 deletions worlds/landstalker/data/world_region.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@
"name": "Route between Gumi and Ryuma",
"canBeHintedAsRequired": False,
"nodeIds": [
"route_gumi_ryuma"
"route_gumi_ryuma",
"tibor_tree",
"mercator_gate_tree"
]
},
{
Expand Down Expand Up @@ -157,15 +159,17 @@
"hintName": "in Greenmaze",
"nodeIds": [
"greenmaze_pre_whistle",
"greenmaze_post_whistle"
"greenmaze_post_whistle",
"greenmaze_post_whistle_tree"
]
},
{
"name": "Verla Shore",
"canBeHintedAsRequired": False,
"nodeIds": [
"verla_shore",
"verla_shore_cliff"
"verla_shore_cliff",
"verla_shore_tree"
]
},
{
Expand Down Expand Up @@ -244,7 +248,8 @@
"name": "Mountainous Area",
"hintName": "in the mountainous area",
"nodeIds": [
"mountainous_area"
"mountainous_area",
"mountainous_area_tree"
]
},
{
Expand Down
10 changes: 5 additions & 5 deletions worlds/landstalker/data/world_teleport_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@
{
"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"
}
],
[
Expand All @@ -44,7 +44,7 @@
{
"name": "Mountainous area tree",
"treeMapId": 535,
"nodeId": "mountainous_area"
"nodeId": "mountainous_area_tree"
}
],
[
Expand All @@ -56,7 +56,7 @@
{
"name": "Greenmaze end tree",
"treeMapId": 511,
"nodeId": "greenmaze_post_whistle"
"nodeId": "greenmaze_post_whistle_tree"
}
]
]
Loading