mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-27 15:53:23 -07:00
Compare commits
7 Commits
use_sphinx
...
appimage-0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53ef2aa786 | ||
|
|
156e9e0e43 | ||
|
|
ef46979bd8 | ||
|
|
b2aa251c47 | ||
|
|
e204a0fce6 | ||
|
|
bb386d3bd7 | ||
|
|
88a225764a |
@@ -5,6 +5,7 @@ import urllib.parse
|
|||||||
import sys
|
import sys
|
||||||
import typing
|
import typing
|
||||||
import time
|
import time
|
||||||
|
import functools
|
||||||
|
|
||||||
import ModuleUpdate
|
import ModuleUpdate
|
||||||
ModuleUpdate.update()
|
ModuleUpdate.update()
|
||||||
@@ -17,7 +18,8 @@ if __name__ == "__main__":
|
|||||||
Utils.init_logging("TextClient", exception_logger="Client")
|
Utils.init_logging("TextClient", exception_logger="Client")
|
||||||
|
|
||||||
from MultiServer import CommandProcessor
|
from MultiServer import CommandProcessor
|
||||||
from NetUtils import Endpoint, decode, NetworkItem, encode, JSONtoTextParser, ClientStatus, Permission, NetworkSlot
|
from NetUtils import Endpoint, decode, NetworkItem, encode, JSONtoTextParser, \
|
||||||
|
ClientStatus, Permission, NetworkSlot, RawJSONtoTextParser
|
||||||
from Utils import Version, stream_input
|
from Utils import Version, stream_input
|
||||||
from worlds import network_data_package, AutoWorldRegister
|
from worlds import network_data_package, AutoWorldRegister
|
||||||
import os
|
import os
|
||||||
@@ -204,6 +206,10 @@ class CommonContext:
|
|||||||
# execution
|
# execution
|
||||||
self.keep_alive_task = asyncio.create_task(keep_alive(self), name="Bouncy")
|
self.keep_alive_task = asyncio.create_task(keep_alive(self), name="Bouncy")
|
||||||
|
|
||||||
|
@functools.cached_property
|
||||||
|
def raw_text_parser(self) -> RawJSONtoTextParser:
|
||||||
|
return RawJSONtoTextParser(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def total_locations(self) -> typing.Optional[int]:
|
def total_locations(self) -> typing.Optional[int]:
|
||||||
"""Will return None until connected."""
|
"""Will return None until connected."""
|
||||||
|
|||||||
53
FF1Client.py
53
FF1Client.py
@@ -1,4 +1,5 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
import copy
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
from asyncio import StreamReader, StreamWriter
|
from asyncio import StreamReader, StreamWriter
|
||||||
@@ -6,7 +7,7 @@ from typing import List
|
|||||||
|
|
||||||
|
|
||||||
import Utils
|
import Utils
|
||||||
from CommonClient import CommonContext, server_loop, gui_enabled, console_loop, ClientCommandProcessor, logger, \
|
from CommonClient import CommonContext, server_loop, gui_enabled, ClientCommandProcessor, logger, \
|
||||||
get_base_parser
|
get_base_parser
|
||||||
|
|
||||||
SYSTEM_MESSAGE_ID = 0
|
SYSTEM_MESSAGE_ID = 0
|
||||||
@@ -64,7 +65,7 @@ class FF1Context(CommonContext):
|
|||||||
|
|
||||||
def _set_message(self, msg: str, msg_id: int):
|
def _set_message(self, msg: str, msg_id: int):
|
||||||
if DISPLAY_MSGS:
|
if DISPLAY_MSGS:
|
||||||
self.messages[(time.time(), msg_id)] = msg
|
self.messages[time.time(), msg_id] = msg
|
||||||
|
|
||||||
def on_package(self, cmd: str, args: dict):
|
def on_package(self, cmd: str, args: dict):
|
||||||
if cmd == 'Connected':
|
if cmd == 'Connected':
|
||||||
@@ -73,32 +74,28 @@ class FF1Context(CommonContext):
|
|||||||
msg = args['text']
|
msg = args['text']
|
||||||
if ': !' not in msg:
|
if ': !' not in msg:
|
||||||
self._set_message(msg, SYSTEM_MESSAGE_ID)
|
self._set_message(msg, SYSTEM_MESSAGE_ID)
|
||||||
elif cmd == "ReceivedItems":
|
|
||||||
msg = f"Received {', '.join([self.item_names[item.item] for item in args['items']])}"
|
def on_print_json(self, args: dict):
|
||||||
self._set_message(msg, SYSTEM_MESSAGE_ID)
|
if self.ui:
|
||||||
elif cmd == 'PrintJSON':
|
self.ui.print_json(copy.deepcopy(args["data"]))
|
||||||
print_type = args['type']
|
else:
|
||||||
item = args['item']
|
text = self.jsontotextparser(copy.deepcopy(args["data"]))
|
||||||
receiving_player_id = args['receiving']
|
logger.info(text)
|
||||||
receiving_player_name = self.player_names[receiving_player_id]
|
relevant = args.get("type", None) in {"Hint", "ItemSend"}
|
||||||
sending_player_id = item.player
|
if relevant:
|
||||||
sending_player_name = self.player_names[item.player]
|
item = args["item"]
|
||||||
if print_type == 'Hint':
|
# goes to this world
|
||||||
msg = f"Hint: Your {self.item_names[item.item]} is at" \
|
if self.slot_concerns_self(args["receiving"]):
|
||||||
f" {self.player_names[item.player]}'s {self.location_names[item.location]}"
|
relevant = True
|
||||||
self._set_message(msg, item.item)
|
# found in this world
|
||||||
elif print_type == 'ItemSend' and receiving_player_id != self.slot:
|
elif self.slot_concerns_self(item.player):
|
||||||
if sending_player_id == self.slot:
|
relevant = True
|
||||||
if receiving_player_id == self.slot:
|
# not related
|
||||||
msg = f"You found your own {self.item_names[item.item]}"
|
else:
|
||||||
else:
|
relevant = False
|
||||||
msg = f"You sent {self.item_names[item.item]} to {receiving_player_name}"
|
if relevant:
|
||||||
else:
|
item = args["item"]
|
||||||
if receiving_player_id == sending_player_id:
|
msg = self.raw_text_parser(copy.deepcopy(args["data"]))
|
||||||
msg = f"{sending_player_name} found their {self.item_names[item.item]}"
|
|
||||||
else:
|
|
||||||
msg = f"{sending_player_name} sent {self.item_names[item.item]} to " \
|
|
||||||
f"{receiving_player_name}"
|
|
||||||
self._set_message(msg, item.item)
|
self._set_message(msg, item.item)
|
||||||
|
|
||||||
def run_gui(self):
|
def run_gui(self):
|
||||||
|
|||||||
@@ -743,6 +743,7 @@ async def countdown(ctx: Context, timer: int):
|
|||||||
broadcast_countdown(ctx, 0, f"[Server]: GO")
|
broadcast_countdown(ctx, 0, f"[Server]: GO")
|
||||||
ctx.countdown_timer = 0
|
ctx.countdown_timer = 0
|
||||||
|
|
||||||
|
|
||||||
def broadcast_text_all(ctx: Context, text: str, additional_arguments: dict = {}):
|
def broadcast_text_all(ctx: Context, text: str, additional_arguments: dict = {}):
|
||||||
old_clients, new_clients = [], []
|
old_clients, new_clients = [], []
|
||||||
|
|
||||||
@@ -755,8 +756,10 @@ def broadcast_text_all(ctx: Context, text: str, additional_arguments: dict = {})
|
|||||||
ctx.broadcast(old_clients, [{"cmd": "Print", "text": text }])
|
ctx.broadcast(old_clients, [{"cmd": "Print", "text": text }])
|
||||||
ctx.broadcast(new_clients, [{**{"cmd": "PrintJSON", "data": [{ "text": text }]}, **additional_arguments}])
|
ctx.broadcast(new_clients, [{**{"cmd": "PrintJSON", "data": [{ "text": text }]}, **additional_arguments}])
|
||||||
|
|
||||||
|
|
||||||
def broadcast_countdown(ctx: Context, timer: int, message: str):
|
def broadcast_countdown(ctx: Context, timer: int, message: str):
|
||||||
broadcast_text_all(ctx, message, { "type": "Countdown", "countdown": timer })
|
broadcast_text_all(ctx, message, {"type": "Countdown", "countdown": timer})
|
||||||
|
|
||||||
|
|
||||||
def get_players_string(ctx: Context):
|
def get_players_string(ctx: Context):
|
||||||
auth_clients = {(c.team, c.slot) for c in ctx.endpoints if c.auth}
|
auth_clients = {(c.team, c.slot) for c in ctx.endpoints if c.auth}
|
||||||
|
|||||||
@@ -15,9 +15,6 @@ import typing
|
|||||||
|
|
||||||
from json import loads, dumps
|
from json import loads, dumps
|
||||||
|
|
||||||
import ModuleUpdate
|
|
||||||
ModuleUpdate.update()
|
|
||||||
|
|
||||||
from Utils import init_logging, messagebox
|
from Utils import init_logging, messagebox
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -19,10 +19,11 @@ from sc2.data import Race
|
|||||||
from sc2.main import run_game
|
from sc2.main import run_game
|
||||||
from sc2.player import Bot
|
from sc2.player import Bot
|
||||||
|
|
||||||
|
import NetUtils
|
||||||
from MultiServer import mark_raw
|
from MultiServer import mark_raw
|
||||||
from Utils import init_logging, is_windows
|
from Utils import init_logging, is_windows
|
||||||
from worlds.sc2wol import SC2WoLWorld
|
from worlds.sc2wol import SC2WoLWorld
|
||||||
from worlds.sc2wol.Items import lookup_id_to_name, item_table
|
from worlds.sc2wol.Items import lookup_id_to_name, item_table, ItemData, type_flaggroups
|
||||||
from worlds.sc2wol.Locations import SC2WOL_LOC_ID_OFFSET
|
from worlds.sc2wol.Locations import SC2WOL_LOC_ID_OFFSET
|
||||||
from worlds.sc2wol.MissionTables import lookup_id_to_mission
|
from worlds.sc2wol.MissionTables import lookup_id_to_mission
|
||||||
from worlds.sc2wol.Regions import MissionInfo
|
from worlds.sc2wol.Regions import MissionInfo
|
||||||
@@ -135,7 +136,7 @@ class SC2Context(CommonContext):
|
|||||||
last_loc_list = None
|
last_loc_list = None
|
||||||
difficulty_override = -1
|
difficulty_override = -1
|
||||||
mission_id_to_location_ids: typing.Dict[int, typing.List[int]] = {}
|
mission_id_to_location_ids: typing.Dict[int, typing.List[int]] = {}
|
||||||
raw_text_parser: RawJSONtoTextParser
|
last_bot: typing.Optional[ArchipelagoBot] = None
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(SC2Context, self).__init__(*args, **kwargs)
|
super(SC2Context, self).__init__(*args, **kwargs)
|
||||||
@@ -164,10 +165,13 @@ class SC2Context(CommonContext):
|
|||||||
check_mod_install()
|
check_mod_install()
|
||||||
|
|
||||||
def on_print_json(self, args: dict):
|
def on_print_json(self, args: dict):
|
||||||
|
# goes to this world
|
||||||
if "receiving" in args and self.slot_concerns_self(args["receiving"]):
|
if "receiving" in args and self.slot_concerns_self(args["receiving"]):
|
||||||
relevant = True
|
relevant = True
|
||||||
|
# found in this world
|
||||||
elif "item" in args and self.slot_concerns_self(args["item"].player):
|
elif "item" in args and self.slot_concerns_self(args["item"].player):
|
||||||
relevant = True
|
relevant = True
|
||||||
|
# not related
|
||||||
else:
|
else:
|
||||||
relevant = False
|
relevant = False
|
||||||
|
|
||||||
@@ -355,6 +359,8 @@ class SC2Context(CommonContext):
|
|||||||
|
|
||||||
async def shutdown(self):
|
async def shutdown(self):
|
||||||
await super(SC2Context, self).shutdown()
|
await super(SC2Context, self).shutdown()
|
||||||
|
if self.last_bot:
|
||||||
|
self.last_bot.want_close = True
|
||||||
if self.sc2_run_task:
|
if self.sc2_run_task:
|
||||||
self.sc2_run_task.cancel()
|
self.sc2_run_task.cancel()
|
||||||
|
|
||||||
@@ -431,47 +437,27 @@ wol_default_categories = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def calculate_items(items):
|
def calculate_items(items: typing.List[NetUtils.NetworkItem]) -> typing.List[int]:
|
||||||
unit_unlocks = 0
|
network_item: NetUtils.NetworkItem
|
||||||
armory1_unlocks = 0
|
accumulators: typing.List[int] = [0 for _ in type_flaggroups]
|
||||||
armory2_unlocks = 0
|
|
||||||
upgrade_unlocks = 0
|
|
||||||
building_unlocks = 0
|
|
||||||
merc_unlocks = 0
|
|
||||||
lab_unlocks = 0
|
|
||||||
protoss_unlock = 0
|
|
||||||
minerals = 0
|
|
||||||
vespene = 0
|
|
||||||
supply = 0
|
|
||||||
|
|
||||||
for item in items:
|
for network_item in items:
|
||||||
data = lookup_id_to_name[item.item]
|
name: str = lookup_id_to_name[network_item.item]
|
||||||
|
item_data: ItemData = item_table[name]
|
||||||
|
|
||||||
if item_table[data].type == "Unit":
|
# exists exactly once
|
||||||
unit_unlocks += (1 << item_table[data].number)
|
if item_data.quantity == 1:
|
||||||
elif item_table[data].type == "Upgrade":
|
accumulators[type_flaggroups[item_data.type]] |= 1 << item_data.number
|
||||||
upgrade_unlocks += (1 << item_table[data].number)
|
|
||||||
elif item_table[data].type == "Armory 1":
|
|
||||||
armory1_unlocks += (1 << item_table[data].number)
|
|
||||||
elif item_table[data].type == "Armory 2":
|
|
||||||
armory2_unlocks += (1 << item_table[data].number)
|
|
||||||
elif item_table[data].type == "Building":
|
|
||||||
building_unlocks += (1 << item_table[data].number)
|
|
||||||
elif item_table[data].type == "Mercenary":
|
|
||||||
merc_unlocks += (1 << item_table[data].number)
|
|
||||||
elif item_table[data].type == "Laboratory":
|
|
||||||
lab_unlocks += (1 << item_table[data].number)
|
|
||||||
elif item_table[data].type == "Protoss":
|
|
||||||
protoss_unlock += (1 << item_table[data].number)
|
|
||||||
elif item_table[data].type == "Minerals":
|
|
||||||
minerals += item_table[data].number
|
|
||||||
elif item_table[data].type == "Vespene":
|
|
||||||
vespene += item_table[data].number
|
|
||||||
elif item_table[data].type == "Supply":
|
|
||||||
supply += item_table[data].number
|
|
||||||
|
|
||||||
return [unit_unlocks, upgrade_unlocks, armory1_unlocks, armory2_unlocks, building_unlocks, merc_unlocks,
|
# exists multiple times
|
||||||
lab_unlocks, protoss_unlock, minerals, vespene, supply]
|
elif item_data.type == "Upgrade":
|
||||||
|
accumulators[type_flaggroups[item_data.type]] += 1 << item_data.number
|
||||||
|
|
||||||
|
# sum
|
||||||
|
else:
|
||||||
|
accumulators[type_flaggroups[item_data.type]] += item_data.number
|
||||||
|
|
||||||
|
return accumulators
|
||||||
|
|
||||||
|
|
||||||
def calc_difficulty(difficulty):
|
def calc_difficulty(difficulty):
|
||||||
@@ -502,7 +488,7 @@ class ArchipelagoBot(sc2.bot_ai.BotAI):
|
|||||||
setup_done: bool
|
setup_done: bool
|
||||||
ctx: SC2Context
|
ctx: SC2Context
|
||||||
mission_id: int
|
mission_id: int
|
||||||
|
want_close: bool = False
|
||||||
can_read_game = False
|
can_read_game = False
|
||||||
|
|
||||||
last_received_update: int = 0
|
last_received_update: int = 0
|
||||||
@@ -510,12 +496,17 @@ class ArchipelagoBot(sc2.bot_ai.BotAI):
|
|||||||
def __init__(self, ctx: SC2Context, mission_id):
|
def __init__(self, ctx: SC2Context, mission_id):
|
||||||
self.setup_done = False
|
self.setup_done = False
|
||||||
self.ctx = ctx
|
self.ctx = ctx
|
||||||
|
self.ctx.last_bot = self
|
||||||
self.mission_id = mission_id
|
self.mission_id = mission_id
|
||||||
self.boni = [False for _ in range(max_bonus)]
|
self.boni = [False for _ in range(max_bonus)]
|
||||||
|
|
||||||
super(ArchipelagoBot, self).__init__()
|
super(ArchipelagoBot, self).__init__()
|
||||||
|
|
||||||
async def on_step(self, iteration: int):
|
async def on_step(self, iteration: int):
|
||||||
|
if self.want_close:
|
||||||
|
self.want_close = False
|
||||||
|
await self._client.leave()
|
||||||
|
return
|
||||||
game_state = 0
|
game_state = 0
|
||||||
if not self.setup_done:
|
if not self.setup_done:
|
||||||
self.setup_done = True
|
self.setup_done = True
|
||||||
|
|||||||
8
setup.py
8
setup.py
@@ -17,7 +17,7 @@ from Launcher import components, icon_paths
|
|||||||
# This is a bit jank. We need cx-Freeze to be able to run anything from this script, so install it
|
# This is a bit jank. We need cx-Freeze to be able to run anything from this script, so install it
|
||||||
import subprocess
|
import subprocess
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
requirement = 'cx-Freeze>=6.11'
|
requirement = 'cx-Freeze==6.10'
|
||||||
try:
|
try:
|
||||||
pkg_resources.require(requirement)
|
pkg_resources.require(requirement)
|
||||||
import cx_Freeze
|
import cx_Freeze
|
||||||
@@ -70,7 +70,7 @@ def _threaded_hash(filepath):
|
|||||||
|
|
||||||
|
|
||||||
# cx_Freeze's build command runs other commands. Override to accept --yes and store that.
|
# cx_Freeze's build command runs other commands. Override to accept --yes and store that.
|
||||||
class BuildCommand(cx_Freeze.command.build.Build):
|
class BuildCommand(cx_Freeze.dist.build):
|
||||||
user_options = [
|
user_options = [
|
||||||
('yes', 'y', 'Answer "yes" to all questions.'),
|
('yes', 'y', 'Answer "yes" to all questions.'),
|
||||||
]
|
]
|
||||||
@@ -87,8 +87,8 @@ class BuildCommand(cx_Freeze.command.build.Build):
|
|||||||
|
|
||||||
|
|
||||||
# Override cx_Freeze's build_exe command for pre and post build steps
|
# Override cx_Freeze's build_exe command for pre and post build steps
|
||||||
class BuildExeCommand(cx_Freeze.command.build_exe.BuildEXE):
|
class BuildExeCommand(cx_Freeze.dist.build_exe):
|
||||||
user_options = cx_Freeze.command.build_exe.BuildEXE.user_options + [
|
user_options = cx_Freeze.dist.build_exe.user_options + [
|
||||||
('yes', 'y', 'Answer "yes" to all questions.'),
|
('yes', 'y', 'Answer "yes" to all questions.'),
|
||||||
('extra-data=', None, 'Additional files to add.'),
|
('extra-data=', None, 'Additional files to add.'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -66,7 +66,10 @@ class FF1World(World):
|
|||||||
def goal_rule_and_shards(state):
|
def goal_rule_and_shards(state):
|
||||||
return goal_rule(state) and state.has("Shard", self.player, 32)
|
return goal_rule(state) and state.has("Shard", self.player, 32)
|
||||||
terminated_event.access_rule = goal_rule_and_shards
|
terminated_event.access_rule = goal_rule_and_shards
|
||||||
|
if "MARK" in items.keys():
|
||||||
|
# Fail generation for Noverworld and provide link to old FFR website
|
||||||
|
raise Exception("FFR Noverworld seeds must be generated on an older version of FFR. Please ensure you generated the settings using "
|
||||||
|
"4-4-0.finalfantasyrandomizer.com")
|
||||||
menu_region.locations.append(terminated_event)
|
menu_region.locations.append(terminated_event)
|
||||||
self.world.regions += [menu_region]
|
self.world.regions += [menu_region]
|
||||||
|
|
||||||
|
|||||||
@@ -163,3 +163,17 @@ filler_items: typing.Tuple[str, ...] = (
|
|||||||
|
|
||||||
lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in get_full_item_list().items() if
|
lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in get_full_item_list().items() if
|
||||||
data.code}
|
data.code}
|
||||||
|
# Map type to expected int
|
||||||
|
type_flaggroups: typing.Dict[str, int] = {
|
||||||
|
"Unit": 0,
|
||||||
|
"Upgrade": 1,
|
||||||
|
"Armory 1": 2,
|
||||||
|
"Armory 2": 3,
|
||||||
|
"Building": 4,
|
||||||
|
"Mercenary": 5,
|
||||||
|
"Laboratory": 6,
|
||||||
|
"Protoss": 7,
|
||||||
|
"Minerals": 8,
|
||||||
|
"Vespene": 9,
|
||||||
|
"Supply": 10,
|
||||||
|
}
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ item_table: Dict[int, ItemDict] = {
|
|||||||
'name': 'Power Transmitter Fragment',
|
'name': 'Power Transmitter Fragment',
|
||||||
'tech_type': 'PowerTransmitterFragment'},
|
'tech_type': 'PowerTransmitterFragment'},
|
||||||
35032: {'classification': ItemClassification.progression,
|
35032: {'classification': ItemClassification.progression,
|
||||||
'count': 4,
|
'count': 5,
|
||||||
'name': 'Prawn Suit Fragment',
|
'name': 'Prawn Suit Fragment',
|
||||||
'tech_type': 'ExosuitFragment'},
|
'tech_type': 'ExosuitFragment'},
|
||||||
35033: {'classification': ItemClassification.useful,
|
35033: {'classification': ItemClassification.useful,
|
||||||
@@ -163,7 +163,7 @@ item_table: Dict[int, ItemDict] = {
|
|||||||
'name': 'Scanner Room Fragment',
|
'name': 'Scanner Room Fragment',
|
||||||
'tech_type': 'BaseMapRoomFragment'},
|
'tech_type': 'BaseMapRoomFragment'},
|
||||||
35038: {'classification': ItemClassification.progression,
|
35038: {'classification': ItemClassification.progression,
|
||||||
'count': 5,
|
'count': 4,
|
||||||
'name': 'Seamoth Fragment',
|
'name': 'Seamoth Fragment',
|
||||||
'tech_type': 'SeamothFragment'},
|
'tech_type': 'SeamothFragment'},
|
||||||
35039: {'classification': ItemClassification.progression,
|
35039: {'classification': ItemClassification.progression,
|
||||||
@@ -203,9 +203,9 @@ item_table: Dict[int, ItemDict] = {
|
|||||||
'name': 'Picture Frame',
|
'name': 'Picture Frame',
|
||||||
'tech_type': 'PictureFrameFragment'},
|
'tech_type': 'PictureFrameFragment'},
|
||||||
35048: {'classification': ItemClassification.filler,
|
35048: {'classification': ItemClassification.filler,
|
||||||
'count': 2,
|
'count': 1,
|
||||||
'name': 'Bench Fragment',
|
'name': 'Bench',
|
||||||
'tech_type': 'BenchFragment'},
|
'tech_type': 'Bench'},
|
||||||
35049: {'classification': ItemClassification.filler,
|
35049: {'classification': ItemClassification.filler,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': 'Basic Plant Pot',
|
'name': 'Basic Plant Pot',
|
||||||
@@ -333,7 +333,12 @@ item_table: Dict[int, ItemDict] = {
|
|||||||
35080: {'classification': ItemClassification.filler,
|
35080: {'classification': ItemClassification.filler,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': 'Water Filtration Machine',
|
'name': 'Water Filtration Machine',
|
||||||
'tech_type': 'BaseFiltrationMachine'}}
|
'tech_type': 'BaseFiltrationMachine'},
|
||||||
|
35081: {'classification': ItemClassification.progression,
|
||||||
|
'count': 1,
|
||||||
|
'name': 'Ultra High Capacity Tank',
|
||||||
|
'tech_type': 'HighCapacityTank'},
|
||||||
|
}
|
||||||
|
|
||||||
advancement_item_names: Set[str] = set()
|
advancement_item_names: Set[str] = set()
|
||||||
non_advancement_item_names: Set[str] = set()
|
non_advancement_item_names: Set[str] = set()
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class SubnauticaWorld(World):
|
|||||||
location_name_to_id = all_locations
|
location_name_to_id = all_locations
|
||||||
option_definitions = Options.options
|
option_definitions = Options.options
|
||||||
|
|
||||||
data_version = 6
|
data_version = 7
|
||||||
required_client_version = (0, 3, 5)
|
required_client_version = (0, 3, 5)
|
||||||
|
|
||||||
prefill_items: List[Item]
|
prefill_items: List[Item]
|
||||||
|
|||||||
Reference in New Issue
Block a user