Skip to content

Commit 92f8cc9

Browse files
authored
Add additional configuration options, bugfixes (ArchipelagoMW#4)
* Update item list * Start updating rules, victory condition * Add all items and locations * Add rules for Research Table item recipes * Regenerate items with requirements, fix bugs * More logic updates * Add progressives, friendly names * Add Relay Station quest * New locations * Update version * Add configuration but build broken atm * Add Caravan Island Frequency * Reorder progressives, revert location change * Add more options * Fixup item generation issue * Slight polishing * Change to resourcepacks.json, comments * Add more frequency location options * Add item duplication option * Make tests pass, allow dupe resource pack usage
1 parent 67ae684 commit 92f8cc9

11 files changed

+388
-320
lines changed

worlds/raft/Items.py

+37-4
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,56 @@
11
import json
22
import os
33

4+
def createResourcePackName(amount: int, itemName: str):
5+
return "Resource Pack: " + str(amount) + " " + itemName
6+
47
with open(os.path.join(os.path.dirname(__file__), 'items.json'), 'r') as file:
58
item_table = json.loads(file.read())
9+
with open(os.path.join(os.path.dirname(__file__), 'progressives.json'), 'r') as file:
10+
progressive_table = json.loads(file.read())
11+
with open(os.path.join(os.path.dirname(__file__), 'resourcepacks.json'), 'r') as file:
12+
resourcepack_items = json.loads(file.read())
613

714
lookup_id_to_name = {}
815
lookup_name_to_item = {}
916
advancement_item_names = set()
10-
non_advancement_item_names = set()
1117

18+
lastItemId = -1
1219
for item in item_table:
1320
item_name = item["name"]
1421
lookup_id_to_name[item["id"]] = item_name
1522
lookup_name_to_item[item_name] = item
1623
if item["progression"]:
1724
advancement_item_names.add(item_name)
18-
else:
19-
non_advancement_item_names.add(item_name)
25+
lastItemId = max(lastItemId, item["id"])
2026

21-
lookup_id_to_name[None] = "Victory"
27+
progressive_item_list = {}
28+
for item in progressive_table:
29+
progressiveName = progressive_table[item]
30+
if progressiveName not in progressive_item_list:
31+
progressive_item_list[progressiveName] = []
32+
progressive_item_list[progressiveName].append(item)
33+
34+
for progressiveItemName in progressive_item_list.keys():
35+
lastItemId += 1
36+
generatedItem = {}
37+
generatedItem["id"] = lastItemId
38+
generatedItem["name"] = progressiveItemName
39+
generatedItem["progression"] = lookup_name_to_item[progressive_item_list[progressiveItemName][0]]["progression"]
40+
lookup_name_to_item[progressiveItemName] = generatedItem
41+
lookup_id_to_name[lastItemId] = progressiveItemName
2242

43+
# Generate resource pack items
44+
for packItem in resourcepack_items:
45+
for i in range(1, 16): # 1-15
46+
lastItemId += 1
47+
rpName = createResourcePackName(i, packItem)
48+
generatedItem = {}
49+
generatedItem["id"] = lastItemId
50+
generatedItem["name"] = rpName
51+
generatedItem["progression"] = False
52+
lookup_name_to_item[rpName] = generatedItem
53+
lookup_id_to_name[lastItemId] = rpName
54+
55+
lookup_id_to_name[None] = "Victory"
2356
lookup_name_to_id = {name: id for id, name in lookup_id_to_name.items()}

worlds/raft/Items.txt

-67
This file was deleted.

worlds/raft/Options.py

+52-14
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,61 @@
1-
from Options import Range
1+
from Options import Range, Toggle, DefaultOnToggle, Choice
22

3-
class ResearchCostMultiplier(Range):
4-
"""The amount of each research item required in the Research Table
5-
to research a given technology"""
6-
displayname = "Research Cost Multiplier"
3+
class UseResourcePacks(DefaultOnToggle):
4+
"""Uses Resource Packs to fill out the item pool from Raft. Resource Packs have basic earlygame items such as planks, plastic, or food."""
5+
displayname = "Use resource packs"
6+
7+
class MinimumResourcePackAmount(Range):
8+
"""The minimum amount of resources available in a resource pack"""
9+
displayname = "Minimum resource pack amount"
710
range_start = 1
8-
range_end = 10
11+
range_end = 15
912
default = 1
1013

11-
class ResourcePackMultiplier(Range):
12-
"""This will multiply the amount of resources obtained from random
13-
resource drops"""
14-
displayname = "Resource Pack Multipler"
14+
class MaximumResourcePackAmount(Range):
15+
"""The maximum amount of resources available in a resource pack"""
16+
displayname = "Maximum resource pack amount"
1517
range_start = 1
16-
range_end = 5
18+
range_end = 15
19+
default = 5
20+
21+
class DuplicateItems(Choice):
22+
"""Adds duplicates of items to the item pool. These will be selected alongside
23+
Resource Packs (if configured). Note that there are not many progression items,
24+
and selecting Progression may produce many of the same duplicate item."""
25+
displayname = "Duplicate items"
26+
option_off = 0
27+
option_progression = 1
28+
option_non_progression = 2
29+
option_any = 3
30+
31+
class IslandFrequencyLocations(Choice):
32+
"""Sets where frequencies for story islands are located."""
33+
displayname = "Frequency locations"
34+
option_vanilla = 0
35+
option_random_on_island = 1
36+
option_progressive = 2
37+
option_anywhere = 3
1738
default = 1
1839

40+
class ProgressiveItems(DefaultOnToggle):
41+
"""Makes some items, like the Bow and Arrow, progressive rather than raw unlocks."""
42+
displayname = "Progressive items"
43+
44+
class BigIslandEarlyCrafting(Toggle):
45+
"""Allows recipes that require items from big islands (eg leather) to lock earlygame items like the Receiver, Bolt, or Smelter."""
46+
displayname = "Early recipes behind big islands"
47+
48+
class PaddleboardMode(Toggle):
49+
"""Sets later story islands to in logic without an Engine or Steering Wheel. May require lots of paddling. Not recommended."""
50+
displayname = "Paddleboard Mode"
1951

20-
options = {
21-
"research_cost_multiplier": ResearchCostMultiplier,
22-
"resource_pack_multiplier": ResourcePackMultiplier
52+
raft_options = {
53+
"use_resource_packs": UseResourcePacks,
54+
"minimum_resource_pack_amount": MinimumResourcePackAmount,
55+
"maximum_resource_pack_amount": MaximumResourcePackAmount,
56+
"duplicate_items": DuplicateItems,
57+
"island_frequency_locations": IslandFrequencyLocations,
58+
"progressive_items": ProgressiveItems,
59+
"big_island_early_crafting": BigIslandEarlyCrafting,
60+
"paddleboard_mode": PaddleboardMode
2361
}

worlds/raft/Progressives.py

-13
This file was deleted.

worlds/raft/Regions.py

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ def create_regions(world, player: int):
1515
if len(exit_array) == 0:
1616
exit_array = None
1717
new_region = create_region(world, player, region, [location["name"] for location in location_table if location["region"] == region], exit_array)
18-
1918
world.regions += [new_region]
2019

2120
menu = create_region(world, player, "Menu", None, ["Raft"])

worlds/raft/Rules.py

+22-25
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@
33
from .Regions import regionMap
44
from ..AutoWorld import LogicMixin
55

6-
# TODOs
7-
# - Maybe put large island unlockables behind Receiver
8-
# -- This will make getting them more consistent
9-
# - Blueprint fuel pipe on Balboa didn't trigger Archipelago sendable ("Error finding ID for location Blueprint_Pipe_Fuel")
10-
# -- Same with Blueprint_Fueltank
11-
# -- All blueprints :(
12-
# - Blueprint_Firework from doll after explosive barrel on Caravan Island doesn't disappear when picked up
13-
146
class RaftLogic(LogicMixin):
7+
def paddleboard_mode_enabled(self, player):
8+
return self.world.paddleboard_mode[player].value
9+
10+
def big_islands_available(self, player):
11+
return self.world.big_island_early_crafting[player].value or self.can_access_radio_tower(player)
12+
1513
def can_smelt_items(self, player):
1614
return self.has("Smelter", player)
1715

@@ -81,8 +79,6 @@ def can_drive(self, player): # The player can go wherever they want with the eng
8179
return self.can_craft_engine(player) and self.can_craft_steeringWheel(player)
8280

8381
def can_access_radio_tower(self, player):
84-
# Technically the player doesn't need things like the sail to reach the Radio Tower,
85-
# but paddling there is not very efficient or engaging gameplay.
8682
return self.can_navigate(player)
8783

8884
def can_complete_radio_tower(self, player):
@@ -95,25 +91,26 @@ def can_complete_vasagatan(self, player):
9591
return self.can_access_vasagatan(player)
9692

9793
def can_access_balboa_island(self, player):
98-
return self.can_complete_vasagatan(player) and self.can_drive(player) and self.has("Balboa Island Frequency", player)
94+
return (self.can_complete_vasagatan(player)
95+
and (self.can_drive(player) or self.paddleboard_mode_enabled(player))
96+
and self.has("Balboa Island Frequency", player))
9997

10098
def can_complete_balboa_island(self, player):
10199
return self.can_access_balboa_island(player) and self.can_craft_machete(player) and self.can_fire_bow(player)
102100

103101
def can_access_caravan_island(self, player):
104-
return self.can_complete_balboa_island(player) and self.can_drive(player) # Coordinates are given from Relay Station quest
102+
return self.can_complete_balboa_island(player) and (self.can_drive(player) or self.paddleboard_mode_enabled(player)) and self.has("Caravan Island Frequency", player)
105103

106104
def can_complete_caravan_island(self, player):
107105
return self.can_access_caravan_island(player) and self.can_craft_ziplineTool(player)
108106

109107
def can_access_tangaroa(self, player):
110-
return self.can_complete_caravan_island(player) and self.can_drive(player) and self.has("Tangaroa Frequency", player)
108+
return self.can_complete_caravan_island(player) and (self.can_drive(player) or self.paddleboard_mode_enabled(player)) and self.has("Tangaroa Frequency", player)
111109

112110
def can_complete_tangaroa(self, player):
113111
return self.can_access_tangaroa(player)
114112

115113
def set_rules(world, player):
116-
# Map region to check to see if we can access it
117114
regionChecks = {
118115
"Raft": lambda state: True,
119116
"ResearchTable": lambda state: True,
@@ -133,14 +130,14 @@ def set_rules(world, player):
133130
"Scrap": lambda state: True,
134131
"SeaVine": lambda state: True,
135132
"Brick_Dry": lambda state: True,
136-
"Leather": lambda state: True, # Conflicting info on whetherwe need state.can_navigate(player) instead, personal testing indicates this is correct
137133
"Thatch": lambda state: True, # Palm Leaf
138134
"Placeable_GiantClam": lambda state: True,
139-
"Feather": lambda state: state.can_craft_birdNest(player), # Maybe add config for this since you technically don't need bird nest
135+
"Leather": lambda state: state.big_islands_available(player),
136+
"Feather": lambda state: state.big_islands_available(player) or state.can_craft_birdNest(player),
140137
"MetalIngot": lambda state: state.can_smelt_items(player),
141138
"CopperIngot": lambda state: state.can_smelt_items(player),
142139
"VineGoo": lambda state: state.can_smelt_items(player),
143-
"ExplosivePowder": lambda state: state.can_smelt_items(player),
140+
"ExplosivePowder": lambda state: state.big_islands_available(player) and state.can_smelt_items(player),
144141
"Glass": lambda state: state.can_smelt_items(player),
145142
"Bolt": lambda state: state.can_craft_bolt(player),
146143
"Hinge": lambda state: state.can_craft_hinge(player),
@@ -158,26 +155,26 @@ def set_rules(world, player):
158155
"Zipline tool": lambda state: state.can_craft_ziplineTool(player)
159156
}
160157

161-
# Location rules
158+
# Region access rules
162159
for region in regionMap:
163160
if region != "Menu":
164161
for exitRegion in world.get_region(region, player).exits:
165162
set_rule(world.get_entrance(exitRegion.name, player), regionChecks[region])
166163

167-
# Process locations
164+
# Location access rules
168165
for location in location_table:
169166
locFromWorld = world.get_location(location["name"], player)
170-
if "requiresAccessToItems" in location:
171-
def ruleLambda(state, location=location):
167+
if "requiresAccessToItems" in location: # Specific item access required
168+
def fullLocationCheck(state, location=location):
172169
canAccess = regionChecks[location["region"]](state)
173170
for item in location["requiresAccessToItems"]:
174171
if not itemChecks[item](state):
175172
canAccess = False
176173
break
177174
return canAccess
178-
set_rule(locFromWorld, ruleLambda)
179-
else:
175+
set_rule(locFromWorld, fullLocationCheck)
176+
else: # Only region access required
180177
set_rule(locFromWorld, regionChecks[location["region"]])
181178

182-
# Victory location
183-
world.completion_condition[player] = lambda state: state.has('Victory', player)
179+
# Victory requirement
180+
world.completion_condition[player] = lambda state: state.has("Victory", player)

0 commit comments

Comments
 (0)