mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-09 09:03:46 -07:00
Compare commits
43 Commits
NewSoupVi-
...
NewSoupVi-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6ffff674c | ||
|
|
507e051a5a | ||
|
|
b5bf9ed1d7 | ||
|
|
215eb7e473 | ||
|
|
f42233699a | ||
|
|
1bec68df4d | ||
|
|
d8576e72eb | ||
|
|
7265468e8d | ||
|
|
d07f36dedd | ||
|
|
364a1b71ec | ||
|
|
daee6d210f | ||
|
|
96be0071e6 | ||
|
|
ff8e1dfb47 | ||
|
|
d26db6f213 | ||
|
|
bb6c753583 | ||
|
|
ca08e4b950 | ||
|
|
5a6b02dbd3 | ||
|
|
14416b1050 | ||
|
|
da4e6fc532 | ||
|
|
57d8b69a6d | ||
|
|
c9d8a8661c | ||
|
|
4a3d23e0e6 | ||
|
|
a3666f2ae5 | ||
|
|
c3e000e574 | ||
|
|
dd5481930a | ||
|
|
842328c661 | ||
|
|
8f75384e2e | ||
|
|
193faa00ce | ||
|
|
5e5383b399 | ||
|
|
cb6b29dbe3 | ||
|
|
82b0819051 | ||
|
|
e12ab4afa4 | ||
|
|
1416f631cc | ||
|
|
dbaac47d1e | ||
|
|
cf0ae5e31b | ||
|
|
8891f07362 | ||
|
|
d78974ec59 | ||
|
|
32be26c4d7 | ||
|
|
9de49aa419 | ||
|
|
294a67a4b4 | ||
|
|
7b21121df1 | ||
|
|
0fdc481082 | ||
|
|
92ca11b729 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,6 +10,7 @@
|
||||
*.apmc
|
||||
*.apz5
|
||||
*.aptloz
|
||||
*.aptww
|
||||
*.apemerald
|
||||
*.pyc
|
||||
*.pyd
|
||||
|
||||
@@ -413,7 +413,8 @@ class CommonContext:
|
||||
await self.server.socket.close()
|
||||
if self.server_task is not None:
|
||||
await self.server_task
|
||||
self.ui.update_hints()
|
||||
if self.ui:
|
||||
self.ui.update_hints()
|
||||
|
||||
async def send_msgs(self, msgs: typing.List[typing.Any]) -> None:
|
||||
""" `msgs` JSON serializable """
|
||||
|
||||
2
Fill.py
2
Fill.py
@@ -348,10 +348,10 @@ def accessibility_corrections(multiworld: MultiWorld, state: CollectionState, lo
|
||||
if (location.item is not None and location.item.advancement and location.address is not None and not
|
||||
location.locked and location.item.player not in minimal_players):
|
||||
pool.append(location.item)
|
||||
state.remove(location.item)
|
||||
location.item = None
|
||||
if location in state.advancements:
|
||||
state.advancements.remove(location)
|
||||
state.remove(location.item)
|
||||
locations.append(location)
|
||||
if pool and locations:
|
||||
locations.sort(key=lambda loc: loc.progress_type != LocationProgressType.PRIORITY)
|
||||
|
||||
22
Generate.py
22
Generate.py
@@ -279,22 +279,30 @@ def get_choice(option, root, value=None) -> Any:
|
||||
raise RuntimeError(f"All options specified in \"{option}\" are weighted as zero.")
|
||||
|
||||
|
||||
class SafeDict(dict):
|
||||
def __missing__(self, key):
|
||||
return '{' + key + '}'
|
||||
class SafeFormatter(string.Formatter):
|
||||
def get_value(self, key, args, kwargs):
|
||||
if isinstance(key, int):
|
||||
if key < len(args):
|
||||
return args[key]
|
||||
else:
|
||||
return "{" + str(key) + "}"
|
||||
else:
|
||||
return kwargs.get(key, "{" + key + "}")
|
||||
|
||||
|
||||
def handle_name(name: str, player: int, name_counter: Counter):
|
||||
name_counter[name.lower()] += 1
|
||||
number = name_counter[name.lower()]
|
||||
new_name = "%".join([x.replace("%number%", "{number}").replace("%player%", "{player}") for x in name.split("%%")])
|
||||
new_name = string.Formatter().vformat(new_name, (), SafeDict(number=number,
|
||||
NUMBER=(number if number > 1 else ''),
|
||||
player=player,
|
||||
PLAYER=(player if player > 1 else '')))
|
||||
|
||||
new_name = SafeFormatter().vformat(new_name, (), {"number": number,
|
||||
"NUMBER": (number if number > 1 else ''),
|
||||
"player": player,
|
||||
"PLAYER": (player if player > 1 else '')})
|
||||
# Run .strip twice for edge case where after the initial .slice new_name has a leading whitespace.
|
||||
# Could cause issues for some clients that cannot handle the additional whitespace.
|
||||
new_name = new_name.strip()[:16].strip()
|
||||
|
||||
if new_name == "Archipelago":
|
||||
raise Exception(f"You cannot name yourself \"{new_name}\"")
|
||||
return new_name
|
||||
|
||||
@@ -81,6 +81,7 @@ Currently, the following games are supported:
|
||||
* Castlevania: Circle of the Moon
|
||||
* Inscryption
|
||||
* Civilization VI
|
||||
* The Legend of Zelda: The Wind Waker
|
||||
|
||||
For setup and instructions check out our [tutorials page](https://archipelago.gg/tutorial/).
|
||||
Downloads can be found at [Releases](https://github.com/ArchipelagoMW/Archipelago/releases), including compiled
|
||||
|
||||
2
Utils.py
2
Utils.py
@@ -47,7 +47,7 @@ class Version(typing.NamedTuple):
|
||||
return ".".join(str(item) for item in self)
|
||||
|
||||
|
||||
__version__ = "0.6.0"
|
||||
__version__ = "0.6.2"
|
||||
version_tuple = tuplize_version(__version__)
|
||||
|
||||
is_linux = sys.platform.startswith("linux")
|
||||
|
||||
@@ -35,6 +35,12 @@ def start_playing():
|
||||
@app.route('/games/<string:game>/info/<string:lang>')
|
||||
@cache.cached()
|
||||
def game_info(game, lang):
|
||||
try:
|
||||
world = AutoWorldRegister.world_types[game]
|
||||
if lang not in world.web.game_info_languages:
|
||||
raise KeyError("Sorry, this game's info page is not available in that language yet.")
|
||||
except KeyError:
|
||||
return abort(404)
|
||||
return render_template('gameInfo.html', game=game, lang=lang, theme=get_world_theme(game))
|
||||
|
||||
|
||||
@@ -52,6 +58,12 @@ def games():
|
||||
@app.route('/tutorial/<string:game>/<string:file>/<string:lang>')
|
||||
@cache.cached()
|
||||
def tutorial(game, file, lang):
|
||||
try:
|
||||
world = AutoWorldRegister.world_types[game]
|
||||
if lang not in [tut.link.split("/")[1] for tut in world.web.tutorials]:
|
||||
raise KeyError("Sorry, the tutorial is not available in that language yet.")
|
||||
except KeyError:
|
||||
return abort(404)
|
||||
return render_template("tutorial.html", game=game, file=file, lang=lang, theme=get_world_theme(game))
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ from typing import Dict, Union
|
||||
from docutils.core import publish_parts
|
||||
|
||||
import yaml
|
||||
from flask import redirect, render_template, request, Response
|
||||
from flask import redirect, render_template, request, Response, abort
|
||||
|
||||
import Options
|
||||
from Utils import local_path
|
||||
@@ -142,7 +142,10 @@ def weighted_options_old():
|
||||
@app.route("/games/<string:game>/weighted-options")
|
||||
@cache.cached()
|
||||
def weighted_options(game: str):
|
||||
return render_options_page("weightedOptions/weightedOptions.html", game, is_complex=True)
|
||||
try:
|
||||
return render_options_page("weightedOptions/weightedOptions.html", game, is_complex=True)
|
||||
except KeyError:
|
||||
return abort(404)
|
||||
|
||||
|
||||
@app.route("/games/<string:game>/generate-weighted-yaml", methods=["POST"])
|
||||
@@ -197,7 +200,10 @@ def generate_weighted_yaml(game: str):
|
||||
@app.route("/games/<string:game>/player-options")
|
||||
@cache.cached()
|
||||
def player_options(game: str):
|
||||
return render_options_page("playerOptions/playerOptions.html", game, is_complex=False)
|
||||
try:
|
||||
return render_options_page("playerOptions/playerOptions.html", game, is_complex=False)
|
||||
except KeyError:
|
||||
return abort(404)
|
||||
|
||||
|
||||
# YAML generator for player-options
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
flask>=3.0.3
|
||||
werkzeug>=3.0.6
|
||||
flask>=3.1.0
|
||||
werkzeug>=3.1.3
|
||||
pony>=0.7.19
|
||||
waitress>=3.0.0
|
||||
waitress>=3.0.2
|
||||
Flask-Caching>=2.3.0
|
||||
Flask-Compress>=1.15
|
||||
Flask-Limiter>=3.8.0
|
||||
bokeh>=3.5.2
|
||||
markupsafe>=2.1.5
|
||||
Flask-Compress>=1.17
|
||||
Flask-Limiter>=3.12
|
||||
bokeh>=3.6.3
|
||||
markupsafe>=3.0.2
|
||||
Markdown>=3.7
|
||||
mdx-breakless-lists>=1.0.1
|
||||
|
||||
@@ -42,10 +42,5 @@ window.addEventListener('load', () => {
|
||||
scrollTarget?.scrollIntoView();
|
||||
}
|
||||
});
|
||||
}).catch((error) => {
|
||||
console.error(error);
|
||||
gameInfo.innerHTML =
|
||||
`<h2>This page is out of logic!</h2>
|
||||
<h3>Click <a href="${window.location.origin}">here</a> to return to safety.</h3>`;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -49,10 +49,5 @@ window.addEventListener('load', () => {
|
||||
scrollTarget?.scrollIntoView();
|
||||
}
|
||||
});
|
||||
}).catch((error) => {
|
||||
console.error(error);
|
||||
tutorialWrapper.innerHTML =
|
||||
`<h2>This page is out of logic!</h2>
|
||||
<h3>Click <a href="${window.location.origin}/tutorial">here</a> to return to safety.</h3>`;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -214,6 +214,9 @@
|
||||
# Wargroove
|
||||
/worlds/wargroove/ @FlySniper
|
||||
|
||||
# The Wind Waker
|
||||
/worlds/tww/ @tanjo3
|
||||
|
||||
# The Witness
|
||||
/worlds/witness/ @NewSoupVi @blastron
|
||||
|
||||
|
||||
@@ -265,14 +265,19 @@ def bake_target_group_lookup(world: World, get_target_groups: Callable[[int], li
|
||||
return { group: get_target_groups(group) for group in unique_groups }
|
||||
|
||||
|
||||
def disconnect_entrance_for_randomization(entrance: Entrance, target_group: int | None = None) -> None:
|
||||
def disconnect_entrance_for_randomization(entrance: Entrance, target_group: int | None = None,
|
||||
one_way_target_name: str | None = None) -> None:
|
||||
"""
|
||||
Given an entrance in a "vanilla" region graph, splits that entrance to prepare it for randomization
|
||||
in randomize_entrances. This should be done after setting the type and group of the entrance.
|
||||
in randomize_entrances. This should be done after setting the type and group of the entrance. Because it attempts
|
||||
to meet strict entrance naming requirements for coupled mode, this function may produce unintuitive results when
|
||||
called only on a single entrance; it produces eventually-correct outputs only after calling it on all entrances.
|
||||
|
||||
:param entrance: The entrance which will be disconnected in preparation for randomization.
|
||||
:param target_group: The group to assign to the created ER target. If not specified, the group from
|
||||
the original entrance will be copied.
|
||||
:param one_way_target_name: The name of the created ER target if `entrance` is one-way. This argument
|
||||
is required for one-way entrances and is ignored otherwise.
|
||||
"""
|
||||
child_region = entrance.connected_region
|
||||
parent_region = entrance.parent_region
|
||||
@@ -287,8 +292,11 @@ def disconnect_entrance_for_randomization(entrance: Entrance, target_group: int
|
||||
# targets in the child region will be created when the other direction edge is disconnected
|
||||
target = parent_region.create_er_target(entrance.name)
|
||||
else:
|
||||
# for 1-ways, the child region needs a target and coupling/naming is not a concern
|
||||
target = child_region.create_er_target(child_region.name)
|
||||
# for 1-ways, the child region needs a target. naming is not a concern for coupling so we
|
||||
# allow it to be user provided (and require it, to prevent an unhelpful assumed name in pairings)
|
||||
if not one_way_target_name:
|
||||
raise ValueError("Cannot disconnect a one-way entrance without a target name specified")
|
||||
target = child_region.create_er_target(one_way_target_name)
|
||||
target.randomization_type = entrance.randomization_type
|
||||
target.randomization_group = target_group or entrance.randomization_group
|
||||
|
||||
|
||||
8
kvui.py
8
kvui.py
@@ -296,7 +296,7 @@ class SelectableLabel(RecycleDataViewBehavior, TooltipLabel):
|
||||
else:
|
||||
# Not a fan of the following few lines, but they work.
|
||||
temp = MarkupLabel(text=self.text).markup
|
||||
text = "".join(part for part in temp if not part.startswith(("[color", "[/color]", "[ref=", "[/ref]")))
|
||||
text = "".join(part for part in temp if not part.startswith("["))
|
||||
cmdinput = App.get_running_app().textinput
|
||||
if not cmdinput.text:
|
||||
input_text = get_input_text_from_response(text, App.get_running_app().last_autofillable_command)
|
||||
@@ -817,6 +817,12 @@ class HintLayout(BoxLayout):
|
||||
boxlayout.add_widget(AutocompleteHintInput())
|
||||
self.add_widget(boxlayout)
|
||||
|
||||
def fix_heights(self):
|
||||
for child in self.children:
|
||||
fix_func = getattr(child, "fix_heights", None)
|
||||
if fix_func:
|
||||
fix_func()
|
||||
|
||||
|
||||
status_names: typing.Dict[HintStatus, str] = {
|
||||
HintStatus.HINT_FOUND: "Found",
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
colorama>=0.4.6
|
||||
websockets>=13.0.1,<14
|
||||
PyYAML>=6.0.2
|
||||
jellyfish>=1.1.0
|
||||
jinja2>=3.1.4
|
||||
jellyfish>=1.1.3
|
||||
jinja2>=3.1.6
|
||||
schema>=0.7.7
|
||||
kivy>=2.3.0
|
||||
bsdiff4>=1.2.4
|
||||
platformdirs>=4.2.2
|
||||
certifi>=2024.12.14
|
||||
cython>=3.0.11
|
||||
cymem>=2.0.8
|
||||
orjson>=3.10.7
|
||||
kivy>=2.3.1
|
||||
bsdiff4>=1.2.6
|
||||
platformdirs>=4.3.6
|
||||
certifi>=2025.1.31
|
||||
cython>=3.0.12
|
||||
cymem>=2.0.11
|
||||
orjson>=3.10.15
|
||||
typing_extensions>=4.12.2
|
||||
|
||||
2
setup.py
2
setup.py
@@ -19,7 +19,7 @@ from typing import Dict, Iterable, List, Optional, Sequence, Set, Tuple, Union
|
||||
|
||||
|
||||
# This is a bit jank. We need cx-Freeze to be able to run anything from this script, so install it
|
||||
requirement = 'cx-Freeze==7.2.0'
|
||||
requirement = 'cx-Freeze==8.0.0'
|
||||
try:
|
||||
import pkg_resources
|
||||
try:
|
||||
|
||||
@@ -148,7 +148,7 @@ class TestDisconnectForRandomization(unittest.TestCase):
|
||||
e.randomization_group = 1
|
||||
e.connect(r2)
|
||||
|
||||
disconnect_entrance_for_randomization(e)
|
||||
disconnect_entrance_for_randomization(e, one_way_target_name="foo")
|
||||
|
||||
self.assertIsNone(e.connected_region)
|
||||
self.assertEqual([], r1.entrances)
|
||||
@@ -158,10 +158,22 @@ class TestDisconnectForRandomization(unittest.TestCase):
|
||||
|
||||
self.assertEqual(1, len(r2.entrances))
|
||||
self.assertIsNone(r2.entrances[0].parent_region)
|
||||
self.assertEqual("r2", r2.entrances[0].name)
|
||||
self.assertEqual("foo", r2.entrances[0].name)
|
||||
self.assertEqual(EntranceType.ONE_WAY, r2.entrances[0].randomization_type)
|
||||
self.assertEqual(1, r2.entrances[0].randomization_group)
|
||||
|
||||
def test_disconnect_default_1way_no_vanilla_target_raises(self):
|
||||
multiworld = generate_test_multiworld()
|
||||
r1 = Region("r1", 1, multiworld)
|
||||
r2 = Region("r2", 1, multiworld)
|
||||
e = r1.create_exit("e")
|
||||
e.randomization_type = EntranceType.ONE_WAY
|
||||
e.randomization_group = 1
|
||||
e.connect(r2)
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
disconnect_entrance_for_randomization(e)
|
||||
|
||||
def test_disconnect_uses_alternate_group(self):
|
||||
multiworld = generate_test_multiworld()
|
||||
r1 = Region("r1", 1, multiworld)
|
||||
@@ -171,7 +183,7 @@ class TestDisconnectForRandomization(unittest.TestCase):
|
||||
e.randomization_group = 1
|
||||
e.connect(r2)
|
||||
|
||||
disconnect_entrance_for_randomization(e, 2)
|
||||
disconnect_entrance_for_randomization(e, 2, "foo")
|
||||
|
||||
self.assertIsNone(e.connected_region)
|
||||
self.assertEqual([], r1.entrances)
|
||||
@@ -181,7 +193,7 @@ class TestDisconnectForRandomization(unittest.TestCase):
|
||||
|
||||
self.assertEqual(1, len(r2.entrances))
|
||||
self.assertIsNone(r2.entrances[0].parent_region)
|
||||
self.assertEqual("r2", r2.entrances[0].name)
|
||||
self.assertEqual("foo", r2.entrances[0].name)
|
||||
self.assertEqual(EntranceType.ONE_WAY, r2.entrances[0].randomization_type)
|
||||
self.assertEqual(2, r2.entrances[0].randomization_group)
|
||||
|
||||
|
||||
14
test/general/test_packages.py
Normal file
14
test/general/test_packages.py
Normal file
@@ -0,0 +1,14 @@
|
||||
import unittest
|
||||
import os
|
||||
|
||||
|
||||
class TestPackages(unittest.TestCase):
|
||||
def test_packages_have_init(self):
|
||||
"""Test that all world folders containing .py files also have a __init__.py file,
|
||||
to indicate full package rather than namespace package."""
|
||||
import Utils
|
||||
|
||||
worlds_path = Utils.local_path("worlds")
|
||||
for dirpath, dirnames, filenames in os.walk(worlds_path):
|
||||
with self.subTest(directory=dirpath):
|
||||
self.assertEqual("__init__.py" in filenames, any(file.endswith(".py") for file in filenames))
|
||||
11
test/general/test_patches.py
Normal file
11
test/general/test_patches.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import unittest
|
||||
from worlds.AutoWorld import AutoWorldRegister
|
||||
from worlds.Files import AutoPatchRegister
|
||||
|
||||
|
||||
class TestPatches(unittest.TestCase):
|
||||
def test_patch_name_matches_game(self) -> None:
|
||||
for game_name in AutoPatchRegister.patch_types:
|
||||
with self.subTest(game=game_name):
|
||||
self.assertIn(game_name, AutoWorldRegister.world_types.keys(),
|
||||
f"Patch '{game_name}' does not match the name of any world.")
|
||||
19
test/general/test_requirements.py
Normal file
19
test/general/test_requirements.py
Normal file
@@ -0,0 +1,19 @@
|
||||
import unittest
|
||||
import os
|
||||
|
||||
|
||||
class TestBase(unittest.TestCase):
|
||||
def test_requirements_file_ends_on_newline(self):
|
||||
"""Test that all requirements files end on a newline"""
|
||||
import Utils
|
||||
requirements_files = [Utils.local_path("requirements.txt"),
|
||||
Utils.local_path("WebHostLib", "requirements.txt")]
|
||||
worlds_path = Utils.local_path("worlds")
|
||||
for entry in os.listdir(worlds_path):
|
||||
requirements_path = os.path.join(worlds_path, entry, "requirements.txt")
|
||||
if os.path.isfile(requirements_path):
|
||||
requirements_files.append(requirements_path)
|
||||
for requirements_file in requirements_files:
|
||||
with self.subTest(path=requirements_file):
|
||||
with open(requirements_file) as f:
|
||||
self.assertEqual(f.read()[-1], "\n")
|
||||
@@ -110,6 +110,16 @@ class AutoLogicRegister(type):
|
||||
elif not item_name.startswith("__"):
|
||||
if hasattr(CollectionState, item_name):
|
||||
raise Exception(f"Name conflict on Logic Mixin {name} trying to overwrite {item_name}")
|
||||
|
||||
assert callable(function) or "init_mixin" in dct, (
|
||||
f"{name} defined class variable {item_name} without also having init_mixin.\n\n"
|
||||
"Explanation:\n"
|
||||
"Class variables that will be mutated need to be inintialized as instance variables in init_mixin.\n"
|
||||
"If your LogicMixin variables aren't actually mutable / you don't intend to mutate them, "
|
||||
"there is no point in using LogixMixin.\n"
|
||||
"LogicMixin exists to track custom state variables that change when items are collected/removed."
|
||||
)
|
||||
|
||||
setattr(CollectionState, item_name, function)
|
||||
return new_class
|
||||
|
||||
|
||||
@@ -88,7 +88,6 @@ processes = weakref.WeakSet()
|
||||
|
||||
|
||||
def launch_subprocess(func: Callable, name: str | None = None, args: Tuple[str, ...] = ()) -> None:
|
||||
global processes
|
||||
import multiprocessing
|
||||
process = multiprocessing.Process(target=func, name=name, args=args)
|
||||
process.start()
|
||||
|
||||
@@ -3,4 +3,4 @@ mpyq>=0.2.5
|
||||
portpicker>=1.5.2
|
||||
aiohttp>=3.8.4
|
||||
loguru>=0.7.0
|
||||
protobuf==3.20.3
|
||||
protobuf==3.20.3
|
||||
|
||||
@@ -121,6 +121,7 @@ class ALTTPWeb(WebWorld):
|
||||
)
|
||||
|
||||
tutorials = [setup_en, setup_de, setup_es, setup_fr, msu, msu_es, msu_fr, plando, oof_sound]
|
||||
game_info_languages = ["en", "fr"]
|
||||
|
||||
|
||||
class ALTTPWorld(World):
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
maseya-z3pr>=1.0.0rc1
|
||||
xxtea>=3.0.0
|
||||
xxtea>=3.0.0
|
||||
|
||||
@@ -41,6 +41,7 @@ class AquariaWeb(WebWorld):
|
||||
)
|
||||
|
||||
tutorials = [setup, setup_fr]
|
||||
game_info_languages = ["en", "fr"]
|
||||
|
||||
|
||||
class AquariaWorld(World):
|
||||
|
||||
@@ -48,6 +48,10 @@ class CivVIContainer(APContainer, metaclass=AutoPatchRegister):
|
||||
opened_zipfile.writestr(filename, yml)
|
||||
super().write_contents(opened_zipfile)
|
||||
|
||||
def sanitize_value(value: str) -> str:
|
||||
"""Removes values that can cause issues in XML"""
|
||||
return value.replace('"', "'").replace('&', 'and')
|
||||
|
||||
|
||||
def get_cost(world: 'CivVIWorld', location: CivVILocationData) -> int:
|
||||
"""
|
||||
@@ -63,7 +67,7 @@ def get_formatted_player_name(world: 'CivVIWorld', player: int) -> str:
|
||||
Returns the name of the player in the world
|
||||
"""
|
||||
if player != world.player:
|
||||
return f"{world.multiworld.player_name[player]}{apo}s"
|
||||
return sanitize_value(f"{world.multiworld.player_name[player]}{apo}s")
|
||||
return "Your"
|
||||
|
||||
|
||||
@@ -106,7 +110,7 @@ def generate_new_items(world: 'CivVIWorld') -> str:
|
||||
<Row TechnologyType="TECH_BLOCKER" Name="TECH_BLOCKER" EraType="ERA_ANCIENT" UITreeRow="0" Cost="99999" AdvisorType="ADVISOR_GENERIC" Description="Archipelago Tech created to prevent players from researching their own tech. If you can read this, then congrats you have reached the end of your tree before beating the game!"/>
|
||||
{"".join([f'{tab}<Row TechnologyType="{location.name}" '
|
||||
f'Name="{get_formatted_player_name(world, location.item.player)} '
|
||||
f'{location.item.name}" '
|
||||
f'{sanitize_value(location.item.name)}" '
|
||||
f'EraType="{world.location_table[location.name].era_type}" '
|
||||
f'UITreeRow="{world.location_table[location.name].uiTreeRow}" '
|
||||
f'Cost="{get_cost(world, world.location_table[location.name])}" '
|
||||
@@ -122,7 +126,7 @@ def generate_new_items(world: 'CivVIWorld') -> str:
|
||||
<Row CivicType="CIVIC_BLOCKER" Name="CIVIC_BLOCKER" EraType="ERA_ANCIENT" UITreeRow="0" Cost="99999" AdvisorType="ADVISOR_GENERIC" Description="Archipelago Civic created to prevent players from researching their own civics. If you can read this, then congrats you have reached the end of your tree before beating the game!"/>
|
||||
{"".join([f'{tab}<Row CivicType="{location.name}" '
|
||||
f'Name="{get_formatted_player_name(world, location.item.player)} '
|
||||
f'{location.item.name}" '
|
||||
f'{sanitize_value(location.item.name)}" '
|
||||
f'EraType="{world.location_table[location.name].era_type}" '
|
||||
f'UITreeRow="{world.location_table[location.name].uiTreeRow}" '
|
||||
f'Cost="{get_cost(world, world.location_table[location.name])}" '
|
||||
|
||||
0
worlds/civ_6/data/__init__.py
Normal file
0
worlds/civ_6/data/__init__.py
Normal file
@@ -31,6 +31,7 @@ class CliqueWebWorld(WebWorld):
|
||||
)
|
||||
|
||||
tutorials = [setup_en, setup_de]
|
||||
game_info_languages = ["en", "de"]
|
||||
|
||||
|
||||
class CliqueWorld(World):
|
||||
|
||||
0
worlds/cv64/data/__init__.py
Normal file
0
worlds/cv64/data/__init__.py
Normal file
@@ -644,6 +644,9 @@ class CV64PatchExtensions(APPatchExtension):
|
||||
# Replace the PowerUp in the Forest Special1 Bridge 3HB rock with an L jewel if 3HBs aren't randomized
|
||||
if not options["multi_hit_breakables"]:
|
||||
rom_data.write_byte(0x10C7A1, 0x03)
|
||||
# Replace the PowerUp in one of the lizard lockers if the lizard locker items aren't randomized.
|
||||
if not options["lizard_locker_items"]:
|
||||
rom_data.write_byte(0xBFCA07, 0x03)
|
||||
# Change the appearance of the Pot-Pourri to that of a larger PowerUp regardless of the above setting, so other
|
||||
# game PermaUps are distinguishable.
|
||||
rom_data.write_int32s(0xEE558, [0x06005F08, 0x3FB00000, 0xFFFFFF00])
|
||||
@@ -714,7 +717,11 @@ class CV64PatchExtensions(APPatchExtension):
|
||||
rom_data.write_int32(0x10CF38, 0x8000FF4D) # CT final room door slab
|
||||
rom_data.write_int32(0x10CF44, 0x1000FF4D) # CT Renon slab
|
||||
rom_data.write_int32(0x10C908, 0x0008FF4D) # Villa foyer chandelier
|
||||
rom_data.write_byte(0x10CF37, 0x04) # pointer for CT final room door slab item data
|
||||
|
||||
# Change the pointer to the Clock Tower final room 3HB door slab drops to not share its values with those of the
|
||||
# 3HB slab near Renon at the top of the room.
|
||||
if options["multi_hit_breakables"]:
|
||||
rom_data.write_byte(0x10CF37, 0x04)
|
||||
|
||||
# Once-per-frame gameplay checks
|
||||
rom_data.write_int32(0x6C848, 0x080FF40D) # J 0x803FD034
|
||||
@@ -1000,6 +1007,7 @@ def write_patch(world: "CV64World", patch: CV64ProcedurePatch, offset_data: Dict
|
||||
"multi_hit_breakables": world.options.multi_hit_breakables.value,
|
||||
"drop_previous_sub_weapon": world.options.drop_previous_sub_weapon.value,
|
||||
"countdown": world.options.countdown.value,
|
||||
"lizard_locker_items": world.options.lizard_locker_items.value,
|
||||
"shopsanity": world.options.shopsanity.value,
|
||||
"panther_dash": world.options.panther_dash.value,
|
||||
"big_toss": world.options.big_toss.value,
|
||||
|
||||
0
worlds/cvcotm/data/__init__.py
Normal file
0
worlds/cvcotm/data/__init__.py
Normal file
@@ -34,6 +34,7 @@ class DLCqwebworld(WebWorld):
|
||||
["Deoxis"]
|
||||
)
|
||||
tutorials = [setup_en, setup_fr]
|
||||
game_info_languages = ["en", "fr"]
|
||||
|
||||
|
||||
class DLCqworld(World):
|
||||
|
||||
@@ -126,7 +126,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 3,
|
||||
'index': 64,
|
||||
'doom_type': 2001,
|
||||
'region': "Toxin Refinery (E1M3) Main"},
|
||||
'region': "Toxin Refinery (E1M3) Start"},
|
||||
351019: {'name': 'Toxin Refinery (E1M3) - Shotgun 2',
|
||||
'episode': 1,
|
||||
'map': 3,
|
||||
@@ -234,7 +234,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 4,
|
||||
'index': 107,
|
||||
'doom_type': 8,
|
||||
'region': "Command Control (E1M4) Main"},
|
||||
'region': "Command Control (E1M4) Start"},
|
||||
351037: {'name': 'Command Control (E1M4) - Shotgun',
|
||||
'episode': 1,
|
||||
'map': 4,
|
||||
@@ -504,7 +504,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 7,
|
||||
'index': 122,
|
||||
'doom_type': 2001,
|
||||
'region': "Computer Station (E1M7) Main"},
|
||||
'region': "Computer Station (E1M7) Start"},
|
||||
351082: {'name': 'Computer Station (E1M7) - Rocket launcher',
|
||||
'episode': 1,
|
||||
'map': 7,
|
||||
@@ -912,7 +912,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 4,
|
||||
'index': 109,
|
||||
'doom_type': 2001,
|
||||
'region': "Deimos Lab (E2M4) Main"},
|
||||
'region': "Deimos Lab (E2M4) Start"},
|
||||
351150: {'name': 'Deimos Lab (E2M4) - Mega Armor',
|
||||
'episode': 2,
|
||||
'map': 4,
|
||||
@@ -1242,7 +1242,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 8,
|
||||
'index': 36,
|
||||
'doom_type': 2019,
|
||||
'region': "Tower of Babel (E2M8) Main"},
|
||||
'region': "Tower of Babel (E2M8) Start"},
|
||||
351205: {'name': 'Fortress of Mystery (E2M9) - Supercharge',
|
||||
'episode': 2,
|
||||
'map': 9,
|
||||
@@ -1638,7 +1638,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 5,
|
||||
'index': 187,
|
||||
'doom_type': 2001,
|
||||
'region': "Unholy Cathedral (E3M5) Main"},
|
||||
'region': "Unholy Cathedral (E3M5) Start"},
|
||||
351271: {'name': 'Unholy Cathedral (E3M5) - Shotgun 2',
|
||||
'episode': 3,
|
||||
'map': 5,
|
||||
|
||||
@@ -33,9 +33,11 @@ regions:List[RegionDict] = [
|
||||
|
||||
# Toxin Refinery (E1M3)
|
||||
{"name":"Toxin Refinery (E1M3) Main",
|
||||
"connects_to_hub":True,
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
"connections":[{"target":"Toxin Refinery (E1M3) Blue","pro":False}]},
|
||||
"connections":[
|
||||
{"target":"Toxin Refinery (E1M3) Blue","pro":False},
|
||||
{"target":"Toxin Refinery (E1M3) Start","pro":False}]},
|
||||
{"name":"Toxin Refinery (E1M3) Blue",
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
@@ -46,15 +48,20 @@ regions:List[RegionDict] = [
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
"connections":[{"target":"Toxin Refinery (E1M3) Blue","pro":False}]},
|
||||
{"name":"Toxin Refinery (E1M3) Start",
|
||||
"connects_to_hub":True,
|
||||
"episode":1,
|
||||
"connections":[{"target":"Toxin Refinery (E1M3) Main","pro":False}]},
|
||||
|
||||
# Command Control (E1M4)
|
||||
{"name":"Command Control (E1M4) Main",
|
||||
"connects_to_hub":True,
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
"connections":[
|
||||
{"target":"Command Control (E1M4) Blue","pro":False},
|
||||
{"target":"Command Control (E1M4) Yellow","pro":False},
|
||||
{"target":"Command Control (E1M4) Ledge","pro":True}]},
|
||||
{"target":"Command Control (E1M4) Ledge","pro":True},
|
||||
{"target":"Command Control (E1M4) Start","pro":False}]},
|
||||
{"name":"Command Control (E1M4) Blue",
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
@@ -72,6 +79,10 @@ regions:List[RegionDict] = [
|
||||
{"target":"Command Control (E1M4) Main","pro":False},
|
||||
{"target":"Command Control (E1M4) Blue","pro":False},
|
||||
{"target":"Command Control (E1M4) Yellow","pro":False}]},
|
||||
{"name":"Command Control (E1M4) Start",
|
||||
"connects_to_hub":True,
|
||||
"episode":1,
|
||||
"connections":[{"target":"Command Control (E1M4) Main","pro":False}]},
|
||||
|
||||
# Phobos Lab (E1M5)
|
||||
{"name":"Phobos Lab (E1M5) Main",
|
||||
@@ -126,11 +137,12 @@ regions:List[RegionDict] = [
|
||||
|
||||
# Computer Station (E1M7)
|
||||
{"name":"Computer Station (E1M7) Main",
|
||||
"connects_to_hub":True,
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
"connections":[
|
||||
{"target":"Computer Station (E1M7) Red","pro":False},
|
||||
{"target":"Computer Station (E1M7) Yellow","pro":False}]},
|
||||
{"target":"Computer Station (E1M7) Yellow","pro":False},
|
||||
{"target":"Computer Station (E1M7) Start","pro":False}]},
|
||||
{"name":"Computer Station (E1M7) Blue",
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
@@ -150,6 +162,10 @@ regions:List[RegionDict] = [
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
"connections":[{"target":"Computer Station (E1M7) Yellow","pro":False}]},
|
||||
{"name":"Computer Station (E1M7) Start",
|
||||
"connects_to_hub":True,
|
||||
"episode":1,
|
||||
"connections":[{"target":"Computer Station (E1M7) Main","pro":False}]},
|
||||
|
||||
# Phobos Anomaly (E1M8)
|
||||
{"name":"Phobos Anomaly (E1M8) Main",
|
||||
@@ -238,9 +254,11 @@ regions:List[RegionDict] = [
|
||||
|
||||
# Deimos Lab (E2M4)
|
||||
{"name":"Deimos Lab (E2M4) Main",
|
||||
"connects_to_hub":True,
|
||||
"connects_to_hub":False,
|
||||
"episode":2,
|
||||
"connections":[{"target":"Deimos Lab (E2M4) Blue","pro":False}]},
|
||||
"connections":[
|
||||
{"target":"Deimos Lab (E2M4) Blue","pro":False},
|
||||
{"target":"Deimos Lab (E2M4) Start","pro":False}]},
|
||||
{"name":"Deimos Lab (E2M4) Blue",
|
||||
"connects_to_hub":False,
|
||||
"episode":2,
|
||||
@@ -251,6 +269,10 @@ regions:List[RegionDict] = [
|
||||
"connects_to_hub":False,
|
||||
"episode":2,
|
||||
"connections":[{"target":"Deimos Lab (E2M4) Blue","pro":False}]},
|
||||
{"name":"Deimos Lab (E2M4) Start",
|
||||
"connects_to_hub":True,
|
||||
"episode":2,
|
||||
"connections":[{"target":"Deimos Lab (E2M4) Main","pro":False}]},
|
||||
|
||||
# Command Center (E2M5)
|
||||
{"name":"Command Center (E2M5) Main",
|
||||
@@ -314,9 +336,13 @@ regions:List[RegionDict] = [
|
||||
|
||||
# Tower of Babel (E2M8)
|
||||
{"name":"Tower of Babel (E2M8) Main",
|
||||
"connects_to_hub":False,
|
||||
"episode":2,
|
||||
"connections":[{"target":"Tower of Babel (E2M8) Start","pro":False}]},
|
||||
{"name":"Tower of Babel (E2M8) Start",
|
||||
"connects_to_hub":True,
|
||||
"episode":2,
|
||||
"connections":[]},
|
||||
"connections":[{"target":"Tower of Babel (E2M8) Main","pro":False}]},
|
||||
|
||||
# Fortress of Mystery (E2M9)
|
||||
{"name":"Fortress of Mystery (E2M9) Main",
|
||||
@@ -392,11 +418,12 @@ regions:List[RegionDict] = [
|
||||
|
||||
# Unholy Cathedral (E3M5)
|
||||
{"name":"Unholy Cathedral (E3M5) Main",
|
||||
"connects_to_hub":True,
|
||||
"connects_to_hub":False,
|
||||
"episode":3,
|
||||
"connections":[
|
||||
{"target":"Unholy Cathedral (E3M5) Yellow","pro":False},
|
||||
{"target":"Unholy Cathedral (E3M5) Blue","pro":False}]},
|
||||
{"target":"Unholy Cathedral (E3M5) Blue","pro":False},
|
||||
{"target":"Unholy Cathedral (E3M5) Start","pro":False}]},
|
||||
{"name":"Unholy Cathedral (E3M5) Blue",
|
||||
"connects_to_hub":False,
|
||||
"episode":3,
|
||||
@@ -405,6 +432,10 @@ regions:List[RegionDict] = [
|
||||
"connects_to_hub":False,
|
||||
"episode":3,
|
||||
"connections":[{"target":"Unholy Cathedral (E3M5) Main","pro":False}]},
|
||||
{"name":"Unholy Cathedral (E3M5) Start",
|
||||
"connects_to_hub":True,
|
||||
"episode":3,
|
||||
"connections":[{"target":"Unholy Cathedral (E3M5) Main","pro":False}]},
|
||||
|
||||
# Mt. Erebus (E3M6)
|
||||
{"name":"Mt. Erebus (E3M6) Main",
|
||||
|
||||
@@ -23,10 +23,6 @@ def set_episode1_rules(player, multiworld, pro):
|
||||
state.has("Nuclear Plant (E1M2) - Red keycard", player, 1))
|
||||
|
||||
# Toxin Refinery (E1M3)
|
||||
set_rule(multiworld.get_entrance("Hub -> Toxin Refinery (E1M3) Main", player), lambda state:
|
||||
(state.has("Toxin Refinery (E1M3)", player, 1)) and
|
||||
(state.has("Shotgun", player, 1) or
|
||||
state.has("Chaingun", player, 1)))
|
||||
set_rule(multiworld.get_entrance("Toxin Refinery (E1M3) Main -> Toxin Refinery (E1M3) Blue", player), lambda state:
|
||||
state.has("Toxin Refinery (E1M3) - Blue keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("Toxin Refinery (E1M3) Blue -> Toxin Refinery (E1M3) Yellow", player), lambda state:
|
||||
@@ -35,12 +31,13 @@ def set_episode1_rules(player, multiworld, pro):
|
||||
state.has("Toxin Refinery (E1M3) - Blue keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("Toxin Refinery (E1M3) Yellow -> Toxin Refinery (E1M3) Blue", player), lambda state:
|
||||
state.has("Toxin Refinery (E1M3) - Yellow keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("Hub -> Toxin Refinery (E1M3) Start", player), lambda state:
|
||||
state.has("Toxin Refinery (E1M3)", player, 1))
|
||||
set_rule(multiworld.get_entrance("Toxin Refinery (E1M3) Start -> Toxin Refinery (E1M3) Main", player), lambda state:
|
||||
state.has("Shotgun", player, 1) or
|
||||
state.has("Chaingun", player, 1))
|
||||
|
||||
# Command Control (E1M4)
|
||||
set_rule(multiworld.get_entrance("Hub -> Command Control (E1M4) Main", player), lambda state:
|
||||
state.has("Command Control (E1M4)", player, 1) and
|
||||
state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1))
|
||||
set_rule(multiworld.get_entrance("Command Control (E1M4) Main -> Command Control (E1M4) Blue", player), lambda state:
|
||||
state.has("Command Control (E1M4) - Blue keycard", player, 1) or
|
||||
state.has("Command Control (E1M4) - Yellow keycard", player, 1))
|
||||
@@ -50,6 +47,11 @@ def set_episode1_rules(player, multiworld, pro):
|
||||
set_rule(multiworld.get_entrance("Command Control (E1M4) Blue -> Command Control (E1M4) Main", player), lambda state:
|
||||
state.has("Command Control (E1M4) - Yellow keycard", player, 1) or
|
||||
state.has("Command Control (E1M4) - Blue keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("Hub -> Command Control (E1M4) Start", player), lambda state:
|
||||
state.has("Command Control (E1M4)", player, 1))
|
||||
set_rule(multiworld.get_entrance("Command Control (E1M4) Start -> Command Control (E1M4) Main", player), lambda state:
|
||||
state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1))
|
||||
|
||||
# Phobos Lab (E1M5)
|
||||
set_rule(multiworld.get_entrance("Hub -> Phobos Lab (E1M5) Main", player), lambda state:
|
||||
@@ -83,11 +85,6 @@ def set_episode1_rules(player, multiworld, pro):
|
||||
state.has("Central Processing (E1M6) - Yellow keycard", player, 1))
|
||||
|
||||
# Computer Station (E1M7)
|
||||
set_rule(multiworld.get_entrance("Hub -> Computer Station (E1M7) Main", player), lambda state:
|
||||
state.has("Computer Station (E1M7)", player, 1) and
|
||||
state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Rocket launcher", player, 1))
|
||||
set_rule(multiworld.get_entrance("Computer Station (E1M7) Main -> Computer Station (E1M7) Red", player), lambda state:
|
||||
state.has("Computer Station (E1M7) - Red keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("Computer Station (E1M7) Main -> Computer Station (E1M7) Yellow", player), lambda state:
|
||||
@@ -103,6 +100,12 @@ def set_episode1_rules(player, multiworld, pro):
|
||||
state.has("Computer Station (E1M7) - Red keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("Computer Station (E1M7) Courtyard -> Computer Station (E1M7) Yellow", player), lambda state:
|
||||
state.has("Computer Station (E1M7) - Yellow keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("Hub -> Computer Station (E1M7) Start", player), lambda state:
|
||||
state.has("Computer Station (E1M7)", player, 1))
|
||||
set_rule(multiworld.get_entrance("Computer Station (E1M7) Start -> Computer Station (E1M7) Main", player), lambda state:
|
||||
state.has("Shotgun", player, 1) and
|
||||
state.has("Rocket launcher", player, 1) and
|
||||
state.has("Chaingun", player, 1))
|
||||
|
||||
# Phobos Anomaly (E1M8)
|
||||
set_rule(multiworld.get_entrance("Hub -> Phobos Anomaly (E1M8) Start", player), lambda state:
|
||||
@@ -172,15 +175,16 @@ def set_episode2_rules(player, multiworld, pro):
|
||||
state.has("Refinery (E2M3) - Blue keycard", player, 1))
|
||||
|
||||
# Deimos Lab (E2M4)
|
||||
set_rule(multiworld.get_entrance("Hub -> Deimos Lab (E2M4) Main", player), lambda state:
|
||||
state.has("Deimos Lab (E2M4)", player, 1) and
|
||||
state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Plasma gun", player, 1))
|
||||
set_rule(multiworld.get_entrance("Deimos Lab (E2M4) Main -> Deimos Lab (E2M4) Blue", player), lambda state:
|
||||
state.has("Deimos Lab (E2M4) - Blue keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("Deimos Lab (E2M4) Blue -> Deimos Lab (E2M4) Yellow", player), lambda state:
|
||||
state.has("Deimos Lab (E2M4) - Yellow keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("Hub -> Deimos Lab (E2M4) Start", player), lambda state:
|
||||
state.has("Deimos Lab (E2M4)", player, 1))
|
||||
set_rule(multiworld.get_entrance("Deimos Lab (E2M4) Start -> Deimos Lab (E2M4) Main", player), lambda state:
|
||||
state.has("Shotgun", player, 1) and
|
||||
state.has("Plasma gun", player, 1) and
|
||||
state.has("Chaingun", player, 1))
|
||||
|
||||
# Command Center (E2M5)
|
||||
set_rule(multiworld.get_entrance("Hub -> Command Center (E2M5) Main", player), lambda state:
|
||||
@@ -238,11 +242,11 @@ def set_episode2_rules(player, multiworld, pro):
|
||||
state.has("Spawning Vats (E2M7) - Red keycard", player, 1))
|
||||
|
||||
# Tower of Babel (E2M8)
|
||||
set_rule(multiworld.get_entrance("Hub -> Tower of Babel (E2M8) Main", player), lambda state:
|
||||
(state.has("Tower of Babel (E2M8)", player, 1) and
|
||||
state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1)) and
|
||||
(state.has("Rocket launcher", player, 1) or
|
||||
set_rule(multiworld.get_entrance("Hub -> Tower of Babel (E2M8) Start", player), lambda state:
|
||||
state.has("Tower of Babel (E2M8)", player, 1))
|
||||
set_rule(multiworld.get_entrance("Tower of Babel (E2M8) Start -> Tower of Babel (E2M8) Main", player), lambda state:
|
||||
(state.has("Chaingun", player, 1) and
|
||||
state.has("Shotgun", player, 1)) and (state.has("Rocket launcher", player, 1) or
|
||||
state.has("Plasma gun", player, 1) or
|
||||
state.has("BFG9000", player, 1)))
|
||||
|
||||
@@ -321,13 +325,6 @@ def set_episode3_rules(player, multiworld, pro):
|
||||
state.has("House of Pain (E3M4) - Yellow skull key", player, 1))
|
||||
|
||||
# Unholy Cathedral (E3M5)
|
||||
set_rule(multiworld.get_entrance("Hub -> Unholy Cathedral (E3M5) Main", player), lambda state:
|
||||
(state.has("Unholy Cathedral (E3M5)", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Shotgun", player, 1)) and
|
||||
(state.has("Rocket launcher", player, 1) or
|
||||
state.has("Plasma gun", player, 1) or
|
||||
state.has("BFG9000", player, 1)))
|
||||
set_rule(multiworld.get_entrance("Unholy Cathedral (E3M5) Main -> Unholy Cathedral (E3M5) Yellow", player), lambda state:
|
||||
state.has("Unholy Cathedral (E3M5) - Yellow skull key", player, 1))
|
||||
set_rule(multiworld.get_entrance("Unholy Cathedral (E3M5) Main -> Unholy Cathedral (E3M5) Blue", player), lambda state:
|
||||
@@ -336,6 +333,13 @@ def set_episode3_rules(player, multiworld, pro):
|
||||
state.has("Unholy Cathedral (E3M5) - Blue skull key", player, 1))
|
||||
set_rule(multiworld.get_entrance("Unholy Cathedral (E3M5) Yellow -> Unholy Cathedral (E3M5) Main", player), lambda state:
|
||||
state.has("Unholy Cathedral (E3M5) - Yellow skull key", player, 1))
|
||||
set_rule(multiworld.get_entrance("Hub -> Unholy Cathedral (E3M5) Start", player), lambda state:
|
||||
state.has("Unholy Cathedral (E3M5)", player, 1))
|
||||
set_rule(multiworld.get_entrance("Unholy Cathedral (E3M5) Start -> Unholy Cathedral (E3M5) Main", player), lambda state:
|
||||
(state.has("Chaingun", player, 1) and
|
||||
state.has("Shotgun", player, 1)) and (state.has("Plasma gun", player, 1) or
|
||||
state.has("Rocket launcher", player, 1) or
|
||||
state.has("BFG9000", player, 1)))
|
||||
|
||||
# Mt. Erebus (E3M6)
|
||||
set_rule(multiworld.get_entrance("Hub -> Mt. Erebus (E3M6) Main", player), lambda state:
|
||||
|
||||
@@ -50,14 +50,14 @@ class DOOM1993World(World):
|
||||
location_name_to_id = {data["name"]: loc_id for loc_id, data in Locations.location_table.items()}
|
||||
location_name_groups = Locations.location_name_groups
|
||||
|
||||
starting_level_for_episode: List[str] = [
|
||||
"Hangar (E1M1)",
|
||||
"Deimos Anomaly (E2M1)",
|
||||
"Hell Keep (E3M1)",
|
||||
"Hell Beneath (E4M1)"
|
||||
]
|
||||
starting_level_for_episode: Dict[int, str] = {
|
||||
1: "Hangar (E1M1)",
|
||||
2: "Deimos Anomaly (E2M1)",
|
||||
3: "Hell Keep (E3M1)",
|
||||
4: "Hell Beneath (E4M1)"
|
||||
}
|
||||
|
||||
boss_level_for_espidoes: List[str] = [
|
||||
all_boss_levels: List[str] = [
|
||||
"Phobos Anomaly (E1M8)",
|
||||
"Tower of Babel (E2M8)",
|
||||
"Dis (E3M8)",
|
||||
@@ -82,6 +82,7 @@ class DOOM1993World(World):
|
||||
def __init__(self, multiworld: MultiWorld, player: int):
|
||||
self.included_episodes = [1, 1, 1, 0]
|
||||
self.location_count = 0
|
||||
self.starting_levels = []
|
||||
|
||||
super().__init__(multiworld, player)
|
||||
|
||||
@@ -99,6 +100,16 @@ class DOOM1993World(World):
|
||||
if self.get_episode_count() == 0:
|
||||
self.included_episodes[0] = 1
|
||||
|
||||
self.starting_levels = [level_name for (episode, level_name) in self.starting_level_for_episode.items()
|
||||
if self.included_episodes[episode - 1]]
|
||||
|
||||
# Solo Episode 3 presents a problem, because Hell Keep has only two locations.
|
||||
# We have to give the player Slough of Despair (E3M2), and also mark a weapon early.
|
||||
if self.get_episode_count() == 1 and self.included_episodes[2]:
|
||||
early_weapon = self.random.choice(["Shotgun", "Chaingun"])
|
||||
self.multiworld.early_items[self.player][early_weapon] = 1
|
||||
self.starting_levels.append("Slough of Despair (E3M2)")
|
||||
|
||||
def create_regions(self):
|
||||
pro = self.options.pro.value
|
||||
|
||||
@@ -152,7 +163,7 @@ class DOOM1993World(World):
|
||||
def completion_rule(self, state: CollectionState):
|
||||
goal_levels = Maps.map_names
|
||||
if self.options.goal.value:
|
||||
goal_levels = self.boss_level_for_espidoes
|
||||
goal_levels = self.all_boss_levels
|
||||
|
||||
for map_name in goal_levels:
|
||||
if map_name + " - Exit" not in self.location_name_to_id:
|
||||
@@ -201,7 +212,7 @@ class DOOM1993World(World):
|
||||
if item["episode"] != -1 and not self.included_episodes[item["episode"] - 1]:
|
||||
continue
|
||||
|
||||
count = item["count"] if item["name"] not in self.starting_level_for_episode else item["count"] - 1
|
||||
count = item["count"] if item["name"] not in self.starting_levels else item["count"] - 1
|
||||
itempool += [self.create_item(item["name"]) for _ in range(count)]
|
||||
|
||||
# Backpack(s) based on options
|
||||
@@ -232,9 +243,8 @@ class DOOM1993World(World):
|
||||
self.location_count -= 1
|
||||
|
||||
# Give starting levels right away
|
||||
for i in range(len(self.included_episodes)):
|
||||
if self.included_episodes[i]:
|
||||
self.multiworld.push_precollected(self.create_item(self.starting_level_for_episode[i]))
|
||||
for map_name in self.starting_levels:
|
||||
self.multiworld.push_precollected(self.create_item(map_name))
|
||||
|
||||
# Give Computer area maps if option selected
|
||||
if self.options.start_with_computer_area_maps.value:
|
||||
|
||||
@@ -412,7 +412,7 @@ item_table: Dict[int, ItemDict] = {
|
||||
'map': 2},
|
||||
360246: {'classification': ItemClassification.progression,
|
||||
'count': 1,
|
||||
'name': 'Barrels o Fun (MAP23) - Yellow skull key',
|
||||
'name': "Barrels o' Fun (MAP23) - Yellow skull key",
|
||||
'doom_type': 39,
|
||||
'episode': 3,
|
||||
'map': 3},
|
||||
@@ -880,19 +880,19 @@ item_table: Dict[int, ItemDict] = {
|
||||
'map': 2},
|
||||
360466: {'classification': ItemClassification.progression,
|
||||
'count': 1,
|
||||
'name': 'Barrels o Fun (MAP23)',
|
||||
'name': "Barrels o' Fun (MAP23)",
|
||||
'doom_type': -1,
|
||||
'episode': 3,
|
||||
'map': 3},
|
||||
360467: {'classification': ItemClassification.progression,
|
||||
'count': 1,
|
||||
'name': 'Barrels o Fun (MAP23) - Complete',
|
||||
'name': "Barrels o' Fun (MAP23) - Complete",
|
||||
'doom_type': -2,
|
||||
'episode': 3,
|
||||
'map': 3},
|
||||
360468: {'classification': ItemClassification.filler,
|
||||
'count': 1,
|
||||
'name': 'Barrels o Fun (MAP23) - Computer area map',
|
||||
'name': "Barrels o' Fun (MAP23) - Computer area map",
|
||||
'doom_type': 2026,
|
||||
'episode': 3,
|
||||
'map': 3},
|
||||
@@ -1024,37 +1024,37 @@ item_table: Dict[int, ItemDict] = {
|
||||
'map': 10},
|
||||
360490: {'classification': ItemClassification.progression,
|
||||
'count': 1,
|
||||
'name': 'Wolfenstein2 (MAP31)',
|
||||
'name': 'Wolfenstein (MAP31)',
|
||||
'doom_type': -1,
|
||||
'episode': 4,
|
||||
'map': 1},
|
||||
360491: {'classification': ItemClassification.progression,
|
||||
'count': 1,
|
||||
'name': 'Wolfenstein2 (MAP31) - Complete',
|
||||
'name': 'Wolfenstein (MAP31) - Complete',
|
||||
'doom_type': -2,
|
||||
'episode': 4,
|
||||
'map': 1},
|
||||
360492: {'classification': ItemClassification.filler,
|
||||
'count': 1,
|
||||
'name': 'Wolfenstein2 (MAP31) - Computer area map',
|
||||
'name': 'Wolfenstein (MAP31) - Computer area map',
|
||||
'doom_type': 2026,
|
||||
'episode': 4,
|
||||
'map': 1},
|
||||
360493: {'classification': ItemClassification.progression,
|
||||
'count': 1,
|
||||
'name': 'Grosse2 (MAP32)',
|
||||
'name': 'Grosse (MAP32)',
|
||||
'doom_type': -1,
|
||||
'episode': 4,
|
||||
'map': 2},
|
||||
360494: {'classification': ItemClassification.progression,
|
||||
'count': 1,
|
||||
'name': 'Grosse2 (MAP32) - Complete',
|
||||
'name': 'Grosse (MAP32) - Complete',
|
||||
'doom_type': -2,
|
||||
'episode': 4,
|
||||
'map': 2},
|
||||
360495: {'classification': ItemClassification.filler,
|
||||
'count': 1,
|
||||
'name': 'Grosse2 (MAP32) - Computer area map',
|
||||
'name': 'Grosse (MAP32) - Computer area map',
|
||||
'doom_type': 2026,
|
||||
'episode': 4,
|
||||
'map': 2},
|
||||
@@ -1087,9 +1087,9 @@ item_table: Dict[int, ItemDict] = {
|
||||
|
||||
item_name_groups: Dict[str, Set[str]] = {
|
||||
'Ammos': {'Box of bullets', 'Box of rockets', 'Box of shotgun shells', 'Energy cell pack', },
|
||||
'Computer area maps': {'Barrels o Fun (MAP23) - Computer area map', 'Bloodfalls (MAP25) - Computer area map', 'Circle of Death (MAP11) - Computer area map', 'Dead Simple (MAP07) - Computer area map', 'Downtown (MAP13) - Computer area map', 'Entryway (MAP01) - Computer area map', 'Gotcha! (MAP20) - Computer area map', 'Grosse2 (MAP32) - Computer area map', 'Icon of Sin (MAP30) - Computer area map', 'Industrial Zone (MAP15) - Computer area map', 'Monster Condo (MAP27) - Computer area map', 'Nirvana (MAP21) - Computer area map', 'Refueling Base (MAP10) - Computer area map', 'Suburbs (MAP16) - Computer area map', 'Tenements (MAP17) - Computer area map', 'The Abandoned Mines (MAP26) - Computer area map', 'The Catacombs (MAP22) - Computer area map', 'The Chasm (MAP24) - Computer area map', 'The Citadel (MAP19) - Computer area map', 'The Courtyard (MAP18) - Computer area map', 'The Crusher (MAP06) - Computer area map', 'The Factory (MAP12) - Computer area map', 'The Focus (MAP04) - Computer area map', 'The Gantlet (MAP03) - Computer area map', 'The Inmost Dens (MAP14) - Computer area map', 'The Living End (MAP29) - Computer area map', 'The Pit (MAP09) - Computer area map', 'The Spirit World (MAP28) - Computer area map', 'The Waste Tunnels (MAP05) - Computer area map', 'Tricks and Traps (MAP08) - Computer area map', 'Underhalls (MAP02) - Computer area map', 'Wolfenstein2 (MAP31) - Computer area map', },
|
||||
'Keys': {'Barrels o Fun (MAP23) - Yellow skull key', 'Bloodfalls (MAP25) - Blue skull key', 'Circle of Death (MAP11) - Blue keycard', 'Circle of Death (MAP11) - Red keycard', 'Downtown (MAP13) - Blue keycard', 'Downtown (MAP13) - Red keycard', 'Downtown (MAP13) - Yellow keycard', 'Industrial Zone (MAP15) - Blue keycard', 'Industrial Zone (MAP15) - Red keycard', 'Industrial Zone (MAP15) - Yellow keycard', 'Monster Condo (MAP27) - Blue skull key', 'Monster Condo (MAP27) - Red skull key', 'Monster Condo (MAP27) - Yellow skull key', 'Nirvana (MAP21) - Blue skull key', 'Nirvana (MAP21) - Red skull key', 'Nirvana (MAP21) - Yellow skull key', 'Refueling Base (MAP10) - Blue keycard', 'Refueling Base (MAP10) - Yellow keycard', 'Suburbs (MAP16) - Blue skull key', 'Suburbs (MAP16) - Red skull key', 'Tenements (MAP17) - Blue keycard', 'Tenements (MAP17) - Red keycard', 'Tenements (MAP17) - Yellow skull key', 'The Abandoned Mines (MAP26) - Blue keycard', 'The Abandoned Mines (MAP26) - Red keycard', 'The Abandoned Mines (MAP26) - Yellow keycard', 'The Catacombs (MAP22) - Blue skull key', 'The Catacombs (MAP22) - Red skull key', 'The Chasm (MAP24) - Blue keycard', 'The Chasm (MAP24) - Red keycard', 'The Citadel (MAP19) - Blue skull key', 'The Citadel (MAP19) - Red skull key', 'The Citadel (MAP19) - Yellow skull key', 'The Courtyard (MAP18) - Blue skull key', 'The Courtyard (MAP18) - Yellow skull key', 'The Crusher (MAP06) - Blue keycard', 'The Crusher (MAP06) - Red keycard', 'The Crusher (MAP06) - Yellow keycard', 'The Factory (MAP12) - Blue keycard', 'The Factory (MAP12) - Yellow keycard', 'The Focus (MAP04) - Blue keycard', 'The Focus (MAP04) - Red keycard', 'The Focus (MAP04) - Yellow keycard', 'The Gantlet (MAP03) - Blue keycard', 'The Gantlet (MAP03) - Red keycard', 'The Inmost Dens (MAP14) - Blue skull key', 'The Inmost Dens (MAP14) - Red skull key', 'The Pit (MAP09) - Blue keycard', 'The Pit (MAP09) - Yellow keycard', 'The Spirit World (MAP28) - Red skull key', 'The Spirit World (MAP28) - Yellow skull key', 'The Waste Tunnels (MAP05) - Blue keycard', 'The Waste Tunnels (MAP05) - Red keycard', 'The Waste Tunnels (MAP05) - Yellow keycard', 'Tricks and Traps (MAP08) - Red skull key', 'Tricks and Traps (MAP08) - Yellow skull key', 'Underhalls (MAP02) - Blue keycard', 'Underhalls (MAP02) - Red keycard', },
|
||||
'Levels': {'Barrels o Fun (MAP23)', 'Bloodfalls (MAP25)', 'Circle of Death (MAP11)', 'Dead Simple (MAP07)', 'Downtown (MAP13)', 'Entryway (MAP01)', 'Gotcha! (MAP20)', 'Grosse2 (MAP32)', 'Icon of Sin (MAP30)', 'Industrial Zone (MAP15)', 'Monster Condo (MAP27)', 'Nirvana (MAP21)', 'Refueling Base (MAP10)', 'Suburbs (MAP16)', 'Tenements (MAP17)', 'The Abandoned Mines (MAP26)', 'The Catacombs (MAP22)', 'The Chasm (MAP24)', 'The Citadel (MAP19)', 'The Courtyard (MAP18)', 'The Crusher (MAP06)', 'The Factory (MAP12)', 'The Focus (MAP04)', 'The Gantlet (MAP03)', 'The Inmost Dens (MAP14)', 'The Living End (MAP29)', 'The Pit (MAP09)', 'The Spirit World (MAP28)', 'The Waste Tunnels (MAP05)', 'Tricks and Traps (MAP08)', 'Underhalls (MAP02)', 'Wolfenstein2 (MAP31)', },
|
||||
'Computer area maps': {"Barrels o' Fun (MAP23) - Computer area map", 'Bloodfalls (MAP25) - Computer area map', 'Circle of Death (MAP11) - Computer area map', 'Dead Simple (MAP07) - Computer area map', 'Downtown (MAP13) - Computer area map', 'Entryway (MAP01) - Computer area map', 'Gotcha! (MAP20) - Computer area map', 'Grosse (MAP32) - Computer area map', 'Icon of Sin (MAP30) - Computer area map', 'Industrial Zone (MAP15) - Computer area map', 'Monster Condo (MAP27) - Computer area map', 'Nirvana (MAP21) - Computer area map', 'Refueling Base (MAP10) - Computer area map', 'Suburbs (MAP16) - Computer area map', 'Tenements (MAP17) - Computer area map', 'The Abandoned Mines (MAP26) - Computer area map', 'The Catacombs (MAP22) - Computer area map', 'The Chasm (MAP24) - Computer area map', 'The Citadel (MAP19) - Computer area map', 'The Courtyard (MAP18) - Computer area map', 'The Crusher (MAP06) - Computer area map', 'The Factory (MAP12) - Computer area map', 'The Focus (MAP04) - Computer area map', 'The Gantlet (MAP03) - Computer area map', 'The Inmost Dens (MAP14) - Computer area map', 'The Living End (MAP29) - Computer area map', 'The Pit (MAP09) - Computer area map', 'The Spirit World (MAP28) - Computer area map', 'The Waste Tunnels (MAP05) - Computer area map', 'Tricks and Traps (MAP08) - Computer area map', 'Underhalls (MAP02) - Computer area map', 'Wolfenstein (MAP31) - Computer area map', },
|
||||
'Keys': {"Barrels o' Fun (MAP23) - Yellow skull key", 'Bloodfalls (MAP25) - Blue skull key', 'Circle of Death (MAP11) - Blue keycard', 'Circle of Death (MAP11) - Red keycard', 'Downtown (MAP13) - Blue keycard', 'Downtown (MAP13) - Red keycard', 'Downtown (MAP13) - Yellow keycard', 'Industrial Zone (MAP15) - Blue keycard', 'Industrial Zone (MAP15) - Red keycard', 'Industrial Zone (MAP15) - Yellow keycard', 'Monster Condo (MAP27) - Blue skull key', 'Monster Condo (MAP27) - Red skull key', 'Monster Condo (MAP27) - Yellow skull key', 'Nirvana (MAP21) - Blue skull key', 'Nirvana (MAP21) - Red skull key', 'Nirvana (MAP21) - Yellow skull key', 'Refueling Base (MAP10) - Blue keycard', 'Refueling Base (MAP10) - Yellow keycard', 'Suburbs (MAP16) - Blue skull key', 'Suburbs (MAP16) - Red skull key', 'Tenements (MAP17) - Blue keycard', 'Tenements (MAP17) - Red keycard', 'Tenements (MAP17) - Yellow skull key', 'The Abandoned Mines (MAP26) - Blue keycard', 'The Abandoned Mines (MAP26) - Red keycard', 'The Abandoned Mines (MAP26) - Yellow keycard', 'The Catacombs (MAP22) - Blue skull key', 'The Catacombs (MAP22) - Red skull key', 'The Chasm (MAP24) - Blue keycard', 'The Chasm (MAP24) - Red keycard', 'The Citadel (MAP19) - Blue skull key', 'The Citadel (MAP19) - Red skull key', 'The Citadel (MAP19) - Yellow skull key', 'The Courtyard (MAP18) - Blue skull key', 'The Courtyard (MAP18) - Yellow skull key', 'The Crusher (MAP06) - Blue keycard', 'The Crusher (MAP06) - Red keycard', 'The Crusher (MAP06) - Yellow keycard', 'The Factory (MAP12) - Blue keycard', 'The Factory (MAP12) - Yellow keycard', 'The Focus (MAP04) - Blue keycard', 'The Focus (MAP04) - Red keycard', 'The Focus (MAP04) - Yellow keycard', 'The Gantlet (MAP03) - Blue keycard', 'The Gantlet (MAP03) - Red keycard', 'The Inmost Dens (MAP14) - Blue skull key', 'The Inmost Dens (MAP14) - Red skull key', 'The Pit (MAP09) - Blue keycard', 'The Pit (MAP09) - Yellow keycard', 'The Spirit World (MAP28) - Red skull key', 'The Spirit World (MAP28) - Yellow skull key', 'The Waste Tunnels (MAP05) - Blue keycard', 'The Waste Tunnels (MAP05) - Red keycard', 'The Waste Tunnels (MAP05) - Yellow keycard', 'Tricks and Traps (MAP08) - Red skull key', 'Tricks and Traps (MAP08) - Yellow skull key', 'Underhalls (MAP02) - Blue keycard', 'Underhalls (MAP02) - Red keycard', },
|
||||
'Levels': {"Barrels o' Fun (MAP23)", 'Bloodfalls (MAP25)', 'Circle of Death (MAP11)', 'Dead Simple (MAP07)', 'Downtown (MAP13)', 'Entryway (MAP01)', 'Gotcha! (MAP20)', 'Grosse (MAP32)', 'Icon of Sin (MAP30)', 'Industrial Zone (MAP15)', 'Monster Condo (MAP27)', 'Nirvana (MAP21)', 'Refueling Base (MAP10)', 'Suburbs (MAP16)', 'Tenements (MAP17)', 'The Abandoned Mines (MAP26)', 'The Catacombs (MAP22)', 'The Chasm (MAP24)', 'The Citadel (MAP19)', 'The Courtyard (MAP18)', 'The Crusher (MAP06)', 'The Factory (MAP12)', 'The Focus (MAP04)', 'The Gantlet (MAP03)', 'The Inmost Dens (MAP14)', 'The Living End (MAP29)', 'The Pit (MAP09)', 'The Spirit World (MAP28)', 'The Waste Tunnels (MAP05)', 'Tricks and Traps (MAP08)', 'Underhalls (MAP02)', 'Wolfenstein (MAP31)', },
|
||||
'Powerups': {'Armor', 'Berserk', 'Invulnerability', 'Mega Armor', 'Megasphere', 'Partial invisibility', 'Supercharge', },
|
||||
'Weapons': {'BFG9000', 'Chaingun', 'Chainsaw', 'Plasma gun', 'Rocket launcher', 'Shotgun', 'Super Shotgun', },
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 5,
|
||||
'index': 46,
|
||||
'doom_type': 82,
|
||||
'region': "The Waste Tunnels (MAP05) Main"},
|
||||
'region': "The Waste Tunnels (MAP05) Start"},
|
||||
361028: {'name': 'The Waste Tunnels (MAP05) - Blue keycard',
|
||||
'episode': 1,
|
||||
'map': 5,
|
||||
@@ -234,7 +234,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 5,
|
||||
'index': 202,
|
||||
'doom_type': 2001,
|
||||
'region': "The Waste Tunnels (MAP05) Main"},
|
||||
'region': "The Waste Tunnels (MAP05) Start"},
|
||||
361037: {'name': 'The Waste Tunnels (MAP05) - Berserk',
|
||||
'episode': 1,
|
||||
'map': 5,
|
||||
@@ -360,7 +360,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 7,
|
||||
'index': 8,
|
||||
'doom_type': 82,
|
||||
'region': "Dead Simple (MAP07) Main"},
|
||||
'region': "Dead Simple (MAP07) Start"},
|
||||
361058: {'name': 'Dead Simple (MAP07) - Chaingun',
|
||||
'episode': 1,
|
||||
'map': 7,
|
||||
@@ -378,7 +378,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 7,
|
||||
'index': 43,
|
||||
'doom_type': 8,
|
||||
'region': "Dead Simple (MAP07) Main"},
|
||||
'region': "Dead Simple (MAP07) Start"},
|
||||
361061: {'name': 'Dead Simple (MAP07) - Berserk',
|
||||
'episode': 1,
|
||||
'map': 7,
|
||||
@@ -570,7 +570,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 9,
|
||||
'index': 26,
|
||||
'doom_type': 2019,
|
||||
'region': "The Pit (MAP09) Main"},
|
||||
'region': "The Pit (MAP09) Start"},
|
||||
361093: {'name': 'The Pit (MAP09) - Supercharge',
|
||||
'episode': 1,
|
||||
'map': 9,
|
||||
@@ -678,7 +678,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 10,
|
||||
'index': 99,
|
||||
'doom_type': 2001,
|
||||
'region': "Refueling Base (MAP10) Main"},
|
||||
'region': "Refueling Base (MAP10) Start"},
|
||||
361111: {'name': 'Refueling Base (MAP10) - Chaingun',
|
||||
'episode': 1,
|
||||
'map': 10,
|
||||
@@ -846,31 +846,31 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 11,
|
||||
'index': 88,
|
||||
'doom_type': 8,
|
||||
'region': "Circle of Death (MAP11) Red"},
|
||||
'region': "Circle of Death (MAP11) Ending"},
|
||||
361139: {'name': 'Circle of Death (MAP11) - Supercharge 2',
|
||||
'episode': 1,
|
||||
'map': 11,
|
||||
'index': 108,
|
||||
'doom_type': 2013,
|
||||
'region': "Circle of Death (MAP11) Red"},
|
||||
'region': "Circle of Death (MAP11) Ending"},
|
||||
361140: {'name': 'Circle of Death (MAP11) - BFG9000',
|
||||
'episode': 1,
|
||||
'map': 11,
|
||||
'index': 110,
|
||||
'doom_type': 2006,
|
||||
'region': "Circle of Death (MAP11) Red"},
|
||||
'region': "Circle of Death (MAP11) Ending"},
|
||||
361141: {'name': 'Circle of Death (MAP11) - Exit',
|
||||
'episode': 1,
|
||||
'map': 11,
|
||||
'index': -1,
|
||||
'doom_type': -1,
|
||||
'region': "Circle of Death (MAP11) Red"},
|
||||
'region': "Circle of Death (MAP11) Ending"},
|
||||
361142: {'name': 'The Factory (MAP12) - Shotgun',
|
||||
'episode': 2,
|
||||
'map': 1,
|
||||
'index': 14,
|
||||
'doom_type': 2001,
|
||||
'region': "The Factory (MAP12) Main"},
|
||||
'region': "The Factory (MAP12) Outdoors"},
|
||||
361143: {'name': 'The Factory (MAP12) - Berserk',
|
||||
'episode': 2,
|
||||
'map': 1,
|
||||
@@ -888,13 +888,13 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 1,
|
||||
'index': 52,
|
||||
'doom_type': 2013,
|
||||
'region': "The Factory (MAP12) Main"},
|
||||
'region': "The Factory (MAP12) Indoors"},
|
||||
361146: {'name': 'The Factory (MAP12) - Blue keycard',
|
||||
'episode': 2,
|
||||
'map': 1,
|
||||
'index': 54,
|
||||
'doom_type': 5,
|
||||
'region': "The Factory (MAP12) Main"},
|
||||
'region': "The Factory (MAP12) Indoors"},
|
||||
361147: {'name': 'The Factory (MAP12) - Armor',
|
||||
'episode': 2,
|
||||
'map': 1,
|
||||
@@ -912,31 +912,31 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 1,
|
||||
'index': 83,
|
||||
'doom_type': 2013,
|
||||
'region': "The Factory (MAP12) Main"},
|
||||
'region': "The Factory (MAP12) Indoors"},
|
||||
361150: {'name': 'The Factory (MAP12) - Armor 2',
|
||||
'episode': 2,
|
||||
'map': 1,
|
||||
'index': 92,
|
||||
'doom_type': 2018,
|
||||
'region': "The Factory (MAP12) Main"},
|
||||
'region': "The Factory (MAP12) Outdoors"},
|
||||
361151: {'name': 'The Factory (MAP12) - Partial invisibility',
|
||||
'episode': 2,
|
||||
'map': 1,
|
||||
'index': 93,
|
||||
'doom_type': 2024,
|
||||
'region': "The Factory (MAP12) Main"},
|
||||
'region': "The Factory (MAP12) Outdoors"},
|
||||
361152: {'name': 'The Factory (MAP12) - Berserk 2',
|
||||
'episode': 2,
|
||||
'map': 1,
|
||||
'index': 107,
|
||||
'doom_type': 2023,
|
||||
'region': "The Factory (MAP12) Main"},
|
||||
'region': "The Factory (MAP12) Indoors"},
|
||||
361153: {'name': 'The Factory (MAP12) - Yellow keycard',
|
||||
'episode': 2,
|
||||
'map': 1,
|
||||
'index': 123,
|
||||
'doom_type': 6,
|
||||
'region': "The Factory (MAP12) Main"},
|
||||
'region': "The Factory (MAP12) Indoors"},
|
||||
361154: {'name': 'The Factory (MAP12) - BFG9000',
|
||||
'episode': 2,
|
||||
'map': 1,
|
||||
@@ -954,7 +954,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 1,
|
||||
'index': 192,
|
||||
'doom_type': 82,
|
||||
'region': "The Factory (MAP12) Main"},
|
||||
'region': "The Factory (MAP12) Indoors"},
|
||||
361157: {'name': 'The Factory (MAP12) - Exit',
|
||||
'episode': 2,
|
||||
'map': 1,
|
||||
@@ -1812,7 +1812,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 1,
|
||||
'index': 70,
|
||||
'doom_type': 82,
|
||||
'region': "Nirvana (MAP21) Main"},
|
||||
'region': "Nirvana (MAP21) Start"},
|
||||
361300: {'name': 'Nirvana (MAP21) - Rocket launcher',
|
||||
'episode': 3,
|
||||
'map': 1,
|
||||
@@ -1884,7 +1884,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 2,
|
||||
'index': 28,
|
||||
'doom_type': 2001,
|
||||
'region': "The Catacombs (MAP22) Main"},
|
||||
'region': "The Catacombs (MAP22) Early"},
|
||||
361312: {'name': 'The Catacombs (MAP22) - Berserk',
|
||||
'episode': 3,
|
||||
'map': 2,
|
||||
@@ -1896,103 +1896,103 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 2,
|
||||
'index': 83,
|
||||
'doom_type': 2004,
|
||||
'region': "The Catacombs (MAP22) Main"},
|
||||
'region': "The Catacombs (MAP22) Early"},
|
||||
361314: {'name': 'The Catacombs (MAP22) - Supercharge',
|
||||
'episode': 3,
|
||||
'map': 2,
|
||||
'index': 118,
|
||||
'doom_type': 2013,
|
||||
'region': "The Catacombs (MAP22) Main"},
|
||||
'region': "The Catacombs (MAP22) Early"},
|
||||
361315: {'name': 'The Catacombs (MAP22) - Armor',
|
||||
'episode': 3,
|
||||
'map': 2,
|
||||
'index': 119,
|
||||
'doom_type': 2018,
|
||||
'region': "The Catacombs (MAP22) Main"},
|
||||
'region': "The Catacombs (MAP22) Early"},
|
||||
361316: {'name': 'The Catacombs (MAP22) - Exit',
|
||||
'episode': 3,
|
||||
'map': 2,
|
||||
'index': -1,
|
||||
'doom_type': -1,
|
||||
'region': "The Catacombs (MAP22) Red"},
|
||||
361317: {'name': 'Barrels o Fun (MAP23) - Shotgun',
|
||||
361317: {'name': "Barrels o' Fun (MAP23) - Shotgun",
|
||||
'episode': 3,
|
||||
'map': 3,
|
||||
'index': 136,
|
||||
'doom_type': 2001,
|
||||
'region': "Barrels o Fun (MAP23) Main"},
|
||||
361318: {'name': 'Barrels o Fun (MAP23) - Berserk',
|
||||
'region': "Barrels o' Fun (MAP23) Main"},
|
||||
361318: {'name': "Barrels o' Fun (MAP23) - Berserk",
|
||||
'episode': 3,
|
||||
'map': 3,
|
||||
'index': 222,
|
||||
'doom_type': 2023,
|
||||
'region': "Barrels o Fun (MAP23) Main"},
|
||||
361319: {'name': 'Barrels o Fun (MAP23) - Backpack',
|
||||
'region': "Barrels o' Fun (MAP23) Main"},
|
||||
361319: {'name': "Barrels o' Fun (MAP23) - Backpack",
|
||||
'episode': 3,
|
||||
'map': 3,
|
||||
'index': 223,
|
||||
'doom_type': 8,
|
||||
'region': "Barrels o Fun (MAP23) Main"},
|
||||
361320: {'name': 'Barrels o Fun (MAP23) - Computer area map',
|
||||
'region': "Barrels o' Fun (MAP23) Main"},
|
||||
361320: {'name': "Barrels o' Fun (MAP23) - Computer area map",
|
||||
'episode': 3,
|
||||
'map': 3,
|
||||
'index': 224,
|
||||
'doom_type': 2026,
|
||||
'region': "Barrels o Fun (MAP23) Main"},
|
||||
361321: {'name': 'Barrels o Fun (MAP23) - Armor',
|
||||
'region': "Barrels o' Fun (MAP23) Main"},
|
||||
361321: {'name': "Barrels o' Fun (MAP23) - Armor",
|
||||
'episode': 3,
|
||||
'map': 3,
|
||||
'index': 249,
|
||||
'doom_type': 2018,
|
||||
'region': "Barrels o Fun (MAP23) Main"},
|
||||
361322: {'name': 'Barrels o Fun (MAP23) - Rocket launcher',
|
||||
'region': "Barrels o' Fun (MAP23) Main"},
|
||||
361322: {'name': "Barrels o' Fun (MAP23) - Rocket launcher",
|
||||
'episode': 3,
|
||||
'map': 3,
|
||||
'index': 264,
|
||||
'doom_type': 2003,
|
||||
'region': "Barrels o Fun (MAP23) Main"},
|
||||
361323: {'name': 'Barrels o Fun (MAP23) - Megasphere',
|
||||
'region': "Barrels o' Fun (MAP23) Main"},
|
||||
361323: {'name': "Barrels o' Fun (MAP23) - Megasphere",
|
||||
'episode': 3,
|
||||
'map': 3,
|
||||
'index': 266,
|
||||
'doom_type': 83,
|
||||
'region': "Barrels o Fun (MAP23) Main"},
|
||||
361324: {'name': 'Barrels o Fun (MAP23) - Supercharge',
|
||||
'region': "Barrels o' Fun (MAP23) Main"},
|
||||
361324: {'name': "Barrels o' Fun (MAP23) - Supercharge",
|
||||
'episode': 3,
|
||||
'map': 3,
|
||||
'index': 277,
|
||||
'doom_type': 2013,
|
||||
'region': "Barrels o Fun (MAP23) Main"},
|
||||
361325: {'name': 'Barrels o Fun (MAP23) - Backpack 2',
|
||||
'region': "Barrels o' Fun (MAP23) Main"},
|
||||
361325: {'name': "Barrels o' Fun (MAP23) - Backpack 2",
|
||||
'episode': 3,
|
||||
'map': 3,
|
||||
'index': 301,
|
||||
'doom_type': 8,
|
||||
'region': "Barrels o Fun (MAP23) Main"},
|
||||
361326: {'name': 'Barrels o Fun (MAP23) - Yellow skull key',
|
||||
'region': "Barrels o' Fun (MAP23) Main"},
|
||||
361326: {'name': "Barrels o' Fun (MAP23) - Yellow skull key",
|
||||
'episode': 3,
|
||||
'map': 3,
|
||||
'index': 307,
|
||||
'doom_type': 39,
|
||||
'region': "Barrels o Fun (MAP23) Main"},
|
||||
361327: {'name': 'Barrels o Fun (MAP23) - BFG9000',
|
||||
'region': "Barrels o' Fun (MAP23) Main"},
|
||||
361327: {'name': "Barrels o' Fun (MAP23) - BFG9000",
|
||||
'episode': 3,
|
||||
'map': 3,
|
||||
'index': 342,
|
||||
'doom_type': 2006,
|
||||
'region': "Barrels o Fun (MAP23) Main"},
|
||||
361328: {'name': 'Barrels o Fun (MAP23) - Exit',
|
||||
'region': "Barrels o' Fun (MAP23) Main"},
|
||||
361328: {'name': "Barrels o' Fun (MAP23) - Exit",
|
||||
'episode': 3,
|
||||
'map': 3,
|
||||
'index': -1,
|
||||
'doom_type': -1,
|
||||
'region': "Barrels o Fun (MAP23) Yellow"},
|
||||
'region': "Barrels o' Fun (MAP23) Yellow"},
|
||||
361329: {'name': 'The Chasm (MAP24) - Plasma gun',
|
||||
'episode': 3,
|
||||
'map': 4,
|
||||
'index': 5,
|
||||
'doom_type': 2004,
|
||||
'region': "The Chasm (MAP24) Main"},
|
||||
'region': "The Chasm (MAP24) Blue"},
|
||||
361330: {'name': 'The Chasm (MAP24) - Shotgun',
|
||||
'episode': 3,
|
||||
'map': 4,
|
||||
@@ -2004,7 +2004,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 4,
|
||||
'index': 12,
|
||||
'doom_type': 2022,
|
||||
'region': "The Chasm (MAP24) Main"},
|
||||
'region': "The Chasm (MAP24) Blue"},
|
||||
361332: {'name': 'The Chasm (MAP24) - Rocket launcher',
|
||||
'episode': 3,
|
||||
'map': 4,
|
||||
@@ -2022,7 +2022,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 4,
|
||||
'index': 31,
|
||||
'doom_type': 8,
|
||||
'region': "The Chasm (MAP24) Main"},
|
||||
'region': "The Chasm (MAP24) Blue"},
|
||||
361335: {'name': 'The Chasm (MAP24) - Berserk',
|
||||
'episode': 3,
|
||||
'map': 4,
|
||||
@@ -2034,19 +2034,19 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 4,
|
||||
'index': 155,
|
||||
'doom_type': 2023,
|
||||
'region': "The Chasm (MAP24) Main"},
|
||||
'region': "The Chasm (MAP24) Blue"},
|
||||
361337: {'name': 'The Chasm (MAP24) - Armor',
|
||||
'episode': 3,
|
||||
'map': 4,
|
||||
'index': 169,
|
||||
'doom_type': 2018,
|
||||
'region': "The Chasm (MAP24) Main"},
|
||||
'region': "The Chasm (MAP24) Blue"},
|
||||
361338: {'name': 'The Chasm (MAP24) - Red keycard',
|
||||
'episode': 3,
|
||||
'map': 4,
|
||||
'index': 261,
|
||||
'doom_type': 13,
|
||||
'region': "The Chasm (MAP24) Main"},
|
||||
'region': "The Chasm (MAP24) Blue"},
|
||||
361339: {'name': 'The Chasm (MAP24) - BFG9000',
|
||||
'episode': 3,
|
||||
'map': 4,
|
||||
@@ -2064,7 +2064,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 4,
|
||||
'index': 355,
|
||||
'doom_type': 83,
|
||||
'region': "The Chasm (MAP24) Main"},
|
||||
'region': "The Chasm (MAP24) Blue"},
|
||||
361342: {'name': 'The Chasm (MAP24) - Megasphere 2',
|
||||
'episode': 3,
|
||||
'map': 4,
|
||||
@@ -2082,7 +2082,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 5,
|
||||
'index': 6,
|
||||
'doom_type': 82,
|
||||
'region': "Bloodfalls (MAP25) Main"},
|
||||
'region': "Bloodfalls (MAP25) Start"},
|
||||
361345: {'name': 'Bloodfalls (MAP25) - Partial invisibility',
|
||||
'episode': 3,
|
||||
'map': 5,
|
||||
@@ -2664,55 +2664,55 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 10,
|
||||
'index': 40,
|
||||
'doom_type': 2006,
|
||||
'region': "Icon of Sin (MAP30) Main"},
|
||||
'region': "Icon of Sin (MAP30) Start"},
|
||||
361442: {'name': 'Icon of Sin (MAP30) - Chaingun',
|
||||
'episode': 3,
|
||||
'map': 10,
|
||||
'index': 41,
|
||||
'doom_type': 2002,
|
||||
'region': "Icon of Sin (MAP30) Main"},
|
||||
'region': "Icon of Sin (MAP30) Start"},
|
||||
361443: {'name': 'Icon of Sin (MAP30) - Chainsaw',
|
||||
'episode': 3,
|
||||
'map': 10,
|
||||
'index': 42,
|
||||
'doom_type': 2005,
|
||||
'region': "Icon of Sin (MAP30) Main"},
|
||||
'region': "Icon of Sin (MAP30) Start"},
|
||||
361444: {'name': 'Icon of Sin (MAP30) - Plasma gun',
|
||||
'episode': 3,
|
||||
'map': 10,
|
||||
'index': 43,
|
||||
'doom_type': 2004,
|
||||
'region': "Icon of Sin (MAP30) Main"},
|
||||
'region': "Icon of Sin (MAP30) Start"},
|
||||
361445: {'name': 'Icon of Sin (MAP30) - Rocket launcher',
|
||||
'episode': 3,
|
||||
'map': 10,
|
||||
'index': 44,
|
||||
'doom_type': 2003,
|
||||
'region': "Icon of Sin (MAP30) Main"},
|
||||
'region': "Icon of Sin (MAP30) Start"},
|
||||
361446: {'name': 'Icon of Sin (MAP30) - Shotgun',
|
||||
'episode': 3,
|
||||
'map': 10,
|
||||
'index': 45,
|
||||
'doom_type': 2001,
|
||||
'region': "Icon of Sin (MAP30) Main"},
|
||||
'region': "Icon of Sin (MAP30) Start"},
|
||||
361447: {'name': 'Icon of Sin (MAP30) - Super Shotgun',
|
||||
'episode': 3,
|
||||
'map': 10,
|
||||
'index': 46,
|
||||
'doom_type': 82,
|
||||
'region': "Icon of Sin (MAP30) Main"},
|
||||
'region': "Icon of Sin (MAP30) Start"},
|
||||
361448: {'name': 'Icon of Sin (MAP30) - Backpack',
|
||||
'episode': 3,
|
||||
'map': 10,
|
||||
'index': 47,
|
||||
'doom_type': 8,
|
||||
'region': "Icon of Sin (MAP30) Main"},
|
||||
'region': "Icon of Sin (MAP30) Start"},
|
||||
361449: {'name': 'Icon of Sin (MAP30) - Megasphere',
|
||||
'episode': 3,
|
||||
'map': 10,
|
||||
'index': 64,
|
||||
'doom_type': 83,
|
||||
'region': "Icon of Sin (MAP30) Main"},
|
||||
'region': "Icon of Sin (MAP30) Start"},
|
||||
361450: {'name': 'Icon of Sin (MAP30) - Megasphere 2',
|
||||
'episode': 3,
|
||||
'map': 10,
|
||||
@@ -2731,179 +2731,179 @@ location_table: Dict[int, LocationDict] = {
|
||||
'index': -1,
|
||||
'doom_type': -1,
|
||||
'region': "Icon of Sin (MAP30) Main"},
|
||||
361453: {'name': 'Wolfenstein2 (MAP31) - Rocket launcher',
|
||||
361453: {'name': 'Wolfenstein (MAP31) - Rocket launcher',
|
||||
'episode': 4,
|
||||
'map': 1,
|
||||
'index': 110,
|
||||
'doom_type': 2003,
|
||||
'region': "Wolfenstein2 (MAP31) Main"},
|
||||
361454: {'name': 'Wolfenstein2 (MAP31) - Shotgun',
|
||||
'region': "Wolfenstein (MAP31) Main"},
|
||||
361454: {'name': 'Wolfenstein (MAP31) - Shotgun',
|
||||
'episode': 4,
|
||||
'map': 1,
|
||||
'index': 139,
|
||||
'doom_type': 2001,
|
||||
'region': "Wolfenstein2 (MAP31) Main"},
|
||||
361455: {'name': 'Wolfenstein2 (MAP31) - Berserk',
|
||||
'region': "Wolfenstein (MAP31) Main"},
|
||||
361455: {'name': 'Wolfenstein (MAP31) - Berserk',
|
||||
'episode': 4,
|
||||
'map': 1,
|
||||
'index': 263,
|
||||
'doom_type': 2023,
|
||||
'region': "Wolfenstein2 (MAP31) Main"},
|
||||
361456: {'name': 'Wolfenstein2 (MAP31) - Supercharge',
|
||||
'region': "Wolfenstein (MAP31) Main"},
|
||||
361456: {'name': 'Wolfenstein (MAP31) - Supercharge',
|
||||
'episode': 4,
|
||||
'map': 1,
|
||||
'index': 278,
|
||||
'doom_type': 2013,
|
||||
'region': "Wolfenstein2 (MAP31) Main"},
|
||||
361457: {'name': 'Wolfenstein2 (MAP31) - Chaingun',
|
||||
'region': "Wolfenstein (MAP31) Main"},
|
||||
361457: {'name': 'Wolfenstein (MAP31) - Chaingun',
|
||||
'episode': 4,
|
||||
'map': 1,
|
||||
'index': 305,
|
||||
'doom_type': 2002,
|
||||
'region': "Wolfenstein2 (MAP31) Main"},
|
||||
361458: {'name': 'Wolfenstein2 (MAP31) - Super Shotgun',
|
||||
'region': "Wolfenstein (MAP31) Main"},
|
||||
361458: {'name': 'Wolfenstein (MAP31) - Super Shotgun',
|
||||
'episode': 4,
|
||||
'map': 1,
|
||||
'index': 308,
|
||||
'doom_type': 82,
|
||||
'region': "Wolfenstein2 (MAP31) Main"},
|
||||
361459: {'name': 'Wolfenstein2 (MAP31) - Partial invisibility',
|
||||
'region': "Wolfenstein (MAP31) Main"},
|
||||
361459: {'name': 'Wolfenstein (MAP31) - Partial invisibility',
|
||||
'episode': 4,
|
||||
'map': 1,
|
||||
'index': 309,
|
||||
'doom_type': 2024,
|
||||
'region': "Wolfenstein2 (MAP31) Main"},
|
||||
361460: {'name': 'Wolfenstein2 (MAP31) - Megasphere',
|
||||
'region': "Wolfenstein (MAP31) Main"},
|
||||
361460: {'name': 'Wolfenstein (MAP31) - Megasphere',
|
||||
'episode': 4,
|
||||
'map': 1,
|
||||
'index': 310,
|
||||
'doom_type': 83,
|
||||
'region': "Wolfenstein2 (MAP31) Main"},
|
||||
361461: {'name': 'Wolfenstein2 (MAP31) - Backpack',
|
||||
'region': "Wolfenstein (MAP31) Main"},
|
||||
361461: {'name': 'Wolfenstein (MAP31) - Backpack',
|
||||
'episode': 4,
|
||||
'map': 1,
|
||||
'index': 311,
|
||||
'doom_type': 8,
|
||||
'region': "Wolfenstein2 (MAP31) Main"},
|
||||
361462: {'name': 'Wolfenstein2 (MAP31) - Backpack 2',
|
||||
'region': "Wolfenstein (MAP31) Main"},
|
||||
361462: {'name': 'Wolfenstein (MAP31) - Backpack 2',
|
||||
'episode': 4,
|
||||
'map': 1,
|
||||
'index': 312,
|
||||
'doom_type': 8,
|
||||
'region': "Wolfenstein2 (MAP31) Main"},
|
||||
361463: {'name': 'Wolfenstein2 (MAP31) - Backpack 3',
|
||||
'region': "Wolfenstein (MAP31) Main"},
|
||||
361463: {'name': 'Wolfenstein (MAP31) - Backpack 3',
|
||||
'episode': 4,
|
||||
'map': 1,
|
||||
'index': 313,
|
||||
'doom_type': 8,
|
||||
'region': "Wolfenstein2 (MAP31) Main"},
|
||||
361464: {'name': 'Wolfenstein2 (MAP31) - Backpack 4',
|
||||
'region': "Wolfenstein (MAP31) Main"},
|
||||
361464: {'name': 'Wolfenstein (MAP31) - Backpack 4',
|
||||
'episode': 4,
|
||||
'map': 1,
|
||||
'index': 314,
|
||||
'doom_type': 8,
|
||||
'region': "Wolfenstein2 (MAP31) Main"},
|
||||
361465: {'name': 'Wolfenstein2 (MAP31) - BFG9000',
|
||||
'region': "Wolfenstein (MAP31) Main"},
|
||||
361465: {'name': 'Wolfenstein (MAP31) - BFG9000',
|
||||
'episode': 4,
|
||||
'map': 1,
|
||||
'index': 315,
|
||||
'doom_type': 2006,
|
||||
'region': "Wolfenstein2 (MAP31) Main"},
|
||||
361466: {'name': 'Wolfenstein2 (MAP31) - Plasma gun',
|
||||
'region': "Wolfenstein (MAP31) Main"},
|
||||
361466: {'name': 'Wolfenstein (MAP31) - Plasma gun',
|
||||
'episode': 4,
|
||||
'map': 1,
|
||||
'index': 316,
|
||||
'doom_type': 2004,
|
||||
'region': "Wolfenstein2 (MAP31) Main"},
|
||||
361467: {'name': 'Wolfenstein2 (MAP31) - Exit',
|
||||
'region': "Wolfenstein (MAP31) Main"},
|
||||
361467: {'name': 'Wolfenstein (MAP31) - Exit',
|
||||
'episode': 4,
|
||||
'map': 1,
|
||||
'index': -1,
|
||||
'doom_type': -1,
|
||||
'region': "Wolfenstein2 (MAP31) Main"},
|
||||
361468: {'name': 'Grosse2 (MAP32) - Plasma gun',
|
||||
'region': "Wolfenstein (MAP31) Main"},
|
||||
361468: {'name': 'Grosse (MAP32) - Plasma gun',
|
||||
'episode': 4,
|
||||
'map': 2,
|
||||
'index': 33,
|
||||
'doom_type': 2004,
|
||||
'region': "Grosse2 (MAP32) Main"},
|
||||
361469: {'name': 'Grosse2 (MAP32) - Rocket launcher',
|
||||
'region': "Grosse (MAP32) Main"},
|
||||
361469: {'name': 'Grosse (MAP32) - Rocket launcher',
|
||||
'episode': 4,
|
||||
'map': 2,
|
||||
'index': 57,
|
||||
'doom_type': 2003,
|
||||
'region': "Grosse2 (MAP32) Main"},
|
||||
361470: {'name': 'Grosse2 (MAP32) - Invulnerability',
|
||||
'region': "Grosse (MAP32) Start"},
|
||||
361470: {'name': 'Grosse (MAP32) - Invulnerability',
|
||||
'episode': 4,
|
||||
'map': 2,
|
||||
'index': 70,
|
||||
'doom_type': 2022,
|
||||
'region': "Grosse2 (MAP32) Main"},
|
||||
361471: {'name': 'Grosse2 (MAP32) - Super Shotgun',
|
||||
'region': "Grosse (MAP32) Main"},
|
||||
361471: {'name': 'Grosse (MAP32) - Super Shotgun',
|
||||
'episode': 4,
|
||||
'map': 2,
|
||||
'index': 74,
|
||||
'doom_type': 82,
|
||||
'region': "Grosse2 (MAP32) Main"},
|
||||
361472: {'name': 'Grosse2 (MAP32) - BFG9000',
|
||||
'region': "Grosse (MAP32) Main"},
|
||||
361472: {'name': 'Grosse (MAP32) - BFG9000',
|
||||
'episode': 4,
|
||||
'map': 2,
|
||||
'index': 75,
|
||||
'doom_type': 2006,
|
||||
'region': "Grosse2 (MAP32) Main"},
|
||||
361473: {'name': 'Grosse2 (MAP32) - Megasphere',
|
||||
'region': "Grosse (MAP32) Main"},
|
||||
361473: {'name': 'Grosse (MAP32) - Megasphere',
|
||||
'episode': 4,
|
||||
'map': 2,
|
||||
'index': 78,
|
||||
'doom_type': 83,
|
||||
'region': "Grosse2 (MAP32) Main"},
|
||||
361474: {'name': 'Grosse2 (MAP32) - Chaingun',
|
||||
'region': "Grosse (MAP32) Main"},
|
||||
361474: {'name': 'Grosse (MAP32) - Chaingun',
|
||||
'episode': 4,
|
||||
'map': 2,
|
||||
'index': 79,
|
||||
'doom_type': 2002,
|
||||
'region': "Grosse2 (MAP32) Main"},
|
||||
361475: {'name': 'Grosse2 (MAP32) - Chaingun 2',
|
||||
'region': "Grosse (MAP32) Main"},
|
||||
361475: {'name': 'Grosse (MAP32) - Chaingun 2',
|
||||
'episode': 4,
|
||||
'map': 2,
|
||||
'index': 80,
|
||||
'doom_type': 2002,
|
||||
'region': "Grosse2 (MAP32) Main"},
|
||||
361476: {'name': 'Grosse2 (MAP32) - Chaingun 3',
|
||||
'region': "Grosse (MAP32) Main"},
|
||||
361476: {'name': 'Grosse (MAP32) - Chaingun 3',
|
||||
'episode': 4,
|
||||
'map': 2,
|
||||
'index': 81,
|
||||
'doom_type': 2002,
|
||||
'region': "Grosse2 (MAP32) Main"},
|
||||
361477: {'name': 'Grosse2 (MAP32) - Berserk',
|
||||
'region': "Grosse (MAP32) Main"},
|
||||
361477: {'name': 'Grosse (MAP32) - Berserk',
|
||||
'episode': 4,
|
||||
'map': 2,
|
||||
'index': 82,
|
||||
'doom_type': 2023,
|
||||
'region': "Grosse2 (MAP32) Main"},
|
||||
361478: {'name': 'Grosse2 (MAP32) - Exit',
|
||||
'region': "Grosse (MAP32) Start"},
|
||||
361478: {'name': 'Grosse (MAP32) - Exit',
|
||||
'episode': 4,
|
||||
'map': 2,
|
||||
'index': -1,
|
||||
'doom_type': -1,
|
||||
'region': "Grosse2 (MAP32) Main"},
|
||||
'region': "Grosse (MAP32) Main"},
|
||||
}
|
||||
|
||||
|
||||
location_name_groups: Dict[str, Set[str]] = {
|
||||
'Barrels o Fun (MAP23)': {
|
||||
'Barrels o Fun (MAP23) - Armor',
|
||||
'Barrels o Fun (MAP23) - BFG9000',
|
||||
'Barrels o Fun (MAP23) - Backpack',
|
||||
'Barrels o Fun (MAP23) - Backpack 2',
|
||||
'Barrels o Fun (MAP23) - Berserk',
|
||||
'Barrels o Fun (MAP23) - Computer area map',
|
||||
'Barrels o Fun (MAP23) - Exit',
|
||||
'Barrels o Fun (MAP23) - Megasphere',
|
||||
'Barrels o Fun (MAP23) - Rocket launcher',
|
||||
'Barrels o Fun (MAP23) - Shotgun',
|
||||
'Barrels o Fun (MAP23) - Supercharge',
|
||||
'Barrels o Fun (MAP23) - Yellow skull key',
|
||||
"Barrels o' Fun (MAP23)": {
|
||||
"Barrels o' Fun (MAP23) - Armor",
|
||||
"Barrels o' Fun (MAP23) - BFG9000",
|
||||
"Barrels o' Fun (MAP23) - Backpack",
|
||||
"Barrels o' Fun (MAP23) - Backpack 2",
|
||||
"Barrels o' Fun (MAP23) - Berserk",
|
||||
"Barrels o' Fun (MAP23) - Computer area map",
|
||||
"Barrels o' Fun (MAP23) - Exit",
|
||||
"Barrels o' Fun (MAP23) - Megasphere",
|
||||
"Barrels o' Fun (MAP23) - Rocket launcher",
|
||||
"Barrels o' Fun (MAP23) - Shotgun",
|
||||
"Barrels o' Fun (MAP23) - Supercharge",
|
||||
"Barrels o' Fun (MAP23) - Yellow skull key",
|
||||
},
|
||||
'Bloodfalls (MAP25)': {
|
||||
'Bloodfalls (MAP25) - Armor',
|
||||
@@ -2998,18 +2998,18 @@ location_name_groups: Dict[str, Set[str]] = {
|
||||
'Gotcha! (MAP20) - Supercharge 3',
|
||||
'Gotcha! (MAP20) - Supercharge 4',
|
||||
},
|
||||
'Grosse2 (MAP32)': {
|
||||
'Grosse2 (MAP32) - BFG9000',
|
||||
'Grosse2 (MAP32) - Berserk',
|
||||
'Grosse2 (MAP32) - Chaingun',
|
||||
'Grosse2 (MAP32) - Chaingun 2',
|
||||
'Grosse2 (MAP32) - Chaingun 3',
|
||||
'Grosse2 (MAP32) - Exit',
|
||||
'Grosse2 (MAP32) - Invulnerability',
|
||||
'Grosse2 (MAP32) - Megasphere',
|
||||
'Grosse2 (MAP32) - Plasma gun',
|
||||
'Grosse2 (MAP32) - Rocket launcher',
|
||||
'Grosse2 (MAP32) - Super Shotgun',
|
||||
'Grosse (MAP32)': {
|
||||
'Grosse (MAP32) - BFG9000',
|
||||
'Grosse (MAP32) - Berserk',
|
||||
'Grosse (MAP32) - Chaingun',
|
||||
'Grosse (MAP32) - Chaingun 2',
|
||||
'Grosse (MAP32) - Chaingun 3',
|
||||
'Grosse (MAP32) - Exit',
|
||||
'Grosse (MAP32) - Invulnerability',
|
||||
'Grosse (MAP32) - Megasphere',
|
||||
'Grosse (MAP32) - Plasma gun',
|
||||
'Grosse (MAP32) - Rocket launcher',
|
||||
'Grosse (MAP32) - Super Shotgun',
|
||||
},
|
||||
'Icon of Sin (MAP30)': {
|
||||
'Icon of Sin (MAP30) - BFG9000',
|
||||
@@ -3417,22 +3417,22 @@ location_name_groups: Dict[str, Set[str]] = {
|
||||
'Underhalls (MAP02) - Red keycard',
|
||||
'Underhalls (MAP02) - Super Shotgun',
|
||||
},
|
||||
'Wolfenstein2 (MAP31)': {
|
||||
'Wolfenstein2 (MAP31) - BFG9000',
|
||||
'Wolfenstein2 (MAP31) - Backpack',
|
||||
'Wolfenstein2 (MAP31) - Backpack 2',
|
||||
'Wolfenstein2 (MAP31) - Backpack 3',
|
||||
'Wolfenstein2 (MAP31) - Backpack 4',
|
||||
'Wolfenstein2 (MAP31) - Berserk',
|
||||
'Wolfenstein2 (MAP31) - Chaingun',
|
||||
'Wolfenstein2 (MAP31) - Exit',
|
||||
'Wolfenstein2 (MAP31) - Megasphere',
|
||||
'Wolfenstein2 (MAP31) - Partial invisibility',
|
||||
'Wolfenstein2 (MAP31) - Plasma gun',
|
||||
'Wolfenstein2 (MAP31) - Rocket launcher',
|
||||
'Wolfenstein2 (MAP31) - Shotgun',
|
||||
'Wolfenstein2 (MAP31) - Super Shotgun',
|
||||
'Wolfenstein2 (MAP31) - Supercharge',
|
||||
'Wolfenstein (MAP31)': {
|
||||
'Wolfenstein (MAP31) - BFG9000',
|
||||
'Wolfenstein (MAP31) - Backpack',
|
||||
'Wolfenstein (MAP31) - Backpack 2',
|
||||
'Wolfenstein (MAP31) - Backpack 3',
|
||||
'Wolfenstein (MAP31) - Backpack 4',
|
||||
'Wolfenstein (MAP31) - Berserk',
|
||||
'Wolfenstein (MAP31) - Chaingun',
|
||||
'Wolfenstein (MAP31) - Exit',
|
||||
'Wolfenstein (MAP31) - Megasphere',
|
||||
'Wolfenstein (MAP31) - Partial invisibility',
|
||||
'Wolfenstein (MAP31) - Plasma gun',
|
||||
'Wolfenstein (MAP31) - Rocket launcher',
|
||||
'Wolfenstein (MAP31) - Shotgun',
|
||||
'Wolfenstein (MAP31) - Super Shotgun',
|
||||
'Wolfenstein (MAP31) - Supercharge',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ map_names: List[str] = [
|
||||
'Gotcha! (MAP20)',
|
||||
'Nirvana (MAP21)',
|
||||
'The Catacombs (MAP22)',
|
||||
'Barrels o Fun (MAP23)',
|
||||
"Barrels o' Fun (MAP23)",
|
||||
'The Chasm (MAP24)',
|
||||
'Bloodfalls (MAP25)',
|
||||
'The Abandoned Mines (MAP26)',
|
||||
@@ -34,6 +34,6 @@ map_names: List[str] = [
|
||||
'The Spirit World (MAP28)',
|
||||
'The Living End (MAP29)',
|
||||
'Icon of Sin (MAP30)',
|
||||
'Wolfenstein2 (MAP31)',
|
||||
'Grosse2 (MAP32)',
|
||||
'Wolfenstein (MAP31)',
|
||||
'Grosse (MAP32)',
|
||||
]
|
||||
|
||||
@@ -84,11 +84,12 @@ regions:List[RegionDict] = [
|
||||
|
||||
# The Waste Tunnels (MAP05)
|
||||
{"name":"The Waste Tunnels (MAP05) Main",
|
||||
"connects_to_hub":True,
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
"connections":[
|
||||
{"target":"The Waste Tunnels (MAP05) Red","pro":False},
|
||||
{"target":"The Waste Tunnels (MAP05) Blue","pro":False}]},
|
||||
{"target":"The Waste Tunnels (MAP05) Blue","pro":False},
|
||||
{"target":"The Waste Tunnels (MAP05) Start","pro":False}]},
|
||||
{"name":"The Waste Tunnels (MAP05) Blue",
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
@@ -103,6 +104,10 @@ regions:List[RegionDict] = [
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
"connections":[{"target":"The Waste Tunnels (MAP05) Main","pro":False}]},
|
||||
{"name":"The Waste Tunnels (MAP05) Start",
|
||||
"connects_to_hub":True,
|
||||
"episode":1,
|
||||
"connections":[{"target":"The Waste Tunnels (MAP05) Main","pro":False}]},
|
||||
|
||||
# The Crusher (MAP06)
|
||||
{"name":"The Crusher (MAP06) Main",
|
||||
@@ -129,9 +134,13 @@ regions:List[RegionDict] = [
|
||||
|
||||
# Dead Simple (MAP07)
|
||||
{"name":"Dead Simple (MAP07) Main",
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
"connections":[{"target":"Dead Simple (MAP07) Start","pro":False}]},
|
||||
{"name":"Dead Simple (MAP07) Start",
|
||||
"connects_to_hub":True,
|
||||
"episode":1,
|
||||
"connections":[]},
|
||||
"connections":[{"target":"Dead Simple (MAP07) Main","pro":False}]},
|
||||
|
||||
# Tricks and Traps (MAP08)
|
||||
{"name":"Tricks and Traps (MAP08) Main",
|
||||
@@ -151,11 +160,12 @@ regions:List[RegionDict] = [
|
||||
|
||||
# The Pit (MAP09)
|
||||
{"name":"The Pit (MAP09) Main",
|
||||
"connects_to_hub":True,
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
"connections":[
|
||||
{"target":"The Pit (MAP09) Yellow","pro":False},
|
||||
{"target":"The Pit (MAP09) Blue","pro":False}]},
|
||||
{"target":"The Pit (MAP09) Blue","pro":False},
|
||||
{"target":"The Pit (MAP09) Start","pro":False}]},
|
||||
{"name":"The Pit (MAP09) Blue",
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
@@ -164,12 +174,18 @@ regions:List[RegionDict] = [
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
"connections":[{"target":"The Pit (MAP09) Main","pro":False}]},
|
||||
{"name":"The Pit (MAP09) Start",
|
||||
"connects_to_hub":True,
|
||||
"episode":1,
|
||||
"connections":[{"target":"The Pit (MAP09) Main","pro":False}]},
|
||||
|
||||
# Refueling Base (MAP10)
|
||||
{"name":"Refueling Base (MAP10) Main",
|
||||
"connects_to_hub":True,
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
"connections":[{"target":"Refueling Base (MAP10) Yellow","pro":False}]},
|
||||
"connections":[
|
||||
{"target":"Refueling Base (MAP10) Yellow","pro":False},
|
||||
{"target":"Refueling Base (MAP10) Start","pro":False}]},
|
||||
{"name":"Refueling Base (MAP10) Yellow",
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
@@ -180,6 +196,10 @@ regions:List[RegionDict] = [
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
"connections":[{"target":"Refueling Base (MAP10) Yellow","pro":False}]},
|
||||
{"name":"Refueling Base (MAP10) Start",
|
||||
"connects_to_hub":True,
|
||||
"episode":1,
|
||||
"connections":[{"target":"Refueling Base (MAP10) Main","pro":False}]},
|
||||
|
||||
# Circle of Death (MAP11)
|
||||
{"name":"Circle of Death (MAP11) Main",
|
||||
@@ -187,31 +207,49 @@ regions:List[RegionDict] = [
|
||||
"episode":1,
|
||||
"connections":[
|
||||
{"target":"Circle of Death (MAP11) Blue","pro":False},
|
||||
{"target":"Circle of Death (MAP11) Red","pro":False}]},
|
||||
{"target":"Circle of Death (MAP11) Red","pro":False},
|
||||
{"target":"Circle of Death (MAP11) Ending","pro":True}]},
|
||||
{"name":"Circle of Death (MAP11) Blue",
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
"connections":[{"target":"Circle of Death (MAP11) Main","pro":False}]},
|
||||
{"name":"Circle of Death (MAP11) Red",
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
"connections":[
|
||||
{"target":"Circle of Death (MAP11) Main","pro":False},
|
||||
{"target":"Circle of Death (MAP11) Ending","pro":False}]},
|
||||
{"name":"Circle of Death (MAP11) Ending",
|
||||
"connects_to_hub":False,
|
||||
"episode":1,
|
||||
"connections":[{"target":"Circle of Death (MAP11) Main","pro":False}]},
|
||||
|
||||
# The Factory (MAP12)
|
||||
{"name":"The Factory (MAP12) Main",
|
||||
"connects_to_hub":True,
|
||||
{"name":"The Factory (MAP12) Indoors",
|
||||
"connects_to_hub":False,
|
||||
"episode":2,
|
||||
"connections":[
|
||||
{"target":"The Factory (MAP12) Yellow","pro":False},
|
||||
{"target":"The Factory (MAP12) Blue","pro":False}]},
|
||||
{"target":"The Factory (MAP12) Blue","pro":False},
|
||||
{"target":"The Factory (MAP12) Main","pro":False}]},
|
||||
{"name":"The Factory (MAP12) Blue",
|
||||
"connects_to_hub":False,
|
||||
"episode":2,
|
||||
"connections":[{"target":"The Factory (MAP12) Main","pro":False}]},
|
||||
"connections":[{"target":"The Factory (MAP12) Indoors","pro":False}]},
|
||||
{"name":"The Factory (MAP12) Yellow",
|
||||
"connects_to_hub":False,
|
||||
"episode":2,
|
||||
"connections":[]},
|
||||
{"name":"The Factory (MAP12) Outdoors",
|
||||
"connects_to_hub":True,
|
||||
"episode":2,
|
||||
"connections":[{"target":"The Factory (MAP12) Main","pro":False}]},
|
||||
{"name":"The Factory (MAP12) Main",
|
||||
"connects_to_hub":False,
|
||||
"episode":2,
|
||||
"connections":[
|
||||
{"target":"The Factory (MAP12) Indoors","pro":False},
|
||||
{"target":"The Factory (MAP12) Outdoors","pro":False}]},
|
||||
|
||||
# Downtown (MAP13)
|
||||
{"name":"Downtown (MAP13) Main",
|
||||
@@ -291,7 +329,8 @@ regions:List[RegionDict] = [
|
||||
"episode":2,
|
||||
"connections":[
|
||||
{"target":"Suburbs (MAP16) Red","pro":False},
|
||||
{"target":"Suburbs (MAP16) Blue","pro":False}]},
|
||||
{"target":"Suburbs (MAP16) Blue","pro":False},
|
||||
{"target":"Suburbs (MAP16) Pro Exit","pro":True}]},
|
||||
{"name":"Suburbs (MAP16) Blue",
|
||||
"connects_to_hub":False,
|
||||
"episode":2,
|
||||
@@ -299,7 +338,13 @@ regions:List[RegionDict] = [
|
||||
{"name":"Suburbs (MAP16) Red",
|
||||
"connects_to_hub":False,
|
||||
"episode":2,
|
||||
"connections":[{"target":"Suburbs (MAP16) Main","pro":False}]},
|
||||
"connections":[
|
||||
{"target":"Suburbs (MAP16) Main","pro":False},
|
||||
{"target":"Suburbs (MAP16) Pro Exit","pro":False}]},
|
||||
{"name":"Suburbs (MAP16) Pro Exit",
|
||||
"connects_to_hub":False,
|
||||
"episode":2,
|
||||
"connections":[{"target":"Suburbs (MAP16) Red","pro":False}]},
|
||||
|
||||
# Tenements (MAP17)
|
||||
{"name":"Tenements (MAP17) Main",
|
||||
@@ -358,7 +403,7 @@ regions:List[RegionDict] = [
|
||||
|
||||
# Nirvana (MAP21)
|
||||
{"name":"Nirvana (MAP21) Main",
|
||||
"connects_to_hub":True,
|
||||
"connects_to_hub":False,
|
||||
"episode":3,
|
||||
"connections":[{"target":"Nirvana (MAP21) Yellow","pro":False}]},
|
||||
{"name":"Nirvana (MAP21) Yellow",
|
||||
@@ -366,19 +411,31 @@ regions:List[RegionDict] = [
|
||||
"episode":3,
|
||||
"connections":[
|
||||
{"target":"Nirvana (MAP21) Main","pro":False},
|
||||
{"target":"Nirvana (MAP21) Magenta","pro":False}]},
|
||||
{"target":"Nirvana (MAP21) Magenta","pro":False},
|
||||
{"target":"Nirvana (MAP21) Pro Magenta","pro":True}]},
|
||||
{"name":"Nirvana (MAP21) Magenta",
|
||||
"connects_to_hub":False,
|
||||
"episode":3,
|
||||
"connections":[{"target":"Nirvana (MAP21) Yellow","pro":False}]},
|
||||
"connections":[
|
||||
{"target":"Nirvana (MAP21) Yellow","pro":False},
|
||||
{"target":"Nirvana (MAP21) Pro Magenta","pro":False}]},
|
||||
{"name":"Nirvana (MAP21) Start",
|
||||
"connects_to_hub":True,
|
||||
"episode":3,
|
||||
"connections":[{"target":"Nirvana (MAP21) Main","pro":False}]},
|
||||
{"name":"Nirvana (MAP21) Pro Magenta",
|
||||
"connects_to_hub":False,
|
||||
"episode":3,
|
||||
"connections":[{"target":"Nirvana (MAP21) Magenta","pro":False}]},
|
||||
|
||||
# The Catacombs (MAP22)
|
||||
{"name":"The Catacombs (MAP22) Main",
|
||||
"connects_to_hub":True,
|
||||
"connects_to_hub":False,
|
||||
"episode":3,
|
||||
"connections":[
|
||||
{"target":"The Catacombs (MAP22) Blue","pro":False},
|
||||
{"target":"The Catacombs (MAP22) Red","pro":False}]},
|
||||
{"target":"The Catacombs (MAP22) Red","pro":False},
|
||||
{"target":"The Catacombs (MAP22) Early","pro":False}]},
|
||||
{"name":"The Catacombs (MAP22) Blue",
|
||||
"connects_to_hub":False,
|
||||
"episode":3,
|
||||
@@ -387,36 +444,59 @@ regions:List[RegionDict] = [
|
||||
"connects_to_hub":False,
|
||||
"episode":3,
|
||||
"connections":[{"target":"The Catacombs (MAP22) Main","pro":False}]},
|
||||
|
||||
# Barrels o Fun (MAP23)
|
||||
{"name":"Barrels o Fun (MAP23) Main",
|
||||
{"name":"The Catacombs (MAP22) Early",
|
||||
"connects_to_hub":True,
|
||||
"episode":3,
|
||||
"connections":[{"target":"Barrels o Fun (MAP23) Yellow","pro":False}]},
|
||||
{"name":"Barrels o Fun (MAP23) Yellow",
|
||||
"connections":[{"target":"The Catacombs (MAP22) Main","pro":False}]},
|
||||
|
||||
# Barrels o' Fun (MAP23)
|
||||
{"name":"Barrels o' Fun (MAP23) Main",
|
||||
"connects_to_hub":True,
|
||||
"episode":3,
|
||||
"connections":[{"target":"Barrels o' Fun (MAP23) Yellow","pro":False}]},
|
||||
{"name":"Barrels o' Fun (MAP23) Yellow",
|
||||
"connects_to_hub":False,
|
||||
"episode":3,
|
||||
"connections":[{"target":"Barrels o Fun (MAP23) Main","pro":False}]},
|
||||
"connections":[{"target":"Barrels o' Fun (MAP23) Main","pro":False}]},
|
||||
|
||||
# The Chasm (MAP24)
|
||||
{"name":"The Chasm (MAP24) Main",
|
||||
"connects_to_hub":True,
|
||||
"episode":3,
|
||||
"connections":[{"target":"The Chasm (MAP24) Red","pro":False}]},
|
||||
"connections":[
|
||||
{"target":"The Chasm (MAP24) Blue","pro":False},
|
||||
{"target":"The Chasm (MAP24) Blue Pro","pro":True}]},
|
||||
{"name":"The Chasm (MAP24) Red",
|
||||
"connects_to_hub":False,
|
||||
"episode":3,
|
||||
"connections":[{"target":"The Chasm (MAP24) Main","pro":False}]},
|
||||
"connections":[{"target":"The Chasm (MAP24) Blue","pro":False}]},
|
||||
{"name":"The Chasm (MAP24) Blue",
|
||||
"connects_to_hub":False,
|
||||
"episode":3,
|
||||
"connections":[
|
||||
{"target":"The Chasm (MAP24) Red","pro":False},
|
||||
{"target":"The Chasm (MAP24) Main","pro":False},
|
||||
{"target":"The Chasm (MAP24) Blue Pro","pro":False}]},
|
||||
{"name":"The Chasm (MAP24) Blue Pro",
|
||||
"connects_to_hub":False,
|
||||
"episode":3,
|
||||
"connections":[{"target":"The Chasm (MAP24) Blue","pro":False}]},
|
||||
|
||||
# Bloodfalls (MAP25)
|
||||
{"name":"Bloodfalls (MAP25) Main",
|
||||
"connects_to_hub":True,
|
||||
"connects_to_hub":False,
|
||||
"episode":3,
|
||||
"connections":[{"target":"Bloodfalls (MAP25) Blue","pro":False}]},
|
||||
"connections":[
|
||||
{"target":"Bloodfalls (MAP25) Blue","pro":False},
|
||||
{"target":"Bloodfalls (MAP25) Start","pro":False}]},
|
||||
{"name":"Bloodfalls (MAP25) Blue",
|
||||
"connects_to_hub":False,
|
||||
"episode":3,
|
||||
"connections":[{"target":"Bloodfalls (MAP25) Main","pro":False}]},
|
||||
{"name":"Bloodfalls (MAP25) Start",
|
||||
"connects_to_hub":True,
|
||||
"episode":3,
|
||||
"connections":[{"target":"Bloodfalls (MAP25) Main","pro":False}]},
|
||||
|
||||
# The Abandoned Mines (MAP26)
|
||||
{"name":"The Abandoned Mines (MAP26) Main",
|
||||
@@ -484,19 +564,27 @@ regions:List[RegionDict] = [
|
||||
|
||||
# Icon of Sin (MAP30)
|
||||
{"name":"Icon of Sin (MAP30) Main",
|
||||
"connects_to_hub":False,
|
||||
"episode":3,
|
||||
"connections":[{"target":"Icon of Sin (MAP30) Start","pro":False}]},
|
||||
{"name":"Icon of Sin (MAP30) Start",
|
||||
"connects_to_hub":True,
|
||||
"episode":3,
|
||||
"connections":[]},
|
||||
"connections":[{"target":"Icon of Sin (MAP30) Main","pro":False}]},
|
||||
|
||||
# Wolfenstein2 (MAP31)
|
||||
{"name":"Wolfenstein2 (MAP31) Main",
|
||||
# Wolfenstein (MAP31)
|
||||
{"name":"Wolfenstein (MAP31) Main",
|
||||
"connects_to_hub":True,
|
||||
"episode":4,
|
||||
"connections":[]},
|
||||
|
||||
# Grosse2 (MAP32)
|
||||
{"name":"Grosse2 (MAP32) Main",
|
||||
# Grosse (MAP32)
|
||||
{"name":"Grosse (MAP32) Main",
|
||||
"connects_to_hub":False,
|
||||
"episode":4,
|
||||
"connections":[{"target":"Grosse (MAP32) Start","pro":False}]},
|
||||
{"name":"Grosse (MAP32) Start",
|
||||
"connects_to_hub":True,
|
||||
"episode":4,
|
||||
"connections":[]},
|
||||
"connections":[{"target":"Grosse (MAP32) Main","pro":False}]},
|
||||
]
|
||||
|
||||
@@ -53,14 +53,6 @@ def set_episode1_rules(player, multiworld, pro):
|
||||
state.has("The Focus (MAP04) - Red keycard", player, 1))
|
||||
|
||||
# The Waste Tunnels (MAP05)
|
||||
set_rule(multiworld.get_entrance("Hub -> The Waste Tunnels (MAP05) Main", player), lambda state:
|
||||
(state.has("The Waste Tunnels (MAP05)", player, 1) and
|
||||
state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Super Shotgun", player, 1)) and
|
||||
(state.has("Rocket launcher", player, 1) or
|
||||
state.has("Plasma gun", player, 1) or
|
||||
state.has("BFG9000", player, 1)))
|
||||
set_rule(multiworld.get_entrance("The Waste Tunnels (MAP05) Main -> The Waste Tunnels (MAP05) Red", player), lambda state:
|
||||
state.has("The Waste Tunnels (MAP05) - Red keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Waste Tunnels (MAP05) Main -> The Waste Tunnels (MAP05) Blue", player), lambda state:
|
||||
@@ -71,18 +63,22 @@ def set_episode1_rules(player, multiworld, pro):
|
||||
state.has("The Waste Tunnels (MAP05) - Blue keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Waste Tunnels (MAP05) Yellow -> The Waste Tunnels (MAP05) Blue", player), lambda state:
|
||||
state.has("The Waste Tunnels (MAP05) - Yellow keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("Hub -> The Waste Tunnels (MAP05) Start", player), lambda state:
|
||||
state.has("The Waste Tunnels (MAP05)", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Waste Tunnels (MAP05) Start -> The Waste Tunnels (MAP05) Main", player), lambda state:
|
||||
(state.has("Shotgun", player, 1) and
|
||||
state.has("Super Shotgun", player, 1)) and (state.has("Chaingun", player, 1) or
|
||||
state.has("Plasma gun", player, 1)))
|
||||
|
||||
# The Crusher (MAP06)
|
||||
set_rule(multiworld.get_entrance("Hub -> The Crusher (MAP06) Main", player), lambda state:
|
||||
(state.has("The Crusher (MAP06)", player, 1) and
|
||||
state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Super Shotgun", player, 1)) and
|
||||
(state.has("Rocket launcher", player, 1) or
|
||||
state.has("Plasma gun", player, 1) or
|
||||
state.has("BFG9000", player, 1)))
|
||||
state.has("Shotgun", player, 1)) and
|
||||
(state.has("Plasma gun", player, 1) or
|
||||
state.has("Chaingun", player, 1)))
|
||||
set_rule(multiworld.get_entrance("The Crusher (MAP06) Main -> The Crusher (MAP06) Blue", player), lambda state:
|
||||
state.has("The Crusher (MAP06) - Blue keycard", player, 1))
|
||||
state.has("The Crusher (MAP06) - Blue keycard", player, 1) and
|
||||
state.has("Super Shotgun", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Crusher (MAP06) Blue -> The Crusher (MAP06) Red", player), lambda state:
|
||||
state.has("The Crusher (MAP06) - Red keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Crusher (MAP06) Blue -> The Crusher (MAP06) Main", player), lambda state:
|
||||
@@ -95,14 +91,14 @@ def set_episode1_rules(player, multiworld, pro):
|
||||
state.has("The Crusher (MAP06) - Red keycard", player, 1))
|
||||
|
||||
# Dead Simple (MAP07)
|
||||
set_rule(multiworld.get_entrance("Hub -> Dead Simple (MAP07) Main", player), lambda state:
|
||||
(state.has("Dead Simple (MAP07)", player, 1) and
|
||||
state.has("Shotgun", player, 1) and
|
||||
set_rule(multiworld.get_entrance("Hub -> Dead Simple (MAP07) Start", player), lambda state:
|
||||
state.has("Dead Simple (MAP07)", player, 1))
|
||||
set_rule(multiworld.get_entrance("Dead Simple (MAP07) Start -> Dead Simple (MAP07) Main", player), lambda state:
|
||||
(state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Super Shotgun", player, 1)) and
|
||||
(state.has("Rocket launcher", player, 1) or
|
||||
state.has("Super Shotgun", player, 1)) and (state.has("BFG9000", player, 1) or
|
||||
state.has("Plasma gun", player, 1) or
|
||||
state.has("BFG9000", player, 1)))
|
||||
state.has("Rocket launcher", player, 1)))
|
||||
|
||||
# Tricks and Traps (MAP08)
|
||||
set_rule(multiworld.get_entrance("Hub -> Tricks and Traps (MAP08) Main", player), lambda state:
|
||||
@@ -119,34 +115,34 @@ def set_episode1_rules(player, multiworld, pro):
|
||||
state.has("Tricks and Traps (MAP08) - Yellow skull key", player, 1))
|
||||
|
||||
# The Pit (MAP09)
|
||||
set_rule(multiworld.get_entrance("Hub -> The Pit (MAP09) Main", player), lambda state:
|
||||
(state.has("The Pit (MAP09)", player, 1) and
|
||||
state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Super Shotgun", player, 1)) and
|
||||
(state.has("Rocket launcher", player, 1) or
|
||||
state.has("Plasma gun", player, 1) or
|
||||
state.has("BFG9000", player, 1)))
|
||||
set_rule(multiworld.get_entrance("The Pit (MAP09) Main -> The Pit (MAP09) Yellow", player), lambda state:
|
||||
state.has("The Pit (MAP09) - Yellow keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Pit (MAP09) Main -> The Pit (MAP09) Blue", player), lambda state:
|
||||
state.has("The Pit (MAP09) - Blue keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Pit (MAP09) Yellow -> The Pit (MAP09) Main", player), lambda state:
|
||||
state.has("The Pit (MAP09) - Yellow keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("Hub -> The Pit (MAP09) Start", player), lambda state:
|
||||
state.has("The Pit (MAP09)", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Pit (MAP09) Start -> The Pit (MAP09) Main", player), lambda state:
|
||||
(state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Super Shotgun", player, 1)) and (state.has("BFG9000", player, 1) or
|
||||
state.has("Plasma gun", player, 1) or
|
||||
state.has("Rocket launcher", player, 1)))
|
||||
|
||||
# Refueling Base (MAP10)
|
||||
set_rule(multiworld.get_entrance("Hub -> Refueling Base (MAP10) Main", player), lambda state:
|
||||
(state.has("Refueling Base (MAP10)", player, 1) and
|
||||
state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Super Shotgun", player, 1)) and
|
||||
(state.has("Rocket launcher", player, 1) or
|
||||
state.has("Plasma gun", player, 1) or
|
||||
state.has("BFG9000", player, 1)))
|
||||
set_rule(multiworld.get_entrance("Refueling Base (MAP10) Main -> Refueling Base (MAP10) Yellow", player), lambda state:
|
||||
state.has("Refueling Base (MAP10) - Yellow keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("Refueling Base (MAP10) Yellow -> Refueling Base (MAP10) Yellow Blue", player), lambda state:
|
||||
state.has("Refueling Base (MAP10) - Blue keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("Hub -> Refueling Base (MAP10) Start", player), lambda state:
|
||||
state.has("Refueling Base (MAP10)", player, 1))
|
||||
set_rule(multiworld.get_entrance("Refueling Base (MAP10) Start -> Refueling Base (MAP10) Main", player), lambda state:
|
||||
(state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Super Shotgun", player, 1)) and (state.has("BFG9000", player, 1) or
|
||||
state.has("Plasma gun", player, 1) or
|
||||
state.has("Rocket launcher", player, 1)))
|
||||
|
||||
# Circle of Death (MAP11)
|
||||
set_rule(multiworld.get_entrance("Hub -> Circle of Death (MAP11) Main", player), lambda state:
|
||||
@@ -165,18 +161,19 @@ def set_episode1_rules(player, multiworld, pro):
|
||||
|
||||
def set_episode2_rules(player, multiworld, pro):
|
||||
# The Factory (MAP12)
|
||||
set_rule(multiworld.get_entrance("Hub -> The Factory (MAP12) Main", player), lambda state:
|
||||
(state.has("The Factory (MAP12)", player, 1) and
|
||||
state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Super Shotgun", player, 1)) and
|
||||
(state.has("Rocket launcher", player, 1) or
|
||||
state.has("Plasma gun", player, 1) or
|
||||
state.has("BFG9000", player, 1)))
|
||||
set_rule(multiworld.get_entrance("The Factory (MAP12) Main -> The Factory (MAP12) Yellow", player), lambda state:
|
||||
set_rule(multiworld.get_entrance("The Factory (MAP12) Indoors -> The Factory (MAP12) Yellow", player), lambda state:
|
||||
state.has("The Factory (MAP12) - Yellow keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Factory (MAP12) Main -> The Factory (MAP12) Blue", player), lambda state:
|
||||
set_rule(multiworld.get_entrance("The Factory (MAP12) Indoors -> The Factory (MAP12) Blue", player), lambda state:
|
||||
state.has("The Factory (MAP12) - Blue keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("Hub -> The Factory (MAP12) Outdoors", player), lambda state:
|
||||
state.has("The Factory (MAP12)", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Factory (MAP12) Outdoors -> The Factory (MAP12) Main", player), lambda state:
|
||||
state.has("Super Shotgun", player, 1) or
|
||||
state.has("Plasma gun", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Factory (MAP12) Main -> The Factory (MAP12) Indoors", player), lambda state:
|
||||
(state.has("Super Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1)) and (state.has("BFG9000", player, 1) or
|
||||
state.has("Plasma gun", player, 1)))
|
||||
|
||||
# Downtown (MAP13)
|
||||
set_rule(multiworld.get_entrance("Hub -> Downtown (MAP13) Main", player), lambda state:
|
||||
@@ -307,54 +304,56 @@ def set_episode2_rules(player, multiworld, pro):
|
||||
|
||||
def set_episode3_rules(player, multiworld, pro):
|
||||
# Nirvana (MAP21)
|
||||
set_rule(multiworld.get_entrance("Hub -> Nirvana (MAP21) Main", player), lambda state:
|
||||
(state.has("Nirvana (MAP21)", player, 1) and
|
||||
state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Super Shotgun", player, 1)) and
|
||||
(state.has("Rocket launcher", player, 1) or
|
||||
state.has("Plasma gun", player, 1) or
|
||||
state.has("BFG9000", player, 1)))
|
||||
set_rule(multiworld.get_entrance("Nirvana (MAP21) Main -> Nirvana (MAP21) Yellow", player), lambda state:
|
||||
state.has("Nirvana (MAP21) - Yellow skull key", player, 1))
|
||||
(state.has("Super Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Nirvana (MAP21) - Yellow skull key", player, 1)) and (state.has("Plasma gun", player, 1) or
|
||||
state.has("BFG9000", player, 1)))
|
||||
set_rule(multiworld.get_entrance("Nirvana (MAP21) Yellow -> Nirvana (MAP21) Main", player), lambda state:
|
||||
state.has("Nirvana (MAP21) - Yellow skull key", player, 1))
|
||||
set_rule(multiworld.get_entrance("Nirvana (MAP21) Yellow -> Nirvana (MAP21) Magenta", player), lambda state:
|
||||
state.has("Nirvana (MAP21) - Red skull key", player, 1) and
|
||||
state.has("Nirvana (MAP21) - Blue skull key", player, 1))
|
||||
set_rule(multiworld.get_entrance("Nirvana (MAP21) Magenta -> Nirvana (MAP21) Yellow", player), lambda state:
|
||||
state.has("Nirvana (MAP21) - Red skull key", player, 1) and
|
||||
state.has("Nirvana (MAP21) - Blue skull key", player, 1))
|
||||
set_rule(multiworld.get_entrance("Hub -> Nirvana (MAP21) Start", player), lambda state:
|
||||
state.has("Nirvana (MAP21)", player, 1))
|
||||
set_rule(multiworld.get_entrance("Nirvana (MAP21) Start -> Nirvana (MAP21) Main", player), lambda state:
|
||||
state.has("Super Shotgun", player, 1) or
|
||||
state.has("Plasma gun", player, 1))
|
||||
set_rule(multiworld.get_entrance("Nirvana (MAP21) Pro Magenta -> Nirvana (MAP21) Magenta", player), lambda state:
|
||||
state.has("Nirvana (MAP21) - Red skull key", player, 1))
|
||||
|
||||
# The Catacombs (MAP22)
|
||||
set_rule(multiworld.get_entrance("Hub -> The Catacombs (MAP22) Main", player), lambda state:
|
||||
(state.has("The Catacombs (MAP22)", player, 1) and
|
||||
state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Super Shotgun", player, 1)) and
|
||||
(state.has("BFG9000", player, 1) or
|
||||
state.has("Rocket launcher", player, 1) or
|
||||
state.has("Plasma gun", player, 1)))
|
||||
set_rule(multiworld.get_entrance("The Catacombs (MAP22) Main -> The Catacombs (MAP22) Blue", player), lambda state:
|
||||
state.has("The Catacombs (MAP22) - Blue skull key", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Catacombs (MAP22) Main -> The Catacombs (MAP22) Red", player), lambda state:
|
||||
state.has("The Catacombs (MAP22) - Red skull key", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Catacombs (MAP22) Red -> The Catacombs (MAP22) Main", player), lambda state:
|
||||
state.has("The Catacombs (MAP22) - Red skull key", player, 1))
|
||||
set_rule(multiworld.get_entrance("Hub -> The Catacombs (MAP22) Early", player), lambda state:
|
||||
(state.has("The Catacombs (MAP22)", player, 1)) and
|
||||
(state.has("Shotgun", player, 1) or
|
||||
state.has("Super Shotgun", player, 1) or
|
||||
state.has("Plasma gun", player, 1)))
|
||||
set_rule(multiworld.get_entrance("The Catacombs (MAP22) Early -> The Catacombs (MAP22) Main", player), lambda state:
|
||||
(state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Super Shotgun", player, 1)) and (state.has("BFG9000", player, 1) or
|
||||
state.has("Plasma gun", player, 1) or
|
||||
state.has("Rocket launcher", player, 1)))
|
||||
|
||||
# Barrels o Fun (MAP23)
|
||||
set_rule(multiworld.get_entrance("Hub -> Barrels o Fun (MAP23) Main", player), lambda state:
|
||||
(state.has("Barrels o Fun (MAP23)", player, 1) and
|
||||
# Barrels o' Fun (MAP23)
|
||||
set_rule(multiworld.get_entrance("Hub -> Barrels o' Fun (MAP23) Main", player), lambda state:
|
||||
(state.has("Barrels o' Fun (MAP23)", player, 1) and
|
||||
state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Super Shotgun", player, 1)) and
|
||||
(state.has("Rocket launcher", player, 1) or
|
||||
state.has("Plasma gun", player, 1) or
|
||||
state.has("BFG9000", player, 1)))
|
||||
set_rule(multiworld.get_entrance("Barrels o Fun (MAP23) Main -> Barrels o Fun (MAP23) Yellow", player), lambda state:
|
||||
state.has("Barrels o Fun (MAP23) - Yellow skull key", player, 1))
|
||||
set_rule(multiworld.get_entrance("Barrels o Fun (MAP23) Yellow -> Barrels o Fun (MAP23) Main", player), lambda state:
|
||||
state.has("Barrels o Fun (MAP23) - Yellow skull key", player, 1))
|
||||
set_rule(multiworld.get_entrance("Barrels o' Fun (MAP23) Main -> Barrels o' Fun (MAP23) Yellow", player), lambda state:
|
||||
state.has("Barrels o' Fun (MAP23) - Yellow skull key", player, 1))
|
||||
set_rule(multiworld.get_entrance("Barrels o' Fun (MAP23) Yellow -> Barrels o' Fun (MAP23) Main", player), lambda state:
|
||||
state.has("Barrels o' Fun (MAP23) - Yellow skull key", player, 1))
|
||||
|
||||
# The Chasm (MAP24)
|
||||
set_rule(multiworld.get_entrance("Hub -> The Chasm (MAP24) Main", player), lambda state:
|
||||
@@ -365,24 +364,26 @@ def set_episode3_rules(player, multiworld, pro):
|
||||
state.has("Plasma gun", player, 1) and
|
||||
state.has("BFG9000", player, 1) and
|
||||
state.has("Super Shotgun", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Chasm (MAP24) Main -> The Chasm (MAP24) Red", player), lambda state:
|
||||
set_rule(multiworld.get_entrance("The Chasm (MAP24) Main -> The Chasm (MAP24) Blue", player), lambda state:
|
||||
state.has("The Chasm (MAP24) - Blue keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Chasm (MAP24) Red -> The Chasm (MAP24) Blue", player), lambda state:
|
||||
state.has("The Chasm (MAP24) - Red keycard", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Chasm (MAP24) Red -> The Chasm (MAP24) Main", player), lambda state:
|
||||
set_rule(multiworld.get_entrance("The Chasm (MAP24) Blue -> The Chasm (MAP24) Red", player), lambda state:
|
||||
state.has("The Chasm (MAP24) - Red keycard", player, 1))
|
||||
|
||||
# Bloodfalls (MAP25)
|
||||
set_rule(multiworld.get_entrance("Hub -> Bloodfalls (MAP25) Main", player), lambda state:
|
||||
state.has("Bloodfalls (MAP25)", player, 1) and
|
||||
state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Rocket launcher", player, 1) and
|
||||
state.has("Plasma gun", player, 1) and
|
||||
state.has("BFG9000", player, 1) and
|
||||
state.has("Super Shotgun", player, 1))
|
||||
set_rule(multiworld.get_entrance("Bloodfalls (MAP25) Main -> Bloodfalls (MAP25) Blue", player), lambda state:
|
||||
state.has("Bloodfalls (MAP25) - Blue skull key", player, 1))
|
||||
(state.has("Bloodfalls (MAP25) - Blue skull key", player, 1)) and (state.has("Rocket launcher", player, 1) or
|
||||
state.has("Plasma gun", player, 1) or
|
||||
state.has("BFG9000", player, 1)))
|
||||
set_rule(multiworld.get_entrance("Bloodfalls (MAP25) Blue -> Bloodfalls (MAP25) Main", player), lambda state:
|
||||
state.has("Bloodfalls (MAP25) - Blue skull key", player, 1))
|
||||
set_rule(multiworld.get_entrance("Hub -> Bloodfalls (MAP25) Start", player), lambda state:
|
||||
state.has("Bloodfalls (MAP25)", player, 1))
|
||||
set_rule(multiworld.get_entrance("Bloodfalls (MAP25) Start -> Bloodfalls (MAP25) Main", player), lambda state:
|
||||
state.has("Super Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Shotgun", player, 1))
|
||||
|
||||
# The Abandoned Mines (MAP26)
|
||||
set_rule(multiworld.get_entrance("Hub -> The Abandoned Mines (MAP26) Main", player), lambda state:
|
||||
@@ -451,36 +452,34 @@ def set_episode3_rules(player, multiworld, pro):
|
||||
state.has("Super Shotgun", player, 1))
|
||||
|
||||
# Icon of Sin (MAP30)
|
||||
set_rule(multiworld.get_entrance("Hub -> Icon of Sin (MAP30) Main", player), lambda state:
|
||||
state.has("Icon of Sin (MAP30)", player, 1) and
|
||||
state.has("Rocket launcher", player, 1) and
|
||||
set_rule(multiworld.get_entrance("Hub -> Icon of Sin (MAP30) Start", player), lambda state:
|
||||
state.has("Icon of Sin (MAP30)", player, 1))
|
||||
set_rule(multiworld.get_entrance("Icon of Sin (MAP30) Start -> Icon of Sin (MAP30) Main", player), lambda state:
|
||||
state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Rocket launcher", player, 1) and
|
||||
state.has("Plasma gun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("BFG9000", player, 1) and
|
||||
state.has("Super Shotgun", player, 1))
|
||||
|
||||
|
||||
def set_episode4_rules(player, multiworld, pro):
|
||||
# Wolfenstein2 (MAP31)
|
||||
set_rule(multiworld.get_entrance("Hub -> Wolfenstein2 (MAP31) Main", player), lambda state:
|
||||
(state.has("Wolfenstein2 (MAP31)", player, 1) and
|
||||
state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Super Shotgun", player, 1)) and
|
||||
(state.has("Rocket launcher", player, 1) or
|
||||
state.has("Plasma gun", player, 1) or
|
||||
state.has("BFG9000", player, 1)))
|
||||
# Wolfenstein (MAP31)
|
||||
set_rule(multiworld.get_entrance("Hub -> Wolfenstein (MAP31) Main", player), lambda state:
|
||||
(state.has("Wolfenstein (MAP31)", player, 1) and
|
||||
state.has("Chaingun", player, 1)) and
|
||||
(state.has("Shotgun", player, 1) or
|
||||
state.has("Super Shotgun", player, 1)))
|
||||
|
||||
# Grosse2 (MAP32)
|
||||
set_rule(multiworld.get_entrance("Hub -> Grosse2 (MAP32) Main", player), lambda state:
|
||||
(state.has("Grosse2 (MAP32)", player, 1) and
|
||||
state.has("Shotgun", player, 1) and
|
||||
# Grosse (MAP32)
|
||||
set_rule(multiworld.get_entrance("Hub -> Grosse (MAP32) Start", player), lambda state:
|
||||
state.has("Grosse (MAP32)", player, 1))
|
||||
set_rule(multiworld.get_entrance("Grosse (MAP32) Start -> Grosse (MAP32) Main", player), lambda state:
|
||||
(state.has("Shotgun", player, 1) and
|
||||
state.has("Chaingun", player, 1) and
|
||||
state.has("Super Shotgun", player, 1)) and
|
||||
(state.has("Rocket launcher", player, 1) or
|
||||
state.has("Super Shotgun", player, 1)) and (state.has("BFG9000", player, 1) or
|
||||
state.has("Plasma gun", player, 1) or
|
||||
state.has("BFG9000", player, 1)))
|
||||
state.has("Rocket launcher", player, 1)))
|
||||
|
||||
|
||||
def set_rules(doom_ii_world: "DOOM2World", included_episodes, pro):
|
||||
|
||||
@@ -51,11 +51,11 @@ class DOOM2World(World):
|
||||
location_name_to_id = {data["name"]: loc_id for loc_id, data in Locations.location_table.items()}
|
||||
location_name_groups = Locations.location_name_groups
|
||||
|
||||
starting_level_for_episode: List[str] = [
|
||||
"Entryway (MAP01)",
|
||||
"The Factory (MAP12)",
|
||||
"Nirvana (MAP21)"
|
||||
]
|
||||
starting_level_for_episode: Dict[int, str] = {
|
||||
1: "Entryway (MAP01)",
|
||||
2: "The Factory (MAP12)",
|
||||
3: "Nirvana (MAP21)"
|
||||
}
|
||||
|
||||
# Item ratio that scales depending on episode count. These are the ratio for 3 episode. In DOOM1.
|
||||
# The ratio have been tweaked seem, and feel good.
|
||||
@@ -77,6 +77,7 @@ class DOOM2World(World):
|
||||
def __init__(self, multiworld: MultiWorld, player: int):
|
||||
self.included_episodes = [1, 1, 1, 0]
|
||||
self.location_count = 0
|
||||
self.starting_levels = []
|
||||
|
||||
super().__init__(multiworld, player)
|
||||
|
||||
@@ -95,6 +96,14 @@ class DOOM2World(World):
|
||||
if self.get_episode_count() == 0:
|
||||
self.included_episodes[0] = 1
|
||||
|
||||
self.starting_levels = [level_name for (episode, level_name) in self.starting_level_for_episode.items()
|
||||
if self.included_episodes[episode - 1]]
|
||||
|
||||
# If soloing MAP21-MAP30, we need to mark a weapon as early to help generation succeed
|
||||
if self.get_episode_count() == 1 and self.included_episodes[2]:
|
||||
early_weapon = self.random.choice(["Super Shotgun", "Plasma gun"])
|
||||
self.multiworld.early_items[self.player][early_weapon] = 1
|
||||
|
||||
def create_regions(self):
|
||||
pro = self.options.pro.value
|
||||
|
||||
@@ -193,7 +202,7 @@ class DOOM2World(World):
|
||||
if item["episode"] != -1 and not self.included_episodes[item["episode"] - 1]:
|
||||
continue
|
||||
|
||||
count = item["count"] if item["name"] not in self.starting_level_for_episode else item["count"] - 1
|
||||
count = item["count"] if item["name"] not in self.starting_levels else item["count"] - 1
|
||||
itempool += [self.create_item(item["name"]) for _ in range(count)]
|
||||
|
||||
# Backpack(s) based on options
|
||||
@@ -224,9 +233,8 @@ class DOOM2World(World):
|
||||
self.location_count -= 1
|
||||
|
||||
# Give starting levels right away
|
||||
for i in range(len(self.starting_level_for_episode)):
|
||||
if self.included_episodes[i]:
|
||||
self.multiworld.push_precollected(self.create_item(self.starting_level_for_episode[i]))
|
||||
for map_name in self.starting_levels:
|
||||
self.multiworld.push_precollected(self.create_item(map_name))
|
||||
|
||||
# Give Computer area maps if option selected
|
||||
if start_with_computer_area_maps:
|
||||
|
||||
@@ -255,7 +255,8 @@ async def game_watcher(ctx: FactorioContext):
|
||||
if "DeathLink" in ctx.tags:
|
||||
async_start(ctx.send_death())
|
||||
if ctx.energy_link_increment:
|
||||
in_world_bridges = data["energy_bridges"]
|
||||
# 1 + quality * 0.3 for each bridge
|
||||
in_world_bridges: float = data["energy_bridges"]
|
||||
if in_world_bridges:
|
||||
in_world_energy = data["energy"]
|
||||
if in_world_energy < (ctx.energy_link_increment * in_world_bridges):
|
||||
@@ -263,14 +264,14 @@ async def game_watcher(ctx: FactorioContext):
|
||||
ctx.last_deplete = time.time()
|
||||
async_start(ctx.send_msgs([{
|
||||
"cmd": "Set", "key": ctx.energylink_key, "operations":
|
||||
[{"operation": "add", "value": -ctx.energy_link_increment * in_world_bridges},
|
||||
[{"operation": "add", "value": int(-ctx.energy_link_increment * in_world_bridges)},
|
||||
{"operation": "max", "value": 0}],
|
||||
"last_deplete": ctx.last_deplete
|
||||
}]))
|
||||
# Above Capacity - (len(Bridges) * ENERGY_INCREMENT)
|
||||
elif in_world_energy > (in_world_bridges * ctx.energy_link_increment * 5) - \
|
||||
ctx.energy_link_increment * in_world_bridges:
|
||||
value = ctx.energy_link_increment * in_world_bridges
|
||||
value = int(ctx.energy_link_increment * in_world_bridges)
|
||||
async_start(ctx.send_msgs([{
|
||||
"cmd": "Set", "key": ctx.energylink_key, "operations":
|
||||
[{"operation": "add", "value": value}]
|
||||
@@ -406,7 +407,7 @@ async def get_info(ctx: FactorioContext, rcon_client: factorio_rcon.RCONClient):
|
||||
ctx.auth = info["slot_name"]
|
||||
ctx.seed_name = info["seed_name"]
|
||||
death_link = info["death_link"]
|
||||
ctx.energy_link_increment = info.get("energy_link", 0)
|
||||
ctx.energy_link_increment = int(info.get("energy_link", 0))
|
||||
logger.debug(f"Energy Link Increment: {ctx.energy_link_increment}")
|
||||
if ctx.energy_link_increment and ctx.ui:
|
||||
ctx.ui.enable_energy_link()
|
||||
|
||||
@@ -102,7 +102,7 @@ class Factorio(World):
|
||||
item_name_groups = {
|
||||
"Progressive": set(progressive_tech_table.keys()),
|
||||
}
|
||||
required_client_version = (0, 5, 1)
|
||||
required_client_version = (0, 6, 0)
|
||||
if Utils.version_tuple < required_client_version:
|
||||
raise Exception(f"Update Archipelago to use this world ({game}).")
|
||||
ordered_science_packs: typing.List[str] = MaxSciencePack.get_ordered_science_packs()
|
||||
|
||||
@@ -3,7 +3,6 @@ import settings
|
||||
import base64
|
||||
import threading
|
||||
import requests
|
||||
import yaml
|
||||
from worlds.AutoWorld import World, WebWorld
|
||||
from BaseClasses import Tutorial
|
||||
from .Regions import create_regions, location_table, set_rules, stage_set_rules, rooms, non_dead_end_crest_rooms,\
|
||||
@@ -44,6 +43,7 @@ class FFMQWebWorld(WebWorld):
|
||||
)
|
||||
|
||||
tutorials = [setup_en, setup_fr]
|
||||
game_info_languages = ["en", "fr"]
|
||||
|
||||
|
||||
class FFMQWorld(World):
|
||||
@@ -134,7 +134,7 @@ class FFMQWorld(World):
|
||||
errors.append([api_url, err])
|
||||
else:
|
||||
if response.ok:
|
||||
world.rooms = rooms_data[query] = yaml.load(response.text, yaml.Loader)
|
||||
world.rooms = rooms_data[query] = Utils.parse_yaml(response.text)
|
||||
break
|
||||
else:
|
||||
api_urls.remove(api_url)
|
||||
|
||||
0
worlds/ffmq/data/__init__.py
Normal file
0
worlds/ffmq/data/__init__.py
Normal file
@@ -514,19 +514,19 @@ item_table: Dict[int, ItemDict] = {
|
||||
'map': 7},
|
||||
370259: {'classification': ItemClassification.progression,
|
||||
'count': 1,
|
||||
'name': 'The Aquifier (E3M9) - Blue key',
|
||||
'name': 'The Aquifer (E3M9) - Blue key',
|
||||
'doom_type': 79,
|
||||
'episode': 3,
|
||||
'map': 9},
|
||||
370260: {'classification': ItemClassification.progression,
|
||||
'count': 1,
|
||||
'name': 'The Aquifier (E3M9) - Green key',
|
||||
'name': 'The Aquifer (E3M9) - Green key',
|
||||
'doom_type': 73,
|
||||
'episode': 3,
|
||||
'map': 9},
|
||||
370261: {'classification': ItemClassification.progression,
|
||||
'count': 1,
|
||||
'name': 'The Aquifier (E3M9) - Yellow key',
|
||||
'name': 'The Aquifer (E3M9) - Yellow key',
|
||||
'doom_type': 80,
|
||||
'episode': 3,
|
||||
'map': 9},
|
||||
@@ -1234,37 +1234,37 @@ item_table: Dict[int, ItemDict] = {
|
||||
'map': 7},
|
||||
370475: {'classification': ItemClassification.progression,
|
||||
'count': 1,
|
||||
'name': "D'Sparil'S Keep (E3M8)",
|
||||
'name': "D'Sparil's Keep (E3M8)",
|
||||
'doom_type': -1,
|
||||
'episode': 3,
|
||||
'map': 8},
|
||||
370476: {'classification': ItemClassification.progression,
|
||||
'count': 1,
|
||||
'name': "D'Sparil'S Keep (E3M8) - Complete",
|
||||
'name': "D'Sparil's Keep (E3M8) - Complete",
|
||||
'doom_type': -2,
|
||||
'episode': 3,
|
||||
'map': 8},
|
||||
370477: {'classification': ItemClassification.filler,
|
||||
'count': 1,
|
||||
'name': "D'Sparil'S Keep (E3M8) - Map Scroll",
|
||||
'name': "D'Sparil's Keep (E3M8) - Map Scroll",
|
||||
'doom_type': 35,
|
||||
'episode': 3,
|
||||
'map': 8},
|
||||
370478: {'classification': ItemClassification.progression,
|
||||
'count': 1,
|
||||
'name': 'The Aquifier (E3M9)',
|
||||
'name': 'The Aquifer (E3M9)',
|
||||
'doom_type': -1,
|
||||
'episode': 3,
|
||||
'map': 9},
|
||||
370479: {'classification': ItemClassification.progression,
|
||||
'count': 1,
|
||||
'name': 'The Aquifier (E3M9) - Complete',
|
||||
'name': 'The Aquifer (E3M9) - Complete',
|
||||
'doom_type': -2,
|
||||
'episode': 3,
|
||||
'map': 9},
|
||||
370480: {'classification': ItemClassification.filler,
|
||||
'count': 1,
|
||||
'name': 'The Aquifier (E3M9) - Map Scroll',
|
||||
'name': 'The Aquifer (E3M9) - Map Scroll',
|
||||
'doom_type': 35,
|
||||
'episode': 3,
|
||||
'map': 9},
|
||||
@@ -1635,8 +1635,8 @@ item_name_groups: Dict[str, Set[str]] = {
|
||||
'Ammos': {'Crystal Geode', 'Energy Orb', 'Greater Runes', 'Inferno Orb', 'Pile of Mace Spheres', 'Quiver of Ethereal Arrows', },
|
||||
'Armors': {'Enchanted Shield', 'Silver Shield', },
|
||||
'Artifacts': {'Chaos Device', 'Morph Ovum', 'Mystic Urn', 'Quartz Flask', 'Ring of Invincibility', 'Shadowsphere', 'Timebomb of the Ancients', 'Tome of Power', 'Torch', },
|
||||
'Keys': {'Ambulatory (E4M3) - Blue key', 'Ambulatory (E4M3) - Green key', 'Ambulatory (E4M3) - Yellow key', 'Blockhouse (E4M2) - Blue key', 'Blockhouse (E4M2) - Green key', 'Blockhouse (E4M2) - Yellow key', 'Catafalque (E4M1) - Green key', 'Catafalque (E4M1) - Yellow key', 'Colonnade (E5M6) - Blue key', 'Colonnade (E5M6) - Green key', 'Colonnade (E5M6) - Yellow key', 'Courtyard (E5M4) - Blue key', 'Courtyard (E5M4) - Green key', 'Courtyard (E5M4) - Yellow key', 'Foetid Manse (E5M7) - Blue key', 'Foetid Manse (E5M7) - Green key', 'Foetid Manse (E5M7) - Yellow key', 'Great Stair (E4M5) - Blue key', 'Great Stair (E4M5) - Green key', 'Great Stair (E4M5) - Yellow key', 'Halls of the Apostate (E4M6) - Blue key', 'Halls of the Apostate (E4M6) - Green key', 'Halls of the Apostate (E4M6) - Yellow key', 'Hydratyr (E5M5) - Blue key', 'Hydratyr (E5M5) - Green key', 'Hydratyr (E5M5) - Yellow key', 'Mausoleum (E4M9) - Yellow key', 'Ochre Cliffs (E5M1) - Blue key', 'Ochre Cliffs (E5M1) - Green key', 'Ochre Cliffs (E5M1) - Yellow key', 'Quay (E5M3) - Blue key', 'Quay (E5M3) - Green key', 'Quay (E5M3) - Yellow key', 'Ramparts of Perdition (E4M7) - Blue key', 'Ramparts of Perdition (E4M7) - Green key', 'Ramparts of Perdition (E4M7) - Yellow key', 'Rapids (E5M2) - Green key', 'Rapids (E5M2) - Yellow key', 'Shattered Bridge (E4M8) - Yellow key', "Skein of D'Sparil (E5M9) - Blue key", "Skein of D'Sparil (E5M9) - Green key", "Skein of D'Sparil (E5M9) - Yellow key", 'The Aquifier (E3M9) - Blue key', 'The Aquifier (E3M9) - Green key', 'The Aquifier (E3M9) - Yellow key', 'The Azure Fortress (E3M4) - Green key', 'The Azure Fortress (E3M4) - Yellow key', 'The Catacombs (E2M5) - Blue key', 'The Catacombs (E2M5) - Green key', 'The Catacombs (E2M5) - Yellow key', 'The Cathedral (E1M6) - Green key', 'The Cathedral (E1M6) - Yellow key', 'The Cesspool (E3M2) - Blue key', 'The Cesspool (E3M2) - Green key', 'The Cesspool (E3M2) - Yellow key', 'The Chasm (E3M7) - Blue key', 'The Chasm (E3M7) - Green key', 'The Chasm (E3M7) - Yellow key', 'The Citadel (E1M5) - Blue key', 'The Citadel (E1M5) - Green key', 'The Citadel (E1M5) - Yellow key', 'The Confluence (E3M3) - Blue key', 'The Confluence (E3M3) - Green key', 'The Confluence (E3M3) - Yellow key', 'The Crater (E2M1) - Green key', 'The Crater (E2M1) - Yellow key', 'The Crypts (E1M7) - Blue key', 'The Crypts (E1M7) - Green key', 'The Crypts (E1M7) - Yellow key', 'The Docks (E1M1) - Yellow key', 'The Dungeons (E1M2) - Blue key', 'The Dungeons (E1M2) - Green key', 'The Dungeons (E1M2) - Yellow key', 'The Gatehouse (E1M3) - Green key', 'The Gatehouse (E1M3) - Yellow key', 'The Glacier (E2M9) - Blue key', 'The Glacier (E2M9) - Green key', 'The Glacier (E2M9) - Yellow key', 'The Graveyard (E1M9) - Blue key', 'The Graveyard (E1M9) - Green key', 'The Graveyard (E1M9) - Yellow key', 'The Great Hall (E2M7) - Blue key', 'The Great Hall (E2M7) - Green key', 'The Great Hall (E2M7) - Yellow key', 'The Guard Tower (E1M4) - Green key', 'The Guard Tower (E1M4) - Yellow key', 'The Halls of Fear (E3M6) - Blue key', 'The Halls of Fear (E3M6) - Green key', 'The Halls of Fear (E3M6) - Yellow key', 'The Ice Grotto (E2M4) - Blue key', 'The Ice Grotto (E2M4) - Green key', 'The Ice Grotto (E2M4) - Yellow key', 'The Labyrinth (E2M6) - Blue key', 'The Labyrinth (E2M6) - Green key', 'The Labyrinth (E2M6) - Yellow key', 'The Lava Pits (E2M2) - Green key', 'The Lava Pits (E2M2) - Yellow key', 'The Ophidian Lair (E3M5) - Green key', 'The Ophidian Lair (E3M5) - Yellow key', 'The River of Fire (E2M3) - Blue key', 'The River of Fire (E2M3) - Green key', 'The River of Fire (E2M3) - Yellow key', 'The Storehouse (E3M1) - Green key', 'The Storehouse (E3M1) - Yellow key', },
|
||||
'Levels': {'Ambulatory (E4M3)', 'Blockhouse (E4M2)', 'Catafalque (E4M1)', 'Colonnade (E5M6)', 'Courtyard (E5M4)', "D'Sparil'S Keep (E3M8)", 'Field of Judgement (E5M8)', 'Foetid Manse (E5M7)', 'Great Stair (E4M5)', 'Halls of the Apostate (E4M6)', "Hell's Maw (E1M8)", 'Hydratyr (E5M5)', 'Mausoleum (E4M9)', 'Ochre Cliffs (E5M1)', 'Quay (E5M3)', 'Ramparts of Perdition (E4M7)', 'Rapids (E5M2)', 'Sepulcher (E4M4)', 'Shattered Bridge (E4M8)', "Skein of D'Sparil (E5M9)", 'The Aquifier (E3M9)', 'The Azure Fortress (E3M4)', 'The Catacombs (E2M5)', 'The Cathedral (E1M6)', 'The Cesspool (E3M2)', 'The Chasm (E3M7)', 'The Citadel (E1M5)', 'The Confluence (E3M3)', 'The Crater (E2M1)', 'The Crypts (E1M7)', 'The Docks (E1M1)', 'The Dungeons (E1M2)', 'The Gatehouse (E1M3)', 'The Glacier (E2M9)', 'The Graveyard (E1M9)', 'The Great Hall (E2M7)', 'The Guard Tower (E1M4)', 'The Halls of Fear (E3M6)', 'The Ice Grotto (E2M4)', 'The Labyrinth (E2M6)', 'The Lava Pits (E2M2)', 'The Ophidian Lair (E3M5)', 'The Portals of Chaos (E2M8)', 'The River of Fire (E2M3)', 'The Storehouse (E3M1)', },
|
||||
'Map Scrolls': {'Ambulatory (E4M3) - Map Scroll', 'Blockhouse (E4M2) - Map Scroll', 'Catafalque (E4M1) - Map Scroll', 'Colonnade (E5M6) - Map Scroll', 'Courtyard (E5M4) - Map Scroll', "D'Sparil'S Keep (E3M8) - Map Scroll", 'Field of Judgement (E5M8) - Map Scroll', 'Foetid Manse (E5M7) - Map Scroll', 'Great Stair (E4M5) - Map Scroll', 'Halls of the Apostate (E4M6) - Map Scroll', "Hell's Maw (E1M8) - Map Scroll", 'Hydratyr (E5M5) - Map Scroll', 'Mausoleum (E4M9) - Map Scroll', 'Ochre Cliffs (E5M1) - Map Scroll', 'Quay (E5M3) - Map Scroll', 'Ramparts of Perdition (E4M7) - Map Scroll', 'Rapids (E5M2) - Map Scroll', 'Sepulcher (E4M4) - Map Scroll', 'Shattered Bridge (E4M8) - Map Scroll', "Skein of D'Sparil (E5M9) - Map Scroll", 'The Aquifier (E3M9) - Map Scroll', 'The Azure Fortress (E3M4) - Map Scroll', 'The Catacombs (E2M5) - Map Scroll', 'The Cathedral (E1M6) - Map Scroll', 'The Cesspool (E3M2) - Map Scroll', 'The Chasm (E3M7) - Map Scroll', 'The Citadel (E1M5) - Map Scroll', 'The Confluence (E3M3) - Map Scroll', 'The Crater (E2M1) - Map Scroll', 'The Crypts (E1M7) - Map Scroll', 'The Docks (E1M1) - Map Scroll', 'The Dungeons (E1M2) - Map Scroll', 'The Gatehouse (E1M3) - Map Scroll', 'The Glacier (E2M9) - Map Scroll', 'The Graveyard (E1M9) - Map Scroll', 'The Great Hall (E2M7) - Map Scroll', 'The Guard Tower (E1M4) - Map Scroll', 'The Halls of Fear (E3M6) - Map Scroll', 'The Ice Grotto (E2M4) - Map Scroll', 'The Labyrinth (E2M6) - Map Scroll', 'The Lava Pits (E2M2) - Map Scroll', 'The Ophidian Lair (E3M5) - Map Scroll', 'The Portals of Chaos (E2M8) - Map Scroll', 'The River of Fire (E2M3) - Map Scroll', 'The Storehouse (E3M1) - Map Scroll', },
|
||||
'Keys': {'Ambulatory (E4M3) - Blue key', 'Ambulatory (E4M3) - Green key', 'Ambulatory (E4M3) - Yellow key', 'Blockhouse (E4M2) - Blue key', 'Blockhouse (E4M2) - Green key', 'Blockhouse (E4M2) - Yellow key', 'Catafalque (E4M1) - Green key', 'Catafalque (E4M1) - Yellow key', 'Colonnade (E5M6) - Blue key', 'Colonnade (E5M6) - Green key', 'Colonnade (E5M6) - Yellow key', 'Courtyard (E5M4) - Blue key', 'Courtyard (E5M4) - Green key', 'Courtyard (E5M4) - Yellow key', 'Foetid Manse (E5M7) - Blue key', 'Foetid Manse (E5M7) - Green key', 'Foetid Manse (E5M7) - Yellow key', 'Great Stair (E4M5) - Blue key', 'Great Stair (E4M5) - Green key', 'Great Stair (E4M5) - Yellow key', 'Halls of the Apostate (E4M6) - Blue key', 'Halls of the Apostate (E4M6) - Green key', 'Halls of the Apostate (E4M6) - Yellow key', 'Hydratyr (E5M5) - Blue key', 'Hydratyr (E5M5) - Green key', 'Hydratyr (E5M5) - Yellow key', 'Mausoleum (E4M9) - Yellow key', 'Ochre Cliffs (E5M1) - Blue key', 'Ochre Cliffs (E5M1) - Green key', 'Ochre Cliffs (E5M1) - Yellow key', 'Quay (E5M3) - Blue key', 'Quay (E5M3) - Green key', 'Quay (E5M3) - Yellow key', 'Ramparts of Perdition (E4M7) - Blue key', 'Ramparts of Perdition (E4M7) - Green key', 'Ramparts of Perdition (E4M7) - Yellow key', 'Rapids (E5M2) - Green key', 'Rapids (E5M2) - Yellow key', 'Shattered Bridge (E4M8) - Yellow key', "Skein of D'Sparil (E5M9) - Blue key", "Skein of D'Sparil (E5M9) - Green key", "Skein of D'Sparil (E5M9) - Yellow key", 'The Aquifer (E3M9) - Blue key', 'The Aquifer (E3M9) - Green key', 'The Aquifer (E3M9) - Yellow key', 'The Azure Fortress (E3M4) - Green key', 'The Azure Fortress (E3M4) - Yellow key', 'The Catacombs (E2M5) - Blue key', 'The Catacombs (E2M5) - Green key', 'The Catacombs (E2M5) - Yellow key', 'The Cathedral (E1M6) - Green key', 'The Cathedral (E1M6) - Yellow key', 'The Cesspool (E3M2) - Blue key', 'The Cesspool (E3M2) - Green key', 'The Cesspool (E3M2) - Yellow key', 'The Chasm (E3M7) - Blue key', 'The Chasm (E3M7) - Green key', 'The Chasm (E3M7) - Yellow key', 'The Citadel (E1M5) - Blue key', 'The Citadel (E1M5) - Green key', 'The Citadel (E1M5) - Yellow key', 'The Confluence (E3M3) - Blue key', 'The Confluence (E3M3) - Green key', 'The Confluence (E3M3) - Yellow key', 'The Crater (E2M1) - Green key', 'The Crater (E2M1) - Yellow key', 'The Crypts (E1M7) - Blue key', 'The Crypts (E1M7) - Green key', 'The Crypts (E1M7) - Yellow key', 'The Docks (E1M1) - Yellow key', 'The Dungeons (E1M2) - Blue key', 'The Dungeons (E1M2) - Green key', 'The Dungeons (E1M2) - Yellow key', 'The Gatehouse (E1M3) - Green key', 'The Gatehouse (E1M3) - Yellow key', 'The Glacier (E2M9) - Blue key', 'The Glacier (E2M9) - Green key', 'The Glacier (E2M9) - Yellow key', 'The Graveyard (E1M9) - Blue key', 'The Graveyard (E1M9) - Green key', 'The Graveyard (E1M9) - Yellow key', 'The Great Hall (E2M7) - Blue key', 'The Great Hall (E2M7) - Green key', 'The Great Hall (E2M7) - Yellow key', 'The Guard Tower (E1M4) - Green key', 'The Guard Tower (E1M4) - Yellow key', 'The Halls of Fear (E3M6) - Blue key', 'The Halls of Fear (E3M6) - Green key', 'The Halls of Fear (E3M6) - Yellow key', 'The Ice Grotto (E2M4) - Blue key', 'The Ice Grotto (E2M4) - Green key', 'The Ice Grotto (E2M4) - Yellow key', 'The Labyrinth (E2M6) - Blue key', 'The Labyrinth (E2M6) - Green key', 'The Labyrinth (E2M6) - Yellow key', 'The Lava Pits (E2M2) - Green key', 'The Lava Pits (E2M2) - Yellow key', 'The Ophidian Lair (E3M5) - Green key', 'The Ophidian Lair (E3M5) - Yellow key', 'The River of Fire (E2M3) - Blue key', 'The River of Fire (E2M3) - Green key', 'The River of Fire (E2M3) - Yellow key', 'The Storehouse (E3M1) - Green key', 'The Storehouse (E3M1) - Yellow key', },
|
||||
'Levels': {'Ambulatory (E4M3)', 'Blockhouse (E4M2)', 'Catafalque (E4M1)', 'Colonnade (E5M6)', 'Courtyard (E5M4)', "D'Sparil's Keep (E3M8)", 'Field of Judgement (E5M8)', 'Foetid Manse (E5M7)', 'Great Stair (E4M5)', 'Halls of the Apostate (E4M6)', "Hell's Maw (E1M8)", 'Hydratyr (E5M5)', 'Mausoleum (E4M9)', 'Ochre Cliffs (E5M1)', 'Quay (E5M3)', 'Ramparts of Perdition (E4M7)', 'Rapids (E5M2)', 'Sepulcher (E4M4)', 'Shattered Bridge (E4M8)', "Skein of D'Sparil (E5M9)", 'The Aquifer (E3M9)', 'The Azure Fortress (E3M4)', 'The Catacombs (E2M5)', 'The Cathedral (E1M6)', 'The Cesspool (E3M2)', 'The Chasm (E3M7)', 'The Citadel (E1M5)', 'The Confluence (E3M3)', 'The Crater (E2M1)', 'The Crypts (E1M7)', 'The Docks (E1M1)', 'The Dungeons (E1M2)', 'The Gatehouse (E1M3)', 'The Glacier (E2M9)', 'The Graveyard (E1M9)', 'The Great Hall (E2M7)', 'The Guard Tower (E1M4)', 'The Halls of Fear (E3M6)', 'The Ice Grotto (E2M4)', 'The Labyrinth (E2M6)', 'The Lava Pits (E2M2)', 'The Ophidian Lair (E3M5)', 'The Portals of Chaos (E2M8)', 'The River of Fire (E2M3)', 'The Storehouse (E3M1)', },
|
||||
'Map Scrolls': {'Ambulatory (E4M3) - Map Scroll', 'Blockhouse (E4M2) - Map Scroll', 'Catafalque (E4M1) - Map Scroll', 'Colonnade (E5M6) - Map Scroll', 'Courtyard (E5M4) - Map Scroll', "D'Sparil's Keep (E3M8) - Map Scroll", 'Field of Judgement (E5M8) - Map Scroll', 'Foetid Manse (E5M7) - Map Scroll', 'Great Stair (E4M5) - Map Scroll', 'Halls of the Apostate (E4M6) - Map Scroll', "Hell's Maw (E1M8) - Map Scroll", 'Hydratyr (E5M5) - Map Scroll', 'Mausoleum (E4M9) - Map Scroll', 'Ochre Cliffs (E5M1) - Map Scroll', 'Quay (E5M3) - Map Scroll', 'Ramparts of Perdition (E4M7) - Map Scroll', 'Rapids (E5M2) - Map Scroll', 'Sepulcher (E4M4) - Map Scroll', 'Shattered Bridge (E4M8) - Map Scroll', "Skein of D'Sparil (E5M9) - Map Scroll", 'The Aquifer (E3M9) - Map Scroll', 'The Azure Fortress (E3M4) - Map Scroll', 'The Catacombs (E2M5) - Map Scroll', 'The Cathedral (E1M6) - Map Scroll', 'The Cesspool (E3M2) - Map Scroll', 'The Chasm (E3M7) - Map Scroll', 'The Citadel (E1M5) - Map Scroll', 'The Confluence (E3M3) - Map Scroll', 'The Crater (E2M1) - Map Scroll', 'The Crypts (E1M7) - Map Scroll', 'The Docks (E1M1) - Map Scroll', 'The Dungeons (E1M2) - Map Scroll', 'The Gatehouse (E1M3) - Map Scroll', 'The Glacier (E2M9) - Map Scroll', 'The Graveyard (E1M9) - Map Scroll', 'The Great Hall (E2M7) - Map Scroll', 'The Guard Tower (E1M4) - Map Scroll', 'The Halls of Fear (E3M6) - Map Scroll', 'The Ice Grotto (E2M4) - Map Scroll', 'The Labyrinth (E2M6) - Map Scroll', 'The Lava Pits (E2M2) - Map Scroll', 'The Ophidian Lair (E3M5) - Map Scroll', 'The Portals of Chaos (E2M8) - Map Scroll', 'The River of Fire (E2M3) - Map Scroll', 'The Storehouse (E3M1) - Map Scroll', },
|
||||
'Weapons': {'Dragon Claw', 'Ethereal Crossbow', 'Firemace', 'Gauntlets of the Necromancer', 'Hellstaff', 'Phoenix Rod', },
|
||||
}
|
||||
|
||||
@@ -3633,300 +3633,300 @@ location_table: Dict[int, LocationDict] = {
|
||||
'index': -1,
|
||||
'doom_type': -1,
|
||||
'region': "The Chasm (E3M7) Blue"},
|
||||
371517: {'name': "D'Sparil'S Keep (E3M8) - Phoenix Rod",
|
||||
371517: {'name': "D'Sparil's Keep (E3M8) - Phoenix Rod",
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 8,
|
||||
'index': 55,
|
||||
'doom_type': 2003,
|
||||
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||
371518: {'name': "D'Sparil'S Keep (E3M8) - Ethereal Crossbow",
|
||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
||||
371518: {'name': "D'Sparil's Keep (E3M8) - Ethereal Crossbow",
|
||||
'episode': 3,
|
||||
'check_sanity': True,
|
||||
'map': 8,
|
||||
'index': 56,
|
||||
'doom_type': 2001,
|
||||
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||
371519: {'name': "D'Sparil'S Keep (E3M8) - Dragon Claw",
|
||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
||||
371519: {'name': "D'Sparil's Keep (E3M8) - Dragon Claw",
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 8,
|
||||
'index': 57,
|
||||
'doom_type': 53,
|
||||
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||
371520: {'name': "D'Sparil'S Keep (E3M8) - Gauntlets of the Necromancer",
|
||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
||||
371520: {'name': "D'Sparil's Keep (E3M8) - Gauntlets of the Necromancer",
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 8,
|
||||
'index': 58,
|
||||
'doom_type': 2005,
|
||||
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||
371521: {'name': "D'Sparil'S Keep (E3M8) - Hellstaff",
|
||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
||||
371521: {'name': "D'Sparil's Keep (E3M8) - Hellstaff",
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 8,
|
||||
'index': 59,
|
||||
'doom_type': 2004,
|
||||
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||
371522: {'name': "D'Sparil'S Keep (E3M8) - Bag of Holding",
|
||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
||||
371522: {'name': "D'Sparil's Keep (E3M8) - Bag of Holding",
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 8,
|
||||
'index': 63,
|
||||
'doom_type': 8,
|
||||
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||
371523: {'name': "D'Sparil'S Keep (E3M8) - Mystic Urn",
|
||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
||||
371523: {'name': "D'Sparil's Keep (E3M8) - Mystic Urn",
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 8,
|
||||
'index': 64,
|
||||
'doom_type': 32,
|
||||
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||
371524: {'name': "D'Sparil'S Keep (E3M8) - Ring of Invincibility",
|
||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
||||
371524: {'name': "D'Sparil's Keep (E3M8) - Ring of Invincibility",
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 8,
|
||||
'index': 65,
|
||||
'doom_type': 84,
|
||||
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||
371525: {'name': "D'Sparil'S Keep (E3M8) - Shadowsphere",
|
||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
||||
371525: {'name': "D'Sparil's Keep (E3M8) - Shadowsphere",
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 8,
|
||||
'index': 66,
|
||||
'doom_type': 75,
|
||||
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||
371526: {'name': "D'Sparil'S Keep (E3M8) - Silver Shield",
|
||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
||||
371526: {'name': "D'Sparil's Keep (E3M8) - Silver Shield",
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 8,
|
||||
'index': 67,
|
||||
'doom_type': 85,
|
||||
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||
371527: {'name': "D'Sparil'S Keep (E3M8) - Enchanted Shield",
|
||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
||||
371527: {'name': "D'Sparil's Keep (E3M8) - Enchanted Shield",
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 8,
|
||||
'index': 68,
|
||||
'doom_type': 31,
|
||||
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||
371528: {'name': "D'Sparil'S Keep (E3M8) - Tome of Power",
|
||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
||||
371528: {'name': "D'Sparil's Keep (E3M8) - Tome of Power",
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 8,
|
||||
'index': 69,
|
||||
'doom_type': 86,
|
||||
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||
371529: {'name': "D'Sparil'S Keep (E3M8) - Tome of Power 2",
|
||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
||||
371529: {'name': "D'Sparil's Keep (E3M8) - Tome of Power 2",
|
||||
'episode': 3,
|
||||
'check_sanity': True,
|
||||
'map': 8,
|
||||
'index': 70,
|
||||
'doom_type': 86,
|
||||
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||
371530: {'name': "D'Sparil'S Keep (E3M8) - Chaos Device",
|
||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
||||
371530: {'name': "D'Sparil's Keep (E3M8) - Chaos Device",
|
||||
'episode': 3,
|
||||
'check_sanity': True,
|
||||
'map': 8,
|
||||
'index': 71,
|
||||
'doom_type': 36,
|
||||
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||
371531: {'name': "D'Sparil'S Keep (E3M8) - Tome of Power 3",
|
||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
||||
371531: {'name': "D'Sparil's Keep (E3M8) - Tome of Power 3",
|
||||
'episode': 3,
|
||||
'check_sanity': True,
|
||||
'map': 8,
|
||||
'index': 245,
|
||||
'doom_type': 86,
|
||||
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||
371532: {'name': "D'Sparil'S Keep (E3M8) - Exit",
|
||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
||||
371532: {'name': "D'Sparil's Keep (E3M8) - Exit",
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 8,
|
||||
'index': -1,
|
||||
'doom_type': -1,
|
||||
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||
371533: {'name': 'The Aquifier (E3M9) - Blue key',
|
||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
||||
371533: {'name': 'The Aquifer (E3M9) - Blue key',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 12,
|
||||
'doom_type': 79,
|
||||
'region': "The Aquifier (E3M9) Green"},
|
||||
371534: {'name': 'The Aquifier (E3M9) - Green key',
|
||||
'region': "The Aquifer (E3M9) Green"},
|
||||
371534: {'name': 'The Aquifer (E3M9) - Green key',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 13,
|
||||
'doom_type': 73,
|
||||
'region': "The Aquifier (E3M9) Yellow"},
|
||||
371535: {'name': 'The Aquifier (E3M9) - Yellow key',
|
||||
'region': "The Aquifer (E3M9) Yellow"},
|
||||
371535: {'name': 'The Aquifer (E3M9) - Yellow key',
|
||||
'episode': 3,
|
||||
'check_sanity': True,
|
||||
'map': 9,
|
||||
'index': 14,
|
||||
'doom_type': 80,
|
||||
'region': "The Aquifier (E3M9) Main"},
|
||||
371536: {'name': 'The Aquifier (E3M9) - Ethereal Crossbow',
|
||||
'region': "The Aquifer (E3M9) Main"},
|
||||
371536: {'name': 'The Aquifer (E3M9) - Ethereal Crossbow',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 141,
|
||||
'doom_type': 2001,
|
||||
'region': "The Aquifier (E3M9) Main"},
|
||||
371537: {'name': 'The Aquifier (E3M9) - Phoenix Rod',
|
||||
'region': "The Aquifer (E3M9) Main"},
|
||||
371537: {'name': 'The Aquifer (E3M9) - Phoenix Rod',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 142,
|
||||
'doom_type': 2003,
|
||||
'region': "The Aquifier (E3M9) Yellow"},
|
||||
371538: {'name': 'The Aquifier (E3M9) - Dragon Claw',
|
||||
'region': "The Aquifer (E3M9) Yellow"},
|
||||
371538: {'name': 'The Aquifer (E3M9) - Dragon Claw',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 143,
|
||||
'doom_type': 53,
|
||||
'region': "The Aquifier (E3M9) Green"},
|
||||
371539: {'name': 'The Aquifier (E3M9) - Hellstaff',
|
||||
'region': "The Aquifer (E3M9) Green"},
|
||||
371539: {'name': 'The Aquifer (E3M9) - Hellstaff',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 144,
|
||||
'doom_type': 2004,
|
||||
'region': "The Aquifier (E3M9) Green"},
|
||||
371540: {'name': 'The Aquifier (E3M9) - Gauntlets of the Necromancer',
|
||||
'region': "The Aquifer (E3M9) Green"},
|
||||
371540: {'name': 'The Aquifer (E3M9) - Gauntlets of the Necromancer',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 145,
|
||||
'doom_type': 2005,
|
||||
'region': "The Aquifier (E3M9) Green"},
|
||||
371541: {'name': 'The Aquifier (E3M9) - Ring of Invincibility',
|
||||
'region': "The Aquifer (E3M9) Green"},
|
||||
371541: {'name': 'The Aquifer (E3M9) - Ring of Invincibility',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 148,
|
||||
'doom_type': 84,
|
||||
'region': "The Aquifier (E3M9) Yellow"},
|
||||
371542: {'name': 'The Aquifier (E3M9) - Mystic Urn',
|
||||
'region': "The Aquifer (E3M9) Yellow"},
|
||||
371542: {'name': 'The Aquifer (E3M9) - Mystic Urn',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 149,
|
||||
'doom_type': 32,
|
||||
'region': "The Aquifier (E3M9) Green"},
|
||||
371543: {'name': 'The Aquifier (E3M9) - Silver Shield',
|
||||
'region': "The Aquifer (E3M9) Green"},
|
||||
371543: {'name': 'The Aquifer (E3M9) - Silver Shield',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 151,
|
||||
'doom_type': 85,
|
||||
'region': "The Aquifier (E3M9) Main"},
|
||||
371544: {'name': 'The Aquifier (E3M9) - Tome of Power',
|
||||
'region': "The Aquifer (E3M9) Main"},
|
||||
371544: {'name': 'The Aquifer (E3M9) - Tome of Power',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 152,
|
||||
'doom_type': 86,
|
||||
'region': "The Aquifier (E3M9) Main"},
|
||||
371545: {'name': 'The Aquifier (E3M9) - Bag of Holding',
|
||||
'region': "The Aquifer (E3M9) Main"},
|
||||
371545: {'name': 'The Aquifer (E3M9) - Bag of Holding',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 153,
|
||||
'doom_type': 8,
|
||||
'region': "The Aquifier (E3M9) Yellow"},
|
||||
371546: {'name': 'The Aquifier (E3M9) - Morph Ovum',
|
||||
'region': "The Aquifer (E3M9) Yellow"},
|
||||
371546: {'name': 'The Aquifer (E3M9) - Morph Ovum',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 154,
|
||||
'doom_type': 30,
|
||||
'region': "The Aquifier (E3M9) Green"},
|
||||
371547: {'name': 'The Aquifier (E3M9) - Map Scroll',
|
||||
'region': "The Aquifer (E3M9) Green"},
|
||||
371547: {'name': 'The Aquifer (E3M9) - Map Scroll',
|
||||
'episode': 3,
|
||||
'check_sanity': True,
|
||||
'map': 9,
|
||||
'index': 155,
|
||||
'doom_type': 35,
|
||||
'region': "The Aquifier (E3M9) Green"},
|
||||
371548: {'name': 'The Aquifier (E3M9) - Chaos Device',
|
||||
'region': "The Aquifer (E3M9) Green"},
|
||||
371548: {'name': 'The Aquifer (E3M9) - Chaos Device',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 156,
|
||||
'doom_type': 36,
|
||||
'region': "The Aquifier (E3M9) Yellow"},
|
||||
371549: {'name': 'The Aquifier (E3M9) - Enchanted Shield',
|
||||
'region': "The Aquifer (E3M9) Yellow"},
|
||||
371549: {'name': 'The Aquifer (E3M9) - Enchanted Shield',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 157,
|
||||
'doom_type': 31,
|
||||
'region': "The Aquifier (E3M9) Green"},
|
||||
371550: {'name': 'The Aquifier (E3M9) - Tome of Power 2',
|
||||
'region': "The Aquifer (E3M9) Green"},
|
||||
371550: {'name': 'The Aquifer (E3M9) - Tome of Power 2',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 158,
|
||||
'doom_type': 86,
|
||||
'region': "The Aquifier (E3M9) Green"},
|
||||
371551: {'name': 'The Aquifier (E3M9) - Torch',
|
||||
'region': "The Aquifer (E3M9) Green"},
|
||||
371551: {'name': 'The Aquifer (E3M9) - Torch',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 159,
|
||||
'doom_type': 33,
|
||||
'region': "The Aquifier (E3M9) Main"},
|
||||
371552: {'name': 'The Aquifier (E3M9) - Shadowsphere',
|
||||
'region': "The Aquifer (E3M9) Main"},
|
||||
371552: {'name': 'The Aquifer (E3M9) - Shadowsphere',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 160,
|
||||
'doom_type': 75,
|
||||
'region': "The Aquifier (E3M9) Green"},
|
||||
371553: {'name': 'The Aquifier (E3M9) - Silver Shield 2',
|
||||
'region': "The Aquifer (E3M9) Green"},
|
||||
371553: {'name': 'The Aquifer (E3M9) - Silver Shield 2',
|
||||
'episode': 3,
|
||||
'check_sanity': True,
|
||||
'map': 9,
|
||||
'index': 374,
|
||||
'doom_type': 85,
|
||||
'region': "The Aquifier (E3M9) Green"},
|
||||
371554: {'name': 'The Aquifier (E3M9) - Firemace',
|
||||
'region': "The Aquifer (E3M9) Green"},
|
||||
371554: {'name': 'The Aquifer (E3M9) - Firemace',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 478,
|
||||
'doom_type': 2002,
|
||||
'region': "The Aquifier (E3M9) Green"},
|
||||
371555: {'name': 'The Aquifier (E3M9) - Firemace 2',
|
||||
'region': "The Aquifer (E3M9) Green"},
|
||||
371555: {'name': 'The Aquifer (E3M9) - Firemace 2',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 526,
|
||||
'doom_type': 2002,
|
||||
'region': "The Aquifier (E3M9) Green"},
|
||||
371556: {'name': 'The Aquifier (E3M9) - Firemace 3',
|
||||
'region': "The Aquifer (E3M9) Green"},
|
||||
371556: {'name': 'The Aquifer (E3M9) - Firemace 3',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': 527,
|
||||
'doom_type': 2002,
|
||||
'region': "The Aquifier (E3M9) Green"},
|
||||
371557: {'name': 'The Aquifier (E3M9) - Firemace 4',
|
||||
'region': "The Aquifer (E3M9) Green"},
|
||||
371557: {'name': 'The Aquifer (E3M9) - Firemace 4',
|
||||
'episode': 3,
|
||||
'check_sanity': True,
|
||||
'map': 9,
|
||||
'index': 528,
|
||||
'doom_type': 2002,
|
||||
'region': "The Aquifier (E3M9) Yellow"},
|
||||
371558: {'name': 'The Aquifier (E3M9) - Exit',
|
||||
'region': "The Aquifer (E3M9) Yellow"},
|
||||
371558: {'name': 'The Aquifer (E3M9) - Exit',
|
||||
'episode': 3,
|
||||
'check_sanity': False,
|
||||
'map': 9,
|
||||
'index': -1,
|
||||
'doom_type': -1,
|
||||
'region': "The Aquifier (E3M9) Blue"},
|
||||
'region': "The Aquifer (E3M9) Blue"},
|
||||
371559: {'name': 'Catafalque (E4M1) - Yellow key',
|
||||
'episode': 4,
|
||||
'check_sanity': False,
|
||||
@@ -5963,7 +5963,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 3,
|
||||
'index': 213,
|
||||
'doom_type': 2005,
|
||||
'region': "Quay (E5M3) Main"},
|
||||
'region': "Quay (E5M3) Blue"},
|
||||
371850: {'name': 'Quay (E5M3) - Dragon Claw',
|
||||
'episode': 5,
|
||||
'check_sanity': False,
|
||||
@@ -6145,7 +6145,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 4,
|
||||
'index': 3,
|
||||
'doom_type': 79,
|
||||
'region': "Courtyard (E5M4) Main"},
|
||||
'region': "Courtyard (E5M4) Green"},
|
||||
371876: {'name': 'Courtyard (E5M4) - Yellow key',
|
||||
'episode': 5,
|
||||
'check_sanity': False,
|
||||
@@ -6159,7 +6159,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 4,
|
||||
'index': 21,
|
||||
'doom_type': 73,
|
||||
'region': "Courtyard (E5M4) Kakis"},
|
||||
'region': "Courtyard (E5M4) Yellow"},
|
||||
371878: {'name': 'Courtyard (E5M4) - Gauntlets of the Necromancer',
|
||||
'episode': 5,
|
||||
'check_sanity': False,
|
||||
@@ -6187,14 +6187,14 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 4,
|
||||
'index': 87,
|
||||
'doom_type': 2004,
|
||||
'region': "Courtyard (E5M4) Kakis"},
|
||||
'region': "Courtyard (E5M4) Yellow"},
|
||||
371882: {'name': 'Courtyard (E5M4) - Phoenix Rod',
|
||||
'episode': 5,
|
||||
'check_sanity': False,
|
||||
'map': 4,
|
||||
'index': 88,
|
||||
'doom_type': 2003,
|
||||
'region': "Courtyard (E5M4) Main"},
|
||||
'region': "Courtyard (E5M4) Green"},
|
||||
371883: {'name': 'Courtyard (E5M4) - Morph Ovum',
|
||||
'episode': 5,
|
||||
'check_sanity': False,
|
||||
@@ -6229,7 +6229,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 4,
|
||||
'index': 104,
|
||||
'doom_type': 84,
|
||||
'region': "Courtyard (E5M4) Kakis"},
|
||||
'region': "Courtyard (E5M4) Yellow"},
|
||||
371888: {'name': 'Courtyard (E5M4) - Shadowsphere',
|
||||
'episode': 5,
|
||||
'check_sanity': False,
|
||||
@@ -6250,14 +6250,14 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 4,
|
||||
'index': 107,
|
||||
'doom_type': 35,
|
||||
'region': "Courtyard (E5M4) Kakis"},
|
||||
'region': "Courtyard (E5M4) Yellow"},
|
||||
371891: {'name': 'Courtyard (E5M4) - Chaos Device',
|
||||
'episode': 5,
|
||||
'check_sanity': False,
|
||||
'map': 4,
|
||||
'index': 108,
|
||||
'doom_type': 36,
|
||||
'region': "Courtyard (E5M4) Main"},
|
||||
'region': "Courtyard (E5M4) Green"},
|
||||
371892: {'name': 'Courtyard (E5M4) - Tome of Power',
|
||||
'episode': 5,
|
||||
'check_sanity': False,
|
||||
@@ -6278,7 +6278,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 4,
|
||||
'index': 111,
|
||||
'doom_type': 86,
|
||||
'region': "Courtyard (E5M4) Kakis"},
|
||||
'region': "Courtyard (E5M4) Yellow"},
|
||||
371895: {'name': 'Courtyard (E5M4) - Torch',
|
||||
'episode': 5,
|
||||
'check_sanity': False,
|
||||
@@ -6299,7 +6299,7 @@ location_table: Dict[int, LocationDict] = {
|
||||
'map': 4,
|
||||
'index': 219,
|
||||
'doom_type': 85,
|
||||
'region': "Courtyard (E5M4) Kakis"},
|
||||
'region': "Courtyard (E5M4) Yellow"},
|
||||
371898: {'name': 'Courtyard (E5M4) - Bag of Holding 3',
|
||||
'episode': 5,
|
||||
'check_sanity': False,
|
||||
@@ -7247,23 +7247,23 @@ location_name_groups: Dict[str, Set[str]] = {
|
||||
'Courtyard (E5M4) - Torch',
|
||||
'Courtyard (E5M4) - Yellow key',
|
||||
},
|
||||
"D'Sparil'S Keep (E3M8)": {
|
||||
"D'Sparil'S Keep (E3M8) - Bag of Holding",
|
||||
"D'Sparil'S Keep (E3M8) - Chaos Device",
|
||||
"D'Sparil'S Keep (E3M8) - Dragon Claw",
|
||||
"D'Sparil'S Keep (E3M8) - Enchanted Shield",
|
||||
"D'Sparil'S Keep (E3M8) - Ethereal Crossbow",
|
||||
"D'Sparil'S Keep (E3M8) - Exit",
|
||||
"D'Sparil'S Keep (E3M8) - Gauntlets of the Necromancer",
|
||||
"D'Sparil'S Keep (E3M8) - Hellstaff",
|
||||
"D'Sparil'S Keep (E3M8) - Mystic Urn",
|
||||
"D'Sparil'S Keep (E3M8) - Phoenix Rod",
|
||||
"D'Sparil'S Keep (E3M8) - Ring of Invincibility",
|
||||
"D'Sparil'S Keep (E3M8) - Shadowsphere",
|
||||
"D'Sparil'S Keep (E3M8) - Silver Shield",
|
||||
"D'Sparil'S Keep (E3M8) - Tome of Power",
|
||||
"D'Sparil'S Keep (E3M8) - Tome of Power 2",
|
||||
"D'Sparil'S Keep (E3M8) - Tome of Power 3",
|
||||
"D'Sparil's Keep (E3M8)": {
|
||||
"D'Sparil's Keep (E3M8) - Bag of Holding",
|
||||
"D'Sparil's Keep (E3M8) - Chaos Device",
|
||||
"D'Sparil's Keep (E3M8) - Dragon Claw",
|
||||
"D'Sparil's Keep (E3M8) - Enchanted Shield",
|
||||
"D'Sparil's Keep (E3M8) - Ethereal Crossbow",
|
||||
"D'Sparil's Keep (E3M8) - Exit",
|
||||
"D'Sparil's Keep (E3M8) - Gauntlets of the Necromancer",
|
||||
"D'Sparil's Keep (E3M8) - Hellstaff",
|
||||
"D'Sparil's Keep (E3M8) - Mystic Urn",
|
||||
"D'Sparil's Keep (E3M8) - Phoenix Rod",
|
||||
"D'Sparil's Keep (E3M8) - Ring of Invincibility",
|
||||
"D'Sparil's Keep (E3M8) - Shadowsphere",
|
||||
"D'Sparil's Keep (E3M8) - Silver Shield",
|
||||
"D'Sparil's Keep (E3M8) - Tome of Power",
|
||||
"D'Sparil's Keep (E3M8) - Tome of Power 2",
|
||||
"D'Sparil's Keep (E3M8) - Tome of Power 3",
|
||||
},
|
||||
'Field of Judgement (E5M8)': {
|
||||
'Field of Judgement (E5M8) - Bag of Holding',
|
||||
@@ -7641,33 +7641,33 @@ location_name_groups: Dict[str, Set[str]] = {
|
||||
"Skein of D'Sparil (E5M9) - Torch",
|
||||
"Skein of D'Sparil (E5M9) - Yellow key",
|
||||
},
|
||||
'The Aquifier (E3M9)': {
|
||||
'The Aquifier (E3M9) - Bag of Holding',
|
||||
'The Aquifier (E3M9) - Blue key',
|
||||
'The Aquifier (E3M9) - Chaos Device',
|
||||
'The Aquifier (E3M9) - Dragon Claw',
|
||||
'The Aquifier (E3M9) - Enchanted Shield',
|
||||
'The Aquifier (E3M9) - Ethereal Crossbow',
|
||||
'The Aquifier (E3M9) - Exit',
|
||||
'The Aquifier (E3M9) - Firemace',
|
||||
'The Aquifier (E3M9) - Firemace 2',
|
||||
'The Aquifier (E3M9) - Firemace 3',
|
||||
'The Aquifier (E3M9) - Firemace 4',
|
||||
'The Aquifier (E3M9) - Gauntlets of the Necromancer',
|
||||
'The Aquifier (E3M9) - Green key',
|
||||
'The Aquifier (E3M9) - Hellstaff',
|
||||
'The Aquifier (E3M9) - Map Scroll',
|
||||
'The Aquifier (E3M9) - Morph Ovum',
|
||||
'The Aquifier (E3M9) - Mystic Urn',
|
||||
'The Aquifier (E3M9) - Phoenix Rod',
|
||||
'The Aquifier (E3M9) - Ring of Invincibility',
|
||||
'The Aquifier (E3M9) - Shadowsphere',
|
||||
'The Aquifier (E3M9) - Silver Shield',
|
||||
'The Aquifier (E3M9) - Silver Shield 2',
|
||||
'The Aquifier (E3M9) - Tome of Power',
|
||||
'The Aquifier (E3M9) - Tome of Power 2',
|
||||
'The Aquifier (E3M9) - Torch',
|
||||
'The Aquifier (E3M9) - Yellow key',
|
||||
'The Aquifer (E3M9)': {
|
||||
'The Aquifer (E3M9) - Bag of Holding',
|
||||
'The Aquifer (E3M9) - Blue key',
|
||||
'The Aquifer (E3M9) - Chaos Device',
|
||||
'The Aquifer (E3M9) - Dragon Claw',
|
||||
'The Aquifer (E3M9) - Enchanted Shield',
|
||||
'The Aquifer (E3M9) - Ethereal Crossbow',
|
||||
'The Aquifer (E3M9) - Exit',
|
||||
'The Aquifer (E3M9) - Firemace',
|
||||
'The Aquifer (E3M9) - Firemace 2',
|
||||
'The Aquifer (E3M9) - Firemace 3',
|
||||
'The Aquifer (E3M9) - Firemace 4',
|
||||
'The Aquifer (E3M9) - Gauntlets of the Necromancer',
|
||||
'The Aquifer (E3M9) - Green key',
|
||||
'The Aquifer (E3M9) - Hellstaff',
|
||||
'The Aquifer (E3M9) - Map Scroll',
|
||||
'The Aquifer (E3M9) - Morph Ovum',
|
||||
'The Aquifer (E3M9) - Mystic Urn',
|
||||
'The Aquifer (E3M9) - Phoenix Rod',
|
||||
'The Aquifer (E3M9) - Ring of Invincibility',
|
||||
'The Aquifer (E3M9) - Shadowsphere',
|
||||
'The Aquifer (E3M9) - Silver Shield',
|
||||
'The Aquifer (E3M9) - Silver Shield 2',
|
||||
'The Aquifer (E3M9) - Tome of Power',
|
||||
'The Aquifer (E3M9) - Tome of Power 2',
|
||||
'The Aquifer (E3M9) - Torch',
|
||||
'The Aquifer (E3M9) - Yellow key',
|
||||
},
|
||||
'The Azure Fortress (E3M4)': {
|
||||
'The Azure Fortress (E3M4) - Bag of Holding',
|
||||
|
||||
@@ -29,8 +29,8 @@ map_names: List[str] = [
|
||||
'The Ophidian Lair (E3M5)',
|
||||
'The Halls of Fear (E3M6)',
|
||||
'The Chasm (E3M7)',
|
||||
"D'Sparil'S Keep (E3M8)",
|
||||
'The Aquifier (E3M9)',
|
||||
"D'Sparil's Keep (E3M8)",
|
||||
'The Aquifer (E3M9)',
|
||||
'Catafalque (E4M1)',
|
||||
'Blockhouse (E4M2)',
|
||||
'Ambulatory (E4M3)',
|
||||
|
||||
@@ -520,34 +520,34 @@ regions:List[RegionDict] = [
|
||||
"episode":3,
|
||||
"connections":[{"target":"The Chasm (E3M7) Yellow","pro":False}]},
|
||||
|
||||
# D'Sparil'S Keep (E3M8)
|
||||
{"name":"D'Sparil'S Keep (E3M8) Main",
|
||||
# D'Sparil's Keep (E3M8)
|
||||
{"name":"D'Sparil's Keep (E3M8) Main",
|
||||
"connects_to_hub":True,
|
||||
"episode":3,
|
||||
"connections":[]},
|
||||
|
||||
# The Aquifier (E3M9)
|
||||
{"name":"The Aquifier (E3M9) Main",
|
||||
# The Aquifer (E3M9)
|
||||
{"name":"The Aquifer (E3M9) Main",
|
||||
"connects_to_hub":True,
|
||||
"episode":3,
|
||||
"connections":[{"target":"The Aquifier (E3M9) Yellow","pro":False}]},
|
||||
{"name":"The Aquifier (E3M9) Blue",
|
||||
"connections":[{"target":"The Aquifer (E3M9) Yellow","pro":False}]},
|
||||
{"name":"The Aquifer (E3M9) Blue",
|
||||
"connects_to_hub":False,
|
||||
"episode":3,
|
||||
"connections":[]},
|
||||
{"name":"The Aquifier (E3M9) Yellow",
|
||||
{"name":"The Aquifer (E3M9) Yellow",
|
||||
"connects_to_hub":False,
|
||||
"episode":3,
|
||||
"connections":[
|
||||
{"target":"The Aquifier (E3M9) Green","pro":False},
|
||||
{"target":"The Aquifier (E3M9) Main","pro":False}]},
|
||||
{"name":"The Aquifier (E3M9) Green",
|
||||
{"target":"The Aquifer (E3M9) Green","pro":False},
|
||||
{"target":"The Aquifer (E3M9) Main","pro":False}]},
|
||||
{"name":"The Aquifer (E3M9) Green",
|
||||
"connects_to_hub":False,
|
||||
"episode":3,
|
||||
"connections":[
|
||||
{"target":"The Aquifier (E3M9) Yellow","pro":False},
|
||||
{"target":"The Aquifier (E3M9) Main","pro":False},
|
||||
{"target":"The Aquifier (E3M9) Blue","pro":False}]},
|
||||
{"target":"The Aquifer (E3M9) Yellow","pro":False},
|
||||
{"target":"The Aquifer (E3M9) Main","pro":False},
|
||||
{"target":"The Aquifer (E3M9) Blue","pro":False}]},
|
||||
|
||||
# Catafalque (E4M1)
|
||||
{"name":"Catafalque (E4M1) Main",
|
||||
@@ -795,16 +795,22 @@ regions:List[RegionDict] = [
|
||||
"connects_to_hub":True,
|
||||
"episode":5,
|
||||
"connections":[
|
||||
{"target":"Courtyard (E5M4) Kakis","pro":False},
|
||||
{"target":"Courtyard (E5M4) Yellow","pro":False},
|
||||
{"target":"Courtyard (E5M4) Blue","pro":False}]},
|
||||
{"name":"Courtyard (E5M4) Blue",
|
||||
"connects_to_hub":False,
|
||||
"episode":5,
|
||||
"connections":[{"target":"Courtyard (E5M4) Main","pro":False}]},
|
||||
{"name":"Courtyard (E5M4) Kakis",
|
||||
{"name":"Courtyard (E5M4) Yellow",
|
||||
"connects_to_hub":False,
|
||||
"episode":5,
|
||||
"connections":[{"target":"Courtyard (E5M4) Main","pro":False}]},
|
||||
"connections":[
|
||||
{"target":"Courtyard (E5M4) Main","pro":False},
|
||||
{"target":"Courtyard (E5M4) Green","pro":False}]},
|
||||
{"name":"Courtyard (E5M4) Green",
|
||||
"connects_to_hub":False,
|
||||
"episode":5,
|
||||
"connections":[{"target":"Courtyard (E5M4) Yellow","pro":False}]},
|
||||
|
||||
# Hydratyr (E5M5)
|
||||
{"name":"Hydratyr (E5M5) Main",
|
||||
|
||||
@@ -388,9 +388,9 @@ def set_episode3_rules(player, multiworld, pro):
|
||||
set_rule(multiworld.get_entrance("The Chasm (E3M7) Green -> The Chasm (E3M7) Yellow", player), lambda state:
|
||||
state.has("The Chasm (E3M7) - Green key", player, 1))
|
||||
|
||||
# D'Sparil'S Keep (E3M8)
|
||||
set_rule(multiworld.get_entrance("Hub -> D'Sparil'S Keep (E3M8) Main", player), lambda state:
|
||||
state.has("D'Sparil'S Keep (E3M8)", player, 1) and
|
||||
# D'Sparil's Keep (E3M8)
|
||||
set_rule(multiworld.get_entrance("Hub -> D'Sparil's Keep (E3M8) Main", player), lambda state:
|
||||
state.has("D'Sparil's Keep (E3M8)", player, 1) and
|
||||
state.has("Gauntlets of the Necromancer", player, 1) and
|
||||
state.has("Ethereal Crossbow", player, 1) and
|
||||
state.has("Dragon Claw", player, 1) and
|
||||
@@ -398,23 +398,23 @@ def set_episode3_rules(player, multiworld, pro):
|
||||
state.has("Firemace", player, 1) and
|
||||
state.has("Hellstaff", player, 1))
|
||||
|
||||
# The Aquifier (E3M9)
|
||||
set_rule(multiworld.get_entrance("Hub -> The Aquifier (E3M9) Main", player), lambda state:
|
||||
state.has("The Aquifier (E3M9)", player, 1) and
|
||||
# The Aquifer (E3M9)
|
||||
set_rule(multiworld.get_entrance("Hub -> The Aquifer (E3M9) Main", player), lambda state:
|
||||
state.has("The Aquifer (E3M9)", player, 1) and
|
||||
state.has("Gauntlets of the Necromancer", player, 1) and
|
||||
state.has("Ethereal Crossbow", player, 1) and
|
||||
state.has("Dragon Claw", player, 1) and
|
||||
state.has("Phoenix Rod", player, 1) and
|
||||
state.has("Firemace", player, 1) and
|
||||
state.has("Hellstaff", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Aquifier (E3M9) Main -> The Aquifier (E3M9) Yellow", player), lambda state:
|
||||
state.has("The Aquifier (E3M9) - Yellow key", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Aquifier (E3M9) Yellow -> The Aquifier (E3M9) Green", player), lambda state:
|
||||
state.has("The Aquifier (E3M9) - Green key", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Aquifier (E3M9) Yellow -> The Aquifier (E3M9) Main", player), lambda state:
|
||||
state.has("The Aquifier (E3M9) - Yellow key", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Aquifier (E3M9) Green -> The Aquifier (E3M9) Yellow", player), lambda state:
|
||||
state.has("The Aquifier (E3M9) - Green key", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Aquifer (E3M9) Main -> The Aquifer (E3M9) Yellow", player), lambda state:
|
||||
state.has("The Aquifer (E3M9) - Yellow key", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Aquifer (E3M9) Yellow -> The Aquifer (E3M9) Green", player), lambda state:
|
||||
state.has("The Aquifer (E3M9) - Green key", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Aquifer (E3M9) Yellow -> The Aquifer (E3M9) Main", player), lambda state:
|
||||
state.has("The Aquifer (E3M9) - Yellow key", player, 1))
|
||||
set_rule(multiworld.get_entrance("The Aquifer (E3M9) Green -> The Aquifer (E3M9) Yellow", player), lambda state:
|
||||
state.has("The Aquifer (E3M9) - Green key", player, 1))
|
||||
|
||||
|
||||
def set_episode4_rules(player, multiworld, pro):
|
||||
@@ -623,15 +623,17 @@ def set_episode5_rules(player, multiworld, pro):
|
||||
(state.has("Phoenix Rod", player, 1) or
|
||||
state.has("Firemace", player, 1) or
|
||||
state.has("Hellstaff", player, 1)))
|
||||
set_rule(multiworld.get_entrance("Courtyard (E5M4) Main -> Courtyard (E5M4) Kakis", player), lambda state:
|
||||
state.has("Courtyard (E5M4) - Yellow key", player, 1) or
|
||||
state.has("Courtyard (E5M4) - Green key", player, 1))
|
||||
set_rule(multiworld.get_entrance("Courtyard (E5M4) Main -> Courtyard (E5M4) Yellow", player), lambda state:
|
||||
state.has("Courtyard (E5M4) - Yellow key", player, 1))
|
||||
set_rule(multiworld.get_entrance("Courtyard (E5M4) Main -> Courtyard (E5M4) Blue", player), lambda state:
|
||||
state.has("Courtyard (E5M4) - Blue key", player, 1))
|
||||
set_rule(multiworld.get_entrance("Courtyard (E5M4) Blue -> Courtyard (E5M4) Main", player), lambda state:
|
||||
state.has("Courtyard (E5M4) - Blue key", player, 1))
|
||||
set_rule(multiworld.get_entrance("Courtyard (E5M4) Kakis -> Courtyard (E5M4) Main", player), lambda state:
|
||||
state.has("Courtyard (E5M4) - Yellow key", player, 1) or
|
||||
set_rule(multiworld.get_entrance("Courtyard (E5M4) Yellow -> Courtyard (E5M4) Main", player), lambda state:
|
||||
state.has("Courtyard (E5M4) - Yellow key", player, 1))
|
||||
set_rule(multiworld.get_entrance("Courtyard (E5M4) Yellow -> Courtyard (E5M4) Green", player), lambda state:
|
||||
state.has("Courtyard (E5M4) - Green key", player, 1))
|
||||
set_rule(multiworld.get_entrance("Courtyard (E5M4) Green -> Courtyard (E5M4) Yellow", player), lambda state:
|
||||
state.has("Courtyard (E5M4) - Green key", player, 1))
|
||||
|
||||
# Hydratyr (E5M5)
|
||||
|
||||
@@ -49,18 +49,18 @@ class HereticWorld(World):
|
||||
location_name_to_id = {data["name"]: loc_id for loc_id, data in Locations.location_table.items()}
|
||||
location_name_groups = Locations.location_name_groups
|
||||
|
||||
starting_level_for_episode: List[str] = [
|
||||
"The Docks (E1M1)",
|
||||
"The Crater (E2M1)",
|
||||
"The Storehouse (E3M1)",
|
||||
"Catafalque (E4M1)",
|
||||
"Ochre Cliffs (E5M1)"
|
||||
]
|
||||
starting_level_for_episode: Dict[int, str] = {
|
||||
1: "The Docks (E1M1)",
|
||||
2: "The Crater (E2M1)",
|
||||
3: "The Storehouse (E3M1)",
|
||||
4: "Catafalque (E4M1)",
|
||||
5: "Ochre Cliffs (E5M1)"
|
||||
}
|
||||
|
||||
boss_level_for_episode: List[str] = [
|
||||
all_boss_levels: List[str] = [
|
||||
"Hell's Maw (E1M8)",
|
||||
"The Portals of Chaos (E2M8)",
|
||||
"D'Sparil'S Keep (E3M8)",
|
||||
"D'Sparil's Keep (E3M8)",
|
||||
"Shattered Bridge (E4M8)",
|
||||
"Field of Judgement (E5M8)"
|
||||
]
|
||||
@@ -82,6 +82,7 @@ class HereticWorld(World):
|
||||
def __init__(self, multiworld: MultiWorld, player: int):
|
||||
self.included_episodes = [1, 1, 1, 0, 0]
|
||||
self.location_count = 0
|
||||
self.starting_levels = []
|
||||
|
||||
super().__init__(multiworld, player)
|
||||
|
||||
@@ -100,6 +101,14 @@ class HereticWorld(World):
|
||||
if self.get_episode_count() == 0:
|
||||
self.included_episodes[0] = 1
|
||||
|
||||
self.starting_levels = [level_name for (episode, level_name) in self.starting_level_for_episode.items()
|
||||
if self.included_episodes[episode - 1]]
|
||||
|
||||
# For Solo Episode 1, place the Yellow Key for E1M1 early.
|
||||
# Gives the generator five potential placements (plus the forced key) instead of only two.
|
||||
if self.get_episode_count() == 1 and self.included_episodes[0]:
|
||||
self.multiworld.early_items[self.player]["The Docks (E1M1) - Yellow key"] = 1
|
||||
|
||||
def create_regions(self):
|
||||
pro = self.options.pro.value
|
||||
check_sanity = self.options.check_sanity.value
|
||||
@@ -154,7 +163,7 @@ class HereticWorld(World):
|
||||
def completion_rule(self, state: CollectionState):
|
||||
goal_levels = Maps.map_names
|
||||
if self.options.goal.value:
|
||||
goal_levels = self.boss_level_for_episode
|
||||
goal_levels = self.all_boss_levels
|
||||
|
||||
for map_name in goal_levels:
|
||||
if map_name + " - Exit" not in self.location_name_to_id:
|
||||
@@ -203,7 +212,7 @@ class HereticWorld(World):
|
||||
if item["episode"] != -1 and not self.included_episodes[item["episode"] - 1]:
|
||||
continue
|
||||
|
||||
count = item["count"] if item["name"] not in self.starting_level_for_episode else item["count"] - 1
|
||||
count = item["count"] if item["name"] not in self.starting_levels else item["count"] - 1
|
||||
itempool += [self.create_item(item["name"]) for _ in range(count)]
|
||||
|
||||
# Bag(s) of Holding based on options
|
||||
@@ -236,9 +245,8 @@ class HereticWorld(World):
|
||||
self.location_count -= 1
|
||||
|
||||
# Give starting levels right away
|
||||
for i in range(len(self.included_episodes)):
|
||||
if self.included_episodes[i]:
|
||||
self.multiworld.push_precollected(self.create_item(self.starting_level_for_episode[i]))
|
||||
for map_name in self.starting_levels:
|
||||
self.multiworld.push_precollected(self.create_item(map_name))
|
||||
|
||||
# Give Computer area maps if option selected
|
||||
if self.options.start_with_map_scrolls.value:
|
||||
|
||||
0
worlds/kh2/Names/__init__.py
Normal file
0
worlds/kh2/Names/__init__.py
Normal file
@@ -1 +1 @@
|
||||
Pymem>=1.10.0
|
||||
Pymem>=1.10.0
|
||||
|
||||
0
worlds/ladx/LADXR/__init__.py
Normal file
0
worlds/ladx/LADXR/__init__.py
Normal file
0
worlds/ladx/LADXR/locations/__init__.py
Normal file
0
worlds/ladx/LADXR/locations/__init__.py
Normal file
0
worlds/ladx/LADXR/mapgen/locations/__init__.py
Normal file
0
worlds/ladx/LADXR/mapgen/locations/__init__.py
Normal file
0
worlds/ladx/LADXR/mapgen/roomtype/__init__.py
Normal file
0
worlds/ladx/LADXR/mapgen/roomtype/__init__.py
Normal file
0
worlds/ladx/LADXR/patches/__init__.py
Normal file
0
worlds/ladx/LADXR/patches/__init__.py
Normal file
@@ -310,7 +310,8 @@ class LinksAwakeningWorld(World):
|
||||
|
||||
def opens_new_regions(item):
|
||||
collection_state = base_collection_state.copy()
|
||||
collection_state.collect(item)
|
||||
collection_state.collect(item, prevent_sweep=True)
|
||||
collection_state.sweep_for_advancements(self.get_locations())
|
||||
return len(collection_state.reachable_regions[self.player]) > reachable_count
|
||||
|
||||
start_items = [item for item in itempool if is_possible_start_item(item)]
|
||||
@@ -329,7 +330,7 @@ class LinksAwakeningWorld(World):
|
||||
if entrance_mapping['start_house'] not in ['start_house', 'shop']:
|
||||
start_items = [item for item in start_items if item.name != 'Shovel']
|
||||
base_collection_state = CollectionState(self.multiworld)
|
||||
base_collection_state.update_reachable_regions(self.player)
|
||||
base_collection_state.sweep_for_advancements(self.get_locations())
|
||||
reachable_count = len(base_collection_state.reachable_regions[self.player])
|
||||
start_item = next((item for item in start_items if opens_new_regions(item)), None)
|
||||
|
||||
|
||||
0
worlds/landstalker/data/__init__.py
Normal file
0
worlds/landstalker/data/__init__.py
Normal file
@@ -100,6 +100,8 @@
|
||||
# paintings is an array of paintings in the room. This is used for painting
|
||||
# shuffling.
|
||||
# - id: The internal painting ID from the LINGO map.
|
||||
# - display_name: The name of the painting location when showed in the
|
||||
# tracker. Not needed for disabled paintings.
|
||||
# - enter_only: If true, painting shuffling will not place a warp exit on
|
||||
# this painting.
|
||||
# - exit_only: If true, painting shuffling will not place a warp entrance
|
||||
@@ -226,6 +228,7 @@
|
||||
- HIDDEN
|
||||
paintings:
|
||||
- id: arrows_painting
|
||||
display_name: Overhead Painting
|
||||
exit_only: True
|
||||
orientation: south
|
||||
- id: arrows_painting2
|
||||
@@ -234,7 +237,24 @@
|
||||
- id: arrows_painting3
|
||||
disable: True
|
||||
move: True
|
||||
- id: symmetry_painting_a_starter
|
||||
display_name: Left Near Painting
|
||||
enter_only: True
|
||||
orientation: west
|
||||
move: True
|
||||
required_door:
|
||||
room: The Wondrous (Doorknob)
|
||||
door: Painting Shortcut
|
||||
- id: eyes_yellow_painting2
|
||||
display_name: Left Far Painting
|
||||
enter_only: True
|
||||
orientation: west
|
||||
move: True
|
||||
required_door:
|
||||
room: Outside The Agreeable
|
||||
door: Painting Shortcut
|
||||
- id: garden_painting_tower2
|
||||
display_name: Front Left Painting
|
||||
enter_only: True
|
||||
orientation: north
|
||||
move: True
|
||||
@@ -242,20 +262,15 @@
|
||||
room: Hedge Maze
|
||||
door: Painting Shortcut
|
||||
- id: flower_painting_8
|
||||
display_name: Front Right Painting
|
||||
enter_only: True
|
||||
orientation: north
|
||||
move: True
|
||||
required_door:
|
||||
room: Courtyard
|
||||
door: Painting Shortcut
|
||||
- id: symmetry_painting_a_starter
|
||||
enter_only: True
|
||||
orientation: west
|
||||
move: True
|
||||
required_door:
|
||||
room: The Wondrous (Doorknob)
|
||||
door: Painting Shortcut
|
||||
- id: pencil_painting6
|
||||
display_name: Right Far Painting
|
||||
enter_only: True
|
||||
orientation: east
|
||||
move: True
|
||||
@@ -263,19 +278,13 @@
|
||||
room: Outside The Bold
|
||||
door: Painting Shortcut
|
||||
- id: blueman_painting_3
|
||||
display_name: Right Near Painting
|
||||
enter_only: True
|
||||
orientation: east
|
||||
move: True
|
||||
required_door:
|
||||
room: Outside The Undeterred
|
||||
door: Painting Shortcut
|
||||
- id: eyes_yellow_painting2
|
||||
enter_only: True
|
||||
orientation: west
|
||||
move: True
|
||||
required_door:
|
||||
room: Outside The Agreeable
|
||||
door: Painting Shortcut
|
||||
Hidden Room:
|
||||
entrances:
|
||||
Starting Room:
|
||||
@@ -340,6 +349,7 @@
|
||||
- OPEN
|
||||
paintings:
|
||||
- id: owl_painting
|
||||
display_name: Painting
|
||||
orientation: north
|
||||
The Seeker:
|
||||
entrances:
|
||||
@@ -599,6 +609,7 @@
|
||||
- OPEN
|
||||
paintings:
|
||||
- id: maze_painting
|
||||
display_name: Near Traveled Painting
|
||||
orientation: west
|
||||
sunwarps:
|
||||
- dots: 1
|
||||
@@ -630,6 +641,7 @@
|
||||
door: Eights
|
||||
paintings:
|
||||
- id: smile_painting_6
|
||||
display_name: Painting
|
||||
orientation: north
|
||||
Sunwarps:
|
||||
# This is a special, meta-ish room.
|
||||
@@ -968,6 +980,7 @@
|
||||
required_door:
|
||||
door: Eye Wall
|
||||
- id: smile_painting_4
|
||||
display_name: Near Discerning Painting
|
||||
orientation: south
|
||||
sunwarps:
|
||||
- dots: 1
|
||||
@@ -1068,6 +1081,7 @@
|
||||
tag: midwhite
|
||||
paintings:
|
||||
- id: west_afar
|
||||
display_name: Painting
|
||||
orientation: south
|
||||
The Tenacious:
|
||||
entrances:
|
||||
@@ -1392,6 +1406,7 @@
|
||||
- RIGHT
|
||||
paintings:
|
||||
- id: eyes_yellow_painting
|
||||
display_name: Near Hallway Painting
|
||||
orientation: east
|
||||
sunwarps:
|
||||
- dots: 6
|
||||
@@ -1451,6 +1466,7 @@
|
||||
- FIRE
|
||||
paintings:
|
||||
- id: pencil_painting7
|
||||
display_name: Compass Room Painting
|
||||
orientation: north
|
||||
Dread Hallway:
|
||||
entrances:
|
||||
@@ -1698,6 +1714,7 @@
|
||||
- GAZE
|
||||
paintings:
|
||||
- id: garden_painting_tower
|
||||
display_name: Painting
|
||||
orientation: north
|
||||
The Fearless (First Floor):
|
||||
entrances:
|
||||
@@ -2077,6 +2094,7 @@
|
||||
panel: A
|
||||
paintings:
|
||||
- id: crown_painting
|
||||
display_name: Near Achievement Painting
|
||||
orientation: east
|
||||
Eight Alcove:
|
||||
entrances:
|
||||
@@ -2088,6 +2106,7 @@
|
||||
door: Eight Door (Outside The Initiated)
|
||||
paintings:
|
||||
- id: eight_painting2
|
||||
display_name: Eight Alcove Painting
|
||||
orientation: north
|
||||
Eight Room:
|
||||
entrances:
|
||||
@@ -2108,6 +2127,7 @@
|
||||
tag: forbid
|
||||
paintings:
|
||||
- id: eight_painting
|
||||
display_name: Eight Room Painting
|
||||
orientation: south
|
||||
exit_only: True
|
||||
required: True
|
||||
@@ -2340,8 +2360,10 @@
|
||||
panel: YELLOW
|
||||
paintings:
|
||||
- id: arrows_painting_6
|
||||
display_name: Left Painting
|
||||
orientation: east
|
||||
- id: flower_painting_5
|
||||
display_name: Right Painting
|
||||
orientation: south
|
||||
sunwarps:
|
||||
- dots: 2
|
||||
@@ -2430,6 +2452,7 @@
|
||||
door: Eights
|
||||
paintings:
|
||||
- id: smile_painting_8
|
||||
display_name: Hot Crusts Painting
|
||||
orientation: north
|
||||
sunwarps:
|
||||
- dots: 2
|
||||
@@ -2531,10 +2554,13 @@
|
||||
- SIZE (Big)
|
||||
paintings:
|
||||
- id: hi_solved_painting3
|
||||
display_name: Cellar Replica Painting
|
||||
orientation: south
|
||||
- id: hi_solved_painting2
|
||||
display_name: Cellar Painting
|
||||
orientation: south
|
||||
- id: east_afar
|
||||
display_name: Seasons Area Painting
|
||||
orientation: north
|
||||
Orange Tower Sixth Floor:
|
||||
entrances:
|
||||
@@ -2546,25 +2572,35 @@
|
||||
painting: True
|
||||
paintings:
|
||||
- id: arrows_painting_10
|
||||
display_name: Back Left Painting
|
||||
orientation: east
|
||||
- id: owl_painting_3
|
||||
orientation: north
|
||||
- id: clock_painting
|
||||
orientation: west
|
||||
- id: scenery_painting_5d_2
|
||||
display_name: Left Near Painting
|
||||
orientation: south
|
||||
- id: symmetry_painting_b_7
|
||||
orientation: north
|
||||
- id: panda_painting_2
|
||||
display_name: Left Middle Painting
|
||||
orientation: south
|
||||
- id: crown_painting2
|
||||
orientation: north
|
||||
- id: colors_painting2
|
||||
display_name: Left Far Painting
|
||||
orientation: south
|
||||
- id: cherry_painting2
|
||||
orientation: east
|
||||
- id: hi_solved_painting
|
||||
- id: clock_painting
|
||||
display_name: Front Left Painting
|
||||
orientation: west
|
||||
- id: hi_solved_painting
|
||||
display_name: Front Right Painting
|
||||
orientation: west
|
||||
- id: crown_painting2
|
||||
display_name: Right Far Painting
|
||||
orientation: north
|
||||
- id: owl_painting_3
|
||||
display_name: Right Middle Painting
|
||||
orientation: north
|
||||
- id: symmetry_painting_b_7
|
||||
display_name: Right Near Painting
|
||||
orientation: north
|
||||
- id: cherry_painting2
|
||||
display_name: Back Right Painting
|
||||
orientation: east
|
||||
Ending Area:
|
||||
entrances:
|
||||
Orange Tower Sixth Floor:
|
||||
@@ -2660,6 +2696,7 @@
|
||||
panel: MASTERY
|
||||
paintings:
|
||||
- id: map_painting2
|
||||
display_name: Painting
|
||||
orientation: north
|
||||
enter_only: True # otherwise you might just skip the whole game!
|
||||
req_blocked_when_no_doors: True # owl hallway in vanilla doors
|
||||
@@ -2755,6 +2792,7 @@
|
||||
non_counting: True
|
||||
paintings:
|
||||
- id: arrows_painting_11
|
||||
display_name: Painting
|
||||
orientation: east
|
||||
req_blocked_when_no_doors: True # owl hallway in vanilla doors
|
||||
Courtyard:
|
||||
@@ -2817,6 +2855,7 @@
|
||||
panel: GREEN
|
||||
paintings:
|
||||
- id: flower_painting_7
|
||||
display_name: Courtyard Painting
|
||||
orientation: north
|
||||
Yellow Backside Area:
|
||||
entrances:
|
||||
@@ -2838,6 +2877,7 @@
|
||||
door: Nines
|
||||
paintings:
|
||||
- id: blueman_painting
|
||||
display_name: Near Nine Painting
|
||||
orientation: east
|
||||
First Second Third Fourth:
|
||||
# We are separating this door + its panels into its own room because they
|
||||
@@ -3173,6 +3213,7 @@
|
||||
achievement: The Colorful
|
||||
paintings:
|
||||
- id: arrows_painting_12
|
||||
display_name: Painting
|
||||
orientation: north
|
||||
progression:
|
||||
Progressive Colorful:
|
||||
@@ -3296,13 +3337,17 @@
|
||||
- STRAYS
|
||||
paintings:
|
||||
- id: arrows_painting_8
|
||||
display_name: Near Maze Painting
|
||||
orientation: south
|
||||
- id: maze_painting_2
|
||||
display_name: Maze Side Middle Painting
|
||||
orientation: north
|
||||
- id: owl_painting_2
|
||||
display_name: Orange Side Middle Painting
|
||||
orientation: south
|
||||
required_when_no_doors: True
|
||||
- id: clock_painting_4
|
||||
display_name: Near Orange Painting
|
||||
orientation: north
|
||||
Outside The Initiated:
|
||||
entrances:
|
||||
@@ -3490,8 +3535,10 @@
|
||||
- OXEN
|
||||
paintings:
|
||||
- id: clock_painting_5
|
||||
display_name: Brown Puzzles Painting
|
||||
orientation: east
|
||||
- id: smile_painting_1
|
||||
display_name: Near Eight Painting
|
||||
orientation: north
|
||||
sunwarps:
|
||||
- dots: 3
|
||||
@@ -3866,8 +3913,10 @@
|
||||
- BEGIN
|
||||
paintings:
|
||||
- id: pencil_painting2
|
||||
display_name: Near Bold Painting
|
||||
orientation: west
|
||||
- id: north_missing2
|
||||
display_name: Directions Area Painting
|
||||
orientation: north
|
||||
The Bold:
|
||||
entrances:
|
||||
@@ -4189,12 +4238,14 @@
|
||||
panel: FOUR
|
||||
paintings:
|
||||
- id: maze_painting_3
|
||||
display_name: Near Four Painting
|
||||
enter_only: True
|
||||
orientation: north
|
||||
move: True
|
||||
required_door:
|
||||
door: Green Painting
|
||||
- id: blueman_painting_2
|
||||
display_name: Near Undeterred Painting
|
||||
orientation: east
|
||||
sunwarps:
|
||||
- dots: 4
|
||||
@@ -4557,6 +4608,7 @@
|
||||
panel: NINE
|
||||
paintings:
|
||||
- id: smile_painting_5
|
||||
display_name: Near Eight Painting
|
||||
enter_only: True
|
||||
orientation: east
|
||||
required_door:
|
||||
@@ -4742,10 +4794,13 @@
|
||||
- LEARN
|
||||
paintings:
|
||||
- id: smile_painting_7
|
||||
display_name: Near Turn/Return Painting
|
||||
orientation: south
|
||||
- id: flower_painting_4
|
||||
display_name: Back Area Right Painting
|
||||
orientation: south
|
||||
- id: pencil_painting3
|
||||
display_name: Back Area Left Painting
|
||||
enter_only: True
|
||||
orientation: east
|
||||
move: True
|
||||
@@ -4753,8 +4808,10 @@
|
||||
room: Number Hunt
|
||||
door: First Six
|
||||
- id: boxes_painting
|
||||
display_name: Near Directions Painting
|
||||
orientation: south
|
||||
- id: cherry_painting
|
||||
display_name: Alcove Painting
|
||||
orientation: east
|
||||
sunwarps:
|
||||
- dots: 6
|
||||
@@ -4848,8 +4905,10 @@
|
||||
- GREEN
|
||||
paintings:
|
||||
- id: arrows_painting_7
|
||||
display_name: Near Sunwarp Painting
|
||||
orientation: east
|
||||
- id: fruitbowl_painting3
|
||||
display_name: Hidden Painting
|
||||
orientation: west
|
||||
enter_only: True
|
||||
required_door:
|
||||
@@ -4888,6 +4947,7 @@
|
||||
tag: forbid
|
||||
paintings:
|
||||
- id: colors_painting
|
||||
display_name: Painting
|
||||
orientation: south
|
||||
The Bearer:
|
||||
entrances:
|
||||
@@ -5369,6 +5429,7 @@
|
||||
panel: ANTECHAMBER
|
||||
paintings:
|
||||
- id: pencil_painting5
|
||||
display_name: Left Painting
|
||||
orientation: south
|
||||
The Steady (Lemon):
|
||||
entrances:
|
||||
@@ -5391,6 +5452,7 @@
|
||||
- MELON
|
||||
paintings:
|
||||
- id: pencil_painting4
|
||||
display_name: Right Painting
|
||||
orientation: south
|
||||
The Steady (Topaz):
|
||||
entrances:
|
||||
@@ -6012,6 +6074,7 @@
|
||||
panel: NIGHT
|
||||
paintings:
|
||||
- id: smile_painting_9
|
||||
display_name: Smiley Painting
|
||||
orientation: north
|
||||
exit_only: True
|
||||
The Artistic (Panda):
|
||||
@@ -6124,6 +6187,7 @@
|
||||
panel: BOWELS
|
||||
paintings:
|
||||
- id: panda_painting_3
|
||||
display_name: Panda Painting
|
||||
exit_only: True
|
||||
orientation: south
|
||||
required_when_no_doors: True
|
||||
@@ -6235,6 +6299,7 @@
|
||||
panel: THING
|
||||
paintings:
|
||||
- id: boxes_painting2
|
||||
display_name: Lattice Painting
|
||||
orientation: south
|
||||
exit_only: True
|
||||
required_when_no_doors: True
|
||||
@@ -6344,6 +6409,7 @@
|
||||
panel: ROOT
|
||||
paintings:
|
||||
- id: cherry_painting3
|
||||
display_name: Apple Painting
|
||||
orientation: north
|
||||
exit_only: True
|
||||
required_when_no_doors: True
|
||||
@@ -6490,8 +6556,10 @@
|
||||
- NEAR
|
||||
paintings:
|
||||
- id: eye_painting_2
|
||||
display_name: Near Pillar Painting
|
||||
orientation: west
|
||||
- id: smile_painting_2
|
||||
display_name: Near Window Painting
|
||||
orientation: north
|
||||
Far Window:
|
||||
entrances:
|
||||
@@ -6512,6 +6580,7 @@
|
||||
door: Exit
|
||||
paintings:
|
||||
- id: arrows_painting_5
|
||||
display_name: Lobby Painting
|
||||
orientation: east
|
||||
Outside The Wondrous:
|
||||
entrances:
|
||||
@@ -6562,9 +6631,11 @@
|
||||
panel: SHRINK
|
||||
paintings:
|
||||
- id: symmetry_painting_a_1
|
||||
display_name: Doorknob Upper Painting
|
||||
orientation: east
|
||||
exit_only: True
|
||||
- id: symmetry_painting_b_1
|
||||
display_name: Doorknob Lower Painting
|
||||
orientation: south
|
||||
The Wondrous (Bookcase):
|
||||
entrances:
|
||||
@@ -6576,6 +6647,7 @@
|
||||
tag: midblue
|
||||
paintings:
|
||||
- id: symmetry_painting_a_3
|
||||
display_name: Bookcase Painting
|
||||
orientation: west
|
||||
exit_only: True
|
||||
- id: symmetry_painting_b_3
|
||||
@@ -6590,6 +6662,7 @@
|
||||
tag: midyellow
|
||||
paintings:
|
||||
- id: symmetry_painting_a_5
|
||||
display_name: Chandelier Painting
|
||||
orientation: east
|
||||
- id: symmetry_painting_b_5
|
||||
disable: True
|
||||
@@ -6603,6 +6676,7 @@
|
||||
tag: botbrown
|
||||
paintings:
|
||||
- id: symmetry_painting_b_4
|
||||
display_name: Window Painting
|
||||
orientation: north
|
||||
exit_only: True
|
||||
- id: symmetry_painting_a_4
|
||||
@@ -6627,8 +6701,10 @@
|
||||
tag: midyellow
|
||||
paintings:
|
||||
- id: symmetry_painting_a_2
|
||||
display_name: Table Lower Painting
|
||||
orientation: west
|
||||
- id: symmetry_painting_b_2
|
||||
display_name: Table Upper Painting
|
||||
orientation: south
|
||||
exit_only: True
|
||||
required: True
|
||||
@@ -6669,6 +6745,7 @@
|
||||
- Achievement
|
||||
paintings:
|
||||
- id: arrows_painting_9
|
||||
display_name: Exit Painting
|
||||
enter_only: True
|
||||
orientation: south
|
||||
move: True
|
||||
@@ -6676,9 +6753,11 @@
|
||||
door: Exit
|
||||
req_blocked_when_no_doors: True # the wondrous (table) in vanilla doors
|
||||
- id: symmetry_painting_a_6
|
||||
display_name: Fireplace Upper Painting
|
||||
orientation: west
|
||||
exit_only: True
|
||||
- id: symmetry_painting_b_6
|
||||
display_name: Fireplace Lower Painting
|
||||
orientation: north
|
||||
req_blocked_when_no_doors: True # the wondrous (table) in vanilla doors
|
||||
Arrow Garden:
|
||||
@@ -6700,6 +6779,7 @@
|
||||
tag: midwhite
|
||||
paintings:
|
||||
- id: flower_painting_6
|
||||
display_name: Painting
|
||||
orientation: south
|
||||
Hallway Room (1):
|
||||
entrances:
|
||||
@@ -6758,6 +6838,7 @@
|
||||
- TOWER
|
||||
paintings:
|
||||
- id: panda_painting
|
||||
display_name: Painting
|
||||
orientation: south
|
||||
progression:
|
||||
Progressive Hallway Room:
|
||||
@@ -6945,6 +7026,7 @@
|
||||
tag: midwhite
|
||||
paintings:
|
||||
- id: south_afar
|
||||
display_name: Painting
|
||||
orientation: south
|
||||
Outside The Wanderer:
|
||||
entrances:
|
||||
@@ -7123,16 +7205,21 @@
|
||||
panels:
|
||||
- ORDER
|
||||
paintings:
|
||||
- id: smile_painting_3
|
||||
orientation: west
|
||||
- id: flower_painting_2
|
||||
display_name: Left Near Painting
|
||||
orientation: east
|
||||
- id: scenery_painting_0a
|
||||
orientation: north
|
||||
- id: map_painting
|
||||
display_name: Left Far Painting
|
||||
orientation: east
|
||||
- id: fruitbowl_painting4
|
||||
display_name: Center Front Painting
|
||||
orientation: south
|
||||
- id: scenery_painting_0a
|
||||
display_name: Center Back Painting
|
||||
orientation: north
|
||||
- id: smile_painting_3
|
||||
display_name: Right Far Painting
|
||||
orientation: west
|
||||
progression:
|
||||
Progressive Art Gallery:
|
||||
doors:
|
||||
@@ -7493,6 +7580,7 @@
|
||||
panel: WORD
|
||||
paintings:
|
||||
- id: arrows_painting_3
|
||||
display_name: Circle Painting
|
||||
orientation: north
|
||||
Rhyme Room (Looped Square):
|
||||
entrances:
|
||||
@@ -7675,6 +7763,7 @@
|
||||
- INNOVATIVE (Bottom)
|
||||
paintings:
|
||||
- id: arrows_painting_4
|
||||
display_name: Target Painting
|
||||
orientation: north
|
||||
Room Room:
|
||||
# This is a bit of a weird room. You can't really get to it from the roof.
|
||||
@@ -7944,8 +8033,10 @@
|
||||
- CAT
|
||||
paintings:
|
||||
- id: arrows_painting_2
|
||||
display_name: Left Painting
|
||||
orientation: east
|
||||
- id: clock_painting_2
|
||||
display_name: Right Painting
|
||||
orientation: east
|
||||
exit_only: True
|
||||
required: True
|
||||
@@ -8022,6 +8113,7 @@
|
||||
tag: midbrown
|
||||
paintings:
|
||||
- id: clock_painting_3
|
||||
display_name: Painting
|
||||
orientation: east
|
||||
req_blocked: True # outside the wise (with or without door shuffle)
|
||||
The Red:
|
||||
@@ -8492,6 +8584,7 @@
|
||||
- OPTICS
|
||||
paintings:
|
||||
- id: hi_solved_painting4
|
||||
display_name: Painting
|
||||
orientation: south
|
||||
req_blocked_when_no_doors: True # owl hallway in vanilla doors
|
||||
Challenge Room:
|
||||
|
||||
Binary file not shown.
@@ -50,7 +50,7 @@ directives = Set["entrances", "panels", "doors", "panel_doors", "paintings", "su
|
||||
panel_directives = Set["id", "required_room", "required_door", "required_panel", "colors", "check", "exclude_reduce", "tag", "link", "subtag", "achievement", "copy_to_sign", "non_counting", "hunt", "location_name"]
|
||||
door_directives = Set["id", "painting_id", "panels", "item_name", "item_group", "location_name", "skip_location", "skip_item", "door_group", "include_reduce", "event", "warp_id"]
|
||||
panel_door_directives = Set["panels", "item_name", "panel_group"]
|
||||
painting_directives = Set["id", "enter_only", "exit_only", "orientation", "required_door", "required", "required_when_no_doors", "move", "req_blocked", "req_blocked_when_no_doors"]
|
||||
painting_directives = Set["id", "display_name", "enter_only", "exit_only", "orientation", "required_door", "required", "required_when_no_doors", "move", "req_blocked", "req_blocked_when_no_doors"]
|
||||
|
||||
non_counting = 0
|
||||
|
||||
@@ -314,6 +314,10 @@ config.each do |room_name, room|
|
||||
next
|
||||
end
|
||||
|
||||
unless painting.include? "display_name" then
|
||||
puts "#{room_name} - #{painting["id"] || "painting"} :::: Missing display name"
|
||||
end
|
||||
|
||||
if painting.include?("orientation") then
|
||||
unless ["north", "south", "east", "west"].include? painting["orientation"] then
|
||||
puts "#{room_name} - #{painting["id"] || "painting"} :::: Invalid orientation #{painting["orientation"]}"
|
||||
|
||||
@@ -1 +1 @@
|
||||
requests >= 2.28.1 # used by client
|
||||
requests >= 2.28.1 # used by client
|
||||
|
||||
0
worlds/mlss/Names/__init__.py
Normal file
0
worlds/mlss/Names/__init__.py
Normal file
Binary file not shown.
0
worlds/mmbn3/Names/__init__.py
Normal file
0
worlds/mmbn3/Names/__init__.py
Normal file
@@ -52,11 +52,13 @@ class MuseDashCollections:
|
||||
"Nyaa SFX Trap": STARTING_CODE + 8,
|
||||
"Error SFX Trap": STARTING_CODE + 9,
|
||||
"Focus Line Trap": STARTING_CODE + 10,
|
||||
"Beefcake SFX Trap": STARTING_CODE + 11,
|
||||
}
|
||||
|
||||
sfx_trap_items: List[str] = [
|
||||
"Nyaa SFX Trap",
|
||||
"Error SFX Trap",
|
||||
"Beefcake SFX Trap",
|
||||
]
|
||||
|
||||
filler_items: Dict[str, int] = {
|
||||
|
||||
@@ -627,4 +627,10 @@ SONG_DATA: Dict[str, SongData] = {
|
||||
"Sharp Bubbles": SongData(2900751, "83-3", "Cosmic Radio 2024", True, 7, 9, 11),
|
||||
"Replay": SongData(2900752, "83-4", "Cosmic Radio 2024", True, 5, 7, 9),
|
||||
"Cosmic Dusty Girl": SongData(2900753, "83-5", "Cosmic Radio 2024", True, 5, 7, 9),
|
||||
"Meow Rock feat. Chun Ge, Yuan Shen": SongData(2900754, "84-0", "Muse Dash Legend", True, None, None, None),
|
||||
"Even if you make an old radio song with AI": SongData(2900755, "84-1", "Muse Dash Legend", False, 3, 6, 8),
|
||||
"Unusual Sketchbook": SongData(2900756, "84-2", "Muse Dash Legend", True, 6, 8, 11),
|
||||
"TransientTears": SongData(2900757, "84-3", "Muse Dash Legend", True, 6, 8, 11),
|
||||
"SHOOTING*STAR": SongData(2900758, "84-4", "Muse Dash Legend", False, 5, 7, 9),
|
||||
"But the Blue Bird is Already Dead": SongData(2900759, "84-5", "Muse Dash Legend", False, 6, 8, 10),
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
2. Choose the automated tab, click the select button and browse to `MuseDash.exe`.
|
||||
- You can find the folder in steam by finding the game in your library, right clicking it and choosing *Manage→Browse Local Files*.
|
||||
- If you click the bar at the top telling you your current folder, this will give you a path you can copy. If you paste that into the window popped up by **MelonLoader**, it will automatically go to the same folder.
|
||||
3. Uncheck "Latest" and select v0.6.1. Then click install.
|
||||
3. Select v0.7.0. Then click install.
|
||||
4. Run the game once, and wait until you get to the Muse Dash start screen before exiting.
|
||||
5. Download the latest [Muse Dash Archipelago Mod](https://github.com/DeamonHunter/ArchipelagoMuseDash/releases/latest) and then extract that into the newly created `/Mods/` folder in MuseDash's install location.
|
||||
- All files must be under the `/Mods/` folder and not within a sub folder inside of `/Mods/`
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
2. Elije la pestaña "automated", haz clic en el botón "select" y busca tu `MuseDash.exe`.
|
||||
- Puedes encontrar la carpeta en Steam buscando el juego en tu biblioteca, haciendo clic derecho sobre el y elegir *Administrar→Ver archivos locales*.
|
||||
- Si haces clic en la barra superior que te indica la carpeta en la que estas, te dará la dirección de ésta para que puedas copiarla. Al pegar esa dirección en la ventana que **MelonLoader** abre, irá automaticamente a esa carpeta.
|
||||
3. Desmarca "Latest" y selecciona v0.6.1. Luego haz clic en "install".
|
||||
3. Selecciona v0.7.0. Luego haz clic en "install".
|
||||
4. Ejecuta el juego una vez, y espera hasta que aparezca la pantalla de inicio de Muse Dash antes de cerrarlo.
|
||||
5. Descarga la última version de [Muse Dash Archipelago Mod](https://github.com/DeamonHunter/ArchipelagoMuseDash/releases/latest) y extraelo en la nueva carpeta creada llamada `/Mods/`, localizada en la carpeta de instalación de Muse Dash.
|
||||
- Todos los archivos deben ir directamente en la carpeta `/Mods/`, y NO en una subcarpeta dentro de la carpeta `/Mods/`
|
||||
|
||||
@@ -130,6 +130,7 @@ class OOTWeb(WebWorld):
|
||||
|
||||
tutorials = [setup, setup_fr, setup_de]
|
||||
option_groups = oot_option_groups
|
||||
game_info_languages = ["en", "de"]
|
||||
|
||||
|
||||
class OOTWorld(World):
|
||||
|
||||
0
worlds/osrs/LogicCSV/__init__.py
Normal file
0
worlds/osrs/LogicCSV/__init__.py
Normal file
@@ -1,3 +1,11 @@
|
||||
# 2.4.1
|
||||
|
||||
### Fixes
|
||||
|
||||
- Fixed handling of shuffle option for badges/HMs in the case that the player sets those items to nonlocal or uses
|
||||
plando to put an item in one of those locations, or in the case that fill gets itself stuck on these items and has to
|
||||
retry.
|
||||
|
||||
# 2.4.0
|
||||
|
||||
### Features
|
||||
|
||||
@@ -8,7 +8,7 @@ import os
|
||||
import pkgutil
|
||||
from typing import Any, Set, List, Dict, Optional, Tuple, ClassVar, TextIO, Union
|
||||
|
||||
from BaseClasses import ItemClassification, MultiWorld, Tutorial, LocationProgressType
|
||||
from BaseClasses import CollectionState, ItemClassification, MultiWorld, Tutorial, LocationProgressType
|
||||
from Fill import FillError, fill_restrictive
|
||||
from Options import OptionError, Toggle
|
||||
import settings
|
||||
@@ -100,6 +100,7 @@ class PokemonEmeraldWorld(World):
|
||||
|
||||
required_client_version = (0, 4, 6)
|
||||
|
||||
item_pool: List[PokemonEmeraldItem]
|
||||
badge_shuffle_info: Optional[List[Tuple[PokemonEmeraldLocation, PokemonEmeraldItem]]]
|
||||
hm_shuffle_info: Optional[List[Tuple[PokemonEmeraldLocation, PokemonEmeraldItem]]]
|
||||
free_fly_location_id: int
|
||||
@@ -185,7 +186,7 @@ class PokemonEmeraldWorld(World):
|
||||
|
||||
# In race mode we don't patch any item location information into the ROM
|
||||
if self.multiworld.is_race and not self.options.remote_items:
|
||||
logging.warning("Pokemon Emerald: Forcing Player %s (%s) to use remote items due to race mode.",
|
||||
logging.warning("Pokemon Emerald: Forcing player %s (%s) to use remote items due to race mode.",
|
||||
self.player, self.player_name)
|
||||
self.options.remote_items.value = Toggle.option_true
|
||||
|
||||
@@ -197,7 +198,7 @@ class PokemonEmeraldWorld(World):
|
||||
|
||||
# Prevent setting the number of required legendaries higher than the number of enabled legendaries
|
||||
if self.options.legendary_hunt_count.value > len(self.options.allowed_legendary_hunt_encounters.value):
|
||||
logging.warning("Pokemon Emerald: Legendary hunt count for Player %s (%s) higher than number of allowed "
|
||||
logging.warning("Pokemon Emerald: Legendary hunt count for player %s (%s) higher than number of allowed "
|
||||
"legendary encounters. Reducing to number of allowed encounters.", self.player,
|
||||
self.player_name)
|
||||
self.options.legendary_hunt_count.value = len(self.options.allowed_legendary_hunt_encounters.value)
|
||||
@@ -234,10 +235,17 @@ class PokemonEmeraldWorld(World):
|
||||
max_norman_count = 4
|
||||
|
||||
if self.options.norman_count.value > max_norman_count:
|
||||
logging.warning("Pokemon Emerald: Norman requirements for Player %s (%s) are unsafe in combination with "
|
||||
logging.warning("Pokemon Emerald: Norman requirements for player %s (%s) are unsafe in combination with "
|
||||
"other settings. Reducing to 4.", self.player, self.player_name)
|
||||
self.options.norman_count.value = max_norman_count
|
||||
|
||||
# Shuffled badges/hms will always be placed locally, so add them to local_items
|
||||
if self.options.badges == RandomizeBadges.option_shuffle:
|
||||
self.options.local_items.value.update(self.item_name_groups["Badge"])
|
||||
|
||||
if self.options.hms == RandomizeHms.option_shuffle:
|
||||
self.options.local_items.value.update(self.item_name_groups["HM"])
|
||||
|
||||
def create_regions(self) -> None:
|
||||
from .regions import create_regions
|
||||
all_regions = create_regions(self)
|
||||
@@ -377,12 +385,11 @@ class PokemonEmeraldWorld(World):
|
||||
item_locations = [location for location in item_locations if emerald_data.locations[location.key].category not in filter_categories]
|
||||
default_itempool = [self.create_item_by_code(location.default_item_code) for location in item_locations]
|
||||
|
||||
# Take the itempool as-is
|
||||
if self.options.item_pool_type == ItemPoolType.option_shuffled:
|
||||
self.multiworld.itempool += default_itempool
|
||||
|
||||
# Recreate the itempool from random items
|
||||
# Take the itempool as-is
|
||||
self.item_pool = default_itempool
|
||||
elif self.options.item_pool_type in (ItemPoolType.option_diverse, ItemPoolType.option_diverse_balanced):
|
||||
# Recreate the itempool from random items
|
||||
item_categories = ["Ball", "Healing", "Rare Candy", "Vitamin", "Evolution Stone",
|
||||
"Money", "TM", "Held", "Misc", "Berry"]
|
||||
|
||||
@@ -392,6 +399,7 @@ class PokemonEmeraldWorld(World):
|
||||
if not item.advancement:
|
||||
item_category_counter.update([tag for tag in item.tags if tag in item_categories])
|
||||
|
||||
self.item_pool = []
|
||||
item_category_weights = [item_category_counter.get(category) for category in item_categories]
|
||||
item_category_weights = [weight if weight is not None else 0 for weight in item_category_weights]
|
||||
|
||||
@@ -436,19 +444,10 @@ class PokemonEmeraldWorld(World):
|
||||
item_code = self.random.choice(fill_item_candidates_by_category[category])
|
||||
item = self.create_item_by_code(item_code)
|
||||
|
||||
self.multiworld.itempool.append(item)
|
||||
self.item_pool.append(item)
|
||||
|
||||
def set_rules(self) -> None:
|
||||
from .rules import set_rules
|
||||
set_rules(self)
|
||||
self.multiworld.itempool += self.item_pool
|
||||
|
||||
def generate_basic(self) -> None:
|
||||
# Create auth
|
||||
# self.auth = self.random.randbytes(16) # Requires >=3.9
|
||||
self.auth = self.random.getrandbits(16 * 8).to_bytes(16, "little")
|
||||
|
||||
randomize_types(self)
|
||||
randomize_wild_encounters(self)
|
||||
set_free_fly(self)
|
||||
set_legendary_cave_entrances(self)
|
||||
|
||||
@@ -475,9 +474,20 @@ class PokemonEmeraldWorld(World):
|
||||
if not self.options.key_items:
|
||||
convert_unrandomized_items_to_events(LocationCategory.KEY)
|
||||
|
||||
def pre_fill(self) -> None:
|
||||
# Badges and HMs that are set to shuffle need to be placed at
|
||||
# their own subset of locations
|
||||
def set_rules(self):
|
||||
from .rules import set_rules
|
||||
set_rules(self)
|
||||
|
||||
def connect_entrances(self):
|
||||
randomize_wild_encounters(self)
|
||||
self.shuffle_badges_hms()
|
||||
# For entrance randomization, disconnect entrances here, randomize map, then
|
||||
# undo badge/HM placement and re-shuffle them in the new map.
|
||||
|
||||
def shuffle_badges_hms(self) -> None:
|
||||
my_progression_items = [item for item in self.item_pool if item.advancement]
|
||||
my_locations = list(self.get_locations())
|
||||
|
||||
if self.options.badges == RandomizeBadges.option_shuffle:
|
||||
badge_locations: List[PokemonEmeraldLocation]
|
||||
badge_items: List[PokemonEmeraldItem]
|
||||
@@ -502,41 +512,20 @@ class PokemonEmeraldWorld(World):
|
||||
badge_priority["Knuckle Badge"] = 0
|
||||
badge_items.sort(key=lambda item: badge_priority.get(item.name, 0))
|
||||
|
||||
# Un-exclude badge locations, since we need to put progression items on them
|
||||
for location in badge_locations:
|
||||
location.progress_type = LocationProgressType.DEFAULT \
|
||||
if location.progress_type == LocationProgressType.EXCLUDED \
|
||||
else location.progress_type
|
||||
|
||||
collection_state = self.multiworld.get_all_state(False)
|
||||
|
||||
# If HM shuffle is on, HMs are not placed and not in the pool, so
|
||||
# `get_all_state` did not contain them. Collect them manually for
|
||||
# this fill. We know that they will be included in all state after
|
||||
# this stage.
|
||||
# Build state
|
||||
state = CollectionState(self.multiworld)
|
||||
for item in my_progression_items:
|
||||
state.collect(item, True)
|
||||
# If HM shuffle is on, HMs are neither placed in locations nor in
|
||||
# the item pool, so we also need to collect them.
|
||||
if self.hm_shuffle_info is not None:
|
||||
for _, item in self.hm_shuffle_info:
|
||||
collection_state.collect(item)
|
||||
state.collect(item, True)
|
||||
state.sweep_for_advancements(my_locations)
|
||||
|
||||
# In specific very constrained conditions, fill_restrictive may run
|
||||
# out of swaps before it finds a valid solution if it gets unlucky.
|
||||
# This is a band-aid until fill/swap can reliably find those solutions.
|
||||
attempts_remaining = 2
|
||||
while attempts_remaining > 0:
|
||||
attempts_remaining -= 1
|
||||
self.random.shuffle(badge_locations)
|
||||
try:
|
||||
fill_restrictive(self.multiworld, collection_state, badge_locations, badge_items,
|
||||
single_player_placement=True, lock=True, allow_excluded=True)
|
||||
break
|
||||
except FillError as exc:
|
||||
if attempts_remaining == 0:
|
||||
raise exc
|
||||
# Shuffle badges
|
||||
self.fill_subset_with_retries(badge_items, badge_locations, state)
|
||||
|
||||
logging.debug(f"Failed to shuffle badges for player {self.player}. Retrying.")
|
||||
continue
|
||||
|
||||
# Badges are guaranteed to be either placed or in the multiworld's itempool now
|
||||
if self.options.hms == RandomizeHms.option_shuffle:
|
||||
hm_locations: List[PokemonEmeraldLocation]
|
||||
hm_items: List[PokemonEmeraldItem]
|
||||
@@ -559,33 +548,56 @@ class PokemonEmeraldWorld(World):
|
||||
if self.options.badges == RandomizeBadges.option_vanilla and \
|
||||
self.options.require_flash in (DarkCavesRequireFlash.option_both, DarkCavesRequireFlash.option_only_granite_cave):
|
||||
hm_priority["HM05 Flash"] = 0
|
||||
hm_items.sort(key=lambda item: hm_priority.get(item.name, 0))
|
||||
hm_items.sort(key=lambda item: hm_priority.get(item.name, 0), reverse=True)
|
||||
|
||||
# Un-exclude HM locations, since we need to put progression items on them
|
||||
for location in hm_locations:
|
||||
location.progress_type = LocationProgressType.DEFAULT \
|
||||
if location.progress_type == LocationProgressType.EXCLUDED \
|
||||
else location.progress_type
|
||||
# Build state
|
||||
# Badges are either in the item pool, or already placed and collected during sweep
|
||||
state = CollectionState(self.multiworld)
|
||||
for item in my_progression_items:
|
||||
state.collect(item, True)
|
||||
state.sweep_for_advancements(my_locations)
|
||||
|
||||
collection_state = self.multiworld.get_all_state(False)
|
||||
# Shuffle HMs
|
||||
self.fill_subset_with_retries(hm_items, hm_locations, state)
|
||||
|
||||
# In specific very constrained conditions, fill_restrictive may run
|
||||
# out of swaps before it finds a valid solution if it gets unlucky.
|
||||
# This is a band-aid until fill/swap can reliably find those solutions.
|
||||
attempts_remaining = 2
|
||||
while attempts_remaining > 0:
|
||||
attempts_remaining -= 1
|
||||
self.random.shuffle(hm_locations)
|
||||
try:
|
||||
fill_restrictive(self.multiworld, collection_state, hm_locations, hm_items,
|
||||
single_player_placement=True, lock=True, allow_excluded=True)
|
||||
break
|
||||
except FillError as exc:
|
||||
if attempts_remaining == 0:
|
||||
raise exc
|
||||
def fill_subset_with_retries(self, items: list[PokemonEmeraldItem], locations: list[PokemonEmeraldLocation], state: CollectionState):
|
||||
# Un-exclude locations, since we need to put progression items on them
|
||||
for location in locations:
|
||||
location.progress_type = LocationProgressType.DEFAULT \
|
||||
if location.progress_type == LocationProgressType.EXCLUDED \
|
||||
else location.progress_type
|
||||
|
||||
logging.debug(f"Failed to shuffle HMs for player {self.player}. Retrying.")
|
||||
continue
|
||||
# In specific very constrained conditions, `fill_restrictive` may run
|
||||
# out of swaps before it finds a valid solution if it gets unlucky.
|
||||
attempts_remaining = 2
|
||||
while attempts_remaining > 0:
|
||||
attempts_remaining -= 1
|
||||
locations_copy = locations.copy()
|
||||
items_copy = items.copy()
|
||||
self.random.shuffle(locations_copy)
|
||||
try:
|
||||
fill_restrictive(self.multiworld, state, locations_copy, items_copy, single_player_placement=True,
|
||||
lock=True)
|
||||
break
|
||||
except FillError as exc:
|
||||
if attempts_remaining <= 0:
|
||||
raise exc
|
||||
|
||||
# Undo partial item placement
|
||||
for location in locations:
|
||||
location.locked = False
|
||||
if location.item is not None:
|
||||
location.item.location = None
|
||||
location.item = None
|
||||
|
||||
logging.debug(f"Failed to shuffle items for player {self.player} ({self.player_name}). Retrying.")
|
||||
continue
|
||||
|
||||
def generate_basic(self) -> None:
|
||||
# Create auth
|
||||
self.auth = self.random.randbytes(16)
|
||||
|
||||
randomize_types(self)
|
||||
|
||||
def generate_output(self, output_directory: str) -> None:
|
||||
self.modified_trainers = copy.deepcopy(emerald_data.trainers)
|
||||
|
||||
@@ -2414,6 +2414,7 @@ def door_shuffle(world, multiworld, player, badges, badge_locs):
|
||||
loc.place_locked_item(badge)
|
||||
|
||||
state = multiworld.state.copy()
|
||||
state.allow_partial_entrances = True
|
||||
for item, data in item_table.items():
|
||||
if (data.id or item in poke_data.pokemon_data) and data.classification == ItemClassification.progression \
|
||||
and ("Badge" not in item or world.options.badgesanity):
|
||||
|
||||
@@ -150,6 +150,26 @@ sample_chao_names = [
|
||||
"Hubert",
|
||||
"Corvus",
|
||||
"Nigel",
|
||||
"Benjamin",
|
||||
"Gooey",
|
||||
"Maddy",
|
||||
"AFGNCAAP",
|
||||
"Reinhardt",
|
||||
"Claire",
|
||||
"Yoshi",
|
||||
"Peasley",
|
||||
"Faux",
|
||||
"Naija",
|
||||
"Kaiba",
|
||||
"Hat Kid",
|
||||
"TzTokJad",
|
||||
"Sora",
|
||||
"WoodMan",
|
||||
"Yachty",
|
||||
"Grieve",
|
||||
"Portia",
|
||||
"Graves",
|
||||
"Kaycee",
|
||||
]
|
||||
|
||||
totally_real_item_names = [
|
||||
@@ -240,6 +260,35 @@ totally_real_item_names = [
|
||||
"Ladder",
|
||||
|
||||
"Visible Dots",
|
||||
|
||||
"CooCoo",
|
||||
|
||||
"Blueberry",
|
||||
|
||||
"Ear of Luigi",
|
||||
|
||||
"Mega Nut",
|
||||
|
||||
"DUELIST ALLIANCE",
|
||||
"DUEL OVERLOAD",
|
||||
"POWER OF THE ELEMENTS",
|
||||
"S:P Little Knight",
|
||||
"Red-Eyes Dark Dragoon",
|
||||
|
||||
"Fire Hat",
|
||||
|
||||
"Area: Taverly",
|
||||
"Area: Meiyerditch",
|
||||
"Fire Cape",
|
||||
|
||||
"Donald Zeta Flare",
|
||||
|
||||
"Category One of a Kind",
|
||||
"Category Fuller House",
|
||||
|
||||
"Passive Camoflage",
|
||||
|
||||
"Earth Card",
|
||||
]
|
||||
|
||||
all_exits = [
|
||||
|
||||
@@ -1,6 +1,84 @@
|
||||
# Sonic Adventure 2 Battle - Changelog
|
||||
|
||||
|
||||
## v2.4 - Minigame Madness
|
||||
|
||||
### Features:
|
||||
- New Goal
|
||||
- Minigame Madness
|
||||
- Win a certain number of each type of Minigame Trap, then defeat the Finalhazard to win!
|
||||
- How many of each Minigame are required can be set by an Option
|
||||
- When the required amount of a Minigame has been received, that Minigame can be replayed in the Chao World Lobby
|
||||
- New optional Location Checks
|
||||
- Bigsanity
|
||||
- Go fishing with Big in each stage for a Location Check
|
||||
- Itemboxsanity
|
||||
- Either Extra Life Boxes or All Item Boxes
|
||||
- New Items
|
||||
- New Traps
|
||||
- Literature Trap
|
||||
- Controller Drift Trap
|
||||
- Poison Trap
|
||||
- Bee Trap
|
||||
- New Minigame Traps
|
||||
- Breakout Trap
|
||||
- Fishing Trap
|
||||
- Trivia Trap
|
||||
- Pokemon Trivia Trap
|
||||
- Pokemon Count Trap
|
||||
- Number Sequence Trap
|
||||
- Light Up Path Trap
|
||||
- Pinball Trap
|
||||
- Math Quiz Trap
|
||||
- Snake Trap
|
||||
- Input Sequence Trap
|
||||
- Trap Link
|
||||
- When you receive a trap, you send a copy of it to every other player with Trap Link enabled
|
||||
- Boss Gate Plando
|
||||
- Expert Logic Difficulty
|
||||
- Use at your own risk. This difficulty requires complete mastery of SA2.
|
||||
- Missions can now be enabled and disabled per-character, instead of just per-style
|
||||
- Minigame Difficulty can now be set to "Chaos", which selects a new difficulty randomly per-trap received
|
||||
|
||||
### Quality of Life:
|
||||
- Gate Stages and Mission Orders are now displayed in the spoiler log
|
||||
- Additional play stats are saved and displayed with the randomizer credits
|
||||
- Stage Locations progress UI now displays in multiple pages when Itemboxsanity is enabled
|
||||
- Current stage mission order and progress are now shown when paused in-level
|
||||
- Chaos Emeralds are now shown when paused in-level
|
||||
- Location Name Groups were created
|
||||
- Moved SA2B to the new Options system
|
||||
- Option Presets were created
|
||||
- Error Messages are more obvious
|
||||
|
||||
### Bug Fixes:
|
||||
- Added missing `Dry Lagoon - 12 Animals` location
|
||||
- Flying Dog boss should no longer crash when you have done at least 3 Intermediate Kart Races
|
||||
- Invincibility can no longer be received in the King Boom Boo fight, preventing a crash
|
||||
- Chaos Emeralds should no longer disproportionately end up in Cannon's Core or the final Level Gate
|
||||
- Going into submenus from the pause menu should no longer reset traps
|
||||
- `Sonic - Magic Gloves` are now plural
|
||||
- Junk items will no longer cause a crash when in a falling state
|
||||
- Saves should no longer incorrectly be marked as not matching the connected server
|
||||
- Fixed miscellaneous crashes
|
||||
- Chao Garden:
|
||||
- Prevent races from occasionally becoming uncompletable when using the "Prize Only" option
|
||||
- Properly allow Hero Chao to participate in Dark Races
|
||||
- Don't allow the Chao Garden to send locations when connected to an invalid server
|
||||
- Prevent the Chao Garden from resetting your life count
|
||||
- Fix Chao World Entrance Shuffle causing inaccessible Neutral Garden
|
||||
- Fix pressing the 'B' button to take you to the proper location in Chao World Entrance Shuffle
|
||||
- Prevent Chao Karate progress icon overflow
|
||||
- Prevent changing Chao Timescale while paused or while a Minigame is active
|
||||
- Logic Fixes:
|
||||
- `Mission Street - Chao Key 1` (Hard Logic) now requires no upgrades
|
||||
- `Mission Street - Chao Key 2` (Hard Logic) now requires no upgrades
|
||||
- `Crazy Gadget - Hidden 1` (Standard Logic) now requires `Sonic - Bounce Bracelet` instead of `Sonic - Light Shoes`
|
||||
- `Lost Colony - Hidden 1` (Standard Logic) now requires `Eggman - Jet Engine`
|
||||
- `Mad Space - Gold Beetle` (Standard Logic) now only requires `Rouge - Iron Boots`
|
||||
- `Cosmic Wall - Gold Beetle` (Standard and Hard Logic) now only requires `Eggman - Jet Engine`
|
||||
|
||||
|
||||
## v2.3 - The Chao Update
|
||||
|
||||
### Features:
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
import typing
|
||||
|
||||
from BaseClasses import MultiWorld
|
||||
from worlds.AutoWorld import World
|
||||
|
||||
speed_characters_1 = "Sonic vs Shadow 1"
|
||||
speed_characters_2 = "Sonic vs Shadow 2"
|
||||
mech_characters_1 = "Tails vs Eggman 1"
|
||||
mech_characters_2 = "Tails vs Eggman 2"
|
||||
hunt_characters_1 = "Knuckles vs Rouge 1"
|
||||
big_foot = "F-6t BIG FOOT"
|
||||
hot_shot = "B-3x HOT SHOT"
|
||||
flying_dog = "R-1/A FLYING DOG"
|
||||
egg_golem_sonic = "Egg Golem (Sonic)"
|
||||
egg_golem_eggman = "Egg Golem (Eggman)"
|
||||
king_boom_boo = "King Boom Boo"
|
||||
from .Names import LocationName
|
||||
from .Options import GateBossPlando
|
||||
|
||||
|
||||
speed_characters_1 = "sonic vs shadow 1"
|
||||
speed_characters_2 = "sonic vs shadow 2"
|
||||
mech_characters_1 = "tails vs eggman 1"
|
||||
mech_characters_2 = "tails vs eggman 2"
|
||||
hunt_characters_1 = "knuckles vs rouge 1"
|
||||
big_foot = "big foot"
|
||||
hot_shot = "hot shot"
|
||||
flying_dog = "flying dog"
|
||||
egg_golem_sonic = "egg golem (sonic)"
|
||||
egg_golem_eggman = "egg golem (eggman)"
|
||||
king_boom_boo = "king boom boo"
|
||||
|
||||
gate_bosses_no_requirements_table = {
|
||||
speed_characters_1: 0,
|
||||
@@ -45,44 +50,83 @@ all_gate_bosses_table = {
|
||||
}
|
||||
|
||||
|
||||
boss_id_to_name = {
|
||||
0: "Sonic vs Shadow 1",
|
||||
1: "Sonic vs Shadow 2",
|
||||
2: "Tails vs Eggman 1",
|
||||
3: "Tails vs Eggman 2",
|
||||
4: "Knuckles vs Rouge 1",
|
||||
5: "F-6t BIG FOOT",
|
||||
6: "B-3x HOT SHOT",
|
||||
7: "R-1/A FLYING DOG",
|
||||
8: "Egg Golem (Sonic)",
|
||||
9: "Egg Golem (Eggman)",
|
||||
10: "King Boom Boo",
|
||||
11: "Sonic vs Shadow 1",
|
||||
12: "Sonic vs Shadow 2",
|
||||
13: "Tails vs Eggman 1",
|
||||
14: "Tails vs Eggman 2",
|
||||
15: "Knuckles vs Rouge 1",
|
||||
}
|
||||
|
||||
def get_boss_name(boss: int):
|
||||
for key, value in gate_bosses_no_requirements_table.items():
|
||||
if value == boss:
|
||||
return key
|
||||
for key, value in gate_bosses_with_requirements_table.items():
|
||||
if value == boss:
|
||||
return key
|
||||
for key, value in extra_boss_rush_bosses_table.items():
|
||||
if value == boss:
|
||||
return key
|
||||
return boss_id_to_name[boss]
|
||||
|
||||
|
||||
def boss_has_requirement(boss: int):
|
||||
return boss >= len(gate_bosses_no_requirements_table)
|
||||
|
||||
|
||||
def get_gate_bosses(multiworld: MultiWorld, world: World):
|
||||
def get_gate_bosses(world: World):
|
||||
selected_bosses: typing.List[int] = []
|
||||
boss_gates: typing.List[int] = []
|
||||
available_bosses: typing.List[str] = list(gate_bosses_no_requirements_table.keys())
|
||||
multiworld.random.shuffle(available_bosses)
|
||||
halfway = False
|
||||
world.random.shuffle(available_bosses)
|
||||
|
||||
gate_boss_plando: typing.Union[int, str] = world.options.gate_boss_plando.value
|
||||
plando_bosses = ["None", "None", "None", "None", "None"]
|
||||
if isinstance(gate_boss_plando, str):
|
||||
# boss plando
|
||||
options = gate_boss_plando.split(";")
|
||||
gate_boss_plando = GateBossPlando.options[options.pop()]
|
||||
for option in options:
|
||||
if "-" in option:
|
||||
loc, boss = option.split("-")
|
||||
boss_num = LocationName.boss_gate_names[loc]
|
||||
|
||||
if boss_num >= world.options.number_of_level_gates.value:
|
||||
# Don't reject bosses plando'd into gate bosses that won't exist
|
||||
pass
|
||||
|
||||
if boss in plando_bosses:
|
||||
# TODO: Raise error here. Duplicates not allowed
|
||||
pass
|
||||
|
||||
plando_bosses[boss_num] = boss
|
||||
|
||||
if boss in available_bosses:
|
||||
available_bosses.remove(boss)
|
||||
|
||||
for x in range(world.options.number_of_level_gates):
|
||||
if (not halfway) and ((x + 1) / world.options.number_of_level_gates) > 0.5:
|
||||
if ("king boom boo" not in selected_bosses) and ("king boom boo" not in available_bosses) and ((x + 1) / world.options.number_of_level_gates) > 0.5:
|
||||
available_bosses.extend(gate_bosses_with_requirements_table)
|
||||
multiworld.random.shuffle(available_bosses)
|
||||
halfway = True
|
||||
selected_bosses.append(all_gate_bosses_table[available_bosses[0]])
|
||||
world.random.shuffle(available_bosses)
|
||||
|
||||
chosen_boss = available_bosses[0]
|
||||
if plando_bosses[x] != "None":
|
||||
available_bosses.append(plando_bosses[x])
|
||||
chosen_boss = plando_bosses[x]
|
||||
|
||||
selected_bosses.append(all_gate_bosses_table[chosen_boss])
|
||||
boss_gates.append(x + 1)
|
||||
available_bosses.remove(available_bosses[0])
|
||||
available_bosses.remove(chosen_boss)
|
||||
|
||||
bosses: typing.Dict[int, int] = dict(zip(boss_gates, selected_bosses))
|
||||
|
||||
return bosses
|
||||
|
||||
|
||||
def get_boss_rush_bosses(multiworld: MultiWorld, world: World):
|
||||
def get_boss_rush_bosses(world: World):
|
||||
|
||||
if world.options.boss_rush_shuffle == 0:
|
||||
boss_list_o = list(range(0, 16))
|
||||
@@ -92,21 +136,21 @@ def get_boss_rush_bosses(multiworld: MultiWorld, world: World):
|
||||
elif world.options.boss_rush_shuffle == 1:
|
||||
boss_list_o = list(range(0, 16))
|
||||
boss_list_s = boss_list_o.copy()
|
||||
multiworld.random.shuffle(boss_list_s)
|
||||
world.random.shuffle(boss_list_s)
|
||||
|
||||
return dict(zip(boss_list_o, boss_list_s))
|
||||
elif world.options.boss_rush_shuffle == 2:
|
||||
boss_list_o = list(range(0, 16))
|
||||
boss_list_s = [multiworld.random.choice(boss_list_o) for i in range(0, 16)]
|
||||
boss_list_s = [world.random.choice(boss_list_o) for i in range(0, 16)]
|
||||
if 10 not in boss_list_s:
|
||||
boss_list_s[multiworld.random.randint(0, 15)] = 10
|
||||
boss_list_s[world.random.randint(0, 15)] = 10
|
||||
|
||||
return dict(zip(boss_list_o, boss_list_s))
|
||||
elif world.options.boss_rush_shuffle == 3:
|
||||
boss_list_o = list(range(0, 16))
|
||||
boss_list_s = [multiworld.random.choice(boss_list_o)] * len(boss_list_o)
|
||||
boss_list_s = [world.random.choice(boss_list_o)] * len(boss_list_o)
|
||||
if 10 not in boss_list_s:
|
||||
boss_list_s[multiworld.random.randint(0, 15)] = 10
|
||||
boss_list_s[world.random.randint(0, 15)] = 10
|
||||
|
||||
return dict(zip(boss_list_o, boss_list_s))
|
||||
else:
|
||||
|
||||
@@ -2,7 +2,6 @@ import typing
|
||||
|
||||
from BaseClasses import Item, ItemClassification
|
||||
from .Names import ItemName
|
||||
from worlds.alttp import ALTTPWorld
|
||||
|
||||
|
||||
class ItemData(typing.NamedTuple):
|
||||
@@ -14,7 +13,7 @@ class ItemData(typing.NamedTuple):
|
||||
|
||||
|
||||
class SA2BItem(Item):
|
||||
game: str = "Sonic Adventure 2: Battle"
|
||||
game: str = "Sonic Adventure 2 Battle"
|
||||
|
||||
def __init__(self, name, classification: ItemClassification, code: int = None, player: int = None):
|
||||
super(SA2BItem, self).__init__(name, classification, code, player)
|
||||
@@ -73,19 +72,36 @@ junk_table = {
|
||||
}
|
||||
|
||||
trap_table = {
|
||||
ItemName.omochao_trap: ItemData(0xFF0030, False, True),
|
||||
ItemName.timestop_trap: ItemData(0xFF0031, False, True),
|
||||
ItemName.confuse_trap: ItemData(0xFF0032, False, True),
|
||||
ItemName.tiny_trap: ItemData(0xFF0033, False, True),
|
||||
ItemName.gravity_trap: ItemData(0xFF0034, False, True),
|
||||
ItemName.exposition_trap: ItemData(0xFF0035, False, True),
|
||||
#ItemName.darkness_trap: ItemData(0xFF0036, False, True),
|
||||
ItemName.ice_trap: ItemData(0xFF0037, False, True),
|
||||
ItemName.slow_trap: ItemData(0xFF0038, False, True),
|
||||
ItemName.cutscene_trap: ItemData(0xFF0039, False, True),
|
||||
ItemName.reverse_trap: ItemData(0xFF003A, False, True),
|
||||
ItemName.omochao_trap: ItemData(0xFF0030, False, True),
|
||||
ItemName.timestop_trap: ItemData(0xFF0031, False, True),
|
||||
ItemName.confuse_trap: ItemData(0xFF0032, False, True),
|
||||
ItemName.tiny_trap: ItemData(0xFF0033, False, True),
|
||||
ItemName.gravity_trap: ItemData(0xFF0034, False, True),
|
||||
ItemName.exposition_trap: ItemData(0xFF0035, False, True),
|
||||
#ItemName.darkness_trap: ItemData(0xFF0036, False, True),
|
||||
ItemName.ice_trap: ItemData(0xFF0037, False, True),
|
||||
ItemName.slow_trap: ItemData(0xFF0038, False, True),
|
||||
ItemName.cutscene_trap: ItemData(0xFF0039, False, True),
|
||||
ItemName.reverse_trap: ItemData(0xFF003A, False, True),
|
||||
ItemName.literature_trap: ItemData(0xFF003B, False, True),
|
||||
ItemName.controller_drift_trap: ItemData(0xFF003C, False, True),
|
||||
ItemName.poison_trap: ItemData(0xFF003D, False, True),
|
||||
ItemName.bee_trap: ItemData(0xFF003E, False, True),
|
||||
}
|
||||
|
||||
ItemName.pong_trap: ItemData(0xFF0050, False, True),
|
||||
minigame_trap_table = {
|
||||
ItemName.pong_trap: ItemData(0xFF0050, False, True),
|
||||
ItemName.breakout_trap: ItemData(0xFF0051, False, True),
|
||||
ItemName.fishing_trap: ItemData(0xFF0052, False, True),
|
||||
ItemName.trivia_trap: ItemData(0xFF0053, False, True),
|
||||
ItemName.pokemon_trivia_trap: ItemData(0xFF0054, False, True),
|
||||
ItemName.pokemon_count_trap: ItemData(0xFF0055, False, True),
|
||||
ItemName.number_sequence_trap: ItemData(0xFF0056, False, True),
|
||||
ItemName.light_up_path_trap: ItemData(0xFF0057, False, True),
|
||||
ItemName.pinball_trap: ItemData(0xFF0058, False, True),
|
||||
ItemName.math_quiz_trap: ItemData(0xFF0059, False, True),
|
||||
ItemName.snake_trap: ItemData(0xFF005A, False, True),
|
||||
ItemName.input_sequence_trap: ItemData(0xFF005B, False, True),
|
||||
}
|
||||
|
||||
emeralds_table = {
|
||||
@@ -235,7 +251,7 @@ chaos_drives_table = {
|
||||
}
|
||||
|
||||
event_table = {
|
||||
ItemName.maria: ItemData(0xFF001D, True),
|
||||
ItemName.maria: ItemData(None, True),
|
||||
}
|
||||
|
||||
# Complete item table.
|
||||
@@ -244,6 +260,7 @@ item_table = {
|
||||
**upgrades_table,
|
||||
**junk_table,
|
||||
**trap_table,
|
||||
**minigame_trap_table,
|
||||
**emeralds_table,
|
||||
**eggs_table,
|
||||
**fruits_table,
|
||||
@@ -251,7 +268,6 @@ item_table = {
|
||||
**hats_table,
|
||||
**animals_table,
|
||||
**chaos_drives_table,
|
||||
**event_table,
|
||||
}
|
||||
|
||||
lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in item_table.items() if data.code}
|
||||
@@ -263,7 +279,12 @@ item_groups: typing.Dict[str, str] = {
|
||||
"Seeds": list(seeds_table.keys()),
|
||||
"Hats": list(hats_table.keys()),
|
||||
"Traps": list(trap_table.keys()),
|
||||
"Minigames": list(minigame_trap_table.keys()),
|
||||
}
|
||||
|
||||
ALTTPWorld.pedestal_credit_texts[item_table[ItemName.sonic_light_shoes].code] = "and the Soap Shoes"
|
||||
ALTTPWorld.pedestal_credit_texts[item_table[ItemName.shadow_air_shoes].code] = "and the Soap Shoes"
|
||||
try:
|
||||
from worlds.alttp import ALTTPWorld
|
||||
ALTTPWorld.pedestal_credit_texts[item_table[ItemName.sonic_light_shoes].code] = "and the Soap Shoes"
|
||||
ALTTPWorld.pedestal_credit_texts[item_table[ItemName.shadow_air_shoes].code] = "and the Soap Shoes"
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -119,11 +119,14 @@ mission_orders: typing.List[typing.List[int]] = [
|
||||
[4, 5, 3, 2, 1],
|
||||
]
|
||||
|
||||
### 0: Speed
|
||||
### 1: Mech
|
||||
### 2: Hunt
|
||||
### 3: Kart
|
||||
### 4: Cannon's Core
|
||||
### 0: Sonic
|
||||
### 1: Tails
|
||||
### 2: Knuckles
|
||||
### 3: Shadow
|
||||
### 4: Eggman
|
||||
### 5: Rouge
|
||||
### 6: Kart
|
||||
### 7: Cannon's Core
|
||||
level_styles: typing.List[int] = [
|
||||
0,
|
||||
2,
|
||||
@@ -133,7 +136,7 @@ level_styles: typing.List[int] = [
|
||||
2,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
6,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
@@ -142,22 +145,22 @@ level_styles: typing.List[int] = [
|
||||
0,
|
||||
0,
|
||||
|
||||
1,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
3,
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
|
||||
4,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
5,
|
||||
4,
|
||||
4,
|
||||
5,
|
||||
3,
|
||||
6,
|
||||
3,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
|
||||
7,
|
||||
]
|
||||
|
||||
stage_name_prefixes: typing.List[str] = [
|
||||
@@ -201,21 +204,33 @@ def get_mission_count_table(multiworld: MultiWorld, world: World, player: int):
|
||||
for level in range(31):
|
||||
mission_count_table[level] = 0
|
||||
else:
|
||||
speed_active_missions = 1
|
||||
mech_active_missions = 1
|
||||
hunt_active_missions = 1
|
||||
sonic_active_missions = 1
|
||||
tails_active_missions = 1
|
||||
knuckles_active_missions = 1
|
||||
shadow_active_missions = 1
|
||||
eggman_active_missions = 1
|
||||
rouge_active_missions = 1
|
||||
kart_active_missions = 1
|
||||
cannons_core_active_missions = 1
|
||||
|
||||
for i in range(2,6):
|
||||
if getattr(world.options, "speed_mission_" + str(i), None):
|
||||
speed_active_missions += 1
|
||||
if getattr(world.options, "sonic_mission_" + str(i), None):
|
||||
sonic_active_missions += 1
|
||||
|
||||
if getattr(world.options, "mech_mission_" + str(i), None):
|
||||
mech_active_missions += 1
|
||||
if getattr(world.options, "tails_mission_" + str(i), None):
|
||||
tails_active_missions += 1
|
||||
|
||||
if getattr(world.options, "hunt_mission_" + str(i), None):
|
||||
hunt_active_missions += 1
|
||||
if getattr(world.options, "knuckles_mission_" + str(i), None):
|
||||
knuckles_active_missions += 1
|
||||
|
||||
if getattr(world.options, "shadow_mission_" + str(i), None):
|
||||
shadow_active_missions += 1
|
||||
|
||||
if getattr(world.options, "eggman_mission_" + str(i), None):
|
||||
eggman_active_missions += 1
|
||||
|
||||
if getattr(world.options, "rouge_mission_" + str(i), None):
|
||||
rouge_active_missions += 1
|
||||
|
||||
if getattr(world.options, "kart_mission_" + str(i), None):
|
||||
kart_active_missions += 1
|
||||
@@ -223,16 +238,22 @@ def get_mission_count_table(multiworld: MultiWorld, world: World, player: int):
|
||||
if getattr(world.options, "cannons_core_mission_" + str(i), None):
|
||||
cannons_core_active_missions += 1
|
||||
|
||||
speed_active_missions = min(speed_active_missions, world.options.speed_mission_count.value)
|
||||
mech_active_missions = min(mech_active_missions, world.options.mech_mission_count.value)
|
||||
hunt_active_missions = min(hunt_active_missions, world.options.hunt_mission_count.value)
|
||||
sonic_active_missions = min(sonic_active_missions, world.options.sonic_mission_count.value)
|
||||
tails_active_missions = min(tails_active_missions, world.options.tails_mission_count.value)
|
||||
knuckles_active_missions = min(knuckles_active_missions, world.options.knuckles_mission_count.value)
|
||||
shadow_active_missions = min(shadow_active_missions, world.options.sonic_mission_count.value)
|
||||
eggman_active_missions = min(eggman_active_missions, world.options.eggman_mission_count.value)
|
||||
rouge_active_missions = min(rouge_active_missions, world.options.rouge_mission_count.value)
|
||||
kart_active_missions = min(kart_active_missions, world.options.kart_mission_count.value)
|
||||
cannons_core_active_missions = min(cannons_core_active_missions, world.options.cannons_core_mission_count.value)
|
||||
|
||||
active_missions: typing.List[typing.List[int]] = [
|
||||
speed_active_missions,
|
||||
mech_active_missions,
|
||||
hunt_active_missions,
|
||||
sonic_active_missions,
|
||||
tails_active_missions,
|
||||
knuckles_active_missions,
|
||||
shadow_active_missions,
|
||||
eggman_active_missions,
|
||||
rouge_active_missions,
|
||||
kart_active_missions,
|
||||
cannons_core_active_missions
|
||||
]
|
||||
@@ -252,22 +273,34 @@ def get_mission_table(multiworld: MultiWorld, world: World, player: int):
|
||||
for level in range(31):
|
||||
mission_table[level] = 0
|
||||
else:
|
||||
speed_active_missions: typing.List[int] = [1]
|
||||
mech_active_missions: typing.List[int] = [1]
|
||||
hunt_active_missions: typing.List[int] = [1]
|
||||
sonic_active_missions: typing.List[int] = [1]
|
||||
tails_active_missions: typing.List[int] = [1]
|
||||
knuckles_active_missions: typing.List[int] = [1]
|
||||
shadow_active_missions: typing.List[int] = [1]
|
||||
eggman_active_missions: typing.List[int] = [1]
|
||||
rouge_active_missions: typing.List[int] = [1]
|
||||
kart_active_missions: typing.List[int] = [1]
|
||||
cannons_core_active_missions: typing.List[int] = [1]
|
||||
|
||||
# Add included missions
|
||||
for i in range(2,6):
|
||||
if getattr(world.options, "speed_mission_" + str(i), None):
|
||||
speed_active_missions.append(i)
|
||||
if getattr(world.options, "sonic_mission_" + str(i), None):
|
||||
sonic_active_missions.append(i)
|
||||
|
||||
if getattr(world.options, "mech_mission_" + str(i), None):
|
||||
mech_active_missions.append(i)
|
||||
if getattr(world.options, "tails_mission_" + str(i), None):
|
||||
tails_active_missions.append(i)
|
||||
|
||||
if getattr(world.options, "hunt_mission_" + str(i), None):
|
||||
hunt_active_missions.append(i)
|
||||
if getattr(world.options, "knuckles_mission_" + str(i), None):
|
||||
knuckles_active_missions.append(i)
|
||||
|
||||
if getattr(world.options, "shadow_mission_" + str(i), None):
|
||||
shadow_active_missions.append(i)
|
||||
|
||||
if getattr(world.options, "eggman_mission_" + str(i), None):
|
||||
eggman_active_missions.append(i)
|
||||
|
||||
if getattr(world.options, "rouge_mission_" + str(i), None):
|
||||
rouge_active_missions.append(i)
|
||||
|
||||
if getattr(world.options, "kart_mission_" + str(i), None):
|
||||
kart_active_missions.append(i)
|
||||
@@ -276,9 +309,12 @@ def get_mission_table(multiworld: MultiWorld, world: World, player: int):
|
||||
cannons_core_active_missions.append(i)
|
||||
|
||||
active_missions: typing.List[typing.List[int]] = [
|
||||
speed_active_missions,
|
||||
mech_active_missions,
|
||||
hunt_active_missions,
|
||||
sonic_active_missions,
|
||||
tails_active_missions,
|
||||
knuckles_active_missions,
|
||||
shadow_active_missions,
|
||||
eggman_active_missions,
|
||||
rouge_active_missions,
|
||||
kart_active_missions,
|
||||
cannons_core_active_missions
|
||||
]
|
||||
@@ -328,13 +364,60 @@ def get_mission_table(multiworld: MultiWorld, world: World, player: int):
|
||||
|
||||
|
||||
def get_first_and_last_cannons_core_missions(mission_map: typing.Dict[int, int], mission_count_map: typing.Dict[int, int]):
|
||||
mission_count = mission_count_map[30]
|
||||
mission_order: typing.List[int] = mission_orders[mission_map[30]]
|
||||
stage_prefix: str = stage_name_prefixes[30]
|
||||
mission_count = mission_count_map[30]
|
||||
mission_order: typing.List[int] = mission_orders[mission_map[30]]
|
||||
stage_prefix: str = stage_name_prefixes[30]
|
||||
|
||||
first_mission_number = mission_order[0]
|
||||
last_mission_number = mission_order[mission_count - 1]
|
||||
first_location_name: str = stage_prefix + str(first_mission_number)
|
||||
last_location_name: str = stage_prefix + str(last_mission_number)
|
||||
first_mission_number = mission_order[0]
|
||||
last_mission_number = mission_order[mission_count - 1]
|
||||
first_location_name: str = stage_prefix + str(first_mission_number)
|
||||
last_location_name: str = stage_prefix + str(last_mission_number)
|
||||
|
||||
return first_location_name, last_location_name
|
||||
return first_location_name, last_location_name
|
||||
|
||||
|
||||
def print_mission_orders_to_spoiler(mission_map: typing.Dict[int, int],
|
||||
mission_count_map: typing.Dict[int, int],
|
||||
shuffled_region_list: typing.Dict[int, int],
|
||||
levels_per_gate: typing.Dict[int, int],
|
||||
player_name: str,
|
||||
spoiler_handle: typing.TextIO):
|
||||
spoiler_handle.write("\n")
|
||||
header_text = "SA2 Mission Orders for {}:\n"
|
||||
header_text = header_text.format(player_name)
|
||||
spoiler_handle.write(header_text)
|
||||
|
||||
level_index = 0
|
||||
for gate_idx in range(len(levels_per_gate)):
|
||||
gate_len = levels_per_gate[gate_idx]
|
||||
gate_levels = shuffled_region_list[int(level_index):int(level_index+gate_len)]
|
||||
gate_levels.sort()
|
||||
|
||||
gate_text = "Gate {}:\n"
|
||||
gate_text = gate_text.format(gate_idx)
|
||||
spoiler_handle.write(gate_text)
|
||||
|
||||
for i in range(len(gate_levels)):
|
||||
stage = gate_levels[i]
|
||||
mission_count = mission_count_map[stage]
|
||||
mission_order: typing.List[int] = mission_orders[mission_map[stage]]
|
||||
stage_prefix: str = stage_name_prefixes[stage]
|
||||
|
||||
for mission in range(mission_count):
|
||||
stage_prefix += str(mission_order[mission]) + " "
|
||||
|
||||
spoiler_handle.write(stage_prefix)
|
||||
spoiler_handle.write("\n")
|
||||
|
||||
level_index += gate_len
|
||||
spoiler_handle.write("\n")
|
||||
|
||||
mission_count = mission_count_map[30]
|
||||
mission_order: typing.List[int] = mission_orders[mission_map[30]]
|
||||
stage_prefix: str = stage_name_prefixes[30]
|
||||
|
||||
for mission in range(mission_count):
|
||||
stage_prefix += str(mission_order[mission]) + " "
|
||||
|
||||
spoiler_handle.write(stage_prefix)
|
||||
spoiler_handle.write("\n\n")
|
||||
|
||||
@@ -5,7 +5,7 @@ emblem = "Emblem"
|
||||
market_token = "Chao Coin"
|
||||
|
||||
# Upgrade Definitions
|
||||
sonic_gloves = "Sonic - Magic Glove"
|
||||
sonic_gloves = "Sonic - Magic Gloves"
|
||||
sonic_light_shoes = "Sonic - Light Shoes"
|
||||
sonic_ancient_light = "Sonic - Ancient Light"
|
||||
sonic_bounce_bracelet = "Sonic - Bounce Bracelet"
|
||||
@@ -51,19 +51,34 @@ invincibility = "Invincibility"
|
||||
|
||||
|
||||
# Traps
|
||||
omochao_trap = "OmoTrap"
|
||||
timestop_trap = "Chaos Control Trap"
|
||||
confuse_trap = "Confusion Trap"
|
||||
tiny_trap = "Tiny Trap"
|
||||
gravity_trap = "Gravity Trap"
|
||||
exposition_trap = "Exposition Trap"
|
||||
darkness_trap = "Darkness Trap"
|
||||
ice_trap = "Ice Trap"
|
||||
slow_trap = "Slow Trap"
|
||||
cutscene_trap = "Cutscene Trap"
|
||||
reverse_trap = "Reverse Trap"
|
||||
omochao_trap = "OmoTrap"
|
||||
timestop_trap = "Chaos Control Trap"
|
||||
confuse_trap = "Confusion Trap"
|
||||
tiny_trap = "Tiny Trap"
|
||||
gravity_trap = "Gravity Trap"
|
||||
exposition_trap = "Exposition Trap"
|
||||
darkness_trap = "Darkness Trap"
|
||||
ice_trap = "Ice Trap"
|
||||
slow_trap = "Slow Trap"
|
||||
cutscene_trap = "Cutscene Trap"
|
||||
reverse_trap = "Reverse Trap"
|
||||
literature_trap = "Literature Trap"
|
||||
controller_drift_trap = "Controller Drift Trap"
|
||||
poison_trap = "Poison Trap"
|
||||
bee_trap = "Bee Trap"
|
||||
|
||||
pong_trap = "Pong Trap"
|
||||
pong_trap = "Pong Trap"
|
||||
breakout_trap = "Breakout Trap"
|
||||
fishing_trap = "Fishing Trap"
|
||||
trivia_trap = "Trivia Trap"
|
||||
pokemon_trivia_trap = "Pokemon Trivia Trap"
|
||||
pokemon_count_trap = "Pokemon Count Trap"
|
||||
number_sequence_trap = "Number Sequence Trap"
|
||||
light_up_path_trap = "Light Up Path Trap"
|
||||
pinball_trap = "Pinball Trap"
|
||||
math_quiz_trap = "Math Quiz Trap"
|
||||
snake_trap = "Snake Trap"
|
||||
input_sequence_trap = "Input Sequence Trap"
|
||||
|
||||
|
||||
# Chaos Emeralds
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,8 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from Options import Choice, Range, Toggle, DeathLink, DefaultOnToggle, OptionGroup, PerGameCommonOptions
|
||||
from Options import Choice, Range, Option, OptionGroup, Toggle, DeathLink, DefaultOnToggle, PerGameCommonOptions, PlandoBosses
|
||||
|
||||
from .Names import LocationName
|
||||
|
||||
|
||||
class Goal(Choice):
|
||||
@@ -22,6 +24,8 @@ class Goal(Choice):
|
||||
Boss Rush Chaos Emerald Hunt: Find the Seven Chaos Emeralds, then beat all of the bosses in the Boss Rush, ending with Finalhazard
|
||||
|
||||
Chaos Chao: Raise a Chaos Chao to win
|
||||
|
||||
Minigame Madness: Win a certain amount of each Minigame Trap, then defeat Finalhazard
|
||||
"""
|
||||
display_name = "Goal"
|
||||
option_biolizard = 0
|
||||
@@ -32,6 +36,7 @@ class Goal(Choice):
|
||||
option_cannons_core_boss_rush = 5
|
||||
option_boss_rush_chaos_emerald_hunt = 6
|
||||
option_chaos_chao = 7
|
||||
option_minigame_madness = 8
|
||||
default = 0
|
||||
|
||||
@classmethod
|
||||
@@ -71,6 +76,66 @@ class BossRushShuffle(Choice):
|
||||
default = 0
|
||||
|
||||
|
||||
class GateBossPlando(PlandoBosses):
|
||||
"""
|
||||
Possible Locations:
|
||||
"Gate 1 Boss"
|
||||
"Gate 2 Boss"
|
||||
"Gate 3 Boss"
|
||||
"Gate 4 Boss"
|
||||
"Gate 5 Boss"
|
||||
|
||||
Possible Bosses:
|
||||
"Sonic vs Shadow 1"
|
||||
"Sonic vs Shadow 2"
|
||||
"Tails vs Eggman 1"
|
||||
"Tails vs Eggman 2"
|
||||
"Knuckles vs Rouge 1"
|
||||
"BIG FOOT"
|
||||
"HOT SHOT"
|
||||
"FLYING DOG"
|
||||
"Egg Golem (Sonic)"
|
||||
"Egg Golem (Eggman)"
|
||||
"King Boom Boo"
|
||||
"""
|
||||
bosses = frozenset(LocationName.boss_names.keys())
|
||||
|
||||
locations = frozenset(LocationName.boss_gate_names.keys())
|
||||
|
||||
duplicate_bosses = False
|
||||
|
||||
@classmethod
|
||||
def can_place_boss(cls, boss: str, location: str) -> bool:
|
||||
return True
|
||||
|
||||
display_name = "Boss Shuffle"
|
||||
option_plando = 0
|
||||
|
||||
|
||||
class MinigameMadnessRequirement(Range):
|
||||
"""
|
||||
Determines how many of each Minigame Trap must be won (for Minigame Madness goal)
|
||||
|
||||
Receiving this many of a Minigame Trap will allow you to replay that minigame at-will in the Chao World lobby
|
||||
"""
|
||||
display_name = "Minigame Madness Trap Requirement"
|
||||
range_start = 1
|
||||
range_end = 10
|
||||
default = 3
|
||||
|
||||
|
||||
class MinigameMadnessMinimum(Range):
|
||||
"""
|
||||
Determines the minimum number of each Minigame Trap that are created (for Minigame Madness goal)
|
||||
|
||||
At least this many of each trap will be created as "Progression Traps", regardless of other trap option selections
|
||||
"""
|
||||
display_name = "Minigame Madness Trap Minimum"
|
||||
range_start = 1
|
||||
range_end = 10
|
||||
default = 5
|
||||
|
||||
|
||||
class BaseTrapWeight(Choice):
|
||||
"""
|
||||
Base Class for Trap Weights
|
||||
@@ -159,6 +224,34 @@ class ReverseTrapWeight(BaseTrapWeight):
|
||||
display_name = "Reverse Trap Weight"
|
||||
|
||||
|
||||
class LiteratureTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of receiving a trap which forces you to read
|
||||
"""
|
||||
display_name = "Literature Trap Weight"
|
||||
|
||||
|
||||
class ControllerDriftTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of receiving a trap which causes your control sticks to drift
|
||||
"""
|
||||
display_name = "Controller Drift Trap Weight"
|
||||
|
||||
|
||||
class PoisonTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of receiving a trap which causes you to lose rings over time
|
||||
"""
|
||||
display_name = "Poison Trap Weight"
|
||||
|
||||
|
||||
class BeeTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of receiving a trap which spawns a swarm of bees
|
||||
"""
|
||||
display_name = "Bee Trap Weight"
|
||||
|
||||
|
||||
class PongTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of receiving a trap which forces you to play a Pong minigame
|
||||
@@ -166,14 +259,106 @@ class PongTrapWeight(BaseTrapWeight):
|
||||
display_name = "Pong Trap Weight"
|
||||
|
||||
|
||||
class BreakoutTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of receiving a trap which forces you to play a Breakout minigame
|
||||
"""
|
||||
display_name = "Breakout Trap Weight"
|
||||
|
||||
|
||||
class FishingTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of receiving a trap which forces you to play a Fishing minigame
|
||||
"""
|
||||
display_name = "Fishing Trap Weight"
|
||||
|
||||
|
||||
class TriviaTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of receiving a trap which forces you to play a Trivia minigame
|
||||
"""
|
||||
display_name = "Trivia Trap Weight"
|
||||
|
||||
|
||||
class PokemonTriviaTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of receiving a trap which forces you to play a Pokemon Trivia minigame
|
||||
"""
|
||||
display_name = "Pokemon Trivia Trap Weight"
|
||||
|
||||
|
||||
class PokemonCountTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of receiving a trap which forces you to play a Pokemon Count minigame
|
||||
"""
|
||||
display_name = "Pokemon Count Trap Weight"
|
||||
|
||||
|
||||
class NumberSequenceTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of receiving a trap which forces you to play a Number Sequence minigame
|
||||
"""
|
||||
display_name = "Number Sequence Trap Weight"
|
||||
|
||||
|
||||
class LightUpPathTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of receiving a trap which forces you to play a Light Up Path minigame
|
||||
"""
|
||||
display_name = "Light Up Path Trap Weight"
|
||||
|
||||
|
||||
class PinballTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of receiving a trap which forces you to play a Pinball minigame
|
||||
"""
|
||||
display_name = "Pinball Trap Weight"
|
||||
|
||||
|
||||
class MathQuizTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of receiving a trap which forces you to solve a math problem
|
||||
"""
|
||||
display_name = "Math Quiz Trap Weight"
|
||||
|
||||
|
||||
class SnakeTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of receiving a trap which forces you to play a Snake minigame
|
||||
"""
|
||||
display_name = "Snake Trap Weight"
|
||||
|
||||
|
||||
class InputSequenceTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of receiving a trap which forces you to press a sequence of inputs
|
||||
"""
|
||||
display_name = "Input Sequence Trap Weight"
|
||||
|
||||
|
||||
class MinigameTrapDifficulty(Choice):
|
||||
"""
|
||||
How difficult any Minigame-style traps are
|
||||
Chaos causes the difficulty to be random per-minigame
|
||||
"""
|
||||
display_name = "Minigame Trap Difficulty"
|
||||
option_easy = 0
|
||||
option_medium = 1
|
||||
option_hard = 2
|
||||
option_chaos = 3
|
||||
default = 1
|
||||
|
||||
|
||||
class BigFishingDifficulty(Choice):
|
||||
"""
|
||||
How difficult Big's Fishing Minigames are
|
||||
Chaos causes the difficulty to be random per-minigame
|
||||
"""
|
||||
display_name = "Big Fishing Difficulty"
|
||||
option_easy = 0
|
||||
option_medium = 1
|
||||
option_hard = 2
|
||||
option_chaos = 3
|
||||
default = 1
|
||||
|
||||
|
||||
@@ -197,7 +382,7 @@ class TrapFillPercentage(Range):
|
||||
default = 0
|
||||
|
||||
|
||||
class Keysanity(Toggle):
|
||||
class Keysanity(DefaultOnToggle):
|
||||
"""
|
||||
Determines whether picking up Chao Keys grants checks
|
||||
(86 Locations)
|
||||
@@ -225,7 +410,7 @@ class Whistlesanity(Choice):
|
||||
default = 0
|
||||
|
||||
|
||||
class Beetlesanity(Toggle):
|
||||
class Beetlesanity(DefaultOnToggle):
|
||||
"""
|
||||
Determines whether destroying Gold Beetles grants checks
|
||||
(27 Locations)
|
||||
@@ -244,13 +429,35 @@ class Omosanity(Toggle):
|
||||
class Animalsanity(Toggle):
|
||||
"""
|
||||
Determines whether unique counts of animals grant checks.
|
||||
(421 Locations)
|
||||
(422 Locations)
|
||||
|
||||
ALL animals must be collected in a single run of a mission to get all checks.
|
||||
"""
|
||||
display_name = "Animalsanity"
|
||||
|
||||
|
||||
class ItemBoxsanity(Choice):
|
||||
"""
|
||||
Determines whether collecting Item Boxes grants checks
|
||||
None: No Item Boxes grant checks
|
||||
Extra Lives: Extra Life Boxes grant checks (94 Locations)
|
||||
All: All Item Boxes grant checks (502 Locations Total)
|
||||
"""
|
||||
display_name = "Itemboxsanity"
|
||||
option_none = 0
|
||||
option_extra_lives = 1
|
||||
option_all = 2
|
||||
default = 0
|
||||
|
||||
|
||||
class Bigsanity(Toggle):
|
||||
"""
|
||||
Determines whether helping Big fish grants checks.
|
||||
(32 Locations)
|
||||
"""
|
||||
display_name = "Bigsanity"
|
||||
|
||||
|
||||
class KartRaceChecks(Choice):
|
||||
"""
|
||||
Determines whether Kart Race Mode grants checks
|
||||
@@ -313,7 +520,7 @@ class LevelGateCosts(Choice):
|
||||
option_low = 0
|
||||
option_medium = 1
|
||||
option_high = 2
|
||||
default = 2
|
||||
default = 0
|
||||
|
||||
|
||||
class MaximumEmblemCap(Range):
|
||||
@@ -523,109 +730,214 @@ class BaseMissionCount(Range):
|
||||
default = 2
|
||||
|
||||
|
||||
class SpeedMissionCount(BaseMissionCount):
|
||||
class SonicMissionCount(BaseMissionCount):
|
||||
"""
|
||||
The number of active missions to include for Sonic and Shadow stages
|
||||
The number of active missions to include for Sonic stages
|
||||
"""
|
||||
display_name = "Speed Mission Count"
|
||||
display_name = "Sonic Mission Count"
|
||||
|
||||
|
||||
class SpeedMission2(DefaultOnToggle):
|
||||
class SonicMission2(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Sonic and Shadow 100 rings missions should be included
|
||||
Determines if the Sonic 100 rings missions should be included
|
||||
"""
|
||||
display_name = "Speed Mission 2"
|
||||
display_name = "Sonic Mission 2"
|
||||
|
||||
|
||||
class SpeedMission3(DefaultOnToggle):
|
||||
class SonicMission3(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Sonic and Shadow lost chao missions should be included
|
||||
Determines if the Sonic lost chao missions should be included
|
||||
"""
|
||||
display_name = "Speed Mission 3"
|
||||
display_name = "Sonic Mission 3"
|
||||
|
||||
|
||||
class SpeedMission4(DefaultOnToggle):
|
||||
class SonicMission4(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Sonic and Shadow time trial missions should be included
|
||||
Determines if the Sonic time trial missions should be included
|
||||
"""
|
||||
display_name = "Speed Mission 4"
|
||||
display_name = "Sonic Mission 4"
|
||||
|
||||
|
||||
class SpeedMission5(DefaultOnToggle):
|
||||
class SonicMission5(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Sonic and Shadow hard missions should be included
|
||||
Determines if the Sonic hard missions should be included
|
||||
"""
|
||||
display_name = "Speed Mission 5"
|
||||
display_name = "Sonic Mission 5"
|
||||
|
||||
|
||||
class MechMissionCount(BaseMissionCount):
|
||||
class ShadowMissionCount(BaseMissionCount):
|
||||
"""
|
||||
The number of active missions to include for Tails and Eggman stages
|
||||
The number of active missions to include for Shadow stages
|
||||
"""
|
||||
display_name = "Mech Mission Count"
|
||||
display_name = "Shadow Mission Count"
|
||||
|
||||
|
||||
class MechMission2(DefaultOnToggle):
|
||||
class ShadowMission2(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Tails and Eggman 100 rings missions should be included
|
||||
Determines if the Shadow 100 rings missions should be included
|
||||
"""
|
||||
display_name = "Mech Mission 2"
|
||||
display_name = "Shadow Mission 2"
|
||||
|
||||
|
||||
class MechMission3(DefaultOnToggle):
|
||||
class ShadowMission3(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Tails and Eggman lost chao missions should be included
|
||||
Determines if the Shadow lost chao missions should be included
|
||||
"""
|
||||
display_name = "Mech Mission 3"
|
||||
display_name = "Shadow Mission 3"
|
||||
|
||||
|
||||
class MechMission4(DefaultOnToggle):
|
||||
class ShadowMission4(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Tails and Eggman time trial missions should be included
|
||||
Determines if the Shadow time trial missions should be included
|
||||
"""
|
||||
display_name = "Mech Mission 4"
|
||||
display_name = "Shadow Mission 4"
|
||||
|
||||
|
||||
class MechMission5(DefaultOnToggle):
|
||||
class ShadowMission5(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Tails and Eggman hard missions should be included
|
||||
Determines if the Shadow hard missions should be included
|
||||
"""
|
||||
display_name = "Mech Mission 5"
|
||||
display_name = "Shadow Mission 5"
|
||||
|
||||
|
||||
class HuntMissionCount(BaseMissionCount):
|
||||
class TailsMissionCount(BaseMissionCount):
|
||||
"""
|
||||
The number of active missions to include for Knuckles and Rouge stages
|
||||
The number of active missions to include for Tails stages
|
||||
"""
|
||||
display_name = "Hunt Mission Count"
|
||||
display_name = "Tails Mission Count"
|
||||
|
||||
|
||||
class HuntMission2(DefaultOnToggle):
|
||||
class TailsMission2(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Knuckles and Rouge 100 rings missions should be included
|
||||
Determines if the Tails 100 rings missions should be included
|
||||
"""
|
||||
display_name = "Hunt Mission 2"
|
||||
display_name = "Tails Mission 2"
|
||||
|
||||
|
||||
class HuntMission3(DefaultOnToggle):
|
||||
class TailsMission3(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Knuckles and Rouge lost chao missions should be included
|
||||
Determines if the Tails lost chao missions should be included
|
||||
"""
|
||||
display_name = "Hunt Mission 3"
|
||||
display_name = "Tails Mission 3"
|
||||
|
||||
|
||||
class HuntMission4(DefaultOnToggle):
|
||||
class TailsMission4(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Knuckles and Rouge time trial missions should be included
|
||||
Determines if the Tails time trial missions should be included
|
||||
"""
|
||||
display_name = "Hunt Mission 4"
|
||||
display_name = "Tails Mission 4"
|
||||
|
||||
|
||||
class HuntMission5(DefaultOnToggle):
|
||||
class TailsMission5(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Knuckles and Rouge hard missions should be included
|
||||
Determines if the Tails hard missions should be included
|
||||
"""
|
||||
display_name = "Hunt Mission 5"
|
||||
display_name = "Tails Mission 5"
|
||||
|
||||
|
||||
class EggmanMissionCount(BaseMissionCount):
|
||||
"""
|
||||
The number of active missions to include for Eggman stages
|
||||
"""
|
||||
display_name = "Eggman Mission Count"
|
||||
|
||||
|
||||
class EggmanMission2(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Eggman 100 rings missions should be included
|
||||
"""
|
||||
display_name = "Eggman Mission 2"
|
||||
|
||||
|
||||
class EggmanMission3(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Eggman lost chao missions should be included
|
||||
"""
|
||||
display_name = "Eggman Mission 3"
|
||||
|
||||
|
||||
class EggmanMission4(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Eggman time trial missions should be included
|
||||
"""
|
||||
display_name = "Eggman Mission 4"
|
||||
|
||||
|
||||
class EggmanMission5(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Eggman hard missions should be included
|
||||
"""
|
||||
display_name = "Eggman Mission 5"
|
||||
|
||||
|
||||
class KnucklesMissionCount(BaseMissionCount):
|
||||
"""
|
||||
The number of active missions to include for Knuckles stages
|
||||
"""
|
||||
display_name = "Knuckles Mission Count"
|
||||
|
||||
|
||||
class KnucklesMission2(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Knuckles 100 rings missions should be included
|
||||
"""
|
||||
display_name = "Knuckles Mission 2"
|
||||
|
||||
|
||||
class KnucklesMission3(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Knuckles lost chao missions should be included
|
||||
"""
|
||||
display_name = "Knuckles Mission 3"
|
||||
|
||||
|
||||
class KnucklesMission4(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Knuckles time trial missions should be included
|
||||
"""
|
||||
display_name = "Knuckles Mission 4"
|
||||
|
||||
|
||||
class KnucklesMission5(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Knuckles hard missions should be included
|
||||
"""
|
||||
display_name = "Knuckles Mission 5"
|
||||
|
||||
|
||||
class RougeMissionCount(BaseMissionCount):
|
||||
"""
|
||||
The number of active missions to include for Rouge stages
|
||||
"""
|
||||
display_name = "Rouge Mission Count"
|
||||
|
||||
|
||||
class RougeMission2(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Rouge 100 rings missions should be included
|
||||
"""
|
||||
display_name = "Rouge Mission 2"
|
||||
|
||||
|
||||
class RougeMission3(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Rouge lost chao missions should be included
|
||||
"""
|
||||
display_name = "Rouge Mission 3"
|
||||
|
||||
|
||||
class RougeMission4(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Rouge time trial missions should be included
|
||||
"""
|
||||
display_name = "Rouge Mission 4"
|
||||
|
||||
|
||||
class RougeMission5(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the Rouge hard missions should be included
|
||||
"""
|
||||
display_name = "Rouge Mission 5"
|
||||
|
||||
|
||||
class KartMissionCount(BaseMissionCount):
|
||||
@@ -706,7 +1018,7 @@ class RingLoss(Choice):
|
||||
|
||||
Modern: You lose 20 rings when hit
|
||||
|
||||
OHKO: You die immediately when hit (NOTE: Some Hard Logic tricks may require damage boosts!)
|
||||
OHKO: You die immediately when hit (NOTE: Some Hard or Expert Logic tricks may require damage boosts!)
|
||||
"""
|
||||
display_name = "Ring Loss"
|
||||
option_classic = 0
|
||||
@@ -729,6 +1041,16 @@ class RingLink(Toggle):
|
||||
display_name = "Ring Link"
|
||||
|
||||
|
||||
class TrapLink(Toggle):
|
||||
"""
|
||||
Whether your received traps are linked to other players
|
||||
|
||||
You will also receive any linked traps from other players with Trap Link enabled,
|
||||
if you have a weight above "none" set for that trap
|
||||
"""
|
||||
display_name = "Trap Link"
|
||||
|
||||
|
||||
class SADXMusic(Choice):
|
||||
"""
|
||||
Whether the randomizer will include Sonic Adventure DX Music in the music pool
|
||||
@@ -823,11 +1145,14 @@ class LogicDifficulty(Choice):
|
||||
|
||||
Standard: The logic assumes the "intended" usage of Upgrades to progress through levels
|
||||
|
||||
Hard: Some simple skips or sequence breaks may be required
|
||||
Hard: Some simple skips or sequence breaks may be required, but no out-of-bounds
|
||||
|
||||
Expert: If it is humanly possible, it may be required
|
||||
"""
|
||||
display_name = "Logic Difficulty"
|
||||
option_standard = 0
|
||||
option_hard = 1
|
||||
option_expert = 2
|
||||
default = 0
|
||||
|
||||
|
||||
@@ -835,6 +1160,8 @@ sa2b_option_groups = [
|
||||
OptionGroup("General Options", [
|
||||
Goal,
|
||||
BossRushShuffle,
|
||||
MinigameMadnessRequirement,
|
||||
MinigameMadnessMinimum,
|
||||
LogicDifficulty,
|
||||
RequiredRank,
|
||||
MaximumEmblemCap,
|
||||
@@ -854,6 +1181,8 @@ sa2b_option_groups = [
|
||||
Beetlesanity,
|
||||
Omosanity,
|
||||
Animalsanity,
|
||||
ItemBoxsanity,
|
||||
Bigsanity,
|
||||
KartRaceChecks,
|
||||
]),
|
||||
OptionGroup("Chao", [
|
||||
@@ -885,29 +1214,68 @@ sa2b_option_groups = [
|
||||
SlowTrapWeight,
|
||||
CutsceneTrapWeight,
|
||||
ReverseTrapWeight,
|
||||
LiteratureTrapWeight,
|
||||
ControllerDriftTrapWeight,
|
||||
PoisonTrapWeight,
|
||||
BeeTrapWeight,
|
||||
]),
|
||||
OptionGroup("Minigames", [
|
||||
PongTrapWeight,
|
||||
BreakoutTrapWeight,
|
||||
FishingTrapWeight,
|
||||
TriviaTrapWeight,
|
||||
PokemonTriviaTrapWeight,
|
||||
PokemonCountTrapWeight,
|
||||
NumberSequenceTrapWeight,
|
||||
LightUpPathTrapWeight,
|
||||
PinballTrapWeight,
|
||||
MathQuizTrapWeight,
|
||||
SnakeTrapWeight,
|
||||
InputSequenceTrapWeight,
|
||||
MinigameTrapDifficulty,
|
||||
BigFishingDifficulty,
|
||||
]),
|
||||
OptionGroup("Speed Missions", [
|
||||
SpeedMissionCount,
|
||||
SpeedMission2,
|
||||
SpeedMission3,
|
||||
SpeedMission4,
|
||||
SpeedMission5,
|
||||
OptionGroup("Sonic Missions", [
|
||||
SonicMissionCount,
|
||||
SonicMission2,
|
||||
SonicMission3,
|
||||
SonicMission4,
|
||||
SonicMission5,
|
||||
]),
|
||||
OptionGroup("Mech Missions", [
|
||||
MechMissionCount,
|
||||
MechMission2,
|
||||
MechMission3,
|
||||
MechMission4,
|
||||
MechMission5,
|
||||
OptionGroup("Shadow Missions", [
|
||||
ShadowMissionCount,
|
||||
ShadowMission2,
|
||||
ShadowMission3,
|
||||
ShadowMission4,
|
||||
ShadowMission5,
|
||||
]),
|
||||
OptionGroup("Hunt Missions", [
|
||||
HuntMissionCount,
|
||||
HuntMission2,
|
||||
HuntMission3,
|
||||
HuntMission4,
|
||||
HuntMission5,
|
||||
OptionGroup("Tails Missions", [
|
||||
TailsMissionCount,
|
||||
TailsMission2,
|
||||
TailsMission3,
|
||||
TailsMission4,
|
||||
TailsMission5,
|
||||
]),
|
||||
OptionGroup("Eggman Missions", [
|
||||
EggmanMissionCount,
|
||||
EggmanMission2,
|
||||
EggmanMission3,
|
||||
EggmanMission4,
|
||||
EggmanMission5,
|
||||
]),
|
||||
OptionGroup("Knuckles Missions", [
|
||||
KnucklesMissionCount,
|
||||
KnucklesMission2,
|
||||
KnucklesMission3,
|
||||
KnucklesMission4,
|
||||
KnucklesMission5,
|
||||
]),
|
||||
OptionGroup("Rouge Missions", [
|
||||
RougeMissionCount,
|
||||
RougeMission2,
|
||||
RougeMission3,
|
||||
RougeMission4,
|
||||
RougeMission5,
|
||||
]),
|
||||
OptionGroup("Kart Missions", [
|
||||
KartMissionCount,
|
||||
@@ -931,11 +1299,13 @@ sa2b_option_groups = [
|
||||
]),
|
||||
]
|
||||
|
||||
|
||||
@dataclass
|
||||
class SA2BOptions(PerGameCommonOptions):
|
||||
goal: Goal
|
||||
boss_rush_shuffle: BossRushShuffle
|
||||
minigame_madness_requirement: MinigameMadnessRequirement
|
||||
minigame_madness_minimum: MinigameMadnessMinimum
|
||||
gate_boss_plando: GateBossPlando
|
||||
logic_difficulty: LogicDifficulty
|
||||
required_rank: RequiredRank
|
||||
max_emblem_cap: MaximumEmblemCap
|
||||
@@ -953,6 +1323,8 @@ class SA2BOptions(PerGameCommonOptions):
|
||||
beetlesanity: Beetlesanity
|
||||
omosanity: Omosanity
|
||||
animalsanity: Animalsanity
|
||||
itemboxsanity: ItemBoxsanity
|
||||
bigsanity: Bigsanity
|
||||
kart_race_checks: KartRaceChecks
|
||||
|
||||
black_market_slots: BlackMarketSlots
|
||||
@@ -983,31 +1355,65 @@ class SA2BOptions(PerGameCommonOptions):
|
||||
slow_trap_weight: SlowTrapWeight
|
||||
cutscene_trap_weight: CutsceneTrapWeight
|
||||
reverse_trap_weight: ReverseTrapWeight
|
||||
literature_trap_weight: LiteratureTrapWeight
|
||||
controller_drift_trap_weight: ControllerDriftTrapWeight
|
||||
poison_trap_weight: PoisonTrapWeight
|
||||
bee_trap_weight: BeeTrapWeight
|
||||
pong_trap_weight: PongTrapWeight
|
||||
breakout_trap_weight: BreakoutTrapWeight
|
||||
fishing_trap_weight: FishingTrapWeight
|
||||
trivia_trap_weight: TriviaTrapWeight
|
||||
pokemon_trivia_trap_weight: PokemonTriviaTrapWeight
|
||||
pokemon_count_trap_weight: PokemonCountTrapWeight
|
||||
number_sequence_trap_weight: NumberSequenceTrapWeight
|
||||
light_up_path_trap_weight: LightUpPathTrapWeight
|
||||
pinball_trap_weight: PinballTrapWeight
|
||||
math_quiz_trap_weight: MathQuizTrapWeight
|
||||
snake_trap_weight: SnakeTrapWeight
|
||||
input_sequence_trap_weight: InputSequenceTrapWeight
|
||||
minigame_trap_difficulty: MinigameTrapDifficulty
|
||||
big_fishing_difficulty: BigFishingDifficulty
|
||||
|
||||
sadx_music: SADXMusic
|
||||
music_shuffle: MusicShuffle
|
||||
voice_shuffle: VoiceShuffle
|
||||
narrator: Narrator
|
||||
|
||||
speed_mission_count: SpeedMissionCount
|
||||
speed_mission_2: SpeedMission2
|
||||
speed_mission_3: SpeedMission3
|
||||
speed_mission_4: SpeedMission4
|
||||
speed_mission_5: SpeedMission5
|
||||
sonic_mission_count: SonicMissionCount
|
||||
sonic_mission_2: SonicMission2
|
||||
sonic_mission_3: SonicMission3
|
||||
sonic_mission_4: SonicMission4
|
||||
sonic_mission_5: SonicMission5
|
||||
|
||||
mech_mission_count: MechMissionCount
|
||||
mech_mission_2: MechMission2
|
||||
mech_mission_3: MechMission3
|
||||
mech_mission_4: MechMission4
|
||||
mech_mission_5: MechMission5
|
||||
shadow_mission_count: ShadowMissionCount
|
||||
shadow_mission_2: ShadowMission2
|
||||
shadow_mission_3: ShadowMission3
|
||||
shadow_mission_4: ShadowMission4
|
||||
shadow_mission_5: ShadowMission5
|
||||
|
||||
hunt_mission_count: HuntMissionCount
|
||||
hunt_mission_2: HuntMission2
|
||||
hunt_mission_3: HuntMission3
|
||||
hunt_mission_4: HuntMission4
|
||||
hunt_mission_5: HuntMission5
|
||||
tails_mission_count: TailsMissionCount
|
||||
tails_mission_2: TailsMission2
|
||||
tails_mission_3: TailsMission3
|
||||
tails_mission_4: TailsMission4
|
||||
tails_mission_5: TailsMission5
|
||||
|
||||
eggman_mission_count: EggmanMissionCount
|
||||
eggman_mission_2: EggmanMission2
|
||||
eggman_mission_3: EggmanMission3
|
||||
eggman_mission_4: EggmanMission4
|
||||
eggman_mission_5: EggmanMission5
|
||||
|
||||
knuckles_mission_count: KnucklesMissionCount
|
||||
knuckles_mission_2: KnucklesMission2
|
||||
knuckles_mission_3: KnucklesMission3
|
||||
knuckles_mission_4: KnucklesMission4
|
||||
knuckles_mission_5: KnucklesMission5
|
||||
|
||||
rouge_mission_count: RougeMissionCount
|
||||
rouge_mission_2: RougeMission2
|
||||
rouge_mission_3: RougeMission3
|
||||
rouge_mission_4: RougeMission4
|
||||
rouge_mission_5: RougeMission5
|
||||
|
||||
kart_mission_count: KartMissionCount
|
||||
kart_mission_2: KartMission2
|
||||
@@ -1022,4 +1428,5 @@ class SA2BOptions(PerGameCommonOptions):
|
||||
cannons_core_mission_5: CannonsCoreMission5
|
||||
|
||||
ring_link: RingLink
|
||||
trap_link: TrapLink
|
||||
death_link: DeathLink
|
||||
|
||||
502
worlds/sa2b/Presets.py
Normal file
502
worlds/sa2b/Presets.py
Normal file
@@ -0,0 +1,502 @@
|
||||
from typing import Dict, Any
|
||||
|
||||
from .Options import *
|
||||
|
||||
minsanity = {
|
||||
"goal": Goal.option_chaos_chao,
|
||||
"max_emblem_cap": MaximumEmblemCap.range_start,
|
||||
|
||||
"keysanity": False,
|
||||
"whistlesanity": Whistlesanity.option_none,
|
||||
"beetlesanity": False,
|
||||
"omosanity": False,
|
||||
"animalsanity": False,
|
||||
"itemboxsanity": ItemBoxsanity.option_none,
|
||||
"bigsanity": False,
|
||||
"kart_race_checks": KartRaceChecks.option_none,
|
||||
|
||||
"junk_fill_percentage": 0,
|
||||
|
||||
"sonic_mission_count": BaseMissionCount.range_start,
|
||||
"sonic_mission_2": False,
|
||||
"sonic_mission_3": False,
|
||||
"sonic_mission_4": False,
|
||||
"sonic_mission_5": False,
|
||||
|
||||
"shadow_mission_count": BaseMissionCount.range_start,
|
||||
"shadow_mission_2": False,
|
||||
"shadow_mission_3": False,
|
||||
"shadow_mission_4": False,
|
||||
"shadow_mission_5": False,
|
||||
|
||||
"tails_mission_count": BaseMissionCount.range_start,
|
||||
"tails_mission_2": False,
|
||||
"tails_mission_3": False,
|
||||
"tails_mission_4": False,
|
||||
"tails_mission_5": False,
|
||||
|
||||
"eggman_mission_count": BaseMissionCount.range_start,
|
||||
"eggman_mission_2": False,
|
||||
"eggman_mission_3": False,
|
||||
"eggman_mission_4": False,
|
||||
"eggman_mission_5": False,
|
||||
|
||||
"knuckles_mission_count": BaseMissionCount.range_start,
|
||||
"knuckles_mission_2": False,
|
||||
"knuckles_mission_3": False,
|
||||
"knuckles_mission_4": False,
|
||||
"knuckles_mission_5": False,
|
||||
|
||||
"rouge_mission_count": BaseMissionCount.range_start,
|
||||
"rouge_mission_2": False,
|
||||
"rouge_mission_3": False,
|
||||
"rouge_mission_4": False,
|
||||
"rouge_mission_5": False,
|
||||
|
||||
"kart_mission_count": BaseMissionCount.range_start,
|
||||
"kart_mission_2": False,
|
||||
"kart_mission_3": False,
|
||||
"kart_mission_4": False,
|
||||
"kart_mission_5": False,
|
||||
|
||||
"cannons_core_mission_count": BaseMissionCount.range_start,
|
||||
"cannons_core_mission_2": False,
|
||||
"cannons_core_mission_3": False,
|
||||
"cannons_core_mission_4": False,
|
||||
"cannons_core_mission_5": False,
|
||||
}
|
||||
|
||||
chao_centric = {
|
||||
"goal": Goal.option_chaos_chao,
|
||||
|
||||
"keysanity": False,
|
||||
"whistlesanity": Whistlesanity.option_none,
|
||||
"beetlesanity": False,
|
||||
"omosanity": False,
|
||||
"animalsanity": False,
|
||||
"itemboxsanity": ItemBoxsanity.option_none,
|
||||
"bigsanity": False,
|
||||
"kart_race_checks": KartRaceChecks.option_none,
|
||||
|
||||
"black_market_slots": BlackMarketSlots.range_end,
|
||||
"black_market_unlock_costs": BlackMarketUnlockCosts.option_high,
|
||||
"chao_race_difficulty": ChaoRaceDifficulty.option_expert,
|
||||
"chao_karate_difficulty": ChaoKarateDifficulty.option_super,
|
||||
"chao_stadium_checks": ChaoStadiumChecks.option_all,
|
||||
"chao_animal_parts": True,
|
||||
"chao_stats": ChaoStats.range_end,
|
||||
"chao_stats_frequency": 1,
|
||||
"chao_stats_stamina": True,
|
||||
"chao_stats_hidden": True,
|
||||
"chao_kindergarten": ChaoKindergarten.option_full,
|
||||
|
||||
"junk_fill_percentage": 50,
|
||||
|
||||
"sonic_mission_count": BaseMissionCount.range_start,
|
||||
"sonic_mission_2": False,
|
||||
"sonic_mission_3": False,
|
||||
"sonic_mission_4": False,
|
||||
"sonic_mission_5": False,
|
||||
|
||||
"shadow_mission_count": BaseMissionCount.range_start,
|
||||
"shadow_mission_2": False,
|
||||
"shadow_mission_3": False,
|
||||
"shadow_mission_4": False,
|
||||
"shadow_mission_5": False,
|
||||
|
||||
"tails_mission_count": BaseMissionCount.range_start,
|
||||
"tails_mission_2": False,
|
||||
"tails_mission_3": False,
|
||||
"tails_mission_4": False,
|
||||
"tails_mission_5": False,
|
||||
|
||||
"eggman_mission_count": BaseMissionCount.range_start,
|
||||
"eggman_mission_2": False,
|
||||
"eggman_mission_3": False,
|
||||
"eggman_mission_4": False,
|
||||
"eggman_mission_5": False,
|
||||
|
||||
"knuckles_mission_count": BaseMissionCount.range_start,
|
||||
"knuckles_mission_2": False,
|
||||
"knuckles_mission_3": False,
|
||||
"knuckles_mission_4": False,
|
||||
"knuckles_mission_5": False,
|
||||
|
||||
"rouge_mission_count": BaseMissionCount.range_start,
|
||||
"rouge_mission_2": False,
|
||||
"rouge_mission_3": False,
|
||||
"rouge_mission_4": False,
|
||||
"rouge_mission_5": False,
|
||||
|
||||
"kart_mission_count": BaseMissionCount.range_start,
|
||||
"kart_mission_2": False,
|
||||
"kart_mission_3": False,
|
||||
"kart_mission_4": False,
|
||||
"kart_mission_5": False,
|
||||
|
||||
"cannons_core_mission_count": BaseMissionCount.range_start,
|
||||
"cannons_core_mission_2": False,
|
||||
"cannons_core_mission_3": False,
|
||||
"cannons_core_mission_4": False,
|
||||
"cannons_core_mission_5": False,
|
||||
}
|
||||
|
||||
allsanity_no_chao = {
|
||||
"goal": Goal.option_cannons_core_boss_rush,
|
||||
"boss_rush_shuffle": BossRushShuffle.option_chaos,
|
||||
"minigame_madness_requirement": MinigameMadnessRequirement.range_end,
|
||||
"minigame_madness_minimum": MinigameMadnessMinimum.range_end,
|
||||
"max_emblem_cap": MaximumEmblemCap.range_end,
|
||||
|
||||
"mission_shuffle": True,
|
||||
"required_cannons_core_missions": RequiredCannonsCoreMissions.option_all_active,
|
||||
"emblem_percentage_for_cannons_core": EmblemPercentageForCannonsCore.range_end,
|
||||
"number_of_level_gates": NumberOfLevelGates.range_end,
|
||||
"level_gate_costs": LevelGateCosts.option_high,
|
||||
|
||||
"keysanity": True,
|
||||
"whistlesanity": Whistlesanity.option_both,
|
||||
"beetlesanity": True,
|
||||
"omosanity": True,
|
||||
"animalsanity": True,
|
||||
"itemboxsanity": ItemBoxsanity.option_all,
|
||||
"bigsanity": True,
|
||||
"kart_race_checks": KartRaceChecks.option_full,
|
||||
|
||||
"junk_fill_percentage": 25,
|
||||
"trap_fill_percentage": 25,
|
||||
"omochao_trap_weight": BaseTrapWeight.option_high,
|
||||
"timestop_trap_weight": BaseTrapWeight.option_high,
|
||||
"confusion_trap_weight": BaseTrapWeight.option_high,
|
||||
"tiny_trap_weight": BaseTrapWeight.option_high,
|
||||
"gravity_trap_weight": BaseTrapWeight.option_high,
|
||||
"exposition_trap_weight": BaseTrapWeight.option_high,
|
||||
"ice_trap_weight": BaseTrapWeight.option_high,
|
||||
"slow_trap_weight": BaseTrapWeight.option_high,
|
||||
"cutscene_trap_weight": BaseTrapWeight.option_high,
|
||||
"reverse_trap_weight": BaseTrapWeight.option_high,
|
||||
"literature_trap_weight": BaseTrapWeight.option_high,
|
||||
"controller_drift_trap_weight": BaseTrapWeight.option_high,
|
||||
"poison_trap_weight": BaseTrapWeight.option_high,
|
||||
"bee_trap_weight": BaseTrapWeight.option_high,
|
||||
"pong_trap_weight": BaseTrapWeight.option_high,
|
||||
"breakout_trap_weight": BaseTrapWeight.option_high,
|
||||
"fishing_trap_weight": BaseTrapWeight.option_high,
|
||||
"trivia_trap_weight": BaseTrapWeight.option_high,
|
||||
"pokemon_trivia_trap_weight": BaseTrapWeight.option_high,
|
||||
"pokemon_count_trap_weight": BaseTrapWeight.option_high,
|
||||
"number_sequence_trap_weight": BaseTrapWeight.option_high,
|
||||
"light_up_path_trap_weight": BaseTrapWeight.option_high,
|
||||
"pinball_trap_weight": BaseTrapWeight.option_high,
|
||||
"math_quiz_trap_weight": BaseTrapWeight.option_high,
|
||||
"snake_trap_weight": BaseTrapWeight.option_high,
|
||||
"input_sequence_trap_weight": BaseTrapWeight.option_high,
|
||||
"minigame_trap_difficulty": MinigameTrapDifficulty.option_chaos,
|
||||
"big_fishing_difficulty": BigFishingDifficulty.option_chaos,
|
||||
|
||||
"music_shuffle": MusicShuffle.option_full,
|
||||
"voice_shuffle": VoiceShuffle.option_shuffled,
|
||||
|
||||
"sonic_mission_count": BaseMissionCount.range_end,
|
||||
"sonic_mission_2": True,
|
||||
"sonic_mission_3": True,
|
||||
"sonic_mission_4": True,
|
||||
"sonic_mission_5": True,
|
||||
|
||||
"shadow_mission_count": BaseMissionCount.range_end,
|
||||
"shadow_mission_2": True,
|
||||
"shadow_mission_3": True,
|
||||
"shadow_mission_4": True,
|
||||
"shadow_mission_5": True,
|
||||
|
||||
"tails_mission_count": BaseMissionCount.range_end,
|
||||
"tails_mission_2": True,
|
||||
"tails_mission_3": True,
|
||||
"tails_mission_4": True,
|
||||
"tails_mission_5": True,
|
||||
|
||||
"eggman_mission_count": BaseMissionCount.range_end,
|
||||
"eggman_mission_2": True,
|
||||
"eggman_mission_3": True,
|
||||
"eggman_mission_4": True,
|
||||
"eggman_mission_5": True,
|
||||
|
||||
"knuckles_mission_count": BaseMissionCount.range_end,
|
||||
"knuckles_mission_2": True,
|
||||
"knuckles_mission_3": True,
|
||||
"knuckles_mission_4": True,
|
||||
"knuckles_mission_5": True,
|
||||
|
||||
"rouge_mission_count": BaseMissionCount.range_end,
|
||||
"rouge_mission_2": True,
|
||||
"rouge_mission_3": True,
|
||||
"rouge_mission_4": True,
|
||||
"rouge_mission_5": True,
|
||||
|
||||
"kart_mission_count": BaseMissionCount.range_end,
|
||||
"kart_mission_2": True,
|
||||
"kart_mission_3": True,
|
||||
"kart_mission_4": True,
|
||||
"kart_mission_5": True,
|
||||
|
||||
"cannons_core_mission_count": BaseMissionCount.range_end,
|
||||
"cannons_core_mission_2": True,
|
||||
"cannons_core_mission_3": True,
|
||||
"cannons_core_mission_4": True,
|
||||
"cannons_core_mission_5": True,
|
||||
}
|
||||
|
||||
allsanity = {
|
||||
"goal": Goal.option_cannons_core_boss_rush,
|
||||
"boss_rush_shuffle": BossRushShuffle.option_chaos,
|
||||
"minigame_madness_requirement": MinigameMadnessRequirement.range_end,
|
||||
"minigame_madness_minimum": MinigameMadnessMinimum.range_end,
|
||||
"max_emblem_cap": MaximumEmblemCap.range_end,
|
||||
|
||||
"mission_shuffle": True,
|
||||
"required_cannons_core_missions": RequiredCannonsCoreMissions.option_all_active,
|
||||
"emblem_percentage_for_cannons_core": EmblemPercentageForCannonsCore.range_end,
|
||||
"number_of_level_gates": NumberOfLevelGates.range_end,
|
||||
"level_gate_costs": LevelGateCosts.option_high,
|
||||
|
||||
"keysanity": True,
|
||||
"whistlesanity": Whistlesanity.option_both,
|
||||
"beetlesanity": True,
|
||||
"omosanity": True,
|
||||
"animalsanity": True,
|
||||
"itemboxsanity": ItemBoxsanity.option_all,
|
||||
"bigsanity": True,
|
||||
"kart_race_checks": KartRaceChecks.option_full,
|
||||
|
||||
"black_market_slots": BlackMarketSlots.range_end,
|
||||
"black_market_unlock_costs": BlackMarketUnlockCosts.option_high,
|
||||
"chao_race_difficulty": ChaoRaceDifficulty.option_expert,
|
||||
"chao_karate_difficulty": ChaoKarateDifficulty.option_super,
|
||||
"chao_stadium_checks": ChaoStadiumChecks.option_all,
|
||||
"chao_animal_parts": True,
|
||||
"chao_stats": ChaoStats.range_end,
|
||||
"chao_stats_frequency": 1,
|
||||
"chao_stats_stamina": True,
|
||||
"chao_stats_hidden": True,
|
||||
"chao_kindergarten": ChaoKindergarten.option_full,
|
||||
|
||||
"junk_fill_percentage": 25,
|
||||
"trap_fill_percentage": 25,
|
||||
"omochao_trap_weight": BaseTrapWeight.option_high,
|
||||
"timestop_trap_weight": BaseTrapWeight.option_high,
|
||||
"confusion_trap_weight": BaseTrapWeight.option_high,
|
||||
"tiny_trap_weight": BaseTrapWeight.option_high,
|
||||
"gravity_trap_weight": BaseTrapWeight.option_high,
|
||||
"exposition_trap_weight": BaseTrapWeight.option_high,
|
||||
"ice_trap_weight": BaseTrapWeight.option_high,
|
||||
"slow_trap_weight": BaseTrapWeight.option_high,
|
||||
"cutscene_trap_weight": BaseTrapWeight.option_high,
|
||||
"reverse_trap_weight": BaseTrapWeight.option_high,
|
||||
"literature_trap_weight": BaseTrapWeight.option_high,
|
||||
"controller_drift_trap_weight": BaseTrapWeight.option_high,
|
||||
"poison_trap_weight": BaseTrapWeight.option_high,
|
||||
"bee_trap_weight": BaseTrapWeight.option_high,
|
||||
"pong_trap_weight": BaseTrapWeight.option_high,
|
||||
"breakout_trap_weight": BaseTrapWeight.option_high,
|
||||
"fishing_trap_weight": BaseTrapWeight.option_high,
|
||||
"trivia_trap_weight": BaseTrapWeight.option_high,
|
||||
"pokemon_trivia_trap_weight": BaseTrapWeight.option_high,
|
||||
"pokemon_count_trap_weight": BaseTrapWeight.option_high,
|
||||
"number_sequence_trap_weight": BaseTrapWeight.option_high,
|
||||
"light_up_path_trap_weight": BaseTrapWeight.option_high,
|
||||
"pinball_trap_weight": BaseTrapWeight.option_high,
|
||||
"math_quiz_trap_weight": BaseTrapWeight.option_high,
|
||||
"snake_trap_weight": BaseTrapWeight.option_high,
|
||||
"input_sequence_trap_weight": BaseTrapWeight.option_high,
|
||||
"minigame_trap_difficulty": MinigameTrapDifficulty.option_chaos,
|
||||
"big_fishing_difficulty": BigFishingDifficulty.option_chaos,
|
||||
|
||||
"music_shuffle": MusicShuffle.option_full,
|
||||
"voice_shuffle": VoiceShuffle.option_shuffled,
|
||||
|
||||
"sonic_mission_count": BaseMissionCount.range_end,
|
||||
"sonic_mission_2": True,
|
||||
"sonic_mission_3": True,
|
||||
"sonic_mission_4": True,
|
||||
"sonic_mission_5": True,
|
||||
|
||||
"shadow_mission_count": BaseMissionCount.range_end,
|
||||
"shadow_mission_2": True,
|
||||
"shadow_mission_3": True,
|
||||
"shadow_mission_4": True,
|
||||
"shadow_mission_5": True,
|
||||
|
||||
"tails_mission_count": BaseMissionCount.range_end,
|
||||
"tails_mission_2": True,
|
||||
"tails_mission_3": True,
|
||||
"tails_mission_4": True,
|
||||
"tails_mission_5": True,
|
||||
|
||||
"eggman_mission_count": BaseMissionCount.range_end,
|
||||
"eggman_mission_2": True,
|
||||
"eggman_mission_3": True,
|
||||
"eggman_mission_4": True,
|
||||
"eggman_mission_5": True,
|
||||
|
||||
"knuckles_mission_count": BaseMissionCount.range_end,
|
||||
"knuckles_mission_2": True,
|
||||
"knuckles_mission_3": True,
|
||||
"knuckles_mission_4": True,
|
||||
"knuckles_mission_5": True,
|
||||
|
||||
"rouge_mission_count": BaseMissionCount.range_end,
|
||||
"rouge_mission_2": True,
|
||||
"rouge_mission_3": True,
|
||||
"rouge_mission_4": True,
|
||||
"rouge_mission_5": True,
|
||||
|
||||
"kart_mission_count": BaseMissionCount.range_end,
|
||||
"kart_mission_2": True,
|
||||
"kart_mission_3": True,
|
||||
"kart_mission_4": True,
|
||||
"kart_mission_5": True,
|
||||
|
||||
"cannons_core_mission_count": BaseMissionCount.range_end,
|
||||
"cannons_core_mission_2": True,
|
||||
"cannons_core_mission_3": True,
|
||||
"cannons_core_mission_4": True,
|
||||
"cannons_core_mission_5": True,
|
||||
}
|
||||
|
||||
all_random = {
|
||||
"goal": "random",
|
||||
"boss_rush_shuffle": "random",
|
||||
"minigame_madness_requirement": "random",
|
||||
"minigame_madness_minimum": "random",
|
||||
"logic_difficulty": "random",
|
||||
"required_rank": "random",
|
||||
"max_emblem_cap": "random",
|
||||
"ring_loss": "random",
|
||||
|
||||
"mission_shuffle": "random",
|
||||
"required_cannons_core_missions": "random",
|
||||
"emblem_percentage_for_cannons_core": "random",
|
||||
"number_of_level_gates": "random",
|
||||
"level_gate_distribution": "random",
|
||||
"level_gate_costs": "random",
|
||||
|
||||
"keysanity": "random",
|
||||
"whistlesanity": "random",
|
||||
"beetlesanity": "random",
|
||||
"omosanity": "random",
|
||||
"animalsanity": "random",
|
||||
"itemboxsanity": "random",
|
||||
"bigsanity": "random",
|
||||
"kart_race_checks": "random",
|
||||
|
||||
"black_market_slots": "random",
|
||||
"black_market_unlock_costs": "random",
|
||||
"black_market_price_multiplier": "random",
|
||||
"chao_race_difficulty": "random",
|
||||
"chao_karate_difficulty": "random",
|
||||
"chao_stadium_checks": "random",
|
||||
"chao_animal_parts": "random",
|
||||
"chao_stats": "random",
|
||||
"chao_stats_frequency": "random",
|
||||
"chao_stats_stamina": "random",
|
||||
"chao_stats_hidden": "random",
|
||||
"chao_kindergarten": "random",
|
||||
"shuffle_starting_chao_eggs": "random",
|
||||
"chao_entrance_randomization": "random",
|
||||
|
||||
"junk_fill_percentage": "random",
|
||||
"trap_fill_percentage": "random",
|
||||
"omochao_trap_weight": "random",
|
||||
"timestop_trap_weight": "random",
|
||||
"confusion_trap_weight": "random",
|
||||
"tiny_trap_weight": "random",
|
||||
"gravity_trap_weight": "random",
|
||||
"exposition_trap_weight": "random",
|
||||
"ice_trap_weight": "random",
|
||||
"slow_trap_weight": "random",
|
||||
"cutscene_trap_weight": "random",
|
||||
"reverse_trap_weight": "random",
|
||||
"literature_trap_weight": "random",
|
||||
"controller_drift_trap_weight": "random",
|
||||
"poison_trap_weight": "random",
|
||||
"bee_trap_weight": "random",
|
||||
"pong_trap_weight": "random",
|
||||
"breakout_trap_weight": "random",
|
||||
"fishing_trap_weight": "random",
|
||||
"trivia_trap_weight": "random",
|
||||
"pokemon_trivia_trap_weight": "random",
|
||||
"pokemon_count_trap_weight": "random",
|
||||
"number_sequence_trap_weight": "random",
|
||||
"light_up_path_trap_weight": "random",
|
||||
"pinball_trap_weight": "random",
|
||||
"math_quiz_trap_weight": "random",
|
||||
"snake_trap_weight": "random",
|
||||
"input_sequence_trap_weight": "random",
|
||||
"minigame_trap_difficulty": "random",
|
||||
"big_fishing_difficulty": "random",
|
||||
|
||||
"sadx_music": "random",
|
||||
"music_shuffle": "random",
|
||||
"voice_shuffle": "random",
|
||||
"narrator": "random",
|
||||
|
||||
"sonic_mission_count": "random",
|
||||
"sonic_mission_2": "random",
|
||||
"sonic_mission_3": "random",
|
||||
"sonic_mission_4": "random",
|
||||
"sonic_mission_5": "random",
|
||||
|
||||
"shadow_mission_count": "random",
|
||||
"shadow_mission_2": "random",
|
||||
"shadow_mission_3": "random",
|
||||
"shadow_mission_4": "random",
|
||||
"shadow_mission_5": "random",
|
||||
|
||||
"tails_mission_count": "random",
|
||||
"tails_mission_2": "random",
|
||||
"tails_mission_3": "random",
|
||||
"tails_mission_4": "random",
|
||||
"tails_mission_5": "random",
|
||||
|
||||
"eggman_mission_count": "random",
|
||||
"eggman_mission_2": "random",
|
||||
"eggman_mission_3": "random",
|
||||
"eggman_mission_4": "random",
|
||||
"eggman_mission_5": "random",
|
||||
|
||||
"knuckles_mission_count": "random",
|
||||
"knuckles_mission_2": "random",
|
||||
"knuckles_mission_3": "random",
|
||||
"knuckles_mission_4": "random",
|
||||
"knuckles_mission_5": "random",
|
||||
|
||||
"rouge_mission_count": "random",
|
||||
"rouge_mission_2": "random",
|
||||
"rouge_mission_3": "random",
|
||||
"rouge_mission_4": "random",
|
||||
"rouge_mission_5": "random",
|
||||
|
||||
"kart_mission_count": "random",
|
||||
"kart_mission_2": "random",
|
||||
"kart_mission_3": "random",
|
||||
"kart_mission_4": "random",
|
||||
"kart_mission_5": "random",
|
||||
|
||||
"cannons_core_mission_count": "random",
|
||||
"cannons_core_mission_2": "random",
|
||||
"cannons_core_mission_3": "random",
|
||||
"cannons_core_mission_4": "random",
|
||||
"cannons_core_mission_5": "random",
|
||||
|
||||
"ring_link": "random",
|
||||
"trap_link": "random",
|
||||
"death_link": "random",
|
||||
}
|
||||
|
||||
sa2b_options_presets: Dict[str, Dict[str, Any]] = {
|
||||
"Minsanity": minsanity,
|
||||
"Chao-centric": chao_centric,
|
||||
"Allsanity No Chao": allsanity_no_chao,
|
||||
"Allsanity": allsanity,
|
||||
"All Random": all_random,
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
2115
worlds/sa2b/Rules.py
2115
worlds/sa2b/Rules.py
File diff suppressed because it is too large
Load Diff
@@ -8,12 +8,13 @@ from worlds.AutoWorld import WebWorld, World
|
||||
from .AestheticData import chao_name_conversion, sample_chao_names, totally_real_item_names, \
|
||||
all_exits, all_destinations, multi_rooms, single_rooms, room_to_exits_map, exit_to_room_map, valid_kindergarten_exits
|
||||
from .GateBosses import get_gate_bosses, get_boss_rush_bosses, get_boss_name
|
||||
from .Items import SA2BItem, ItemData, item_table, upgrades_table, emeralds_table, junk_table, trap_table, item_groups, \
|
||||
eggs_table, fruits_table, seeds_table, hats_table, animals_table, chaos_drives_table
|
||||
from .Locations import SA2BLocation, all_locations, setup_locations, chao_animal_event_location_table, black_market_location_table
|
||||
from .Missions import get_mission_table, get_mission_count_table, get_first_and_last_cannons_core_missions
|
||||
from .Items import SA2BItem, ItemData, item_table, upgrades_table, emeralds_table, junk_table, minigame_trap_table, item_groups, \
|
||||
eggs_table, fruits_table, seeds_table, hats_table, animals_table, chaos_drives_table, event_table
|
||||
from .Locations import SA2BLocation, all_locations, location_groups, setup_locations, chao_animal_event_location_table, black_market_location_table
|
||||
from .Missions import get_mission_table, get_mission_count_table, get_first_and_last_cannons_core_missions, print_mission_orders_to_spoiler
|
||||
from .Names import ItemName, LocationName
|
||||
from .Options import SA2BOptions, sa2b_option_groups
|
||||
from .Presets import sa2b_options_presets
|
||||
from .Regions import create_regions, shuffleable_regions, connect_regions, LevelGate, gate_0_whitelist_regions, \
|
||||
gate_0_blacklist_regions
|
||||
from .Rules import set_rules
|
||||
@@ -33,6 +34,7 @@ class SA2BWeb(WebWorld):
|
||||
|
||||
tutorials = [setup_en]
|
||||
option_groups = sa2b_option_groups
|
||||
options_presets = sa2b_options_presets
|
||||
|
||||
|
||||
def check_for_impossible_shuffle(shuffled_levels: typing.List[int], gate_0_range: int, multiworld: MultiWorld):
|
||||
@@ -60,11 +62,14 @@ class SA2BWorld(World):
|
||||
topology_present = False
|
||||
|
||||
item_name_groups = item_groups
|
||||
location_name_groups = location_groups
|
||||
item_name_to_id = {name: data.code for name, data in item_table.items()}
|
||||
location_name_to_id = all_locations
|
||||
|
||||
location_table: typing.Dict[str, int]
|
||||
|
||||
shuffled_region_list: typing.List[int]
|
||||
levels_per_gate: typing.List[int]
|
||||
mission_map: typing.Dict[int, int]
|
||||
mission_count_map: typing.Dict[int, int]
|
||||
emblems_for_cannons_core: int
|
||||
@@ -78,7 +83,7 @@ class SA2BWorld(World):
|
||||
|
||||
def fill_slot_data(self) -> dict:
|
||||
return {
|
||||
"ModVersion": 203,
|
||||
"ModVersion": 204,
|
||||
"Goal": self.options.goal.value,
|
||||
"MusicMap": self.generate_music_data(),
|
||||
"VoiceMap": self.generate_voice_data(),
|
||||
@@ -89,14 +94,20 @@ class SA2BWorld(World):
|
||||
"MusicShuffle": self.options.music_shuffle.value,
|
||||
"Narrator": self.options.narrator.value,
|
||||
"MinigameTrapDifficulty": self.options.minigame_trap_difficulty.value,
|
||||
"BigFishingDifficulty": self.options.big_fishing_difficulty.value,
|
||||
"RingLoss": self.options.ring_loss.value,
|
||||
"RingLink": self.options.ring_link.value,
|
||||
"TrapLink": self.options.trap_link.value,
|
||||
"RequiredRank": self.options.required_rank.value,
|
||||
"MinigameMadnessAmount": self.options.minigame_madness_requirement.value,
|
||||
"LogicDifficulty": self.options.logic_difficulty.value,
|
||||
"ChaoKeys": self.options.keysanity.value,
|
||||
"Whistlesanity": self.options.whistlesanity.value,
|
||||
"GoldBeetles": self.options.beetlesanity.value,
|
||||
"OmochaoChecks": self.options.omosanity.value,
|
||||
"AnimalChecks": self.options.animalsanity.value,
|
||||
"ItemBoxChecks": self.options.itemboxsanity.value,
|
||||
"BigChecks": self.options.bigsanity.value,
|
||||
"KartRaceChecks": self.options.kart_race_checks.value,
|
||||
"ChaoStadiumChecks": self.options.chao_stadium_checks.value,
|
||||
"ChaoRaceDifficulty": self.options.chao_race_difficulty.value,
|
||||
@@ -122,6 +133,7 @@ class SA2BWorld(World):
|
||||
"GateCosts": self.gate_costs,
|
||||
"GateBosses": self.gate_bosses,
|
||||
"BossRushMap": self.boss_rush_map,
|
||||
"ActiveTraps": self.output_active_traps(),
|
||||
"PlayerNum": self.player,
|
||||
}
|
||||
|
||||
@@ -151,12 +163,42 @@ class SA2BWorld(World):
|
||||
|
||||
valid_trap_weights = self.options.exposition_trap_weight.value + \
|
||||
self.options.reverse_trap_weight.value + \
|
||||
self.options.pong_trap_weight.value
|
||||
self.options.literature_trap_weight.value + \
|
||||
self.options.controller_drift_trap_weight.value + \
|
||||
self.options.poison_trap_weight.value + \
|
||||
self.options.bee_trap_weight.value + \
|
||||
self.options.pong_trap_weight.value + \
|
||||
self.options.breakout_trap_weight.value + \
|
||||
self.options.fishing_trap_weight.value + \
|
||||
self.options.trivia_trap_weight.value + \
|
||||
self.options.pokemon_trivia_trap_weight.value + \
|
||||
self.options.pokemon_count_trap_weight.value + \
|
||||
self.options.number_sequence_trap_weight.value + \
|
||||
self.options.light_up_path_trap_weight.value + \
|
||||
self.options.pinball_trap_weight.value + \
|
||||
self.options.math_quiz_trap_weight.value + \
|
||||
self.options.snake_trap_weight.value + \
|
||||
self.options.input_sequence_trap_weight.value
|
||||
|
||||
if valid_trap_weights == 0:
|
||||
self.options.exposition_trap_weight.value = 4
|
||||
self.options.reverse_trap_weight.value = 4
|
||||
self.options.literature_trap_weight.value = 4
|
||||
self.options.controller_drift_trap_weight.value = 4
|
||||
self.options.poison_trap_weight.value = 4
|
||||
self.options.bee_trap_weight.value = 4
|
||||
self.options.pong_trap_weight.value = 4
|
||||
self.options.breakout_trap_weight.value = 4
|
||||
self.options.fishing_trap_weight.value = 4
|
||||
self.options.trivia_trap_weight.value = 4
|
||||
self.options.pokemon_trivia_trap_weight.value = 4
|
||||
self.options.pokemon_count_trap_weight.value = 4
|
||||
self.options.number_sequence_trap_weight.value = 4
|
||||
self.options.light_up_path_trap_weight.value = 4
|
||||
self.options.pinball_trap_weight.value = 4
|
||||
self.options.math_quiz_trap_weight.value = 4
|
||||
self.options.snake_trap_weight.value = 4
|
||||
self.options.input_sequence_trap_weight.value = 4
|
||||
|
||||
if self.options.kart_race_checks.value == 0:
|
||||
self.options.kart_race_checks.value = 2
|
||||
@@ -164,8 +206,8 @@ class SA2BWorld(World):
|
||||
self.gate_bosses = {}
|
||||
self.boss_rush_map = {}
|
||||
else:
|
||||
self.gate_bosses = get_gate_bosses(self.multiworld, self)
|
||||
self.boss_rush_map = get_boss_rush_bosses(self.multiworld, self)
|
||||
self.gate_bosses = get_gate_bosses(self)
|
||||
self.boss_rush_map = get_boss_rush_bosses(self)
|
||||
|
||||
def create_regions(self):
|
||||
self.mission_map = get_mission_table(self.multiworld, self, self.player)
|
||||
@@ -177,7 +219,7 @@ class SA2BWorld(World):
|
||||
# Not Generate Basic
|
||||
self.black_market_costs = dict()
|
||||
|
||||
if self.options.goal.value in [0, 2, 4, 5, 6]:
|
||||
if self.options.goal.value in [0, 2, 4, 5, 6, 8]:
|
||||
self.multiworld.get_location(LocationName.finalhazard, self.player).place_locked_item(self.create_item(ItemName.maria))
|
||||
elif self.options.goal.value == 1:
|
||||
self.multiworld.get_location(LocationName.green_hill, self.player).place_locked_item(self.create_item(ItemName.maria))
|
||||
@@ -202,7 +244,7 @@ class SA2BWorld(World):
|
||||
if self.options.goal.value != 3:
|
||||
# Fill item pool with all required items
|
||||
for item in {**upgrades_table}:
|
||||
itempool += [self.create_item(item, False, self.options.goal.value)]
|
||||
itempool += [self.create_item(item, None, self.options.goal.value)]
|
||||
|
||||
if self.options.goal.value in [1, 2, 6]:
|
||||
# Some flavor of Chaos Emerald Hunt
|
||||
@@ -212,6 +254,25 @@ class SA2BWorld(World):
|
||||
# Black Market
|
||||
itempool += [self.create_item(ItemName.market_token) for _ in range(self.options.black_market_slots.value)]
|
||||
|
||||
if self.options.goal.value in [8]:
|
||||
available_locations: int = total_required_locations - len(itempool) - self.options.number_of_level_gates.value
|
||||
|
||||
while (self.options.minigame_madness_requirement.value * len(minigame_trap_table)) > available_locations:
|
||||
self.options.minigame_madness_requirement.value -= 1
|
||||
|
||||
while (self.options.minigame_madness_minimum.value * len(minigame_trap_table)) > available_locations:
|
||||
self.options.minigame_madness_minimum.value -= 1
|
||||
|
||||
traps_to_create: int = max(self.options.minigame_madness_minimum.value, self.options.minigame_madness_requirement.value)
|
||||
|
||||
# Minigame Madness
|
||||
for item in {**minigame_trap_table}:
|
||||
for i in range(traps_to_create):
|
||||
classification: ItemClassification = ItemClassification.trap
|
||||
if i < self.options.minigame_madness_requirement.value:
|
||||
classification |= ItemClassification.progression
|
||||
itempool.append(self.create_item(item, classification))
|
||||
|
||||
black_market_unlock_mult = 1.0
|
||||
if self.options.black_market_unlock_costs.value == 0:
|
||||
black_market_unlock_mult = 0.5
|
||||
@@ -235,12 +296,12 @@ class SA2BWorld(World):
|
||||
elif self.options.level_gate_costs.value == 1:
|
||||
gate_cost_mult = 0.8
|
||||
|
||||
shuffled_region_list = list(range(30))
|
||||
self.shuffled_region_list = list(range(30))
|
||||
emblem_requirement_list = list()
|
||||
self.multiworld.random.shuffle(shuffled_region_list)
|
||||
levels_per_gate = self.get_levels_per_gate()
|
||||
self.multiworld.random.shuffle(self.shuffled_region_list)
|
||||
self.levels_per_gate = self.get_levels_per_gate()
|
||||
|
||||
check_for_impossible_shuffle(shuffled_region_list, math.ceil(levels_per_gate[0]), self.multiworld)
|
||||
check_for_impossible_shuffle(self.shuffled_region_list, math.ceil(self.levels_per_gate[0]), self.multiworld)
|
||||
levels_added_to_gate = 0
|
||||
total_levels_added = 0
|
||||
current_gate = 0
|
||||
@@ -250,11 +311,11 @@ class SA2BWorld(World):
|
||||
gates = list()
|
||||
gates.append(LevelGate(0))
|
||||
for i in range(30):
|
||||
gates[current_gate].gate_levels.append(shuffled_region_list[i])
|
||||
gates[current_gate].gate_levels.append(self.shuffled_region_list[i])
|
||||
emblem_requirement_list.append(current_gate_emblems)
|
||||
levels_added_to_gate += 1
|
||||
total_levels_added += 1
|
||||
if levels_added_to_gate >= levels_per_gate[current_gate]:
|
||||
if levels_added_to_gate >= self.levels_per_gate[current_gate]:
|
||||
current_gate += 1
|
||||
if current_gate > self.options.number_of_level_gates.value:
|
||||
current_gate = self.options.number_of_level_gates.value
|
||||
@@ -265,18 +326,19 @@ class SA2BWorld(World):
|
||||
self.gate_costs[current_gate] = current_gate_emblems
|
||||
levels_added_to_gate = 0
|
||||
|
||||
self.region_emblem_map = dict(zip(shuffled_region_list, emblem_requirement_list))
|
||||
self.region_emblem_map = dict(zip(self.shuffled_region_list, emblem_requirement_list))
|
||||
|
||||
first_cannons_core_mission, final_cannons_core_mission = get_first_and_last_cannons_core_missions(self.mission_map, self.mission_count_map)
|
||||
|
||||
connect_regions(self.multiworld, self, self.player, gates, self.emblems_for_cannons_core, self.gate_bosses, self.boss_rush_map, first_cannons_core_mission, final_cannons_core_mission)
|
||||
|
||||
max_required_emblems = max(max(emblem_requirement_list), self.emblems_for_cannons_core)
|
||||
max_required_emblems = min(int(max_required_emblems * 1.1), total_emblem_count)
|
||||
itempool += [self.create_item(ItemName.emblem) for _ in range(max_required_emblems)]
|
||||
|
||||
non_required_emblems = (total_emblem_count - max_required_emblems)
|
||||
junk_count = math.floor(non_required_emblems * (self.options.junk_fill_percentage.value / 100.0))
|
||||
itempool += [self.create_item(ItemName.emblem, True) for _ in range(non_required_emblems - junk_count)]
|
||||
itempool += [self.create_item(ItemName.emblem, ItemClassification.filler) for _ in range(non_required_emblems - junk_count)]
|
||||
|
||||
# Carve Traps out of junk_count
|
||||
trap_weights = []
|
||||
@@ -291,7 +353,22 @@ class SA2BWorld(World):
|
||||
trap_weights += ([ItemName.slow_trap] * self.options.slow_trap_weight.value)
|
||||
trap_weights += ([ItemName.cutscene_trap] * self.options.cutscene_trap_weight.value)
|
||||
trap_weights += ([ItemName.reverse_trap] * self.options.reverse_trap_weight.value)
|
||||
trap_weights += ([ItemName.literature_trap] * self.options.literature_trap_weight.value)
|
||||
trap_weights += ([ItemName.controller_drift_trap] * self.options.controller_drift_trap_weight.value)
|
||||
trap_weights += ([ItemName.poison_trap] * self.options.poison_trap_weight.value)
|
||||
trap_weights += ([ItemName.bee_trap] * self.options.bee_trap_weight.value)
|
||||
trap_weights += ([ItemName.pong_trap] * self.options.pong_trap_weight.value)
|
||||
trap_weights += ([ItemName.breakout_trap] * self.options.breakout_trap_weight.value)
|
||||
trap_weights += ([ItemName.fishing_trap] * self.options.fishing_trap_weight.value)
|
||||
trap_weights += ([ItemName.trivia_trap] * self.options.trivia_trap_weight.value)
|
||||
trap_weights += ([ItemName.pokemon_trivia_trap] * self.options.pokemon_trivia_trap_weight.value)
|
||||
trap_weights += ([ItemName.pokemon_count_trap] * self.options.pokemon_count_trap_weight.value)
|
||||
trap_weights += ([ItemName.number_sequence_trap] * self.options.number_sequence_trap_weight.value)
|
||||
trap_weights += ([ItemName.light_up_path_trap] * self.options.light_up_path_trap_weight.value)
|
||||
trap_weights += ([ItemName.pinball_trap] * self.options.pinball_trap_weight.value)
|
||||
trap_weights += ([ItemName.math_quiz_trap] * self.options.math_quiz_trap_weight.value)
|
||||
trap_weights += ([ItemName.snake_trap] * self.options.snake_trap_weight.value)
|
||||
trap_weights += ([ItemName.input_sequence_trap] * self.options.input_sequence_trap_weight.value)
|
||||
|
||||
junk_count += extra_junk_count
|
||||
trap_count = 0 if (len(trap_weights) == 0) else math.ceil(junk_count * (self.options.trap_fill_percentage.value / 100.0))
|
||||
@@ -347,11 +424,15 @@ class SA2BWorld(World):
|
||||
|
||||
|
||||
|
||||
def create_item(self, name: str, force_non_progression=False, goal=0) -> Item:
|
||||
data = item_table[name]
|
||||
def create_item(self, name: str, force_classification=None, goal=0) -> Item:
|
||||
data = None
|
||||
if name in event_table:
|
||||
data = event_table[name]
|
||||
else:
|
||||
data = item_table[name]
|
||||
|
||||
if force_non_progression:
|
||||
classification = ItemClassification.filler
|
||||
if force_classification is not None:
|
||||
classification = force_classification
|
||||
elif name == ItemName.emblem or \
|
||||
name in emeralds_table.keys() or \
|
||||
(name == ItemName.knuckles_shovel_claws and goal in [4, 5]):
|
||||
@@ -380,9 +461,16 @@ class SA2BWorld(World):
|
||||
set_rules(self.multiworld, self, self.player, self.gate_bosses, self.boss_rush_map, self.mission_map, self.mission_count_map, self.black_market_costs)
|
||||
|
||||
def write_spoiler(self, spoiler_handle: typing.TextIO):
|
||||
print_mission_orders_to_spoiler(self.mission_map,
|
||||
self.mission_count_map,
|
||||
self.shuffled_region_list,
|
||||
self.levels_per_gate,
|
||||
self.multiworld.player_name[self.player],
|
||||
spoiler_handle)
|
||||
|
||||
if self.options.number_of_level_gates.value > 0 or self.options.goal.value in [4, 5, 6]:
|
||||
spoiler_handle.write("\n")
|
||||
header_text = "Sonic Adventure 2 Bosses for {}:\n"
|
||||
header_text = "SA2 Bosses for {}:\n"
|
||||
header_text = header_text.format(self.multiworld.player_name[self.player])
|
||||
spoiler_handle.write(header_text)
|
||||
|
||||
@@ -435,20 +523,20 @@ class SA2BWorld(World):
|
||||
continue
|
||||
level_region = exit.connected_region
|
||||
for location in level_region.locations:
|
||||
er_hint_data[location.address] = gate_name
|
||||
if location.address != None:
|
||||
er_hint_data[location.address] = gate_name
|
||||
|
||||
for i in range(self.options.black_market_slots.value):
|
||||
location = self.multiworld.get_location(LocationName.chao_black_market_base + str(i + 1), self.player)
|
||||
er_hint_data[location.address] = str(self.black_market_costs[i]) + " " + str(ItemName.market_token)
|
||||
|
||||
|
||||
hint_data[self.player] = er_hint_data
|
||||
|
||||
@classmethod
|
||||
def stage_fill_hook(cls, multiworld: MultiWorld, progitempool, usefulitempool, filleritempool, fill_locations):
|
||||
if multiworld.get_game_players("Sonic Adventure 2 Battle"):
|
||||
progitempool.sort(
|
||||
key=lambda item: 0 if (item.name != 'Emblem') else 1)
|
||||
key=lambda item: 0 if ("Emblem" in item.name and item.game == "Sonic Adventure 2 Battle") else 1)
|
||||
|
||||
def get_levels_per_gate(self) -> list:
|
||||
levels_per_gate = list()
|
||||
@@ -486,6 +574,39 @@ class SA2BWorld(World):
|
||||
|
||||
return levels_per_gate
|
||||
|
||||
def output_active_traps(self) -> typing.Dict[int, int]:
|
||||
trap_data = {}
|
||||
|
||||
trap_data[0x30] = self.options.omochao_trap_weight.value
|
||||
trap_data[0x31] = self.options.timestop_trap_weight.value
|
||||
trap_data[0x32] = self.options.confusion_trap_weight.value
|
||||
trap_data[0x33] = self.options.tiny_trap_weight.value
|
||||
trap_data[0x34] = self.options.gravity_trap_weight.value
|
||||
trap_data[0x35] = self.options.exposition_trap_weight.value
|
||||
trap_data[0x37] = self.options.ice_trap_weight.value
|
||||
trap_data[0x38] = self.options.slow_trap_weight.value
|
||||
trap_data[0x39] = self.options.cutscene_trap_weight.value
|
||||
trap_data[0x3A] = self.options.reverse_trap_weight.value
|
||||
trap_data[0x3B] = self.options.literature_trap_weight.value
|
||||
trap_data[0x3C] = self.options.controller_drift_trap_weight.value
|
||||
trap_data[0x3D] = self.options.poison_trap_weight.value
|
||||
trap_data[0x3E] = self.options.bee_trap_weight.value
|
||||
|
||||
trap_data[0x50] = self.options.pong_trap_weight.value
|
||||
trap_data[0x51] = self.options.breakout_trap_weight.value
|
||||
trap_data[0x52] = self.options.fishing_trap_weight.value
|
||||
trap_data[0x53] = self.options.trivia_trap_weight.value
|
||||
trap_data[0x54] = self.options.pokemon_trivia_trap_weight.value
|
||||
trap_data[0x55] = self.options.pokemon_count_trap_weight.value
|
||||
trap_data[0x56] = self.options.number_sequence_trap_weight.value
|
||||
trap_data[0x57] = self.options.light_up_path_trap_weight.value
|
||||
trap_data[0x58] = self.options.pinball_trap_weight.value
|
||||
trap_data[0x59] = self.options.math_quiz_trap_weight.value
|
||||
trap_data[0x5A] = self.options.snake_trap_weight.value
|
||||
trap_data[0x5B] = self.options.input_sequence_trap_weight.value
|
||||
|
||||
return trap_data
|
||||
|
||||
def any_chao_locations_active(self) -> bool:
|
||||
if self.options.chao_race_difficulty.value > 0 or \
|
||||
self.options.chao_karate_difficulty.value > 0 or \
|
||||
@@ -686,7 +807,6 @@ class SA2BWorld(World):
|
||||
exit_choice = self.random.choice(valid_kindergarten_exits)
|
||||
exit_room = exit_to_room_map[exit_choice]
|
||||
all_exits_copy.remove(exit_choice)
|
||||
multi_rooms_copy.remove(exit_room)
|
||||
|
||||
destination = 0x06
|
||||
single_rooms_copy.remove(destination)
|
||||
@@ -723,7 +843,8 @@ class SA2BWorld(World):
|
||||
|
||||
er_layout[exit_choice] = destination
|
||||
|
||||
reverse_exit = self.random.choice(room_to_exits_map[destination])
|
||||
possible_reverse_exits = [exit for exit in room_to_exits_map[destination] if exit in all_exits_copy]
|
||||
reverse_exit = self.random.choice(possible_reverse_exits)
|
||||
|
||||
er_layout[reverse_exit] = exit_room
|
||||
|
||||
|
||||
@@ -129,7 +129,10 @@ If you wish to use the `SADX Music` option of the Randomizer, you must own a cop
|
||||
- If you enabled an `SADX Music` option, then most likely the music data was not copied properly into the mod folder (See Additional Options for instructions).
|
||||
|
||||
- Mission 1 is missing a texture in the stage select UI.
|
||||
- Most likely another mod is conflicting and overwriting the texture pack. It is recommeded to have the SA2B Archipelago mod load last in the mod manager.
|
||||
- Most likely another mod is conflicting and overwriting the texture pack. It is recommended to have the SA2B Archipelago mod load last in the mod manager.
|
||||
|
||||
- Minigame trap is un-winnable
|
||||
- If you are using the SA2 Input Controls mod, it conflicts with certain minigames such as the Input Sequence Trap and medium difficulty Fishing Trap. Disabling the SA2 Input Controls mod should resolve the issue.
|
||||
|
||||
## Save File Safeguard (Advanced Option)
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ class Starcraft2WebWorld(WebWorld):
|
||||
)
|
||||
|
||||
tutorials = [setup_en, setup_fr]
|
||||
game_info_languages = ["en", "fr"]
|
||||
|
||||
|
||||
class SC2World(World):
|
||||
|
||||
@@ -124,7 +124,7 @@ class SMWorld(World):
|
||||
Logic.factory('vanilla')
|
||||
|
||||
dummy_rom_file = Utils.user_path(SMSettings.RomFile.copy_to) # actual rom set in generate_output
|
||||
self.variaRando = VariaRandomizer(self.options, dummy_rom_file, self.player)
|
||||
self.variaRando = VariaRandomizer(self.options, dummy_rom_file, self.player, self.multiworld.seed, self.random)
|
||||
self.multiworld.state.smbm[self.player] = SMBoolManager(self.player, self.variaRando.maxDifficulty)
|
||||
|
||||
# keeps Nothing items local so no player will ever pickup Nothing
|
||||
@@ -314,11 +314,11 @@ class SMWorld(World):
|
||||
raise KeyError(f"Item {name} for {self.player_name} is invalid.")
|
||||
|
||||
def get_filler_item_name(self) -> str:
|
||||
if self.multiworld.random.randint(0, 100) < self.options.minor_qty.value:
|
||||
if self.random.randint(0, 100) < self.options.minor_qty.value:
|
||||
power_bombs = self.options.power_bomb_qty.value
|
||||
missiles = self.options.missile_qty.value
|
||||
super_missiles = self.options.super_qty.value
|
||||
roll = self.multiworld.random.randint(1, power_bombs + missiles + super_missiles)
|
||||
roll = self.random.randint(1, power_bombs + missiles + super_missiles)
|
||||
if roll <= power_bombs:
|
||||
return "Power Bomb"
|
||||
elif roll <= power_bombs + missiles:
|
||||
@@ -340,8 +340,8 @@ class SMWorld(World):
|
||||
else:
|
||||
nonChozoLoc.append(loc)
|
||||
|
||||
self.multiworld.random.shuffle(nonChozoLoc)
|
||||
self.multiworld.random.shuffle(chozoLoc)
|
||||
self.random.shuffle(nonChozoLoc)
|
||||
self.random.shuffle(chozoLoc)
|
||||
missingCount = len(self.NothingPool) - len(nonChozoLoc)
|
||||
locations = nonChozoLoc
|
||||
if (missingCount > 0):
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import copy
|
||||
import random
|
||||
from ..logic.logic import Logic
|
||||
from ..utils.parameters import Knows
|
||||
from ..graph.location import locationsDict
|
||||
@@ -136,7 +135,8 @@ class GraphUtils:
|
||||
refused[apName] = cause
|
||||
return ret, refused
|
||||
|
||||
def updateLocClassesStart(startGraphArea, split, possibleMajLocs, preserveMajLocs, nLocs):
|
||||
@staticmethod
|
||||
def updateLocClassesStart(startGraphArea, split, possibleMajLocs, preserveMajLocs, nLocs, random):
|
||||
locs = locationsDict
|
||||
preserveMajLocs = [locs[locName] for locName in preserveMajLocs if locs[locName].isClass(split)]
|
||||
possLocs = [locs[locName] for locName in possibleMajLocs][:nLocs]
|
||||
@@ -160,7 +160,8 @@ class GraphUtils:
|
||||
ap = getAccessPoint(startApName)
|
||||
return ap.Start['patches'] if 'patches' in ap.Start else []
|
||||
|
||||
def createBossesTransitions():
|
||||
@staticmethod
|
||||
def createBossesTransitions(random):
|
||||
transitions = vanillaBossesTransitions
|
||||
def isVanilla():
|
||||
for t in vanillaBossesTransitions:
|
||||
@@ -180,13 +181,15 @@ class GraphUtils:
|
||||
transitions.append((src,dst))
|
||||
return transitions
|
||||
|
||||
def createAreaTransitions(lightAreaRando=False):
|
||||
@staticmethod
|
||||
def createAreaTransitions(lightAreaRando=False, *, random):
|
||||
if lightAreaRando:
|
||||
return GraphUtils.createLightAreaTransitions()
|
||||
return GraphUtils.createLightAreaTransitions(random=random)
|
||||
else:
|
||||
return GraphUtils.createRegularAreaTransitions()
|
||||
return GraphUtils.createRegularAreaTransitions(random=random)
|
||||
|
||||
def createRegularAreaTransitions(apList=None, apPred=None):
|
||||
@staticmethod
|
||||
def createRegularAreaTransitions(apList=None, apPred=None, *, random):
|
||||
if apList is None:
|
||||
apList = Logic.accessPoints
|
||||
if apPred is None:
|
||||
@@ -239,7 +242,8 @@ class GraphUtils:
|
||||
transitions.append((ap.Name, ap.Name))
|
||||
|
||||
# crateria can be forced in corner cases
|
||||
def createMinimizerTransitions(startApName, locLimit, forcedAreas=None):
|
||||
@staticmethod
|
||||
def createMinimizerTransitions(startApName, locLimit, forcedAreas=None, *, random):
|
||||
if forcedAreas is None:
|
||||
forcedAreas = []
|
||||
if startApName == 'Ceres':
|
||||
@@ -316,7 +320,8 @@ class GraphUtils:
|
||||
GraphUtils.log.debug("FINAL MINIMIZER areas: "+str(areas))
|
||||
return transitions
|
||||
|
||||
def createLightAreaTransitions():
|
||||
@staticmethod
|
||||
def createLightAreaTransitions(random):
|
||||
# group APs by area
|
||||
aps = {}
|
||||
totalCount = 0
|
||||
@@ -407,7 +412,8 @@ class GraphUtils:
|
||||
|
||||
return rooms
|
||||
|
||||
def escapeAnimalsTransitions(graph, possibleTargets, firstEscape):
|
||||
@staticmethod
|
||||
def escapeAnimalsTransitions(graph, possibleTargets, firstEscape, random):
|
||||
n = len(possibleTargets)
|
||||
assert (n < 4 and firstEscape is not None) or (n <= 4 and firstEscape is None), "Invalid possibleTargets list: " + str(possibleTargets)
|
||||
GraphUtils.log.debug("escapeAnimalsTransitions. possibleTargets="+str(possibleTargets)+", firstEscape="+str(firstEscape))
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import random
|
||||
from ..utils import log
|
||||
from ..utils.utils import getRangeDict, chooseFromRange
|
||||
from ..rando.ItemLocContainer import ItemLocation
|
||||
@@ -23,8 +22,9 @@ class Choice(object):
|
||||
|
||||
# simple random choice, that chooses an item first, then a locatio to put it in
|
||||
class ItemThenLocChoice(Choice):
|
||||
def __init__(self, restrictions):
|
||||
def __init__(self, restrictions, random):
|
||||
super(ItemThenLocChoice, self).__init__(restrictions)
|
||||
self.random = random
|
||||
|
||||
def chooseItemLoc(self, itemLocDict, isProg):
|
||||
itemList = self.getItemList(itemLocDict)
|
||||
@@ -49,7 +49,7 @@ class ItemThenLocChoice(Choice):
|
||||
return self.chooseItemRandom(itemList)
|
||||
|
||||
def chooseItemRandom(self, itemList):
|
||||
return random.choice(itemList)
|
||||
return self.random.choice(itemList)
|
||||
|
||||
def chooseLocation(self, locList, item, isProg):
|
||||
if len(locList) == 0:
|
||||
@@ -63,12 +63,12 @@ class ItemThenLocChoice(Choice):
|
||||
return self.chooseLocationRandom(locList)
|
||||
|
||||
def chooseLocationRandom(self, locList):
|
||||
return random.choice(locList)
|
||||
return self.random.choice(locList)
|
||||
|
||||
# Choice specialization for prog speed based filler
|
||||
class ItemThenLocChoiceProgSpeed(ItemThenLocChoice):
|
||||
def __init__(self, restrictions, progSpeedParams, distanceProp, services):
|
||||
super(ItemThenLocChoiceProgSpeed, self).__init__(restrictions)
|
||||
def __init__(self, restrictions, progSpeedParams, distanceProp, services, random):
|
||||
super(ItemThenLocChoiceProgSpeed, self).__init__(restrictions, random)
|
||||
self.progSpeedParams = progSpeedParams
|
||||
self.distanceProp = distanceProp
|
||||
self.services = services
|
||||
@@ -104,7 +104,7 @@ class ItemThenLocChoiceProgSpeed(ItemThenLocChoice):
|
||||
if self.restrictions.isLateMorph() and canRollback and len(itemLocDict) == 1:
|
||||
item, locList = list(itemLocDict.items())[0]
|
||||
if item.Type == 'Morph':
|
||||
morphLocs = self.restrictions.lateMorphCheck(container, locList)
|
||||
morphLocs = self.restrictions.lateMorphCheck(container, locList, self.random)
|
||||
if morphLocs is not None:
|
||||
itemLocDict[item] = morphLocs
|
||||
else:
|
||||
@@ -115,7 +115,7 @@ class ItemThenLocChoiceProgSpeed(ItemThenLocChoice):
|
||||
assert len(locs) == 1 and locs[0].Name == item.Name
|
||||
return ItemLocation(item, locs[0])
|
||||
# late doors check for random door colors
|
||||
if self.restrictions.isLateDoors() and random.random() < self.lateDoorsProb:
|
||||
if self.restrictions.isLateDoors() and self.random.random() < self.lateDoorsProb:
|
||||
self.processLateDoors(itemLocDict, ap, container)
|
||||
self.progressionItemLocs = progressionItemLocs
|
||||
self.ap = ap
|
||||
@@ -145,14 +145,14 @@ class ItemThenLocChoiceProgSpeed(ItemThenLocChoice):
|
||||
|
||||
def chooseLocationProg(self, locs, item):
|
||||
locs = self.getLocsSpreadProgression(locs)
|
||||
random.shuffle(locs)
|
||||
self.random.shuffle(locs)
|
||||
ret = self.getChooseFunc(self.chooseLocRanges, self.chooseLocFuncs)(locs)
|
||||
self.log.debug('chooseLocationProg. ret='+ret.Name)
|
||||
return ret
|
||||
|
||||
# get choose function from a weighted dict
|
||||
def getChooseFunc(self, rangeDict, funcDict):
|
||||
v = chooseFromRange(rangeDict)
|
||||
v = chooseFromRange(rangeDict, self.random)
|
||||
|
||||
return funcDict[v]
|
||||
|
||||
@@ -209,6 +209,6 @@ class ItemThenLocChoiceProgSpeed(ItemThenLocChoice):
|
||||
for i in range(len(availableLocations)):
|
||||
loc = availableLocations[i]
|
||||
d = distances[i]
|
||||
if d == maxDist or random.random() >= self.spreadProb:
|
||||
if d == maxDist or self.random.random() >= self.spreadProb:
|
||||
locs.append(loc)
|
||||
return locs
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
import copy, time, random
|
||||
import copy, time
|
||||
from ..utils import log
|
||||
from ..logic.cache import RequestCache
|
||||
from ..rando.RandoServices import RandoServices
|
||||
@@ -15,11 +15,11 @@ from ..graph.graph_utils import GraphUtils
|
||||
# item pool is not empty).
|
||||
# entry point is generateItems
|
||||
class Filler(object):
|
||||
def __init__(self, startAP, graph, restrictions, emptyContainer, endDate=infinity):
|
||||
def __init__(self, startAP, graph, restrictions, emptyContainer, endDate=infinity, *, random):
|
||||
self.startAP = startAP
|
||||
self.cache = RequestCache()
|
||||
self.graph = graph
|
||||
self.services = RandoServices(graph, restrictions, self.cache)
|
||||
self.services = RandoServices(graph, restrictions, self.cache, random=random)
|
||||
self.restrictions = restrictions
|
||||
self.settings = restrictions.settings
|
||||
self.endDate = endDate
|
||||
@@ -108,9 +108,9 @@ class Filler(object):
|
||||
|
||||
# very simple front fill algorithm with no rollback and no "softlock checks" (== dessy algorithm)
|
||||
class FrontFiller(Filler):
|
||||
def __init__(self, startAP, graph, restrictions, emptyContainer, endDate=infinity):
|
||||
super(FrontFiller, self).__init__(startAP, graph, restrictions, emptyContainer, endDate)
|
||||
self.choice = ItemThenLocChoice(restrictions)
|
||||
def __init__(self, startAP, graph, restrictions, emptyContainer, endDate=infinity, *, random):
|
||||
super(FrontFiller, self).__init__(startAP, graph, restrictions, emptyContainer, endDate, random=random)
|
||||
self.choice = ItemThenLocChoice(restrictions, random)
|
||||
self.stdStart = GraphUtils.isStandardStart(self.startAP)
|
||||
|
||||
def isEarlyGame(self):
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
import random, copy
|
||||
import copy
|
||||
from ..utils import log
|
||||
from ..graph.graph_utils import GraphUtils, vanillaTransitions, vanillaBossesTransitions, escapeSource, escapeTargets, graphAreas, getAccessPoint
|
||||
from ..logic.logic import Logic
|
||||
@@ -11,13 +11,14 @@ from collections import defaultdict
|
||||
|
||||
# creates graph and handles randomized escape
|
||||
class GraphBuilder(object):
|
||||
def __init__(self, graphSettings):
|
||||
def __init__(self, graphSettings, random):
|
||||
self.graphSettings = graphSettings
|
||||
self.areaRando = graphSettings.areaRando
|
||||
self.bossRando = graphSettings.bossRando
|
||||
self.escapeRando = graphSettings.escapeRando
|
||||
self.minimizerN = graphSettings.minimizerN
|
||||
self.log = log.get('GraphBuilder')
|
||||
self.random = random
|
||||
|
||||
# builds everything but escape transitions
|
||||
def createGraph(self, maxDiff):
|
||||
@@ -48,18 +49,18 @@ class GraphBuilder(object):
|
||||
objForced = forcedAreas.intersection(escAreas)
|
||||
escAreasList = sorted(list(escAreas))
|
||||
while len(objForced) < n and len(escAreasList) > 0:
|
||||
objForced.add(escAreasList.pop(random.randint(0, len(escAreasList)-1)))
|
||||
objForced.add(escAreasList.pop(self.random.randint(0, len(escAreasList)-1)))
|
||||
forcedAreas = forcedAreas.union(objForced)
|
||||
transitions = GraphUtils.createMinimizerTransitions(self.graphSettings.startAP, self.minimizerN, sorted(list(forcedAreas)))
|
||||
transitions = GraphUtils.createMinimizerTransitions(self.graphSettings.startAP, self.minimizerN, sorted(list(forcedAreas)), random=self.random)
|
||||
else:
|
||||
if not self.bossRando:
|
||||
transitions += vanillaBossesTransitions
|
||||
else:
|
||||
transitions += GraphUtils.createBossesTransitions()
|
||||
transitions += GraphUtils.createBossesTransitions(self.random)
|
||||
if not self.areaRando:
|
||||
transitions += vanillaTransitions
|
||||
else:
|
||||
transitions += GraphUtils.createAreaTransitions(self.graphSettings.lightAreaRando)
|
||||
transitions += GraphUtils.createAreaTransitions(self.graphSettings.lightAreaRando, random=self.random)
|
||||
ret = AccessGraph(Logic.accessPoints, transitions, self.graphSettings.dotFile)
|
||||
Objectives.objDict[self.graphSettings.player].setGraph(ret, maxDiff)
|
||||
return ret
|
||||
@@ -100,7 +101,7 @@ class GraphBuilder(object):
|
||||
self.escapeTimer(graph, paths, self.areaRando or escapeTrigger is not None)
|
||||
self.log.debug("escapeGraph: ({}, {}) timer: {}".format(escapeSource, dst, graph.EscapeAttributes['Timer']))
|
||||
# animals
|
||||
GraphUtils.escapeAnimalsTransitions(graph, possibleTargets, dst)
|
||||
GraphUtils.escapeAnimalsTransitions(graph, possibleTargets, dst, self.random)
|
||||
return True
|
||||
|
||||
def _getTargets(self, sm, graph, maxDiff):
|
||||
@@ -110,7 +111,7 @@ class GraphBuilder(object):
|
||||
if len(possibleTargets) == 0:
|
||||
self.log.debug("Can't randomize escape, fallback to vanilla")
|
||||
possibleTargets.append('Climb Bottom Left')
|
||||
random.shuffle(possibleTargets)
|
||||
self.random.shuffle(possibleTargets)
|
||||
return possibleTargets
|
||||
|
||||
def getPossibleEscapeTargets(self, emptyContainer, graph, maxDiff):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from ..utils.utils import randGaussBounds, getRangeDict, chooseFromRange
|
||||
from ..utils import log
|
||||
import logging, copy, random
|
||||
import logging, copy
|
||||
|
||||
class Item:
|
||||
__slots__ = ( 'Category', 'Class', 'Name', 'Code', 'Type', 'BeamBits', 'ItemBits', 'Id' )
|
||||
@@ -335,7 +335,7 @@ class ItemManager:
|
||||
itemCode = item.Code + modifier
|
||||
return itemCode
|
||||
|
||||
def __init__(self, majorsSplit, qty, sm, nLocs, bossesItems, maxDiff):
|
||||
def __init__(self, majorsSplit, qty, sm, nLocs, bossesItems, maxDiff, random):
|
||||
self.qty = qty
|
||||
self.sm = sm
|
||||
self.majorsSplit = majorsSplit
|
||||
@@ -344,6 +344,7 @@ class ItemManager:
|
||||
self.maxDiff = maxDiff
|
||||
self.majorClass = 'Chozo' if majorsSplit == 'Chozo' else 'Major'
|
||||
self.itemPool = []
|
||||
self.random = random
|
||||
|
||||
def newItemPool(self, addBosses=True):
|
||||
self.itemPool = []
|
||||
@@ -386,7 +387,7 @@ class ItemManager:
|
||||
return ItemManager.Items[itemType].withClass(itemClass)
|
||||
|
||||
def createItemPool(self, exclude=None):
|
||||
itemPoolGenerator = ItemPoolGenerator.factory(self.majorsSplit, self, self.qty, self.sm, exclude, self.nLocs, self.maxDiff)
|
||||
itemPoolGenerator = ItemPoolGenerator.factory(self.majorsSplit, self, self.qty, self.sm, exclude, self.nLocs, self.maxDiff, self.random)
|
||||
self.itemPool = itemPoolGenerator.getItemPool()
|
||||
|
||||
@staticmethod
|
||||
@@ -402,20 +403,20 @@ class ItemPoolGenerator(object):
|
||||
nbBosses = 9
|
||||
|
||||
@staticmethod
|
||||
def factory(majorsSplit, itemManager, qty, sm, exclude, nLocs, maxDiff):
|
||||
def factory(majorsSplit, itemManager, qty, sm, exclude, nLocs, maxDiff, random):
|
||||
if majorsSplit == 'Chozo':
|
||||
return ItemPoolGeneratorChozo(itemManager, qty, sm, maxDiff)
|
||||
return ItemPoolGeneratorChozo(itemManager, qty, sm, maxDiff, random)
|
||||
elif majorsSplit == 'Plando':
|
||||
return ItemPoolGeneratorPlando(itemManager, qty, sm, exclude, nLocs, maxDiff)
|
||||
return ItemPoolGeneratorPlando(itemManager, qty, sm, exclude, nLocs, maxDiff, random)
|
||||
elif nLocs == ItemPoolGenerator.maxLocs:
|
||||
if majorsSplit == "Scavenger":
|
||||
return ItemPoolGeneratorScavenger(itemManager, qty, sm, maxDiff)
|
||||
return ItemPoolGeneratorScavenger(itemManager, qty, sm, maxDiff, random)
|
||||
else:
|
||||
return ItemPoolGeneratorMajors(itemManager, qty, sm, maxDiff)
|
||||
return ItemPoolGeneratorMajors(itemManager, qty, sm, maxDiff, random)
|
||||
else:
|
||||
return ItemPoolGeneratorMinimizer(itemManager, qty, sm, nLocs, maxDiff)
|
||||
return ItemPoolGeneratorMinimizer(itemManager, qty, sm, nLocs, maxDiff, random)
|
||||
|
||||
def __init__(self, itemManager, qty, sm, maxDiff):
|
||||
def __init__(self, itemManager, qty, sm, maxDiff, random):
|
||||
self.itemManager = itemManager
|
||||
self.qty = qty
|
||||
self.sm = sm
|
||||
@@ -423,12 +424,13 @@ class ItemPoolGenerator(object):
|
||||
self.maxEnergy = 18 # 14E, 4R
|
||||
self.maxDiff = maxDiff
|
||||
self.log = log.get('ItemPool')
|
||||
self.random = random
|
||||
|
||||
def isUltraSparseNoTanks(self):
|
||||
# if low stuff botwoon is not known there is a hard energy req of one tank, even
|
||||
# with both suits
|
||||
lowStuffBotwoon = self.sm.knowsLowStuffBotwoon()
|
||||
return random.random() < 0.5 and (lowStuffBotwoon.bool == True and lowStuffBotwoon.difficulty <= self.maxDiff)
|
||||
return self.random.random() < 0.5 and (lowStuffBotwoon.bool == True and lowStuffBotwoon.difficulty <= self.maxDiff)
|
||||
|
||||
def calcMaxMinors(self):
|
||||
pool = self.itemManager.getItemPool()
|
||||
@@ -464,7 +466,7 @@ class ItemPoolGenerator(object):
|
||||
rangeDict = getRangeDict(ammoQty)
|
||||
self.log.debug("rangeDict: {}".format(rangeDict))
|
||||
while len(self.itemManager.getItemPool()) < maxItems:
|
||||
item = chooseFromRange(rangeDict)
|
||||
item = chooseFromRange(rangeDict, self.random)
|
||||
self.itemManager.addMinor(item)
|
||||
else:
|
||||
minorsTypes = ['Missile', 'Super', 'PowerBomb']
|
||||
@@ -522,7 +524,7 @@ class ItemPoolGeneratorChozo(ItemPoolGenerator):
|
||||
# no etank nor reserve
|
||||
self.itemManager.removeItem('ETank')
|
||||
self.itemManager.addItem('NoEnergy', 'Chozo')
|
||||
elif random.random() < 0.5:
|
||||
elif self.random.random() < 0.5:
|
||||
# replace only etank with reserve
|
||||
self.itemManager.removeItem('ETank')
|
||||
self.itemManager.addItem('Reserve', 'Chozo')
|
||||
@@ -535,9 +537,9 @@ class ItemPoolGeneratorChozo(ItemPoolGenerator):
|
||||
# 4-6
|
||||
# already 3E and 1R
|
||||
alreadyInPool = 4
|
||||
rest = randGaussBounds(2, 5)
|
||||
rest = randGaussBounds(self.random, 2, 5)
|
||||
if rest >= 1:
|
||||
if random.random() < 0.5:
|
||||
if self.random.random() < 0.5:
|
||||
self.itemManager.addItem('Reserve', 'Minor')
|
||||
else:
|
||||
self.itemManager.addItem('ETank', 'Minor')
|
||||
@@ -550,13 +552,13 @@ class ItemPoolGeneratorChozo(ItemPoolGenerator):
|
||||
# 8-12
|
||||
# add up to 3 Reserves or ETanks (cannot add more than 3 reserves)
|
||||
for i in range(3):
|
||||
if random.random() < 0.5:
|
||||
if self.random.random() < 0.5:
|
||||
self.itemManager.addItem('Reserve', 'Minor')
|
||||
else:
|
||||
self.itemManager.addItem('ETank', 'Minor')
|
||||
# 7 already in the pool (3 E, 1 R, + the previous 3)
|
||||
alreadyInPool = 7
|
||||
rest = 1 + randGaussBounds(4, 3.7)
|
||||
rest = 1 + randGaussBounds(self.random, 4, 3.7)
|
||||
for i in range(rest):
|
||||
self.itemManager.addItem('ETank', 'Minor')
|
||||
# fill the rest with NoEnergy
|
||||
@@ -581,10 +583,10 @@ class ItemPoolGeneratorChozo(ItemPoolGenerator):
|
||||
return self.itemManager.getItemPool()
|
||||
|
||||
class ItemPoolGeneratorMajors(ItemPoolGenerator):
|
||||
def __init__(self, itemManager, qty, sm, maxDiff):
|
||||
super(ItemPoolGeneratorMajors, self).__init__(itemManager, qty, sm, maxDiff)
|
||||
self.sparseRest = 1 + randGaussBounds(2, 5)
|
||||
self.mediumRest = 3 + randGaussBounds(4, 3.7)
|
||||
def __init__(self, itemManager, qty, sm, maxDiff, random):
|
||||
super(ItemPoolGeneratorMajors, self).__init__(itemManager, qty, sm, maxDiff, random)
|
||||
self.sparseRest = 1 + randGaussBounds(self.random,2, 5)
|
||||
self.mediumRest = 3 + randGaussBounds(self.random, 4, 3.7)
|
||||
self.ultraSparseNoTanks = self.isUltraSparseNoTanks()
|
||||
|
||||
def addNoEnergy(self):
|
||||
@@ -609,7 +611,7 @@ class ItemPoolGeneratorMajors(ItemPoolGenerator):
|
||||
# no energy at all
|
||||
self.addNoEnergy()
|
||||
else:
|
||||
if random.random() < 0.5:
|
||||
if self.random.random() < 0.5:
|
||||
self.itemManager.addItem('ETank')
|
||||
else:
|
||||
self.itemManager.addItem('Reserve')
|
||||
@@ -620,7 +622,7 @@ class ItemPoolGeneratorMajors(ItemPoolGenerator):
|
||||
|
||||
elif energyQty == 'sparse':
|
||||
# 4-6
|
||||
if random.random() < 0.5:
|
||||
if self.random.random() < 0.5:
|
||||
self.itemManager.addItem('Reserve')
|
||||
else:
|
||||
self.itemManager.addItem('ETank')
|
||||
@@ -639,7 +641,7 @@ class ItemPoolGeneratorMajors(ItemPoolGenerator):
|
||||
alreadyInPool = 2
|
||||
n = getE(3)
|
||||
for i in range(n):
|
||||
if random.random() < 0.5:
|
||||
if self.random.random() < 0.5:
|
||||
self.itemManager.addItem('Reserve')
|
||||
else:
|
||||
self.itemManager.addItem('ETank')
|
||||
@@ -676,15 +678,15 @@ class ItemPoolGeneratorMajors(ItemPoolGenerator):
|
||||
return self.itemManager.getItemPool()
|
||||
|
||||
class ItemPoolGeneratorScavenger(ItemPoolGeneratorMajors):
|
||||
def __init__(self, itemManager, qty, sm, maxDiff):
|
||||
super(ItemPoolGeneratorScavenger, self).__init__(itemManager, qty, sm, maxDiff)
|
||||
def __init__(self, itemManager, qty, sm, maxDiff, random):
|
||||
super(ItemPoolGeneratorScavenger, self).__init__(itemManager, qty, sm, maxDiff, random)
|
||||
|
||||
def addNoEnergy(self):
|
||||
self.itemManager.addItem('Nothing')
|
||||
|
||||
class ItemPoolGeneratorMinimizer(ItemPoolGeneratorMajors):
|
||||
def __init__(self, itemManager, qty, sm, nLocs, maxDiff):
|
||||
super(ItemPoolGeneratorMinimizer, self).__init__(itemManager, qty, sm, maxDiff)
|
||||
def __init__(self, itemManager, qty, sm, nLocs, maxDiff, random):
|
||||
super(ItemPoolGeneratorMinimizer, self).__init__(itemManager, qty, sm, maxDiff, random)
|
||||
self.maxItems = nLocs
|
||||
self.calcMaxAmmo()
|
||||
nMajors = len([itemName for itemName,item in ItemManager.Items.items() if item.Class == 'Major' and item.Category != 'Energy'])
|
||||
@@ -716,8 +718,8 @@ class ItemPoolGeneratorMinimizer(ItemPoolGeneratorMajors):
|
||||
self.log.debug("maxEnergy: "+str(self.maxEnergy))
|
||||
|
||||
class ItemPoolGeneratorPlando(ItemPoolGenerator):
|
||||
def __init__(self, itemManager, qty, sm, exclude, nLocs, maxDiff):
|
||||
super(ItemPoolGeneratorPlando, self).__init__(itemManager, qty, sm, maxDiff)
|
||||
def __init__(self, itemManager, qty, sm, exclude, nLocs, maxDiff, random):
|
||||
super(ItemPoolGeneratorPlando, self).__init__(itemManager, qty, sm, maxDiff, random)
|
||||
# in exclude dict:
|
||||
# in alreadyPlacedItems:
|
||||
# dict of 'itemType: count' of items already added in the plando.
|
||||
@@ -805,7 +807,7 @@ class ItemPoolGeneratorPlando(ItemPoolGenerator):
|
||||
if ammoQty:
|
||||
rangeDict = getRangeDict(ammoQty)
|
||||
while len(self.itemManager.getItemPool()) < maxItems and remain > 0:
|
||||
item = chooseFromRange(rangeDict)
|
||||
item = chooseFromRange(rangeDict, self.random)
|
||||
self.itemManager.addMinor(item)
|
||||
remain -= 1
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import sys, random, time
|
||||
import sys, time
|
||||
|
||||
from ..utils import log
|
||||
from ..logic.logic import Logic
|
||||
@@ -14,7 +14,7 @@ from ..utils.doorsmanager import DoorsManager
|
||||
|
||||
# entry point for rando execution ("randomize" method)
|
||||
class RandoExec(object):
|
||||
def __init__(self, seedName, vcr, randoSettings, graphSettings, player):
|
||||
def __init__(self, seedName, vcr, randoSettings, graphSettings, player, random):
|
||||
self.errorMsg = ""
|
||||
self.seedName = seedName
|
||||
self.vcr = vcr
|
||||
@@ -22,6 +22,7 @@ class RandoExec(object):
|
||||
self.graphSettings = graphSettings
|
||||
self.log = log.get('RandoExec')
|
||||
self.player = player
|
||||
self.random = random
|
||||
|
||||
# processes settings to :
|
||||
# - create Restrictions and GraphBuilder objects
|
||||
@@ -31,7 +32,7 @@ class RandoExec(object):
|
||||
vcr = VCR(self.seedName, 'rando') if self.vcr == True else None
|
||||
self.errorMsg = ""
|
||||
split = self.randoSettings.restrictions['MajorMinor']
|
||||
self.graphBuilder = GraphBuilder(self.graphSettings)
|
||||
self.graphBuilder = GraphBuilder(self.graphSettings, self.random)
|
||||
container = None
|
||||
i = 0
|
||||
attempts = 500 if self.graphSettings.areaRando or self.graphSettings.doorsColorsRando or split == 'Scavenger' else 1
|
||||
@@ -43,10 +44,10 @@ class RandoExec(object):
|
||||
while container is None and i < attempts and now <= endDate:
|
||||
self.restrictions = Restrictions(self.randoSettings)
|
||||
if self.graphSettings.doorsColorsRando == True:
|
||||
DoorsManager.randomize(self.graphSettings.allowGreyDoors, self.player)
|
||||
DoorsManager.randomize(self.graphSettings.allowGreyDoors, self.player, self.random)
|
||||
self.areaGraph = self.graphBuilder.createGraph(self.randoSettings.maxDiff)
|
||||
services = RandoServices(self.areaGraph, self.restrictions)
|
||||
setup = RandoSetup(self.graphSettings, Logic.locations[:], services, self.player)
|
||||
services = RandoServices(self.areaGraph, self.restrictions, random=self.random)
|
||||
setup = RandoSetup(self.graphSettings, Logic.locations[:], services, self.player, self.random)
|
||||
self.setup = setup
|
||||
container = setup.createItemLocContainer(endDate, vcr)
|
||||
if container is None:
|
||||
@@ -78,7 +79,7 @@ class RandoExec(object):
|
||||
n = nMaj
|
||||
elif split == 'Chozo':
|
||||
n = nChozo
|
||||
GraphUtils.updateLocClassesStart(startAP.GraphArea, split, possibleMajLocs, preserveMajLocs, n)
|
||||
GraphUtils.updateLocClassesStart(startAP.GraphArea, split, possibleMajLocs, preserveMajLocs, n, self.random)
|
||||
|
||||
def postProcessItemLocs(self, itemLocs, hide):
|
||||
# hide some items like in dessy's
|
||||
@@ -89,7 +90,7 @@ class RandoExec(object):
|
||||
if (item.Category != "Nothing"
|
||||
and loc.CanHidden == True
|
||||
and loc.Visibility == 'Visible'):
|
||||
if bool(random.getrandbits(1)) == True:
|
||||
if bool(self.random.getrandbits(1)) == True:
|
||||
loc.Visibility = 'Hidden'
|
||||
# put nothing in unfilled locations
|
||||
filledLocNames = [il.Location.Name for il in itemLocs]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user