mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-04-06 08:38:16 -07:00
Compare commits
1 Commits
adventure-
...
empty-deat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c5418d708 |
1
.github/pyright-config.json
vendored
1
.github/pyright-config.json
vendored
@@ -2,7 +2,6 @@
|
|||||||
"include": [
|
"include": [
|
||||||
"../BizHawkClient.py",
|
"../BizHawkClient.py",
|
||||||
"../Patch.py",
|
"../Patch.py",
|
||||||
"../test/param.py",
|
|
||||||
"../test/general/test_groups.py",
|
"../test/general/test_groups.py",
|
||||||
"../test/general/test_helpers.py",
|
"../test/general/test_helpers.py",
|
||||||
"../test/general/test_memory.py",
|
"../test/general/test_memory.py",
|
||||||
|
|||||||
4
.github/workflows/ctest.yml
vendored
4
.github/workflows/ctest.yml
vendored
@@ -36,9 +36,9 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756
|
- uses: ilammy/msvc-dev-cmd@v1
|
||||||
if: startsWith(matrix.os,'windows')
|
if: startsWith(matrix.os,'windows')
|
||||||
- uses: Bacondish2023/setup-googletest@49065d1f7a6d21f6134864dd65980fe5dbe06c73
|
- uses: Bacondish2023/setup-googletest@v1
|
||||||
with:
|
with:
|
||||||
build-type: 'Release'
|
build-type: 'Release'
|
||||||
- name: Build tests
|
- name: Build tests
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,7 +10,6 @@
|
|||||||
*.apmc
|
*.apmc
|
||||||
*.apz5
|
*.apz5
|
||||||
*.aptloz
|
*.aptloz
|
||||||
*.aptww
|
|
||||||
*.apemerald
|
*.apemerald
|
||||||
*.pyc
|
*.pyc
|
||||||
*.pyd
|
*.pyd
|
||||||
|
|||||||
@@ -511,7 +511,7 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
import colorama
|
import colorama
|
||||||
|
|
||||||
colorama.just_fix_windows_console()
|
colorama.init()
|
||||||
|
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
colorama.deinit()
|
colorama.deinit()
|
||||||
|
|||||||
@@ -413,8 +413,7 @@ class CommonContext:
|
|||||||
await self.server.socket.close()
|
await self.server.socket.close()
|
||||||
if self.server_task is not None:
|
if self.server_task is not None:
|
||||||
await self.server_task
|
await self.server_task
|
||||||
if self.ui:
|
self.ui.update_hints()
|
||||||
self.ui.update_hints()
|
|
||||||
|
|
||||||
async def send_msgs(self, msgs: typing.List[typing.Any]) -> None:
|
async def send_msgs(self, msgs: typing.List[typing.Any]) -> None:
|
||||||
""" `msgs` JSON serializable """
|
""" `msgs` JSON serializable """
|
||||||
@@ -625,6 +624,9 @@ class CommonContext:
|
|||||||
|
|
||||||
def consume_network_data_package(self, data_package: dict):
|
def consume_network_data_package(self, data_package: dict):
|
||||||
self.update_data_package(data_package)
|
self.update_data_package(data_package)
|
||||||
|
current_cache = Utils.persistent_load().get("datapackage", {}).get("games", {})
|
||||||
|
current_cache.update(data_package["games"])
|
||||||
|
Utils.persistent_store("datapackage", "games", current_cache)
|
||||||
logger.info(f"Got new ID/Name DataPackage for {', '.join(data_package['games'])}")
|
logger.info(f"Got new ID/Name DataPackage for {', '.join(data_package['games'])}")
|
||||||
for game, game_data in data_package["games"].items():
|
for game, game_data in data_package["games"].items():
|
||||||
Utils.store_data_package_for_checksum(game, game_data)
|
Utils.store_data_package_for_checksum(game, game_data)
|
||||||
@@ -1126,7 +1128,7 @@ def run_as_textclient(*args):
|
|||||||
args = handle_url_arg(args, parser=parser)
|
args = handle_url_arg(args, parser=parser)
|
||||||
|
|
||||||
# use colorama to display colored text highlighting on windows
|
# use colorama to display colored text highlighting on windows
|
||||||
colorama.just_fix_windows_console()
|
colorama.init()
|
||||||
|
|
||||||
asyncio.run(main(args))
|
asyncio.run(main(args))
|
||||||
colorama.deinit()
|
colorama.deinit()
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
parser = get_base_parser()
|
parser = get_base_parser()
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
colorama.just_fix_windows_console()
|
colorama.init()
|
||||||
|
|
||||||
asyncio.run(main(args))
|
asyncio.run(main(args))
|
||||||
colorama.deinit()
|
colorama.deinit()
|
||||||
|
|||||||
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
|
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):
|
location.locked and location.item.player not in minimal_players):
|
||||||
pool.append(location.item)
|
pool.append(location.item)
|
||||||
|
state.remove(location.item)
|
||||||
location.item = None
|
location.item = None
|
||||||
if location in state.advancements:
|
if location in state.advancements:
|
||||||
state.advancements.remove(location)
|
state.advancements.remove(location)
|
||||||
state.remove(location.item)
|
|
||||||
locations.append(location)
|
locations.append(location)
|
||||||
if pool and locations:
|
if pool and locations:
|
||||||
locations.sort(key=lambda loc: loc.progress_type != LocationProgressType.PRIORITY)
|
locations.sort(key=lambda loc: loc.progress_type != LocationProgressType.PRIORITY)
|
||||||
|
|||||||
22
Generate.py
22
Generate.py
@@ -279,30 +279,22 @@ def get_choice(option, root, value=None) -> Any:
|
|||||||
raise RuntimeError(f"All options specified in \"{option}\" are weighted as zero.")
|
raise RuntimeError(f"All options specified in \"{option}\" are weighted as zero.")
|
||||||
|
|
||||||
|
|
||||||
class SafeFormatter(string.Formatter):
|
class SafeDict(dict):
|
||||||
def get_value(self, key, args, kwargs):
|
def __missing__(self, key):
|
||||||
if isinstance(key, int):
|
return '{' + key + '}'
|
||||||
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):
|
def handle_name(name: str, player: int, name_counter: Counter):
|
||||||
name_counter[name.lower()] += 1
|
name_counter[name.lower()] += 1
|
||||||
number = name_counter[name.lower()]
|
number = name_counter[name.lower()]
|
||||||
new_name = "%".join([x.replace("%number%", "{number}").replace("%player%", "{player}") for x in name.split("%%")])
|
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,
|
||||||
new_name = SafeFormatter().vformat(new_name, (), {"number": number,
|
NUMBER=(number if number > 1 else ''),
|
||||||
"NUMBER": (number if number > 1 else ''),
|
player=player,
|
||||||
"player": player,
|
PLAYER=(player if player > 1 else '')))
|
||||||
"PLAYER": (player if player > 1 else '')})
|
|
||||||
# Run .strip twice for edge case where after the initial .slice new_name has a leading whitespace.
|
# 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.
|
# Could cause issues for some clients that cannot handle the additional whitespace.
|
||||||
new_name = new_name.strip()[:16].strip()
|
new_name = new_name.strip()[:16].strip()
|
||||||
|
|
||||||
if new_name == "Archipelago":
|
if new_name == "Archipelago":
|
||||||
raise Exception(f"You cannot name yourself \"{new_name}\"")
|
raise Exception(f"You cannot name yourself \"{new_name}\"")
|
||||||
return new_name
|
return new_name
|
||||||
|
|||||||
@@ -506,7 +506,7 @@ class LinksAwakeningContext(CommonContext):
|
|||||||
la_task = None
|
la_task = None
|
||||||
client = None
|
client = None
|
||||||
# TODO: does this need to re-read on reset?
|
# TODO: does this need to re-read on reset?
|
||||||
found_checks = set()
|
found_checks = []
|
||||||
last_resend = time.time()
|
last_resend = time.time()
|
||||||
|
|
||||||
magpie_enabled = False
|
magpie_enabled = False
|
||||||
@@ -558,6 +558,10 @@ class LinksAwakeningContext(CommonContext):
|
|||||||
|
|
||||||
self.ui = LADXManager(self)
|
self.ui = LADXManager(self)
|
||||||
self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")
|
self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")
|
||||||
|
|
||||||
|
async def send_checks(self):
|
||||||
|
message = [{"cmd": "LocationChecks", "locations": self.found_checks}]
|
||||||
|
await self.send_msgs(message)
|
||||||
|
|
||||||
async def send_new_entrances(self, entrances: typing.Dict[str, str]):
|
async def send_new_entrances(self, entrances: typing.Dict[str, str]):
|
||||||
# Store the entrances we find on the server for future sessions
|
# Store the entrances we find on the server for future sessions
|
||||||
@@ -609,8 +613,8 @@ class LinksAwakeningContext(CommonContext):
|
|||||||
self.client.pending_deathlink = True
|
self.client.pending_deathlink = True
|
||||||
|
|
||||||
def new_checks(self, item_ids, ladxr_ids):
|
def new_checks(self, item_ids, ladxr_ids):
|
||||||
self.found_checks.update(item_ids)
|
self.found_checks += item_ids
|
||||||
create_task_log_exception(self.check_locations(self.found_checks))
|
create_task_log_exception(self.send_checks())
|
||||||
if self.magpie_enabled:
|
if self.magpie_enabled:
|
||||||
create_task_log_exception(self.magpie.send_new_checks(ladxr_ids))
|
create_task_log_exception(self.magpie.send_new_checks(ladxr_ids))
|
||||||
|
|
||||||
@@ -717,7 +721,7 @@ class LinksAwakeningContext(CommonContext):
|
|||||||
|
|
||||||
if self.last_resend + 5.0 < now:
|
if self.last_resend + 5.0 < now:
|
||||||
self.last_resend = now
|
self.last_resend = now
|
||||||
await self.check_locations(self.found_checks)
|
await self.send_checks()
|
||||||
if self.magpie_enabled:
|
if self.magpie_enabled:
|
||||||
try:
|
try:
|
||||||
self.magpie.set_checks(self.client.tracker.all_checks)
|
self.magpie.set_checks(self.client.tracker.all_checks)
|
||||||
@@ -799,6 +803,6 @@ async def main():
|
|||||||
await ctx.shutdown()
|
await ctx.shutdown()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
colorama.just_fix_windows_console()
|
colorama.init()
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
colorama.deinit()
|
colorama.deinit()
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
import colorama
|
import colorama
|
||||||
|
|
||||||
colorama.just_fix_windows_console()
|
colorama.init()
|
||||||
|
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
colorama.deinit()
|
colorama.deinit()
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ from NetUtils import Endpoint, ClientStatus, NetworkItem, decode, encode, Networ
|
|||||||
from BaseClasses import ItemClassification
|
from BaseClasses import ItemClassification
|
||||||
|
|
||||||
min_client_version = Version(0, 1, 6)
|
min_client_version = Version(0, 1, 6)
|
||||||
colorama.just_fix_windows_console()
|
colorama.init()
|
||||||
|
|
||||||
|
|
||||||
def remove_from_list(container, value):
|
def remove_from_list(container, value):
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
import colorama
|
import colorama
|
||||||
|
|
||||||
colorama.just_fix_windows_console()
|
colorama.init()
|
||||||
|
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
colorama.deinit()
|
colorama.deinit()
|
||||||
|
|||||||
@@ -1579,7 +1579,6 @@ def dump_player_options(multiworld: MultiWorld) -> None:
|
|||||||
player_output = {
|
player_output = {
|
||||||
"Game": multiworld.game[player],
|
"Game": multiworld.game[player],
|
||||||
"Name": multiworld.get_player_name(player),
|
"Name": multiworld.get_player_name(player),
|
||||||
"ID": player,
|
|
||||||
}
|
}
|
||||||
output.append(player_output)
|
output.append(player_output)
|
||||||
for option_key, option in world.options_dataclass.type_hints.items():
|
for option_key, option in world.options_dataclass.type_hints.items():
|
||||||
@@ -1592,7 +1591,7 @@ def dump_player_options(multiworld: MultiWorld) -> None:
|
|||||||
game_option_names.append(display_name)
|
game_option_names.append(display_name)
|
||||||
|
|
||||||
with open(output_path(f"generate_{multiworld.seed_name}.csv"), mode="w", newline="") as file:
|
with open(output_path(f"generate_{multiworld.seed_name}.csv"), mode="w", newline="") as file:
|
||||||
fields = ["ID", "Game", "Name", *all_option_names]
|
fields = ["Game", "Name", *all_option_names]
|
||||||
writer = DictWriter(file, fields)
|
writer = DictWriter(file, fields)
|
||||||
writer.writeheader()
|
writer.writeheader()
|
||||||
writer.writerows(output)
|
writer.writerows(output)
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ Currently, the following games are supported:
|
|||||||
* Castlevania: Circle of the Moon
|
* Castlevania: Circle of the Moon
|
||||||
* Inscryption
|
* Inscryption
|
||||||
* Civilization VI
|
* Civilization VI
|
||||||
* The Legend of Zelda: The Wind Waker
|
|
||||||
|
|
||||||
For setup and instructions check out our [tutorials page](https://archipelago.gg/tutorial/).
|
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
|
Downloads can be found at [Releases](https://github.com/ArchipelagoMW/Archipelago/releases), including compiled
|
||||||
|
|||||||
@@ -735,6 +735,6 @@ async def main() -> None:
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
colorama.just_fix_windows_console()
|
colorama.init()
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
colorama.deinit()
|
colorama.deinit()
|
||||||
|
|||||||
@@ -500,7 +500,7 @@ def main():
|
|||||||
|
|
||||||
import colorama
|
import colorama
|
||||||
|
|
||||||
colorama.just_fix_windows_console()
|
colorama.init()
|
||||||
|
|
||||||
asyncio.run(_main())
|
asyncio.run(_main())
|
||||||
colorama.deinit()
|
colorama.deinit()
|
||||||
|
|||||||
2
Utils.py
2
Utils.py
@@ -47,7 +47,7 @@ class Version(typing.NamedTuple):
|
|||||||
return ".".join(str(item) for item in self)
|
return ".".join(str(item) for item in self)
|
||||||
|
|
||||||
|
|
||||||
__version__ = "0.6.2"
|
__version__ = "0.6.0"
|
||||||
version_tuple = tuplize_version(__version__)
|
version_tuple = tuplize_version(__version__)
|
||||||
|
|
||||||
is_linux = sys.platform.startswith("linux")
|
is_linux = sys.platform.startswith("linux")
|
||||||
|
|||||||
@@ -446,6 +446,6 @@ if __name__ == '__main__':
|
|||||||
parser = get_base_parser(description="Wargroove Client, for text interfacing.")
|
parser = get_base_parser(description="Wargroove Client, for text interfacing.")
|
||||||
|
|
||||||
args, rest = parser.parse_known_args()
|
args, rest = parser.parse_known_args()
|
||||||
colorama.just_fix_windows_console()
|
colorama.init()
|
||||||
asyncio.run(main(args))
|
asyncio.run(main(args))
|
||||||
colorama.deinit()
|
colorama.deinit()
|
||||||
|
|||||||
@@ -35,12 +35,6 @@ def start_playing():
|
|||||||
@app.route('/games/<string:game>/info/<string:lang>')
|
@app.route('/games/<string:game>/info/<string:lang>')
|
||||||
@cache.cached()
|
@cache.cached()
|
||||||
def game_info(game, lang):
|
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))
|
return render_template('gameInfo.html', game=game, lang=lang, theme=get_world_theme(game))
|
||||||
|
|
||||||
|
|
||||||
@@ -58,12 +52,6 @@ def games():
|
|||||||
@app.route('/tutorial/<string:game>/<string:file>/<string:lang>')
|
@app.route('/tutorial/<string:game>/<string:file>/<string:lang>')
|
||||||
@cache.cached()
|
@cache.cached()
|
||||||
def tutorial(game, file, lang):
|
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))
|
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
|
from docutils.core import publish_parts
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from flask import redirect, render_template, request, Response, abort
|
from flask import redirect, render_template, request, Response
|
||||||
|
|
||||||
import Options
|
import Options
|
||||||
from Utils import local_path
|
from Utils import local_path
|
||||||
@@ -142,10 +142,7 @@ def weighted_options_old():
|
|||||||
@app.route("/games/<string:game>/weighted-options")
|
@app.route("/games/<string:game>/weighted-options")
|
||||||
@cache.cached()
|
@cache.cached()
|
||||||
def weighted_options(game: str):
|
def weighted_options(game: str):
|
||||||
try:
|
return render_options_page("weightedOptions/weightedOptions.html", game, is_complex=True)
|
||||||
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"])
|
@app.route("/games/<string:game>/generate-weighted-yaml", methods=["POST"])
|
||||||
@@ -200,10 +197,7 @@ def generate_weighted_yaml(game: str):
|
|||||||
@app.route("/games/<string:game>/player-options")
|
@app.route("/games/<string:game>/player-options")
|
||||||
@cache.cached()
|
@cache.cached()
|
||||||
def player_options(game: str):
|
def player_options(game: str):
|
||||||
try:
|
return render_options_page("playerOptions/playerOptions.html", game, is_complex=False)
|
||||||
return render_options_page("playerOptions/playerOptions.html", game, is_complex=False)
|
|
||||||
except KeyError:
|
|
||||||
return abort(404)
|
|
||||||
|
|
||||||
|
|
||||||
# YAML generator for player-options
|
# YAML generator for player-options
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
flask>=3.1.0
|
flask>=3.0.3
|
||||||
werkzeug>=3.1.3
|
werkzeug>=3.0.6
|
||||||
pony>=0.7.19
|
pony>=0.7.19
|
||||||
waitress>=3.0.2
|
waitress>=3.0.0
|
||||||
Flask-Caching>=2.3.0
|
Flask-Caching>=2.3.0
|
||||||
Flask-Compress>=1.17
|
Flask-Compress>=1.15
|
||||||
Flask-Limiter>=3.12
|
Flask-Limiter>=3.8.0
|
||||||
bokeh>=3.6.3
|
bokeh>=3.5.2
|
||||||
markupsafe>=3.0.2
|
markupsafe>=2.1.5
|
||||||
Markdown>=3.7
|
Markdown>=3.7
|
||||||
mdx-breakless-lists>=1.0.1
|
mdx-breakless-lists>=1.0.1
|
||||||
|
|||||||
@@ -42,5 +42,10 @@ window.addEventListener('load', () => {
|
|||||||
scrollTarget?.scrollIntoView();
|
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,5 +49,10 @@ window.addEventListener('load', () => {
|
|||||||
scrollTarget?.scrollIntoView();
|
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>`;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -213,7 +213,7 @@
|
|||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro RandomizeButton(option_name, option) %}
|
{% macro RandomizeButton(option_name, option) %}
|
||||||
<div class="randomize-button" data-tooltip="Pick a random value for this option.">
|
<div class="randomize-button" data-tooltip="Toggle randomization for this option!">
|
||||||
<label for="random-{{ option_name }}">
|
<label for="random-{{ option_name }}">
|
||||||
<input type="checkbox" id="random-{{ option_name }}" name="random-{{ option_name }}" class="randomize-checkbox" data-option-name="{{ option_name }}" {{ "checked" if option.default == "random" }} />
|
<input type="checkbox" id="random-{{ option_name }}" name="random-{{ option_name }}" class="randomize-checkbox" data-option-name="{{ option_name }}" {{ "checked" if option.default == "random" }} />
|
||||||
🎲
|
🎲
|
||||||
|
|||||||
@@ -100,7 +100,7 @@
|
|||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="unsupported-option">
|
<div class="unsupported-option">
|
||||||
This option cannot be modified here. Please edit your .yaml file manually.
|
This option is not supported. Please edit your .yaml file manually.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -386,7 +386,7 @@ if __name__ == '__main__':
|
|||||||
parser.add_argument('diff_file', default="", type=str, nargs="?",
|
parser.add_argument('diff_file', default="", type=str, nargs="?",
|
||||||
help='Path to a Archipelago Binary Patch file')
|
help='Path to a Archipelago Binary Patch file')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
colorama.just_fix_windows_console()
|
colorama.init()
|
||||||
|
|
||||||
asyncio.run(main(args))
|
asyncio.run(main(args))
|
||||||
colorama.deinit()
|
colorama.deinit()
|
||||||
|
|||||||
@@ -214,9 +214,6 @@
|
|||||||
# Wargroove
|
# Wargroove
|
||||||
/worlds/wargroove/ @FlySniper
|
/worlds/wargroove/ @FlySniper
|
||||||
|
|
||||||
# The Wind Waker
|
|
||||||
/worlds/tww/ @tanjo3
|
|
||||||
|
|
||||||
# The Witness
|
# The Witness
|
||||||
/worlds/witness/ @NewSoupVi @blastron
|
/worlds/witness/ @NewSoupVi @blastron
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
# Adding Games
|
# Adding Games
|
||||||
|
|
||||||
Like all contributions to Archipelago, New Game implementations should follow the [Contributing](/docs/contributing.md)
|
|
||||||
guide.
|
|
||||||
|
|
||||||
Adding a new game to Archipelago has two major parts:
|
Adding a new game to Archipelago has two major parts:
|
||||||
|
|
||||||
* Game Modification to communicate with Archipelago server (hereafter referred to as "client")
|
* Game Modification to communicate with Archipelago server (hereafter referred to as "client")
|
||||||
@@ -16,51 +13,30 @@ it will not be detailed here.
|
|||||||
|
|
||||||
The client is an intermediary program between the game and the Archipelago server. This can either be a direct
|
The client is an intermediary program between the game and the Archipelago server. This can either be a direct
|
||||||
modification to the game, an external program, or both. This can be implemented in nearly any modern language, but it
|
modification to the game, an external program, or both. This can be implemented in nearly any modern language, but it
|
||||||
must fulfill a few requirements in order to function as expected. Libraries for most modern languages and the spec for
|
must fulfill a few requirements in order to function as expected. The specific requirements the game client must follow
|
||||||
various packets can be found in the [network protocol](/docs/network%20protocol.md) API reference document.
|
to behave as expected are:
|
||||||
|
|
||||||
### Hard Requirements
|
|
||||||
|
|
||||||
In order for the game client to behave as expected, it must be able to perform these functions:
|
|
||||||
|
|
||||||
* Handle both secure and unsecure websocket connections
|
* Handle both secure and unsecure websocket connections
|
||||||
* Reconnect if the connection is unstable and lost while playing
|
* Detect and react when a location has been "checked" by the player by sending a network packet to the server
|
||||||
|
* Receive and parse network packets when the player receives an item from the server, and reward it to the player on
|
||||||
|
demand
|
||||||
|
* **Any** of your items can be received any number of times, up to and far surpassing those that the game might
|
||||||
|
normally expect from features such as starting inventory, item link replacement, or item cheating
|
||||||
|
* Players and the admin can cheat items to the player at any time with a server command, and these items may not have
|
||||||
|
a player or location attributed to them
|
||||||
* Be able to change the port for saved connection info
|
* Be able to change the port for saved connection info
|
||||||
* Rooms hosted on the website attempt to reserve their port, but since there are a limited number of ports, this
|
* Rooms hosted on the website attempt to reserve their port, but since there are a limited number of ports, this
|
||||||
privilege can be lost, requiring the room to be moved to a new port
|
privilege can be lost, requiring the room to be moved to a new port
|
||||||
|
* Reconnect if the connection is unstable and lost while playing
|
||||||
|
* Keep an index for items received in order to resync. The ItemsReceived Packets are a single list with guaranteed
|
||||||
|
order.
|
||||||
|
* Receive items that were sent to the player while they were not connected to the server
|
||||||
|
* The player being able to complete checks while offline and sending them when reconnecting is a good bonus, but not
|
||||||
|
strictly required
|
||||||
* Send a status update packet alerting the server that the player has completed their goal
|
* Send a status update packet alerting the server that the player has completed their goal
|
||||||
|
|
||||||
Regarding items and locations, the game client must be able to handle these tasks:
|
Libraries for most modern languages and the spec for various packets can be found in the
|
||||||
|
[network protocol](/docs/network%20protocol.md) API reference document.
|
||||||
#### Location Handling
|
|
||||||
|
|
||||||
Send a network packet to the server when it detects a location has been "checked" by the player in-game.
|
|
||||||
|
|
||||||
* If actions were taken in game that would usually trigger a location check, and those actions can only ever be taken
|
|
||||||
once, but the client was not connected when they happened: The client must send those location checks on connection
|
|
||||||
so that they are not permanently lost, e.g. by reading flags in the game state or save file.
|
|
||||||
|
|
||||||
#### Item Handling
|
|
||||||
|
|
||||||
Receive and parse network packets from the server when the player receives an item.
|
|
||||||
|
|
||||||
* It must reward items to the player on demand, as items can come from other players at any time.
|
|
||||||
* It must be able to reward copies of an item, up to and beyond the number the game normally expects. This may happen
|
|
||||||
due to features such as starting inventory, item link replacement, admin commands, or item cheating. **Any** of
|
|
||||||
your items can be received **any** number of times.
|
|
||||||
* Admins and players may use server commands to create items without a player or location attributed to them. The
|
|
||||||
client must be able to handle these items.
|
|
||||||
* It must keep an index for items received in order to resync. The ItemsReceived Packets are a single list with a
|
|
||||||
guaranteed order.
|
|
||||||
* It must be able to receive items that were sent to the player while they were not connected to the server.
|
|
||||||
|
|
||||||
### Encouraged Features
|
|
||||||
|
|
||||||
These are "nice to have" features for a client, but they are not strictly required. It is encouraged to add them
|
|
||||||
if possible.
|
|
||||||
|
|
||||||
* If your client appears in the Archipelago Launcher, you may define an icon for it that differentiates it from
|
|
||||||
other clients. The icon size is 38x38 pixels, but it will accept larger images with downscaling.
|
|
||||||
|
|
||||||
## World
|
## World
|
||||||
|
|
||||||
@@ -68,90 +44,35 @@ The world is your game integration for the Archipelago generator, webhost, and m
|
|||||||
information necessary for creating the items and locations to be randomized, the logic for item placement, the
|
information necessary for creating the items and locations to be randomized, the logic for item placement, the
|
||||||
datapackage information so other game clients can recognize your game data, and documentation. Your world must be
|
datapackage information so other game clients can recognize your game data, and documentation. Your world must be
|
||||||
written as a Python package to be loaded by Archipelago. This is currently done by creating a fork of the Archipelago
|
written as a Python package to be loaded by Archipelago. This is currently done by creating a fork of the Archipelago
|
||||||
repository and creating a new world package in `/worlds/`.
|
repository and creating a new world package in `/worlds/`. A bare minimum world implementation must satisfy the
|
||||||
|
following requirements:
|
||||||
|
|
||||||
The base World class can be found in [AutoWorld](/worlds/AutoWorld.py). Methods available for your world to call
|
* A folder within `/worlds/` that contains an `__init__.py`
|
||||||
during generation can be found in [BaseClasses](/BaseClasses.py) and [Fill](/Fill.py). Some examples and documentation
|
* A `World` subclass where you create your world and define all of its rules
|
||||||
regarding the API can be found in the [world api doc](/docs/world%20api.md). Before publishing, make sure to also
|
* A unique game name
|
||||||
check out [world maintainer.md](/docs/world%20maintainer.md).
|
* For webhost documentation and behaviors, a `WebWorld` subclass that must be instantiated in the `World` class
|
||||||
|
definition
|
||||||
### Hard Requirements
|
* The game_info doc must follow the format `{language_code}_{game_name}.md`
|
||||||
|
|
||||||
A bare minimum world implementation must satisfy the following requirements:
|
|
||||||
|
|
||||||
* It has a folder with the name of your game (or an abbreviation) under `/worlds/`
|
|
||||||
* The `/worlds/{game}` folder contains an `__init__.py`
|
|
||||||
* Any subfolders within `/worlds/{game}` that contain `*.py` files also contain an `__init__.py` for frozen build
|
|
||||||
packaging
|
|
||||||
* The game folder has at least one game_info doc named with follow the format `{language_code}_{game_name}.md`
|
|
||||||
* The game folder has at least one setup doc
|
|
||||||
* There must be a `World` subclass in your game folder (typically in `/worlds/{game}/__init__.py`) where you create
|
|
||||||
your world and define all of its rules and features
|
|
||||||
|
|
||||||
Within the `World` subclass you should also have:
|
|
||||||
|
|
||||||
* A [unique game name](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L260)
|
|
||||||
* An [instance](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L295) of a `WebWorld`
|
|
||||||
subclass for webhost documentation and behaviors
|
|
||||||
* In your `WebWorld`, if you wrote a game_info doc in more than one language, override the list of
|
|
||||||
[game info languages](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L210) with the
|
|
||||||
ones you include.
|
|
||||||
* In your `WebWorld`, override the list of
|
|
||||||
[tutorials](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L213) with each tutorial
|
|
||||||
or setup doc you included in the game folder.
|
|
||||||
* A mapping for items and locations defining their names and ids for clients to be able to identify them. These are
|
* A mapping for items and locations defining their names and ids for clients to be able to identify them. These are
|
||||||
`item_name_to_id` and `location_name_to_id`, respectively.
|
`item_name_to_id` and `location_name_to_id`, respectively.
|
||||||
* An implementation of `create_item` that can create an item when called by either your code or by another process
|
* Create an item when `create_item` is called both by your code and externally
|
||||||
within Archipelago
|
|
||||||
* At least one `Region` for your player to start from (i.e. the Origin Region)
|
|
||||||
* The default name of this region is "Menu" but you may configure a different name with
|
|
||||||
[origin_region_name](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L298-L299)
|
|
||||||
* A non-zero number of locations, added to your regions
|
|
||||||
* A non-zero number of items **equal** to the number of locations, added to the multiworld itempool
|
|
||||||
* In rare cases, there may be 0-location-0-item games, but this is extremely atypical.
|
|
||||||
|
|
||||||
### Encouraged Features
|
|
||||||
|
|
||||||
These are "nice to have" features for a world, but they are not strictly required. It is encouraged to add them
|
|
||||||
if possible.
|
|
||||||
|
|
||||||
* An implementation of
|
|
||||||
[get_filler_item_name](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L473)
|
|
||||||
* By default, this function chooses any item name from `item_name_to_id`, so you want to limit it to only the true
|
|
||||||
filler items.
|
|
||||||
* An `options_dataclass` defining the options players have available to them
|
* An `options_dataclass` defining the options players have available to them
|
||||||
* This should be accompanied by a type hint for `options` with the same class name
|
* A `Region` for your player with the name "Menu" to start from
|
||||||
* A [bug report page](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L220)
|
* Create a non-zero number of locations and add them to your regions
|
||||||
* A list of [option groups](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L226)
|
* Create a non-zero number of items **equal** to the number of locations and add them to the multiworld itempool
|
||||||
for better organization on the webhost
|
* All items submitted to the multiworld itempool must not be manually placed by the World. If you need to place specific
|
||||||
* A dictionary of [options presets](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L223)
|
items, there are multiple ways to do so, but they should not be added to the multiworld itempool.
|
||||||
for player convenience
|
|
||||||
* A dictionary of [item name groups](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L273)
|
|
||||||
for player convenience
|
|
||||||
* A dictionary of
|
|
||||||
[location name groups](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L276)
|
|
||||||
for player convenience
|
|
||||||
* Other games may also benefit from your name group dictionaries for hints, features, etc.
|
|
||||||
|
|
||||||
### Discouraged or Prohibited Behavior
|
Notable caveats:
|
||||||
|
* The "Menu" region will always be considered the "start" for the player
|
||||||
These are behaviors or implementations that are known to cause various issues. Some of these points have notable
|
* The "Menu" region is *always* considered accessible; i.e. the player is expected to always be able to return to the
|
||||||
workarounds or preferred methods which should be used instead:
|
|
||||||
|
|
||||||
* All items submitted to the multiworld itempool must not be manually placed by the World.
|
|
||||||
* If you need to place specific items, there are multiple ways to do so, but they should not be added to the
|
|
||||||
multiworld itempool.
|
|
||||||
* It is not allowed to use `eval` for most reasons, chiefly due to security concerns.
|
|
||||||
* It is discouraged to use `yaml.load` directly due to security concerns.
|
|
||||||
* When possible, use `Utils.yaml_load` instead, as this defaults to the safe loader.
|
|
||||||
* When submitting regions or items to the multiworld (`multiworld.regions` and `multiworld.itempool` respectively),
|
|
||||||
Do **not** use `=` as this will overwrite all elements for all games in the seed.
|
|
||||||
* Instead, use `append`, `extend`, or `+=`.
|
|
||||||
|
|
||||||
### Notable Caveats
|
|
||||||
|
|
||||||
* The Origin Region will always be considered the "start" for the player
|
|
||||||
* The Origin Region is *always* considered accessible; i.e. the player is expected to always be able to return to the
|
|
||||||
start of the game from anywhere
|
start of the game from anywhere
|
||||||
|
* When submitting regions or items to the multiworld (multiworld.regions and multiworld.itempool respectively), use
|
||||||
|
`append`, `extend`, or `+=`. **Do not use `=`**
|
||||||
* Regions are simply containers for locations that share similar access rules. They do not have to map to
|
* Regions are simply containers for locations that share similar access rules. They do not have to map to
|
||||||
concrete, physical areas within your game and can be more abstract like tech trees or a questline.
|
concrete, physical areas within your game and can be more abstract like tech trees or a questline.
|
||||||
|
|
||||||
|
The base World class can be found in [AutoWorld](/worlds/AutoWorld.py). Methods available for your world to call during
|
||||||
|
generation can be found in [BaseClasses](/BaseClasses.py) and [Fill](/Fill.py). Some examples and documentation
|
||||||
|
regarding the API can be found in the [world api doc](/docs/world%20api.md).
|
||||||
|
Before publishing, make sure to also check out [world maintainer.md](/docs/world%20maintainer.md).
|
||||||
|
|||||||
@@ -82,38 +82,6 @@ Unit tests can also be created using [TestBase](/test/bases.py#L16) or
|
|||||||
may be useful for generating a multiworld under very specific constraints without using the generic world setup, or for
|
may be useful for generating a multiworld under very specific constraints without using the generic world setup, or for
|
||||||
testing portions of your code that can be tested without relying on a multiworld to be created first.
|
testing portions of your code that can be tested without relying on a multiworld to be created first.
|
||||||
|
|
||||||
#### Parametrization
|
|
||||||
|
|
||||||
When defining a test that needs to cover a range of inputs it is useful to parameterize (to run the same test
|
|
||||||
for multiple inputs) the base test. Some important things to consider when attempting to parametrize your test are:
|
|
||||||
|
|
||||||
* [Subtests](https://docs.python.org/3/library/unittest.html#distinguishing-test-iterations-using-subtests)
|
|
||||||
can be used to have parametrized assertions that show up similar to individual tests but without the overhead
|
|
||||||
of needing to instantiate multiple tests; however, subtests can not be multithreaded and do not have individual
|
|
||||||
timing data, so they are not suitable for slow tests.
|
|
||||||
|
|
||||||
* Archipelago's tests are test-runner-agnostic. That means tests are not allowed to use e.g. `@pytest.mark.parametrize`.
|
|
||||||
Instead, we define our own parametrization helpers in [test.param](/test/param.py).
|
|
||||||
|
|
||||||
* Classes inheriting from `WorldTestBase`, including those created by the helpers in `test.param`, will run all
|
|
||||||
base tests by default, make sure the produced tests actually do what you aim for and do not waste a lot of
|
|
||||||
extra CPU time. Consider using `TestBase` or `unittest.TestCase` directly
|
|
||||||
or setting `WorldTestBase.run_default_tests` to False.
|
|
||||||
|
|
||||||
#### Performance Considerations
|
|
||||||
|
|
||||||
Archipelago is big enough that the runtime of unittests can have an impact on productivity.
|
|
||||||
|
|
||||||
Individual tests should take less than a second, so they can be properly multithreaded.
|
|
||||||
|
|
||||||
Ideally, thorough tests are directed at actual code/functionality. Do not just create and/or fill a ton of individual
|
|
||||||
Multiworlds that spend most of the test time outside what you actually want to test.
|
|
||||||
|
|
||||||
Consider generating/validating "random" games as part of your APWorld release workflow rather than having that be part
|
|
||||||
of continuous integration, and add minimal reproducers to the "normal" tests for problems that were found.
|
|
||||||
You can use [@unittest.skipIf](https://docs.python.org/3/library/unittest.html#unittest.skipIf) with an environment
|
|
||||||
variable to keep all the benefits of the test framework while not running the marked tests by default.
|
|
||||||
|
|
||||||
## Running Tests
|
## Running Tests
|
||||||
|
|
||||||
#### Using Pycharm
|
#### Using Pycharm
|
||||||
@@ -132,11 +100,3 @@ next to the run and debug buttons.
|
|||||||
#### Running Tests without Pycharm
|
#### Running Tests without Pycharm
|
||||||
|
|
||||||
Run `pip install pytest pytest-subtests`, then use your IDE to run tests or run `pytest` from the source folder.
|
Run `pip install pytest pytest-subtests`, then use your IDE to run tests or run `pytest` from the source folder.
|
||||||
|
|
||||||
#### Running Tests Multithreaded
|
|
||||||
|
|
||||||
pytest can run multiple test runners in parallel with the pytest-xdist extension.
|
|
||||||
|
|
||||||
Install with `pip install pytest-xdist`.
|
|
||||||
|
|
||||||
Run with `pytest -n12` to spawn 12 process that each run 1/12th of the tests.
|
|
||||||
|
|||||||
@@ -265,19 +265,14 @@ def bake_target_group_lookup(world: World, get_target_groups: Callable[[int], li
|
|||||||
return { group: get_target_groups(group) for group in unique_groups }
|
return { group: get_target_groups(group) for group in unique_groups }
|
||||||
|
|
||||||
|
|
||||||
def disconnect_entrance_for_randomization(entrance: Entrance, target_group: int | None = None,
|
def disconnect_entrance_for_randomization(entrance: Entrance, target_group: int | None = 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
|
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. Because it attempts
|
in randomize_entrances. This should be done after setting the type and group of the entrance.
|
||||||
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 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
|
:param target_group: The group to assign to the created ER target. If not specified, the group from
|
||||||
the original entrance will be copied.
|
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
|
child_region = entrance.connected_region
|
||||||
parent_region = entrance.parent_region
|
parent_region = entrance.parent_region
|
||||||
@@ -292,11 +287,8 @@ 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
|
# targets in the child region will be created when the other direction edge is disconnected
|
||||||
target = parent_region.create_er_target(entrance.name)
|
target = parent_region.create_er_target(entrance.name)
|
||||||
else:
|
else:
|
||||||
# for 1-ways, the child region needs a target. naming is not a concern for coupling so we
|
# for 1-ways, the child region needs a target and coupling/naming is not a concern
|
||||||
# allow it to be user provided (and require it, to prevent an unhelpful assumed name in pairings)
|
target = child_region.create_er_target(child_region.name)
|
||||||
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_type = entrance.randomization_type
|
||||||
target.randomization_group = target_group or entrance.randomization_group
|
target.randomization_group = target_group or entrance.randomization_group
|
||||||
|
|
||||||
@@ -366,34 +358,6 @@ def randomize_entrances(
|
|||||||
if on_connect:
|
if on_connect:
|
||||||
on_connect(er_state, placed_exits)
|
on_connect(er_state, placed_exits)
|
||||||
|
|
||||||
def needs_speculative_sweep(dead_end: bool, require_new_exits: bool, placeable_exits: list[Entrance]) -> bool:
|
|
||||||
# speculative sweep is expensive. We currently only do it as a last resort, if we might cap off the graph
|
|
||||||
# entirely
|
|
||||||
if len(placeable_exits) > 1:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# in certain stages of randomization we either expect or don't care if the search space shrinks.
|
|
||||||
# we should never speculative sweep here.
|
|
||||||
if dead_end or not require_new_exits or not perform_validity_check:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# edge case - if all dead ends have pre-placed progression or indirect connections, they are pulled forward
|
|
||||||
# into the non dead end stage. In this case, and only this case, it's possible that the last connection may
|
|
||||||
# actually be placeable in stage 1. We need to skip speculative sweep in this case because we expect the graph
|
|
||||||
# to get capped off.
|
|
||||||
|
|
||||||
# check to see if we are proposing the last placement
|
|
||||||
if not coupled:
|
|
||||||
# in uncoupled, this check is easy as there will only be one target.
|
|
||||||
is_last_placement = len(entrance_lookup) == 1
|
|
||||||
else:
|
|
||||||
# a bit harder, there may be 1 or 2 targets depending on if the exit to place is one way or two way.
|
|
||||||
# if it is two way, we can safely assume that one of the targets is the logical pair of the exit.
|
|
||||||
desired_target_count = 2 if placeable_exits[0].randomization_type == EntranceType.TWO_WAY else 1
|
|
||||||
is_last_placement = len(entrance_lookup) == desired_target_count
|
|
||||||
# if it's not the last placement, we need a sweep
|
|
||||||
return not is_last_placement
|
|
||||||
|
|
||||||
def find_pairing(dead_end: bool, require_new_exits: bool) -> bool:
|
def find_pairing(dead_end: bool, require_new_exits: bool) -> bool:
|
||||||
nonlocal perform_validity_check
|
nonlocal perform_validity_check
|
||||||
placeable_exits = er_state.find_placeable_exits(perform_validity_check, exits)
|
placeable_exits = er_state.find_placeable_exits(perform_validity_check, exits)
|
||||||
@@ -407,9 +371,11 @@ def randomize_entrances(
|
|||||||
# very last exit and check whatever exits we open up are functionally accessible.
|
# very last exit and check whatever exits we open up are functionally accessible.
|
||||||
# this requirement can be ignored on a beaten minimal, islands are no issue there.
|
# this requirement can be ignored on a beaten minimal, islands are no issue there.
|
||||||
exit_requirement_satisfied = (not perform_validity_check or not require_new_exits
|
exit_requirement_satisfied = (not perform_validity_check or not require_new_exits
|
||||||
or target_entrance.connected_region not in er_state.placed_regions)
|
or target_entrance.connected_region not in er_state.placed_regions)
|
||||||
|
needs_speculative_sweep = (not dead_end and require_new_exits and perform_validity_check
|
||||||
|
and len(placeable_exits) == 1)
|
||||||
if exit_requirement_satisfied and source_exit.can_connect_to(target_entrance, dead_end, er_state):
|
if exit_requirement_satisfied and source_exit.can_connect_to(target_entrance, dead_end, er_state):
|
||||||
if (needs_speculative_sweep(dead_end, require_new_exits, placeable_exits)
|
if (needs_speculative_sweep
|
||||||
and not er_state.test_speculative_connection(source_exit, target_entrance, exits_set)):
|
and not er_state.test_speculative_connection(source_exit, target_entrance, exits_set)):
|
||||||
continue
|
continue
|
||||||
do_placement(source_exit, target_entrance)
|
do_placement(source_exit, target_entrance)
|
||||||
|
|||||||
8
kvui.py
8
kvui.py
@@ -296,7 +296,7 @@ class SelectableLabel(RecycleDataViewBehavior, TooltipLabel):
|
|||||||
else:
|
else:
|
||||||
# Not a fan of the following few lines, but they work.
|
# Not a fan of the following few lines, but they work.
|
||||||
temp = MarkupLabel(text=self.text).markup
|
temp = MarkupLabel(text=self.text).markup
|
||||||
text = "".join(part for part in temp if not part.startswith("["))
|
text = "".join(part for part in temp if not part.startswith(("[color", "[/color]", "[ref=", "[/ref]")))
|
||||||
cmdinput = App.get_running_app().textinput
|
cmdinput = App.get_running_app().textinput
|
||||||
if not cmdinput.text:
|
if not cmdinput.text:
|
||||||
input_text = get_input_text_from_response(text, App.get_running_app().last_autofillable_command)
|
input_text = get_input_text_from_response(text, App.get_running_app().last_autofillable_command)
|
||||||
@@ -817,12 +817,6 @@ class HintLayout(BoxLayout):
|
|||||||
boxlayout.add_widget(AutocompleteHintInput())
|
boxlayout.add_widget(AutocompleteHintInput())
|
||||||
self.add_widget(boxlayout)
|
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] = {
|
status_names: typing.Dict[HintStatus, str] = {
|
||||||
HintStatus.HINT_FOUND: "Found",
|
HintStatus.HINT_FOUND: "Found",
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
colorama>=0.4.6
|
colorama>=0.4.6
|
||||||
websockets>=13.0.1,<14
|
websockets>=13.0.1,<14
|
||||||
PyYAML>=6.0.2
|
PyYAML>=6.0.2
|
||||||
jellyfish>=1.1.3
|
jellyfish>=1.1.0
|
||||||
jinja2>=3.1.6
|
jinja2>=3.1.4
|
||||||
schema>=0.7.7
|
schema>=0.7.7
|
||||||
kivy>=2.3.1
|
kivy>=2.3.0
|
||||||
bsdiff4>=1.2.6
|
bsdiff4>=1.2.4
|
||||||
platformdirs>=4.3.6
|
platformdirs>=4.2.2
|
||||||
certifi>=2025.1.31
|
certifi>=2024.12.14
|
||||||
cython>=3.0.12
|
cython>=3.0.11
|
||||||
cymem>=2.0.11
|
cymem>=2.0.8
|
||||||
orjson>=3.10.15
|
orjson>=3.10.7
|
||||||
typing_extensions>=4.12.2
|
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
|
# This is a bit jank. We need cx-Freeze to be able to run anything from this script, so install it
|
||||||
requirement = 'cx-Freeze==8.0.0'
|
requirement = 'cx-Freeze==7.2.0'
|
||||||
try:
|
try:
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ class TestDisconnectForRandomization(unittest.TestCase):
|
|||||||
e.randomization_group = 1
|
e.randomization_group = 1
|
||||||
e.connect(r2)
|
e.connect(r2)
|
||||||
|
|
||||||
disconnect_entrance_for_randomization(e, one_way_target_name="foo")
|
disconnect_entrance_for_randomization(e)
|
||||||
|
|
||||||
self.assertIsNone(e.connected_region)
|
self.assertIsNone(e.connected_region)
|
||||||
self.assertEqual([], r1.entrances)
|
self.assertEqual([], r1.entrances)
|
||||||
@@ -158,22 +158,10 @@ class TestDisconnectForRandomization(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(1, len(r2.entrances))
|
self.assertEqual(1, len(r2.entrances))
|
||||||
self.assertIsNone(r2.entrances[0].parent_region)
|
self.assertIsNone(r2.entrances[0].parent_region)
|
||||||
self.assertEqual("foo", r2.entrances[0].name)
|
self.assertEqual("r2", r2.entrances[0].name)
|
||||||
self.assertEqual(EntranceType.ONE_WAY, r2.entrances[0].randomization_type)
|
self.assertEqual(EntranceType.ONE_WAY, r2.entrances[0].randomization_type)
|
||||||
self.assertEqual(1, r2.entrances[0].randomization_group)
|
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):
|
def test_disconnect_uses_alternate_group(self):
|
||||||
multiworld = generate_test_multiworld()
|
multiworld = generate_test_multiworld()
|
||||||
r1 = Region("r1", 1, multiworld)
|
r1 = Region("r1", 1, multiworld)
|
||||||
@@ -183,7 +171,7 @@ class TestDisconnectForRandomization(unittest.TestCase):
|
|||||||
e.randomization_group = 1
|
e.randomization_group = 1
|
||||||
e.connect(r2)
|
e.connect(r2)
|
||||||
|
|
||||||
disconnect_entrance_for_randomization(e, 2, "foo")
|
disconnect_entrance_for_randomization(e, 2)
|
||||||
|
|
||||||
self.assertIsNone(e.connected_region)
|
self.assertIsNone(e.connected_region)
|
||||||
self.assertEqual([], r1.entrances)
|
self.assertEqual([], r1.entrances)
|
||||||
@@ -193,7 +181,7 @@ class TestDisconnectForRandomization(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(1, len(r2.entrances))
|
self.assertEqual(1, len(r2.entrances))
|
||||||
self.assertIsNone(r2.entrances[0].parent_region)
|
self.assertIsNone(r2.entrances[0].parent_region)
|
||||||
self.assertEqual("foo", r2.entrances[0].name)
|
self.assertEqual("r2", r2.entrances[0].name)
|
||||||
self.assertEqual(EntranceType.ONE_WAY, r2.entrances[0].randomization_type)
|
self.assertEqual(EntranceType.ONE_WAY, r2.entrances[0].randomization_type)
|
||||||
self.assertEqual(2, r2.entrances[0].randomization_group)
|
self.assertEqual(2, r2.entrances[0].randomization_group)
|
||||||
|
|
||||||
@@ -230,7 +218,7 @@ class TestRandomizeEntrances(unittest.TestCase):
|
|||||||
self.assertEqual(80, len(result.pairings))
|
self.assertEqual(80, len(result.pairings))
|
||||||
self.assertEqual(80, len(result.placements))
|
self.assertEqual(80, len(result.placements))
|
||||||
|
|
||||||
def test_coupled(self):
|
def test_coupling(self):
|
||||||
"""tests that in coupled mode, all 2 way transitions have an inverse"""
|
"""tests that in coupled mode, all 2 way transitions have an inverse"""
|
||||||
multiworld = generate_test_multiworld()
|
multiworld = generate_test_multiworld()
|
||||||
generate_disconnected_region_grid(multiworld, 5)
|
generate_disconnected_region_grid(multiworld, 5)
|
||||||
@@ -248,36 +236,6 @@ class TestRandomizeEntrances(unittest.TestCase):
|
|||||||
# if we didn't visit every placement the verification on_connect doesn't really mean much
|
# if we didn't visit every placement the verification on_connect doesn't really mean much
|
||||||
self.assertEqual(len(result.placements), seen_placement_count)
|
self.assertEqual(len(result.placements), seen_placement_count)
|
||||||
|
|
||||||
def test_uncoupled_succeeds_stage1_indirect_condition(self):
|
|
||||||
multiworld = generate_test_multiworld()
|
|
||||||
menu = multiworld.get_region("Menu", 1)
|
|
||||||
generate_entrance_pair(menu, "_right", ERTestGroups.RIGHT)
|
|
||||||
end = Region("End", 1, multiworld)
|
|
||||||
multiworld.regions.append(end)
|
|
||||||
generate_entrance_pair(end, "_left", ERTestGroups.LEFT)
|
|
||||||
multiworld.register_indirect_condition(end, None)
|
|
||||||
|
|
||||||
result = randomize_entrances(multiworld.worlds[1], False, directionally_matched_group_lookup)
|
|
||||||
self.assertSetEqual({
|
|
||||||
("Menu_right", "End_left"),
|
|
||||||
("End_left", "Menu_right")
|
|
||||||
}, set(result.pairings))
|
|
||||||
|
|
||||||
def test_coupled_succeeds_stage1_indirect_condition(self):
|
|
||||||
multiworld = generate_test_multiworld()
|
|
||||||
menu = multiworld.get_region("Menu", 1)
|
|
||||||
generate_entrance_pair(menu, "_right", ERTestGroups.RIGHT)
|
|
||||||
end = Region("End", 1, multiworld)
|
|
||||||
multiworld.regions.append(end)
|
|
||||||
generate_entrance_pair(end, "_left", ERTestGroups.LEFT)
|
|
||||||
multiworld.register_indirect_condition(end, None)
|
|
||||||
|
|
||||||
result = randomize_entrances(multiworld.worlds[1], True, directionally_matched_group_lookup)
|
|
||||||
self.assertSetEqual({
|
|
||||||
("Menu_right", "End_left"),
|
|
||||||
("End_left", "Menu_right")
|
|
||||||
}, set(result.pairings))
|
|
||||||
|
|
||||||
def test_uncoupled(self):
|
def test_uncoupled(self):
|
||||||
"""tests that in uncoupled mode, no transitions have an (intentional) inverse"""
|
"""tests that in uncoupled mode, no transitions have an (intentional) inverse"""
|
||||||
multiworld = generate_test_multiworld()
|
multiworld = generate_test_multiworld()
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
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))
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
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.")
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
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")
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import unittest
|
import unittest
|
||||||
from typing import ClassVar, List, Tuple
|
from typing import List, Tuple
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
from BaseClasses import CollectionState, Location, MultiWorld
|
from BaseClasses import CollectionState, Location, MultiWorld
|
||||||
@@ -7,7 +7,6 @@ from Fill import distribute_items_restrictive
|
|||||||
from Options import Accessibility
|
from Options import Accessibility
|
||||||
from worlds.AutoWorld import AutoWorldRegister, call_all, call_single
|
from worlds.AutoWorld import AutoWorldRegister, call_all, call_single
|
||||||
from ..general import gen_steps, setup_multiworld
|
from ..general import gen_steps, setup_multiworld
|
||||||
from ..param import classvar_matrix
|
|
||||||
|
|
||||||
|
|
||||||
class MultiworldTestBase(TestCase):
|
class MultiworldTestBase(TestCase):
|
||||||
@@ -64,18 +63,15 @@ class TestAllGamesMultiworld(MultiworldTestBase):
|
|||||||
self.assertTrue(self.fulfills_accessibility(), "Collected all locations, but can't beat the game")
|
self.assertTrue(self.fulfills_accessibility(), "Collected all locations, but can't beat the game")
|
||||||
|
|
||||||
|
|
||||||
@classvar_matrix(game=AutoWorldRegister.world_types.keys())
|
|
||||||
class TestTwoPlayerMulti(MultiworldTestBase):
|
class TestTwoPlayerMulti(MultiworldTestBase):
|
||||||
game: ClassVar[str]
|
|
||||||
|
|
||||||
def test_two_player_single_game_fills(self) -> None:
|
def test_two_player_single_game_fills(self) -> None:
|
||||||
"""Tests that a multiworld of two players for each registered game world can generate."""
|
"""Tests that a multiworld of two players for each registered game world can generate."""
|
||||||
world_type = AutoWorldRegister.world_types[self.game]
|
for world_type in AutoWorldRegister.world_types.values():
|
||||||
self.multiworld = setup_multiworld([world_type, world_type], ())
|
self.multiworld = setup_multiworld([world_type, world_type], ())
|
||||||
for world in self.multiworld.worlds.values():
|
for world in self.multiworld.worlds.values():
|
||||||
world.options.accessibility.value = Accessibility.option_full
|
world.options.accessibility.value = Accessibility.option_full
|
||||||
self.assertSteps(gen_steps)
|
self.assertSteps(gen_steps)
|
||||||
with self.subTest("filling multiworld", games=world_type.game, seed=self.multiworld.seed):
|
with self.subTest("filling multiworld", games=world_type.game, seed=self.multiworld.seed):
|
||||||
distribute_items_restrictive(self.multiworld)
|
distribute_items_restrictive(self.multiworld)
|
||||||
call_all(self.multiworld, "post_fill")
|
call_all(self.multiworld, "post_fill")
|
||||||
self.assertTrue(self.fulfills_accessibility(), "Collected all locations, but can't beat the game")
|
self.assertTrue(self.fulfills_accessibility(), "Collected all locations, but can't beat the game")
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
import itertools
|
|
||||||
import sys
|
|
||||||
from typing import Any, Callable, Iterable
|
|
||||||
|
|
||||||
|
|
||||||
def classvar_matrix(**kwargs: Iterable[Any]) -> Callable[[type], None]:
|
|
||||||
"""
|
|
||||||
Create a new class for each variation of input, allowing to generate a TestCase matrix / parametrization that
|
|
||||||
supports multi-threading and has better reporting for ``unittest --durations=...`` and ``pytest --durations=...``
|
|
||||||
than subtests.
|
|
||||||
|
|
||||||
The kwargs will be set as ClassVars in the newly created classes. Use as ::
|
|
||||||
|
|
||||||
@classvar_matrix(var_name=[value1, value2])
|
|
||||||
class MyTestCase(unittest.TestCase):
|
|
||||||
var_name: typing.ClassVar[...]
|
|
||||||
|
|
||||||
:param kwargs: A dict of ClassVars to set, where key is the variable name and value is a list of all values.
|
|
||||||
:return: A decorator to be applied to a class.
|
|
||||||
"""
|
|
||||||
keys: tuple[str]
|
|
||||||
values: Iterable[Iterable[Any]]
|
|
||||||
keys, values = zip(*kwargs.items())
|
|
||||||
values = map(lambda v: sorted(v) if isinstance(v, (set, frozenset)) else v, values)
|
|
||||||
permutations_dicts = [dict(zip(keys, v)) for v in itertools.product(*values)]
|
|
||||||
|
|
||||||
def decorator(cls: type) -> None:
|
|
||||||
mod = sys.modules[cls.__module__]
|
|
||||||
|
|
||||||
for permutation in permutations_dicts:
|
|
||||||
|
|
||||||
class Unrolled(cls): # type: ignore
|
|
||||||
pass
|
|
||||||
|
|
||||||
for k, v in permutation.items():
|
|
||||||
setattr(Unrolled, k, v)
|
|
||||||
params = ", ".join([f"{k}={repr(v)}" for k, v in permutation.items()])
|
|
||||||
params = f"{{{params}}}"
|
|
||||||
|
|
||||||
Unrolled.__module__ = cls.__module__
|
|
||||||
Unrolled.__qualname__ = f"{cls.__qualname__}{params}"
|
|
||||||
setattr(mod, f"{cls.__name__}{params}", Unrolled)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
return decorator
|
|
||||||
@@ -88,6 +88,7 @@ processes = weakref.WeakSet()
|
|||||||
|
|
||||||
|
|
||||||
def launch_subprocess(func: Callable, name: str | None = None, args: Tuple[str, ...] = ()) -> None:
|
def launch_subprocess(func: Callable, name: str | None = None, args: Tuple[str, ...] = ()) -> None:
|
||||||
|
global processes
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
process = multiprocessing.Process(target=func, name=name, args=args)
|
process = multiprocessing.Process(target=func, name=name, args=args)
|
||||||
process.start()
|
process.start()
|
||||||
|
|||||||
@@ -276,6 +276,6 @@ def launch(*launch_args: str) -> None:
|
|||||||
|
|
||||||
Utils.init_logging("BizHawkClient", exception_logger="Client")
|
Utils.init_logging("BizHawkClient", exception_logger="Client")
|
||||||
import colorama
|
import colorama
|
||||||
colorama.just_fix_windows_console()
|
colorama.init()
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
colorama.deinit()
|
colorama.deinit()
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ mpyq>=0.2.5
|
|||||||
portpicker>=1.5.2
|
portpicker>=1.5.2
|
||||||
aiohttp>=3.8.4
|
aiohttp>=3.8.4
|
||||||
loguru>=0.7.0
|
loguru>=0.7.0
|
||||||
protobuf==3.20.3
|
protobuf==3.20.3
|
||||||
@@ -238,12 +238,14 @@ class AdventureWorld(World):
|
|||||||
|
|
||||||
def create_regions(self) -> None:
|
def create_regions(self) -> None:
|
||||||
create_regions(self.options, self.multiworld, self.player, self.dragon_rooms)
|
create_regions(self.options, self.multiworld, self.player, self.dragon_rooms)
|
||||||
|
|
||||||
|
set_rules = set_rules
|
||||||
|
|
||||||
|
def generate_basic(self) -> None:
|
||||||
self.multiworld.get_location("Chalice Home", self.player).place_locked_item(
|
self.multiworld.get_location("Chalice Home", self.player).place_locked_item(
|
||||||
self.create_event("Victory", ItemClassification.progression))
|
self.create_event("Victory", ItemClassification.progression))
|
||||||
self.multiworld.completion_condition[self.player] = lambda state: state.has("Victory", self.player)
|
self.multiworld.completion_condition[self.player] = lambda state: state.has("Victory", self.player)
|
||||||
|
|
||||||
set_rules = set_rules
|
|
||||||
|
|
||||||
def pre_fill(self):
|
def pre_fill(self):
|
||||||
# Place empty items in filler locations here, to limit
|
# Place empty items in filler locations here, to limit
|
||||||
# the number of exported empty items and the density of stuff in overworld.
|
# the number of exported empty items and the density of stuff in overworld.
|
||||||
|
|||||||
@@ -261,6 +261,6 @@ def launch():
|
|||||||
# options = Utils.get_options()
|
# options = Utils.get_options()
|
||||||
|
|
||||||
import colorama
|
import colorama
|
||||||
colorama.just_fix_windows_console()
|
colorama.init()
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
colorama.deinit()
|
colorama.deinit()
|
||||||
|
|||||||
@@ -515,15 +515,10 @@ def _populate_sprite_table():
|
|||||||
logging.debug(f"Spritefile {file} could not be loaded as a valid sprite.")
|
logging.debug(f"Spritefile {file} could not be loaded as a valid sprite.")
|
||||||
|
|
||||||
with concurrent.futures.ThreadPoolExecutor() as pool:
|
with concurrent.futures.ThreadPoolExecutor() as pool:
|
||||||
sprite_paths = [user_path('data', 'sprites', 'alttpr'), user_path('data', 'sprites', 'custom')]
|
for dir in [user_path('data', 'sprites', 'alttpr'), user_path('data', 'sprites', 'custom')]:
|
||||||
for dir in [dir for dir in sprite_paths if os.path.isdir(dir)]:
|
|
||||||
for file in os.listdir(dir):
|
for file in os.listdir(dir):
|
||||||
pool.submit(load_sprite_from_file, os.path.join(dir, file))
|
pool.submit(load_sprite_from_file, os.path.join(dir, file))
|
||||||
|
|
||||||
if "link" not in _sprite_table:
|
|
||||||
logging.info("Link sprite was not loaded. Loading link from base rom")
|
|
||||||
load_sprite_from_file(get_base_rom_path())
|
|
||||||
|
|
||||||
|
|
||||||
class Sprite():
|
class Sprite():
|
||||||
sprite_size = 28672
|
sprite_size = 28672
|
||||||
@@ -559,11 +554,6 @@ class Sprite():
|
|||||||
self.sprite = filedata[0x80000:0x87000]
|
self.sprite = filedata[0x80000:0x87000]
|
||||||
self.palette = filedata[0xDD308:0xDD380]
|
self.palette = filedata[0xDD308:0xDD380]
|
||||||
self.glove_palette = filedata[0xDEDF5:0xDEDF9]
|
self.glove_palette = filedata[0xDEDF5:0xDEDF9]
|
||||||
h = hashlib.md5()
|
|
||||||
h.update(filedata)
|
|
||||||
if h.hexdigest() == LTTPJPN10HASH:
|
|
||||||
self.name = "Link"
|
|
||||||
self.author_name = "Nintendo"
|
|
||||||
elif filedata.startswith(b'ZSPR'):
|
elif filedata.startswith(b'ZSPR'):
|
||||||
self.from_zspr(filedata, filename)
|
self.from_zspr(filedata, filename)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -121,7 +121,6 @@ class ALTTPWeb(WebWorld):
|
|||||||
)
|
)
|
||||||
|
|
||||||
tutorials = [setup_en, setup_de, setup_es, setup_fr, msu, msu_es, msu_fr, plando, oof_sound]
|
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):
|
class ALTTPWorld(World):
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
maseya-z3pr>=1.0.0rc1
|
maseya-z3pr>=1.0.0rc1
|
||||||
xxtea>=3.0.0
|
xxtea>=3.0.0
|
||||||
@@ -41,7 +41,6 @@ class AquariaWeb(WebWorld):
|
|||||||
)
|
)
|
||||||
|
|
||||||
tutorials = [setup, setup_fr]
|
tutorials = [setup, setup_fr]
|
||||||
game_info_languages = ["en", "fr"]
|
|
||||||
|
|
||||||
|
|
||||||
class AquariaWorld(World):
|
class AquariaWorld(World):
|
||||||
|
|||||||
@@ -1,31 +1,6 @@
|
|||||||
# Celeste 64 - Changelog
|
# Celeste 64 - Changelog
|
||||||
|
|
||||||
|
|
||||||
## v1.3
|
|
||||||
|
|
||||||
### Features:
|
|
||||||
|
|
||||||
- New optional Location Checks
|
|
||||||
- Checkpointsanity
|
|
||||||
- Hair Color
|
|
||||||
- Allows for setting of Maddy's hair color in each of No Dash, One Dash, Two Dash, and Feather states
|
|
||||||
- Other Player Ghosts
|
|
||||||
- A game config option allows you to see ghosts of other Celeste 64 players in the multiworld
|
|
||||||
|
|
||||||
### Quality of Life:
|
|
||||||
|
|
||||||
- Checkpoint Warping
|
|
||||||
- Received Checkpoint items allow for warping to their respective checkpoint
|
|
||||||
- These items are on their respective checkpoint location if Checkpointsanity is disabled
|
|
||||||
- Logic accounts for being able to warp to otherwise inaccessible areas
|
|
||||||
- Checkpoints are a possible option for a starting item on Standard Logic + Move Shuffle + Checkpointsanity
|
|
||||||
- New Options toggle to enable/disable background input
|
|
||||||
|
|
||||||
### Bug Fixes:
|
|
||||||
|
|
||||||
- Traffic Blocks now correctly appear disabled within Cassettes
|
|
||||||
|
|
||||||
|
|
||||||
## v1.2
|
## v1.2
|
||||||
|
|
||||||
### Features:
|
### Features:
|
||||||
|
|||||||
@@ -39,22 +39,6 @@ move_item_data_table: Dict[str, Celeste64ItemData] = {
|
|||||||
ItemName.climb: Celeste64ItemData(celeste_64_base_id + 0xD, ItemClassification.progression),
|
ItemName.climb: Celeste64ItemData(celeste_64_base_id + 0xD, ItemClassification.progression),
|
||||||
}
|
}
|
||||||
|
|
||||||
checkpoint_item_data_table: Dict[str, Celeste64ItemData] = {
|
item_data_table: Dict[str, Celeste64ItemData] = {**collectable_item_data_table, **unlockable_item_data_table, **move_item_data_table}
|
||||||
ItemName.checkpoint_1: Celeste64ItemData(celeste_64_base_id + 0x20, ItemClassification.progression),
|
|
||||||
ItemName.checkpoint_2: Celeste64ItemData(celeste_64_base_id + 0x21, ItemClassification.progression),
|
|
||||||
ItemName.checkpoint_3: Celeste64ItemData(celeste_64_base_id + 0x22, ItemClassification.progression),
|
|
||||||
ItemName.checkpoint_4: Celeste64ItemData(celeste_64_base_id + 0x23, ItemClassification.progression),
|
|
||||||
ItemName.checkpoint_5: Celeste64ItemData(celeste_64_base_id + 0x24, ItemClassification.progression),
|
|
||||||
ItemName.checkpoint_6: Celeste64ItemData(celeste_64_base_id + 0x25, ItemClassification.progression),
|
|
||||||
ItemName.checkpoint_7: Celeste64ItemData(celeste_64_base_id + 0x26, ItemClassification.progression),
|
|
||||||
ItemName.checkpoint_8: Celeste64ItemData(celeste_64_base_id + 0x27, ItemClassification.progression),
|
|
||||||
ItemName.checkpoint_9: Celeste64ItemData(celeste_64_base_id + 0x28, ItemClassification.progression),
|
|
||||||
ItemName.checkpoint_10: Celeste64ItemData(celeste_64_base_id + 0x29, ItemClassification.progression),
|
|
||||||
}
|
|
||||||
|
|
||||||
item_data_table: Dict[str, Celeste64ItemData] = {**collectable_item_data_table,
|
|
||||||
**unlockable_item_data_table,
|
|
||||||
**move_item_data_table,
|
|
||||||
**checkpoint_item_data_table}
|
|
||||||
|
|
||||||
item_table = {name: data.code for name, data in item_data_table.items() if data.code is not None}
|
item_table = {name: data.code for name, data in item_data_table.items() if data.code is not None}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from typing import Dict, NamedTuple, Optional
|
from typing import Dict, NamedTuple, Optional
|
||||||
|
|
||||||
from BaseClasses import Location
|
from BaseClasses import Location
|
||||||
from .Names import LocationName, RegionName
|
from .Names import LocationName
|
||||||
|
|
||||||
|
|
||||||
celeste_64_base_id: int = 0xCA0000
|
celeste_64_base_id: int = 0xCA0000
|
||||||
@@ -17,80 +17,66 @@ class Celeste64LocationData(NamedTuple):
|
|||||||
|
|
||||||
|
|
||||||
strawberry_location_data_table: Dict[str, Celeste64LocationData] = {
|
strawberry_location_data_table: Dict[str, Celeste64LocationData] = {
|
||||||
LocationName.strawberry_1: Celeste64LocationData(RegionName.intro_islands, celeste_64_base_id + 0x00),
|
LocationName.strawberry_1: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x00),
|
||||||
LocationName.strawberry_2: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x01),
|
LocationName.strawberry_2: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x01),
|
||||||
LocationName.strawberry_3: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x02),
|
LocationName.strawberry_3: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x02),
|
||||||
LocationName.strawberry_4: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x03),
|
LocationName.strawberry_4: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x03),
|
||||||
LocationName.strawberry_5: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x04),
|
LocationName.strawberry_5: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x04),
|
||||||
LocationName.strawberry_6: Celeste64LocationData(RegionName.highway_island, celeste_64_base_id + 0x05),
|
LocationName.strawberry_6: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x05),
|
||||||
LocationName.strawberry_7: Celeste64LocationData(RegionName.highway_island, celeste_64_base_id + 0x06),
|
LocationName.strawberry_7: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x06),
|
||||||
LocationName.strawberry_8: Celeste64LocationData(RegionName.nw_girders_island, celeste_64_base_id + 0x07),
|
LocationName.strawberry_8: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x07),
|
||||||
LocationName.strawberry_9: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x08),
|
LocationName.strawberry_9: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x08),
|
||||||
LocationName.strawberry_10: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x09),
|
LocationName.strawberry_10: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x09),
|
||||||
LocationName.strawberry_11: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x0A),
|
LocationName.strawberry_11: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x0A),
|
||||||
LocationName.strawberry_12: Celeste64LocationData(RegionName.badeline_tower_lower, celeste_64_base_id + 0x0B),
|
LocationName.strawberry_12: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x0B),
|
||||||
LocationName.strawberry_13: Celeste64LocationData(RegionName.highway_island, celeste_64_base_id + 0x0C),
|
LocationName.strawberry_13: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x0C),
|
||||||
LocationName.strawberry_14: Celeste64LocationData(RegionName.ne_feathers_island, celeste_64_base_id + 0x0D),
|
LocationName.strawberry_14: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x0D),
|
||||||
LocationName.strawberry_15: Celeste64LocationData(RegionName.ne_feathers_island, celeste_64_base_id + 0x0E),
|
LocationName.strawberry_15: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x0E),
|
||||||
LocationName.strawberry_16: Celeste64LocationData(RegionName.ne_feathers_island, celeste_64_base_id + 0x0F),
|
LocationName.strawberry_16: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x0F),
|
||||||
LocationName.strawberry_17: Celeste64LocationData(RegionName.se_house_island, celeste_64_base_id + 0x10),
|
LocationName.strawberry_17: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x10),
|
||||||
LocationName.strawberry_18: Celeste64LocationData(RegionName.se_house_island, celeste_64_base_id + 0x11),
|
LocationName.strawberry_18: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x11),
|
||||||
LocationName.strawberry_19: Celeste64LocationData(RegionName.se_house_island, celeste_64_base_id + 0x12),
|
LocationName.strawberry_19: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x12),
|
||||||
LocationName.strawberry_20: Celeste64LocationData(RegionName.badeline_tower_lower, celeste_64_base_id + 0x13),
|
LocationName.strawberry_20: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x13),
|
||||||
LocationName.strawberry_21: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x14),
|
LocationName.strawberry_21: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x14),
|
||||||
LocationName.strawberry_22: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x15),
|
LocationName.strawberry_22: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x15),
|
||||||
LocationName.strawberry_23: Celeste64LocationData(RegionName.highway_island, celeste_64_base_id + 0x16),
|
LocationName.strawberry_23: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x16),
|
||||||
LocationName.strawberry_24: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x17),
|
LocationName.strawberry_24: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x17),
|
||||||
LocationName.strawberry_25: Celeste64LocationData(RegionName.se_house_island, celeste_64_base_id + 0x18),
|
LocationName.strawberry_25: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x18),
|
||||||
LocationName.strawberry_26: Celeste64LocationData(RegionName.highway_island, celeste_64_base_id + 0x19),
|
LocationName.strawberry_26: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x19),
|
||||||
LocationName.strawberry_27: Celeste64LocationData(RegionName.ne_feathers_island, celeste_64_base_id + 0x1A),
|
LocationName.strawberry_27: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x1A),
|
||||||
LocationName.strawberry_28: Celeste64LocationData(RegionName.ne_feathers_island, celeste_64_base_id + 0x1B),
|
LocationName.strawberry_28: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x1B),
|
||||||
LocationName.strawberry_29: Celeste64LocationData(RegionName.badeline_tower_upper, celeste_64_base_id + 0x1C),
|
LocationName.strawberry_29: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x1C),
|
||||||
LocationName.strawberry_30: Celeste64LocationData(RegionName.badeline_island, celeste_64_base_id + 0x1D),
|
LocationName.strawberry_30: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x1D),
|
||||||
}
|
}
|
||||||
|
|
||||||
friend_location_data_table: Dict[str, Celeste64LocationData] = {
|
friend_location_data_table: Dict[str, Celeste64LocationData] = {
|
||||||
LocationName.granny_1: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x100 + 0x00),
|
LocationName.granny_1: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x100 + 0x00),
|
||||||
LocationName.granny_2: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x100 + 0x01),
|
LocationName.granny_2: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x100 + 0x01),
|
||||||
LocationName.granny_3: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x100 + 0x02),
|
LocationName.granny_3: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x100 + 0x02),
|
||||||
LocationName.theo_1: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x100 + 0x03),
|
LocationName.theo_1: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x100 + 0x03),
|
||||||
LocationName.theo_2: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x100 + 0x04),
|
LocationName.theo_2: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x100 + 0x04),
|
||||||
LocationName.theo_3: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x100 + 0x05),
|
LocationName.theo_3: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x100 + 0x05),
|
||||||
LocationName.badeline_1: Celeste64LocationData(RegionName.badeline_island, celeste_64_base_id + 0x100 + 0x06),
|
LocationName.badeline_1: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x100 + 0x06),
|
||||||
LocationName.badeline_2: Celeste64LocationData(RegionName.badeline_island, celeste_64_base_id + 0x100 + 0x07),
|
LocationName.badeline_2: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x100 + 0x07),
|
||||||
LocationName.badeline_3: Celeste64LocationData(RegionName.badeline_island, celeste_64_base_id + 0x100 + 0x08),
|
LocationName.badeline_3: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x100 + 0x08),
|
||||||
}
|
}
|
||||||
|
|
||||||
sign_location_data_table: Dict[str, Celeste64LocationData] = {
|
sign_location_data_table: Dict[str, Celeste64LocationData] = {
|
||||||
LocationName.sign_1: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x200 + 0x00),
|
LocationName.sign_1: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x200 + 0x00),
|
||||||
LocationName.sign_2: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x200 + 0x01),
|
LocationName.sign_2: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x200 + 0x01),
|
||||||
LocationName.sign_3: Celeste64LocationData(RegionName.highway_island, celeste_64_base_id + 0x200 + 0x02),
|
LocationName.sign_3: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x200 + 0x02),
|
||||||
LocationName.sign_4: Celeste64LocationData(RegionName.se_house_island, celeste_64_base_id + 0x200 + 0x03),
|
LocationName.sign_4: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x200 + 0x03),
|
||||||
LocationName.sign_5: Celeste64LocationData(RegionName.badeline_island, celeste_64_base_id + 0x200 + 0x04),
|
LocationName.sign_5: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x200 + 0x04),
|
||||||
}
|
}
|
||||||
|
|
||||||
car_location_data_table: Dict[str, Celeste64LocationData] = {
|
car_location_data_table: Dict[str, Celeste64LocationData] = {
|
||||||
LocationName.car_1: Celeste64LocationData(RegionName.intro_islands, celeste_64_base_id + 0x300 + 0x00),
|
LocationName.car_1: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x300 + 0x00),
|
||||||
LocationName.car_2: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x300 + 0x01),
|
LocationName.car_2: Celeste64LocationData("Forsaken City", celeste_64_base_id + 0x300 + 0x01),
|
||||||
}
|
|
||||||
|
|
||||||
checkpoint_location_data_table: Dict[str, Celeste64LocationData] = {
|
|
||||||
LocationName.checkpoint_1: Celeste64LocationData(RegionName.intro_islands, celeste_64_base_id + 0x400 + 0x00),
|
|
||||||
LocationName.checkpoint_2: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x400 + 0x01),
|
|
||||||
LocationName.checkpoint_3: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x400 + 0x02),
|
|
||||||
LocationName.checkpoint_4: Celeste64LocationData(RegionName.granny_island, celeste_64_base_id + 0x400 + 0x03),
|
|
||||||
LocationName.checkpoint_5: Celeste64LocationData(RegionName.highway_island, celeste_64_base_id + 0x400 + 0x04),
|
|
||||||
LocationName.checkpoint_6: Celeste64LocationData(RegionName.highway_island, celeste_64_base_id + 0x400 + 0x05),
|
|
||||||
LocationName.checkpoint_7: Celeste64LocationData(RegionName.ne_feathers_island, celeste_64_base_id + 0x400 + 0x06),
|
|
||||||
LocationName.checkpoint_8: Celeste64LocationData(RegionName.se_house_island, celeste_64_base_id + 0x400 + 0x07),
|
|
||||||
LocationName.checkpoint_9: Celeste64LocationData(RegionName.badeline_tower_upper, celeste_64_base_id + 0x400 + 0x08),
|
|
||||||
LocationName.checkpoint_10: Celeste64LocationData(RegionName.badeline_island, celeste_64_base_id + 0x400 + 0x09),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
location_data_table: Dict[str, Celeste64LocationData] = {**strawberry_location_data_table,
|
location_data_table: Dict[str, Celeste64LocationData] = {**strawberry_location_data_table,
|
||||||
**friend_location_data_table,
|
**friend_location_data_table,
|
||||||
**sign_location_data_table,
|
**sign_location_data_table,
|
||||||
**car_location_data_table,
|
**car_location_data_table}
|
||||||
**checkpoint_location_data_table}
|
|
||||||
|
|
||||||
location_table = {name: data.address for name, data in location_data_table.items() if data.address is not None}
|
location_table = {name: data.address for name, data in location_data_table.items() if data.address is not None}
|
||||||
|
|||||||
@@ -15,18 +15,3 @@ ground_dash = "Ground Dash"
|
|||||||
air_dash = "Air Dash"
|
air_dash = "Air Dash"
|
||||||
skid_jump = "Skid Jump"
|
skid_jump = "Skid Jump"
|
||||||
climb = "Climb"
|
climb = "Climb"
|
||||||
|
|
||||||
# Checkpoint Items
|
|
||||||
checkpoint_1 = "Intro Checkpoint"
|
|
||||||
checkpoint_2 = "Granny Checkpoint"
|
|
||||||
checkpoint_3 = "South-East Tower Checkpoint"
|
|
||||||
checkpoint_4 = "Climb Sign Checkpoint"
|
|
||||||
checkpoint_5 = "Freeway Checkpoint"
|
|
||||||
checkpoint_6 = "Freeway Feather Checkpoint"
|
|
||||||
checkpoint_7 = "Feather Maze Checkpoint"
|
|
||||||
checkpoint_8 = "Double Dash House Checkpoint"
|
|
||||||
checkpoint_9 = "Badeline Tower Checkpoint"
|
|
||||||
checkpoint_10 = "Badeline Island Checkpoint"
|
|
||||||
|
|
||||||
# Item used for logic definitions that are not possible with the given options
|
|
||||||
cannot_access = "CANNOT ACCESS"
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ strawberry_8 = "Traffic Block Strawberry"
|
|||||||
strawberry_9 = "South-West Dash Refills Strawberry"
|
strawberry_9 = "South-West Dash Refills Strawberry"
|
||||||
strawberry_10 = "South-East Tower Side Strawberry"
|
strawberry_10 = "South-East Tower Side Strawberry"
|
||||||
strawberry_11 = "Girders Strawberry"
|
strawberry_11 = "Girders Strawberry"
|
||||||
strawberry_12 = "Badeline Tower Bottom Strawberry"
|
strawberry_12 = "North-East Tower Bottom Strawberry"
|
||||||
strawberry_13 = "Breakable Blocks Strawberry"
|
strawberry_13 = "Breakable Blocks Strawberry"
|
||||||
strawberry_14 = "Feather Maze Strawberry"
|
strawberry_14 = "Feather Maze Strawberry"
|
||||||
strawberry_15 = "Feather Chain Strawberry"
|
strawberry_15 = "Feather Chain Strawberry"
|
||||||
@@ -18,7 +18,7 @@ strawberry_16 = "Feather Hidden Strawberry"
|
|||||||
strawberry_17 = "Double Dash Puzzle Strawberry"
|
strawberry_17 = "Double Dash Puzzle Strawberry"
|
||||||
strawberry_18 = "Double Dash Spike Climb Strawberry"
|
strawberry_18 = "Double Dash Spike Climb Strawberry"
|
||||||
strawberry_19 = "Double Dash Spring Strawberry"
|
strawberry_19 = "Double Dash Spring Strawberry"
|
||||||
strawberry_20 = "Badeline Tower Breakable Bottom Strawberry"
|
strawberry_20 = "North-East Tower Breakable Bottom Strawberry"
|
||||||
strawberry_21 = "Theo Tower Lower Cassette Strawberry"
|
strawberry_21 = "Theo Tower Lower Cassette Strawberry"
|
||||||
strawberry_22 = "Theo Tower Upper Cassette Strawberry"
|
strawberry_22 = "Theo Tower Upper Cassette Strawberry"
|
||||||
strawberry_23 = "South End of Bridge Cassette Strawberry"
|
strawberry_23 = "South End of Bridge Cassette Strawberry"
|
||||||
@@ -27,8 +27,8 @@ strawberry_25 = "Cassette Hidden in the House Strawberry"
|
|||||||
strawberry_26 = "North End of Bridge Cassette Strawberry"
|
strawberry_26 = "North End of Bridge Cassette Strawberry"
|
||||||
strawberry_27 = "Distant Feather Cassette Strawberry"
|
strawberry_27 = "Distant Feather Cassette Strawberry"
|
||||||
strawberry_28 = "Feather Arches Cassette Strawberry"
|
strawberry_28 = "Feather Arches Cassette Strawberry"
|
||||||
strawberry_29 = "Badeline Tower Cassette Strawberry"
|
strawberry_29 = "North-East Tower Cassette Strawberry"
|
||||||
strawberry_30 = "Badeline Island Cassette Strawberry"
|
strawberry_30 = "Badeline Cassette Strawberry"
|
||||||
|
|
||||||
# Friend Locations
|
# Friend Locations
|
||||||
granny_1 = "Granny Conversation 1"
|
granny_1 = "Granny Conversation 1"
|
||||||
@@ -51,15 +51,3 @@ sign_5 = "Credits Sign"
|
|||||||
# Car Locations
|
# Car Locations
|
||||||
car_1 = "Intro Car"
|
car_1 = "Intro Car"
|
||||||
car_2 = "Secret Car"
|
car_2 = "Secret Car"
|
||||||
|
|
||||||
# Checkpoint Locations
|
|
||||||
checkpoint_1 = "Intro Checkpoint"
|
|
||||||
checkpoint_2 = "Granny Checkpoint"
|
|
||||||
checkpoint_3 = "South-East Tower Checkpoint"
|
|
||||||
checkpoint_4 = "Climb Sign Checkpoint"
|
|
||||||
checkpoint_5 = "Freeway Checkpoint"
|
|
||||||
checkpoint_6 = "Freeway Feather Checkpoint"
|
|
||||||
checkpoint_7 = "Feather Maze Checkpoint"
|
|
||||||
checkpoint_8 = "Double Dash House Checkpoint"
|
|
||||||
checkpoint_9 = "Badeline Tower Checkpoint"
|
|
||||||
checkpoint_10 = "Badeline Island Checkpoint"
|
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
# Level Base Regions
|
|
||||||
forsaken_city = "Forsaken City"
|
|
||||||
|
|
||||||
# Forsaken City Regions
|
|
||||||
intro_islands = "Intro Islands"
|
|
||||||
granny_island = "Granny Island"
|
|
||||||
highway_island = "Freeway Island"
|
|
||||||
nw_girders_island = "North-West Girders Island"
|
|
||||||
ne_feathers_island = "North-East Feathers Island"
|
|
||||||
se_house_island = "South-East House Island"
|
|
||||||
badeline_tower_lower = "Badeline Tower Lower"
|
|
||||||
badeline_tower_upper = "Badeline Tower Upper"
|
|
||||||
badeline_island = "Badeline Island"
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
import random
|
|
||||||
|
|
||||||
from Options import Choice, TextChoice, Range, Toggle, DeathLink, OptionGroup, PerGameCommonOptions, OptionError
|
from Options import Choice, Range, Toggle, DeathLink, OptionGroup, PerGameCommonOptions
|
||||||
from worlds.AutoWorld import World
|
|
||||||
|
|
||||||
|
|
||||||
class DeathLinkAmnesty(Range):
|
class DeathLinkAmnesty(Range):
|
||||||
@@ -20,7 +18,7 @@ class TotalStrawberries(Range):
|
|||||||
"""
|
"""
|
||||||
display_name = "Total Strawberries"
|
display_name = "Total Strawberries"
|
||||||
range_start = 0
|
range_start = 0
|
||||||
range_end = 55
|
range_end = 46
|
||||||
default = 20
|
default = 20
|
||||||
|
|
||||||
class StrawberriesRequiredPercentage(Range):
|
class StrawberriesRequiredPercentage(Range):
|
||||||
@@ -75,93 +73,6 @@ class Carsanity(Toggle):
|
|||||||
"""
|
"""
|
||||||
display_name = "Carsanity"
|
display_name = "Carsanity"
|
||||||
|
|
||||||
class Checkpointsanity(Toggle):
|
|
||||||
"""
|
|
||||||
Whether activating Checkpoints grants location checks
|
|
||||||
|
|
||||||
Activating this will also shuffle items into the pool which allow usage and warping to each Checkpoint
|
|
||||||
"""
|
|
||||||
display_name = "Checkpointsanity"
|
|
||||||
|
|
||||||
|
|
||||||
class ColorChoice(TextChoice):
|
|
||||||
option_strawberry = 0xDB2C00
|
|
||||||
option_empty = 0x6EC0FF
|
|
||||||
option_double = 0xFA91FF
|
|
||||||
option_golden = 0xF2D450
|
|
||||||
option_baddy = 0x9B3FB5
|
|
||||||
option_fire_red = 0xFF0000
|
|
||||||
option_maroon = 0x800000
|
|
||||||
option_salmon = 0xFF3A65
|
|
||||||
option_orange = 0xD86E0A
|
|
||||||
option_lime_green = 0x8DF920
|
|
||||||
option_bright_green = 0x0DAF05
|
|
||||||
option_forest_green = 0x132818
|
|
||||||
option_royal_blue = 0x0036BF
|
|
||||||
option_brown = 0xB78726
|
|
||||||
option_black = 0x000000
|
|
||||||
option_white = 0xFFFFFF
|
|
||||||
option_grey = 0x808080
|
|
||||||
option_any_color = -1
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_text(cls, text: str) -> Choice:
|
|
||||||
text = text.lower()
|
|
||||||
if text == "random":
|
|
||||||
choice_list = list(cls.name_lookup)
|
|
||||||
choice_list.remove(cls.option_any_color)
|
|
||||||
return cls(random.choice(choice_list))
|
|
||||||
return super().from_text(text)
|
|
||||||
|
|
||||||
|
|
||||||
class MadelineOneDashHairColor(ColorChoice):
|
|
||||||
"""
|
|
||||||
What color Madeline's hair is when she has one dash
|
|
||||||
|
|
||||||
The `any_color` option will choose a fully random color
|
|
||||||
|
|
||||||
A custom color entry may be supplied as a 6-character RGB hex color code
|
|
||||||
e.g. F542C8
|
|
||||||
"""
|
|
||||||
display_name = "Madeline One Dash Hair Color"
|
|
||||||
default = ColorChoice.option_strawberry
|
|
||||||
|
|
||||||
class MadelineTwoDashHairColor(ColorChoice):
|
|
||||||
"""
|
|
||||||
What color Madeline's hair is when she has two dashes
|
|
||||||
|
|
||||||
The `any_color` option will choose a fully random color
|
|
||||||
|
|
||||||
A custom color entry may be supplied as a 6-character RGB hex color code
|
|
||||||
e.g. F542C8
|
|
||||||
"""
|
|
||||||
display_name = "Madeline Two Dash Hair Color"
|
|
||||||
default = ColorChoice.option_double
|
|
||||||
|
|
||||||
class MadelineNoDashHairColor(ColorChoice):
|
|
||||||
"""
|
|
||||||
What color Madeline's hair is when she has no dashes
|
|
||||||
|
|
||||||
The `any_color` option will choose a fully random color
|
|
||||||
|
|
||||||
A custom color entry may be supplied as a 6-character RGB hex color code
|
|
||||||
e.g. F542C8
|
|
||||||
"""
|
|
||||||
display_name = "Madeline No Dash Hair Color"
|
|
||||||
default = ColorChoice.option_empty
|
|
||||||
|
|
||||||
class MadelineFeatherHairColor(ColorChoice):
|
|
||||||
"""
|
|
||||||
What color Madeline's hair is when she has a feather
|
|
||||||
|
|
||||||
The `any_color` option will choose a fully random color
|
|
||||||
|
|
||||||
A custom color entry may be supplied as a 6-character RGB hex color code
|
|
||||||
e.g. F542C8
|
|
||||||
"""
|
|
||||||
display_name = "Madeline Feather Hair Color"
|
|
||||||
default = ColorChoice.option_golden
|
|
||||||
|
|
||||||
|
|
||||||
class BadelineChaserSource(Choice):
|
class BadelineChaserSource(Choice):
|
||||||
"""
|
"""
|
||||||
@@ -208,13 +119,6 @@ celeste_64_option_groups = [
|
|||||||
Friendsanity,
|
Friendsanity,
|
||||||
Signsanity,
|
Signsanity,
|
||||||
Carsanity,
|
Carsanity,
|
||||||
Checkpointsanity,
|
|
||||||
]),
|
|
||||||
OptionGroup("Aesthetic Options", [
|
|
||||||
MadelineOneDashHairColor,
|
|
||||||
MadelineTwoDashHairColor,
|
|
||||||
MadelineNoDashHairColor,
|
|
||||||
MadelineFeatherHairColor,
|
|
||||||
]),
|
]),
|
||||||
OptionGroup("Badeline Chasers", [
|
OptionGroup("Badeline Chasers", [
|
||||||
BadelineChaserSource,
|
BadelineChaserSource,
|
||||||
@@ -238,68 +142,7 @@ class Celeste64Options(PerGameCommonOptions):
|
|||||||
friendsanity: Friendsanity
|
friendsanity: Friendsanity
|
||||||
signsanity: Signsanity
|
signsanity: Signsanity
|
||||||
carsanity: Carsanity
|
carsanity: Carsanity
|
||||||
checkpointsanity: Checkpointsanity
|
|
||||||
|
|
||||||
madeline_one_dash_hair_color: MadelineOneDashHairColor
|
|
||||||
madeline_two_dash_hair_color: MadelineTwoDashHairColor
|
|
||||||
madeline_no_dash_hair_color: MadelineNoDashHairColor
|
|
||||||
madeline_feather_hair_color: MadelineFeatherHairColor
|
|
||||||
|
|
||||||
badeline_chaser_source: BadelineChaserSource
|
badeline_chaser_source: BadelineChaserSource
|
||||||
badeline_chaser_frequency: BadelineChaserFrequency
|
badeline_chaser_frequency: BadelineChaserFrequency
|
||||||
badeline_chaser_speed: BadelineChaserSpeed
|
badeline_chaser_speed: BadelineChaserSpeed
|
||||||
|
|
||||||
|
|
||||||
def resolve_options(world: World):
|
|
||||||
# One Dash Hair
|
|
||||||
if isinstance(world.options.madeline_one_dash_hair_color.value, str):
|
|
||||||
try:
|
|
||||||
world.madeline_one_dash_hair_color = int(world.options.madeline_one_dash_hair_color.value.strip("#")[:6], 16)
|
|
||||||
except ValueError:
|
|
||||||
raise OptionError(f"Invalid input for option `madeline_one_dash_hair_color`:"
|
|
||||||
f"{world.options.madeline_one_dash_hair_color.value} for "
|
|
||||||
f"{world.player_name}")
|
|
||||||
elif world.options.madeline_one_dash_hair_color.value == ColorChoice.option_any_color:
|
|
||||||
world.madeline_one_dash_hair_color = world.random.randint(0, 0xFFFFFF)
|
|
||||||
else:
|
|
||||||
world.madeline_one_dash_hair_color = world.options.madeline_one_dash_hair_color.value
|
|
||||||
|
|
||||||
# Two Dash Hair
|
|
||||||
if isinstance(world.options.madeline_two_dash_hair_color.value, str):
|
|
||||||
try:
|
|
||||||
world.madeline_two_dash_hair_color = int(world.options.madeline_two_dash_hair_color.value.strip("#")[:6], 16)
|
|
||||||
except ValueError:
|
|
||||||
raise OptionError(f"Invalid input for option `madeline_two_dash_hair_color`:"
|
|
||||||
f"{world.options.madeline_two_dash_hair_color.value} for "
|
|
||||||
f"{world.player_name}")
|
|
||||||
elif world.options.madeline_two_dash_hair_color.value == ColorChoice.option_any_color:
|
|
||||||
world.madeline_two_dash_hair_color = world.random.randint(0, 0xFFFFFF)
|
|
||||||
else:
|
|
||||||
world.madeline_two_dash_hair_color = world.options.madeline_two_dash_hair_color.value
|
|
||||||
|
|
||||||
# No Dash Hair
|
|
||||||
if isinstance(world.options.madeline_no_dash_hair_color.value, str):
|
|
||||||
try:
|
|
||||||
world.madeline_no_dash_hair_color = int(world.options.madeline_no_dash_hair_color.value.strip("#")[:6], 16)
|
|
||||||
except ValueError:
|
|
||||||
raise OptionError(f"Invalid input for option `madeline_no_dash_hair_color`:"
|
|
||||||
f"{world.options.madeline_no_dash_hair_color.value} for "
|
|
||||||
f"{world.player_name}")
|
|
||||||
elif world.options.madeline_no_dash_hair_color.value == ColorChoice.option_any_color:
|
|
||||||
world.madeline_no_dash_hair_color = world.random.randint(0, 0xFFFFFF)
|
|
||||||
else:
|
|
||||||
world.madeline_no_dash_hair_color = world.options.madeline_no_dash_hair_color.value
|
|
||||||
|
|
||||||
# Feather Hair
|
|
||||||
if isinstance(world.options.madeline_feather_hair_color.value, str):
|
|
||||||
try:
|
|
||||||
world.madeline_feather_hair_color = int(world.options.madeline_feather_hair_color.value.strip("#")[:6], 16)
|
|
||||||
except ValueError:
|
|
||||||
raise OptionError(f"Invalid input for option `madeline_feather_hair_color`:"
|
|
||||||
f"{world.options.madeline_feather_hair_color.value} for "
|
|
||||||
f"{world.player_name}")
|
|
||||||
elif world.options.madeline_feather_hair_color.value == ColorChoice.option_any_color:
|
|
||||||
world.madeline_feather_hair_color = world.random.randint(0, 0xFFFFFF)
|
|
||||||
else:
|
|
||||||
world.madeline_feather_hair_color = world.options.madeline_feather_hair_color.value
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,11 @@
|
|||||||
from typing import Dict, List, NamedTuple
|
from typing import Dict, List, NamedTuple
|
||||||
|
|
||||||
from .Names import RegionName
|
|
||||||
|
|
||||||
class Celeste64RegionData(NamedTuple):
|
class Celeste64RegionData(NamedTuple):
|
||||||
connecting_regions: List[str] = []
|
connecting_regions: List[str] = []
|
||||||
|
|
||||||
|
|
||||||
region_data_table: Dict[str, Celeste64RegionData] = {
|
region_data_table: Dict[str, Celeste64RegionData] = {
|
||||||
"Menu": Celeste64RegionData([RegionName.forsaken_city]),
|
"Menu": Celeste64RegionData(["Forsaken City"]),
|
||||||
|
"Forsaken City": Celeste64RegionData(),
|
||||||
RegionName.forsaken_city: Celeste64RegionData([RegionName.intro_islands, RegionName.granny_island, RegionName.highway_island, RegionName.ne_feathers_island, RegionName.se_house_island, RegionName.badeline_tower_upper, RegionName.badeline_island]),
|
|
||||||
|
|
||||||
RegionName.intro_islands: Celeste64RegionData([RegionName.granny_island]),
|
|
||||||
RegionName.granny_island: Celeste64RegionData([RegionName.highway_island, RegionName.nw_girders_island, RegionName.badeline_tower_lower, RegionName.se_house_island]),
|
|
||||||
RegionName.highway_island: Celeste64RegionData([RegionName.granny_island, RegionName.ne_feathers_island, RegionName.nw_girders_island]),
|
|
||||||
RegionName.nw_girders_island: Celeste64RegionData([RegionName.highway_island]),
|
|
||||||
RegionName.ne_feathers_island: Celeste64RegionData([RegionName.se_house_island, RegionName.highway_island, RegionName.badeline_tower_lower, RegionName.badeline_tower_upper]),
|
|
||||||
RegionName.se_house_island: Celeste64RegionData([RegionName.ne_feathers_island, RegionName.granny_island, RegionName.badeline_tower_lower]),
|
|
||||||
RegionName.badeline_tower_lower: Celeste64RegionData([RegionName.se_house_island, RegionName.ne_feathers_island, RegionName.granny_island, RegionName.badeline_tower_upper]),
|
|
||||||
RegionName.badeline_tower_upper: Celeste64RegionData([RegionName.badeline_island, RegionName.badeline_tower_lower, RegionName.se_house_island, RegionName.ne_feathers_island, RegionName.granny_island]),
|
|
||||||
RegionName.badeline_island: Celeste64RegionData([RegionName.badeline_tower_upper, RegionName.granny_island, RegionName.highway_island]),
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,85 +1,265 @@
|
|||||||
from typing import Dict, List, Tuple, Callable
|
from typing import Dict, List
|
||||||
|
|
||||||
from BaseClasses import CollectionState, Region
|
from BaseClasses import CollectionState
|
||||||
from worlds.generic.Rules import set_rule
|
from worlds.generic.Rules import set_rule
|
||||||
|
|
||||||
from . import Celeste64World
|
from . import Celeste64World
|
||||||
from .Names import ItemName, LocationName, RegionName
|
from .Names import ItemName, LocationName
|
||||||
|
|
||||||
|
|
||||||
def set_rules(world: Celeste64World):
|
def set_rules(world: Celeste64World):
|
||||||
if world.options.logic_difficulty == "standard":
|
if world.options.logic_difficulty == "standard":
|
||||||
world.active_logic_mapping = location_standard_moves_logic
|
if world.options.move_shuffle:
|
||||||
world.active_region_logic_mapping = region_standard_moves_logic
|
world.active_logic_mapping = location_standard_moves_logic
|
||||||
|
else:
|
||||||
|
world.active_logic_mapping = location_standard_logic
|
||||||
else:
|
else:
|
||||||
world.active_logic_mapping = location_hard_moves_logic
|
if world.options.move_shuffle:
|
||||||
world.active_region_logic_mapping = region_hard_moves_logic
|
world.active_logic_mapping = location_hard_moves_logic
|
||||||
|
else:
|
||||||
|
world.active_logic_mapping = location_hard_logic
|
||||||
|
|
||||||
for location in world.multiworld.get_locations(world.player):
|
for location in world.multiworld.get_locations(world.player):
|
||||||
set_rule(location, lambda state, location=location: location_rule(state, world, location.name))
|
set_rule(location, lambda state, location=location: location_rule(state, world, location.name))
|
||||||
|
|
||||||
|
if world.options.logic_difficulty == "standard":
|
||||||
|
if world.options.move_shuffle:
|
||||||
|
world.goal_logic_mapping = goal_standard_moves_logic
|
||||||
|
else:
|
||||||
|
world.goal_logic_mapping = goal_standard_logic
|
||||||
|
else:
|
||||||
|
if world.options.move_shuffle:
|
||||||
|
world.goal_logic_mapping = goal_hard_moves_logic
|
||||||
|
else:
|
||||||
|
world.goal_logic_mapping = goal_hard_logic
|
||||||
|
|
||||||
# Completion condition.
|
# Completion condition.
|
||||||
world.multiworld.completion_condition[world.player] = lambda state: goal_rule(state, world)
|
world.multiworld.completion_condition[world.player] = lambda state: goal_rule(state, world)
|
||||||
|
|
||||||
|
|
||||||
|
goal_standard_logic: List[List[str]] = [[ItemName.feather, ItemName.traffic_block, ItemName.breakables, ItemName.double_dash_refill]]
|
||||||
|
goal_hard_logic: List[List[str]] = [[]]
|
||||||
|
goal_standard_moves_logic: List[List[str]] = [[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.breakables, ItemName.air_dash, ItemName.climb]]
|
||||||
|
goal_hard_moves_logic: List[List[str]] = [[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.breakables, ItemName.air_dash, ItemName.climb],
|
||||||
|
[ItemName.traffic_block, ItemName.air_dash, ItemName.skid_jump],
|
||||||
|
[ItemName.ground_dash, ItemName.air_dash, ItemName.skid_jump],
|
||||||
|
[ItemName.feather, ItemName.traffic_block, ItemName.air_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.ground_dash, ItemName.air_dash]]
|
||||||
|
|
||||||
|
|
||||||
|
location_standard_logic: Dict[str, List[List[str]]] = {
|
||||||
|
LocationName.strawberry_4: [[ItemName.traffic_block, ItemName.breakables]],
|
||||||
|
LocationName.strawberry_6: [[ItemName.dash_refill],
|
||||||
|
[ItemName.traffic_block]],
|
||||||
|
LocationName.strawberry_7: [[ItemName.dash_refill],
|
||||||
|
[ItemName.traffic_block]],
|
||||||
|
LocationName.strawberry_8: [[ItemName.traffic_block]],
|
||||||
|
LocationName.strawberry_9: [[ItemName.dash_refill]],
|
||||||
|
LocationName.strawberry_11: [[ItemName.dash_refill],
|
||||||
|
[ItemName.traffic_block]],
|
||||||
|
LocationName.strawberry_12: [[ItemName.dash_refill, ItemName.double_dash_refill],
|
||||||
|
[ItemName.traffic_block, ItemName.double_dash_refill]],
|
||||||
|
LocationName.strawberry_13: [[ItemName.dash_refill, ItemName.breakables],
|
||||||
|
[ItemName.traffic_block, ItemName.breakables]],
|
||||||
|
LocationName.strawberry_14: [[ItemName.dash_refill, ItemName.feather],
|
||||||
|
[ItemName.traffic_block, ItemName.feather]],
|
||||||
|
LocationName.strawberry_15: [[ItemName.dash_refill, ItemName.feather],
|
||||||
|
[ItemName.traffic_block, ItemName.feather]],
|
||||||
|
LocationName.strawberry_16: [[ItemName.dash_refill, ItemName.feather],
|
||||||
|
[ItemName.traffic_block, ItemName.feather]],
|
||||||
|
LocationName.strawberry_17: [[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block]],
|
||||||
|
LocationName.strawberry_18: [[ItemName.dash_refill, ItemName.double_dash_refill],
|
||||||
|
[ItemName.traffic_block, ItemName.feather, ItemName.double_dash_refill]],
|
||||||
|
LocationName.strawberry_19: [[ItemName.dash_refill, ItemName.double_dash_refill, ItemName.spring],
|
||||||
|
[ItemName.traffic_block, ItemName.double_dash_refill, ItemName.feather, ItemName.spring]],
|
||||||
|
LocationName.strawberry_20: [[ItemName.dash_refill, ItemName.feather, ItemName.breakables],
|
||||||
|
[ItemName.traffic_block, ItemName.feather, ItemName.breakables]],
|
||||||
|
|
||||||
|
LocationName.strawberry_21: [[ItemName.cassette, ItemName.traffic_block, ItemName.breakables]],
|
||||||
|
LocationName.strawberry_22: [[ItemName.cassette, ItemName.dash_refill, ItemName.breakables]],
|
||||||
|
LocationName.strawberry_23: [[ItemName.cassette, ItemName.dash_refill, ItemName.coin],
|
||||||
|
[ItemName.cassette, ItemName.traffic_block, ItemName.coin]],
|
||||||
|
LocationName.strawberry_24: [[ItemName.cassette, ItemName.dash_refill, ItemName.traffic_block]],
|
||||||
|
LocationName.strawberry_25: [[ItemName.cassette, ItemName.dash_refill, ItemName.double_dash_refill],
|
||||||
|
[ItemName.cassette, ItemName.traffic_block, ItemName.feather, ItemName.double_dash_refill]],
|
||||||
|
LocationName.strawberry_26: [[ItemName.cassette, ItemName.dash_refill],
|
||||||
|
[ItemName.cassette, ItemName.traffic_block]],
|
||||||
|
LocationName.strawberry_27: [[ItemName.cassette, ItemName.dash_refill, ItemName.feather, ItemName.coin],
|
||||||
|
[ItemName.cassette, ItemName.traffic_block, ItemName.feather, ItemName.coin]],
|
||||||
|
LocationName.strawberry_28: [[ItemName.cassette, ItemName.dash_refill, ItemName.feather, ItemName.coin],
|
||||||
|
[ItemName.cassette, ItemName.traffic_block, ItemName.feather, ItemName.coin]],
|
||||||
|
LocationName.strawberry_29: [[ItemName.cassette, ItemName.dash_refill, ItemName.feather, ItemName.coin]],
|
||||||
|
LocationName.strawberry_30: [[ItemName.cassette, ItemName.dash_refill, ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.spring, ItemName.breakables]],
|
||||||
|
|
||||||
|
LocationName.theo_1: [[ItemName.traffic_block, ItemName.breakables]],
|
||||||
|
LocationName.theo_2: [[ItemName.traffic_block, ItemName.breakables]],
|
||||||
|
LocationName.theo_3: [[ItemName.traffic_block, ItemName.breakables]],
|
||||||
|
LocationName.badeline_1: [[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.breakables]],
|
||||||
|
LocationName.badeline_2: [[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.breakables]],
|
||||||
|
LocationName.badeline_3: [[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.breakables]],
|
||||||
|
|
||||||
|
LocationName.sign_2: [[ItemName.breakables]],
|
||||||
|
LocationName.sign_3: [[ItemName.dash_refill],
|
||||||
|
[ItemName.traffic_block]],
|
||||||
|
LocationName.sign_4: [[ItemName.dash_refill, ItemName.double_dash_refill],
|
||||||
|
[ItemName.dash_refill, ItemName.feather],
|
||||||
|
[ItemName.traffic_block, ItemName.feather]],
|
||||||
|
LocationName.sign_5: [[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.breakables]],
|
||||||
|
|
||||||
|
LocationName.car_2: [[ItemName.breakables]],
|
||||||
|
}
|
||||||
|
|
||||||
|
location_hard_logic: Dict[str, List[List[str]]] = {
|
||||||
|
LocationName.strawberry_13: [[ItemName.breakables]],
|
||||||
|
LocationName.strawberry_17: [[ItemName.double_dash_refill, ItemName.traffic_block]],
|
||||||
|
LocationName.strawberry_20: [[ItemName.breakables]],
|
||||||
|
|
||||||
|
LocationName.strawberry_21: [[ItemName.cassette, ItemName.traffic_block, ItemName.breakables]],
|
||||||
|
LocationName.strawberry_22: [[ItemName.cassette]],
|
||||||
|
LocationName.strawberry_23: [[ItemName.cassette, ItemName.coin]],
|
||||||
|
LocationName.strawberry_24: [[ItemName.cassette]],
|
||||||
|
LocationName.strawberry_25: [[ItemName.cassette, ItemName.double_dash_refill]],
|
||||||
|
LocationName.strawberry_26: [[ItemName.cassette]],
|
||||||
|
LocationName.strawberry_27: [[ItemName.cassette]],
|
||||||
|
LocationName.strawberry_28: [[ItemName.cassette, ItemName.feather]],
|
||||||
|
LocationName.strawberry_29: [[ItemName.cassette]],
|
||||||
|
LocationName.strawberry_30: [[ItemName.cassette, ItemName.dash_refill, ItemName.double_dash_refill, ItemName.traffic_block, ItemName.breakables]],
|
||||||
|
|
||||||
|
LocationName.sign_2: [[ItemName.breakables]],
|
||||||
|
|
||||||
|
LocationName.car_2: [[ItemName.breakables]],
|
||||||
|
}
|
||||||
|
|
||||||
location_standard_moves_logic: Dict[str, List[List[str]]] = {
|
location_standard_moves_logic: Dict[str, List[List[str]]] = {
|
||||||
LocationName.strawberry_1: [[ItemName.ground_dash],
|
LocationName.strawberry_1: [[ItemName.ground_dash],
|
||||||
[ItemName.air_dash],
|
[ItemName.air_dash],
|
||||||
|
[ItemName.skid_jump],
|
||||||
|
[ItemName.climb]],
|
||||||
|
LocationName.strawberry_2: [[ItemName.ground_dash],
|
||||||
|
[ItemName.air_dash],
|
||||||
|
[ItemName.skid_jump],
|
||||||
[ItemName.climb]],
|
[ItemName.climb]],
|
||||||
LocationName.strawberry_2: [[ItemName.air_dash],
|
|
||||||
[ItemName.skid_jump]],
|
|
||||||
LocationName.strawberry_3: [[ItemName.air_dash],
|
LocationName.strawberry_3: [[ItemName.air_dash],
|
||||||
[ItemName.skid_jump]],
|
[ItemName.skid_jump]],
|
||||||
LocationName.strawberry_4: [[ItemName.traffic_block, ItemName.breakables, ItemName.air_dash]],
|
LocationName.strawberry_4: [[ItemName.traffic_block, ItemName.breakables, ItemName.air_dash]],
|
||||||
LocationName.strawberry_5: [[ItemName.air_dash]],
|
LocationName.strawberry_5: [[ItemName.air_dash]],
|
||||||
|
LocationName.strawberry_6: [[ItemName.dash_refill, ItemName.air_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.ground_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.air_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.skid_jump],
|
||||||
|
[ItemName.traffic_block, ItemName.climb]],
|
||||||
|
LocationName.strawberry_7: [[ItemName.dash_refill, ItemName.air_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.ground_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.air_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.skid_jump],
|
||||||
|
[ItemName.traffic_block, ItemName.climb]],
|
||||||
|
LocationName.strawberry_8: [[ItemName.traffic_block, ItemName.ground_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.air_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.skid_jump],
|
||||||
|
[ItemName.traffic_block, ItemName.climb]],
|
||||||
LocationName.strawberry_9: [[ItemName.dash_refill, ItemName.air_dash]],
|
LocationName.strawberry_9: [[ItemName.dash_refill, ItemName.air_dash]],
|
||||||
LocationName.strawberry_10: [[ItemName.climb]],
|
LocationName.strawberry_10: [[ItemName.climb]],
|
||||||
LocationName.strawberry_11: [[ItemName.air_dash, ItemName.climb]],
|
LocationName.strawberry_11: [[ItemName.dash_refill, ItemName.air_dash, ItemName.climb],
|
||||||
LocationName.strawberry_13: [[ItemName.breakables, ItemName.air_dash],
|
[ItemName.traffic_block, ItemName.climb]],
|
||||||
[ItemName.breakables, ItemName.ground_dash]],
|
LocationName.strawberry_12: [[ItemName.dash_refill, ItemName.double_dash_refill, ItemName.air_dash],
|
||||||
LocationName.strawberry_14: [[ItemName.feather, ItemName.air_dash]],
|
[ItemName.traffic_block, ItemName.double_dash_refill, ItemName.air_dash]],
|
||||||
LocationName.strawberry_15: [[ItemName.feather, ItemName.air_dash, ItemName.climb]],
|
LocationName.strawberry_13: [[ItemName.dash_refill, ItemName.breakables, ItemName.air_dash],
|
||||||
LocationName.strawberry_16: [[ItemName.feather]],
|
[ItemName.traffic_block, ItemName.breakables, ItemName.ground_dash],
|
||||||
LocationName.strawberry_17: [[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block]],
|
[ItemName.traffic_block, ItemName.breakables, ItemName.air_dash]],
|
||||||
LocationName.strawberry_18: [[ItemName.double_dash_refill, ItemName.air_dash, ItemName.climb]],
|
LocationName.strawberry_14: [[ItemName.dash_refill, ItemName.feather, ItemName.air_dash],
|
||||||
LocationName.strawberry_19: [[ItemName.double_dash_refill, ItemName.spring, ItemName.air_dash, ItemName.skid_jump]],
|
[ItemName.traffic_block, ItemName.feather, ItemName.air_dash]],
|
||||||
LocationName.strawberry_20: [[ItemName.feather, ItemName.breakables, ItemName.air_dash]],
|
LocationName.strawberry_15: [[ItemName.dash_refill, ItemName.feather, ItemName.air_dash, ItemName.climb],
|
||||||
|
[ItemName.traffic_block, ItemName.feather, ItemName.climb]],
|
||||||
|
LocationName.strawberry_16: [[ItemName.dash_refill, ItemName.feather, ItemName.air_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.feather]],
|
||||||
|
LocationName.strawberry_17: [[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.ground_dash],
|
||||||
|
[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.air_dash],
|
||||||
|
[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.skid_jump],
|
||||||
|
[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.climb]],
|
||||||
|
LocationName.strawberry_18: [[ItemName.dash_refill, ItemName.double_dash_refill, ItemName.air_dash, ItemName.climb],
|
||||||
|
[ItemName.traffic_block, ItemName.feather, ItemName.double_dash_refill, ItemName.air_dash, ItemName.climb]],
|
||||||
|
LocationName.strawberry_19: [[ItemName.dash_refill, ItemName.double_dash_refill, ItemName.spring, ItemName.air_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.double_dash_refill, ItemName.feather, ItemName.spring, ItemName.air_dash]],
|
||||||
|
LocationName.strawberry_20: [[ItemName.dash_refill, ItemName.feather, ItemName.breakables, ItemName.air_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.feather, ItemName.breakables, ItemName.air_dash]],
|
||||||
|
|
||||||
LocationName.strawberry_21: [[ItemName.cassette, ItemName.traffic_block, ItemName.breakables, ItemName.air_dash]],
|
LocationName.strawberry_21: [[ItemName.cassette, ItemName.traffic_block, ItemName.breakables, ItemName.air_dash]],
|
||||||
LocationName.strawberry_22: [[ItemName.cassette, ItemName.dash_refill, ItemName.breakables, ItemName.air_dash]],
|
LocationName.strawberry_22: [[ItemName.cassette, ItemName.dash_refill, ItemName.breakables, ItemName.air_dash]],
|
||||||
LocationName.strawberry_23: [[ItemName.cassette, ItemName.coin, ItemName.air_dash, ItemName.climb]],
|
LocationName.strawberry_23: [[ItemName.cassette, ItemName.dash_refill, ItemName.coin, ItemName.air_dash, ItemName.climb],
|
||||||
|
[ItemName.cassette, ItemName.traffic_block, ItemName.coin, ItemName.air_dash, ItemName.climb]],
|
||||||
LocationName.strawberry_24: [[ItemName.cassette, ItemName.dash_refill, ItemName.traffic_block, ItemName.air_dash]],
|
LocationName.strawberry_24: [[ItemName.cassette, ItemName.dash_refill, ItemName.traffic_block, ItemName.air_dash]],
|
||||||
LocationName.strawberry_25: [[ItemName.cassette, ItemName.double_dash_refill, ItemName.air_dash, ItemName.climb]],
|
LocationName.strawberry_25: [[ItemName.cassette, ItemName.dash_refill, ItemName.double_dash_refill, ItemName.air_dash, ItemName.climb],
|
||||||
LocationName.strawberry_26: [[ItemName.cassette, ItemName.air_dash, ItemName.climb]],
|
[ItemName.cassette, ItemName.traffic_block, ItemName.feather, ItemName.double_dash_refill, ItemName.air_dash, ItemName.climb]],
|
||||||
LocationName.strawberry_27: [[ItemName.cassette, ItemName.feather, ItemName.coin, ItemName.air_dash, ItemName.climb]],
|
LocationName.strawberry_26: [[ItemName.cassette, ItemName.dash_refill, ItemName.air_dash, ItemName.climb],
|
||||||
LocationName.strawberry_28: [[ItemName.cassette, ItemName.feather, ItemName.coin, ItemName.air_dash, ItemName.climb]],
|
[ItemName.cassette, ItemName.traffic_block, ItemName.air_dash, ItemName.climb]],
|
||||||
LocationName.strawberry_29: [[ItemName.cassette, ItemName.dash_refill, ItemName.coin, ItemName.air_dash, ItemName.skid_jump]],
|
LocationName.strawberry_27: [[ItemName.cassette, ItemName.dash_refill, ItemName.feather, ItemName.coin, ItemName.air_dash],
|
||||||
|
[ItemName.cassette, ItemName.traffic_block, ItemName.feather, ItemName.coin, ItemName.air_dash]],
|
||||||
|
LocationName.strawberry_28: [[ItemName.cassette, ItemName.dash_refill, ItemName.feather, ItemName.coin, ItemName.air_dash, ItemName.climb],
|
||||||
|
[ItemName.cassette, ItemName.traffic_block, ItemName.feather, ItemName.coin, ItemName.air_dash, ItemName.climb]],
|
||||||
|
LocationName.strawberry_29: [[ItemName.cassette, ItemName.dash_refill, ItemName.feather, ItemName.coin, ItemName.air_dash, ItemName.skid_jump]],
|
||||||
LocationName.strawberry_30: [[ItemName.cassette, ItemName.dash_refill, ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.spring, ItemName.breakables, ItemName.air_dash, ItemName.climb]],
|
LocationName.strawberry_30: [[ItemName.cassette, ItemName.dash_refill, ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.spring, ItemName.breakables, ItemName.air_dash, ItemName.climb]],
|
||||||
|
|
||||||
|
LocationName.granny_1: [[ItemName.ground_dash],
|
||||||
|
[ItemName.air_dash],
|
||||||
|
[ItemName.skid_jump],
|
||||||
|
[ItemName.climb]],
|
||||||
|
LocationName.granny_2: [[ItemName.ground_dash],
|
||||||
|
[ItemName.air_dash],
|
||||||
|
[ItemName.skid_jump],
|
||||||
|
[ItemName.climb]],
|
||||||
|
LocationName.granny_3: [[ItemName.ground_dash],
|
||||||
|
[ItemName.air_dash],
|
||||||
|
[ItemName.skid_jump],
|
||||||
|
[ItemName.climb]],
|
||||||
LocationName.theo_1: [[ItemName.traffic_block, ItemName.breakables, ItemName.air_dash]],
|
LocationName.theo_1: [[ItemName.traffic_block, ItemName.breakables, ItemName.air_dash]],
|
||||||
LocationName.theo_2: [[ItemName.traffic_block, ItemName.breakables, ItemName.air_dash]],
|
LocationName.theo_2: [[ItemName.traffic_block, ItemName.breakables, ItemName.air_dash]],
|
||||||
LocationName.theo_3: [[ItemName.traffic_block, ItemName.breakables, ItemName.air_dash]],
|
LocationName.theo_3: [[ItemName.traffic_block, ItemName.breakables, ItemName.air_dash]],
|
||||||
|
LocationName.badeline_1: [[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.breakables, ItemName.air_dash, ItemName.climb]],
|
||||||
|
LocationName.badeline_2: [[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.breakables, ItemName.air_dash, ItemName.climb]],
|
||||||
|
LocationName.badeline_3: [[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.breakables, ItemName.air_dash, ItemName.climb]],
|
||||||
|
|
||||||
|
LocationName.sign_1: [[ItemName.ground_dash],
|
||||||
|
[ItemName.air_dash],
|
||||||
|
[ItemName.skid_jump],
|
||||||
|
[ItemName.climb]],
|
||||||
LocationName.sign_2: [[ItemName.breakables, ItemName.ground_dash],
|
LocationName.sign_2: [[ItemName.breakables, ItemName.ground_dash],
|
||||||
[ItemName.breakables, ItemName.air_dash]],
|
[ItemName.breakables, ItemName.air_dash]],
|
||||||
|
LocationName.sign_3: [[ItemName.dash_refill, ItemName.air_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.ground_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.air_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.skid_jump],
|
||||||
|
[ItemName.traffic_block, ItemName.climb]],
|
||||||
|
LocationName.sign_4: [[ItemName.dash_refill, ItemName.double_dash_refill, ItemName.air_dash],
|
||||||
|
[ItemName.dash_refill, ItemName.feather, ItemName.air_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.feather, ItemName.ground_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.feather, ItemName.air_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.feather, ItemName.skid_jump],
|
||||||
|
[ItemName.traffic_block, ItemName.feather, ItemName.climb]],
|
||||||
|
LocationName.sign_5: [[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.breakables, ItemName.air_dash, ItemName.climb]],
|
||||||
|
|
||||||
LocationName.car_2: [[ItemName.breakables, ItemName.ground_dash, ItemName.climb],
|
LocationName.car_2: [[ItemName.breakables, ItemName.ground_dash],
|
||||||
[ItemName.breakables, ItemName.air_dash, ItemName.climb]],
|
[ItemName.breakables, ItemName.air_dash]],
|
||||||
}
|
}
|
||||||
|
|
||||||
location_hard_moves_logic: Dict[str, List[List[str]]] = {
|
location_hard_moves_logic: Dict[str, List[List[str]]] = {
|
||||||
|
LocationName.strawberry_3: [[ItemName.air_dash],
|
||||||
|
[ItemName.skid_jump]],
|
||||||
LocationName.strawberry_5: [[ItemName.ground_dash],
|
LocationName.strawberry_5: [[ItemName.ground_dash],
|
||||||
[ItemName.air_dash]],
|
[ItemName.air_dash]],
|
||||||
|
LocationName.strawberry_8: [[ItemName.traffic_block],
|
||||||
|
[ItemName.ground_dash, ItemName.air_dash]],
|
||||||
LocationName.strawberry_10: [[ItemName.air_dash],
|
LocationName.strawberry_10: [[ItemName.air_dash],
|
||||||
[ItemName.climb]],
|
[ItemName.climb]],
|
||||||
LocationName.strawberry_11: [[ItemName.ground_dash],
|
LocationName.strawberry_11: [[ItemName.ground_dash],
|
||||||
[ItemName.air_dash],
|
[ItemName.air_dash],
|
||||||
[ItemName.skid_jump]],
|
[ItemName.skid_jump]],
|
||||||
|
LocationName.strawberry_12: [[ItemName.feather],
|
||||||
|
[ItemName.ground_dash],
|
||||||
|
[ItemName.air_dash]],
|
||||||
LocationName.strawberry_13: [[ItemName.breakables, ItemName.ground_dash],
|
LocationName.strawberry_13: [[ItemName.breakables, ItemName.ground_dash],
|
||||||
[ItemName.breakables, ItemName.air_dash]],
|
[ItemName.breakables, ItemName.air_dash]],
|
||||||
LocationName.strawberry_14: [[ItemName.feather, ItemName.air_dash],
|
LocationName.strawberry_14: [[ItemName.feather, ItemName.air_dash],
|
||||||
[ItemName.air_dash, ItemName.climb],
|
[ItemName.air_dash, ItemName.climb]],
|
||||||
[ItemName.double_dash_refill, ItemName.air_dash]],
|
|
||||||
LocationName.strawberry_15: [[ItemName.feather],
|
LocationName.strawberry_15: [[ItemName.feather],
|
||||||
[ItemName.ground_dash, ItemName.air_dash]],
|
[ItemName.ground_dash, ItemName.air_dash]],
|
||||||
LocationName.strawberry_17: [[ItemName.double_dash_refill, ItemName.traffic_block]],
|
LocationName.strawberry_17: [[ItemName.double_dash_refill, ItemName.traffic_block]],
|
||||||
@@ -107,94 +287,42 @@ location_hard_moves_logic: Dict[str, List[List[str]]] = {
|
|||||||
[ItemName.cassette, ItemName.feather, ItemName.climb]],
|
[ItemName.cassette, ItemName.feather, ItemName.climb]],
|
||||||
LocationName.strawberry_29: [[ItemName.cassette, ItemName.dash_refill, ItemName.air_dash, ItemName.skid_jump],
|
LocationName.strawberry_29: [[ItemName.cassette, ItemName.dash_refill, ItemName.air_dash, ItemName.skid_jump],
|
||||||
[ItemName.cassette, ItemName.ground_dash, ItemName.air_dash]],
|
[ItemName.cassette, ItemName.ground_dash, ItemName.air_dash]],
|
||||||
LocationName.strawberry_30: [[ItemName.cassette, ItemName.dash_refill, ItemName.double_dash_refill, ItemName.traffic_block, ItemName.breakables, ItemName.air_dash, ItemName.climb, ItemName.skid_jump],
|
LocationName.strawberry_30: [[ItemName.cassette, ItemName.dash_refill, ItemName.double_dash_refill, ItemName.traffic_block, ItemName.breakables, ItemName.ground_dash, ItemName.air_dash, ItemName.climb, ItemName.skid_jump],
|
||||||
[ItemName.cassette, ItemName.dash_refill, ItemName.double_dash_refill, ItemName.traffic_block, ItemName.breakables, ItemName.spring, ItemName.air_dash, ItemName.climb]],
|
[ItemName.cassette, ItemName.dash_refill, ItemName.double_dash_refill, ItemName.traffic_block, ItemName.breakables, ItemName.feather, ItemName.air_dash, ItemName.climb, ItemName.skid_jump],
|
||||||
|
[ItemName.cassette, ItemName.dash_refill, ItemName.double_dash_refill, ItemName.traffic_block, ItemName.breakables, ItemName.spring, ItemName.ground_dash, ItemName.air_dash, ItemName.climb],
|
||||||
|
[ItemName.cassette, ItemName.dash_refill, ItemName.double_dash_refill, ItemName.traffic_block, ItemName.breakables, ItemName.spring, ItemName.feather, ItemName.air_dash, ItemName.climb]],
|
||||||
|
|
||||||
|
LocationName.badeline_1: [[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.breakables, ItemName.air_dash, ItemName.climb],
|
||||||
|
[ItemName.traffic_block, ItemName.air_dash, ItemName.skid_jump],
|
||||||
|
[ItemName.ground_dash, ItemName.air_dash, ItemName.skid_jump],
|
||||||
|
[ItemName.feather, ItemName.traffic_block, ItemName.air_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.ground_dash, ItemName.air_dash]],
|
||||||
|
LocationName.badeline_2: [[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.breakables, ItemName.air_dash, ItemName.climb],
|
||||||
|
[ItemName.traffic_block, ItemName.air_dash, ItemName.skid_jump],
|
||||||
|
[ItemName.ground_dash, ItemName.air_dash, ItemName.skid_jump],
|
||||||
|
[ItemName.feather, ItemName.traffic_block, ItemName.air_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.ground_dash, ItemName.air_dash]],
|
||||||
|
LocationName.badeline_3: [[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.breakables, ItemName.air_dash, ItemName.climb],
|
||||||
|
[ItemName.traffic_block, ItemName.air_dash, ItemName.skid_jump],
|
||||||
|
[ItemName.ground_dash, ItemName.air_dash, ItemName.skid_jump],
|
||||||
|
[ItemName.feather, ItemName.traffic_block, ItemName.air_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.ground_dash, ItemName.air_dash]],
|
||||||
|
|
||||||
LocationName.sign_2: [[ItemName.breakables, ItemName.ground_dash],
|
LocationName.sign_2: [[ItemName.breakables, ItemName.ground_dash],
|
||||||
[ItemName.breakables, ItemName.air_dash]],
|
[ItemName.breakables, ItemName.air_dash]],
|
||||||
|
LocationName.sign_5: [[ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.breakables, ItemName.air_dash, ItemName.climb],
|
||||||
|
[ItemName.traffic_block, ItemName.air_dash, ItemName.skid_jump],
|
||||||
|
[ItemName.ground_dash, ItemName.air_dash, ItemName.skid_jump],
|
||||||
|
[ItemName.feather, ItemName.traffic_block, ItemName.air_dash],
|
||||||
|
[ItemName.traffic_block, ItemName.ground_dash, ItemName.air_dash]],
|
||||||
|
|
||||||
LocationName.car_2: [[ItemName.breakables, ItemName.ground_dash],
|
LocationName.car_2: [[ItemName.breakables, ItemName.ground_dash],
|
||||||
[ItemName.breakables, ItemName.air_dash]],
|
[ItemName.breakables, ItemName.air_dash]],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
region_standard_moves_logic: Dict[Tuple[str], List[List[str]]] = {
|
|
||||||
(RegionName.forsaken_city, RegionName.granny_island): [[ItemName.checkpoint_2], [ItemName.checkpoint_3], [ItemName.checkpoint_4]],
|
|
||||||
(RegionName.forsaken_city, RegionName.highway_island): [[ItemName.checkpoint_5], [ItemName.checkpoint_6]],
|
|
||||||
(RegionName.forsaken_city, RegionName.ne_feathers_island): [[ItemName.checkpoint_7]],
|
|
||||||
(RegionName.forsaken_city, RegionName.se_house_island): [[ItemName.checkpoint_8]],
|
|
||||||
(RegionName.forsaken_city, RegionName.badeline_tower_upper): [[ItemName.checkpoint_9]],
|
|
||||||
(RegionName.forsaken_city, RegionName.badeline_island): [[ItemName.checkpoint_10]],
|
|
||||||
|
|
||||||
(RegionName.intro_islands, RegionName.granny_island): [[ItemName.ground_dash],
|
|
||||||
[ItemName.air_dash],
|
|
||||||
[ItemName.skid_jump],
|
|
||||||
[ItemName.climb]],
|
|
||||||
|
|
||||||
(RegionName.granny_island, RegionName.highway_island): [[ItemName.air_dash, ItemName.dash_refill]],
|
|
||||||
(RegionName.granny_island, RegionName.nw_girders_island): [[ItemName.traffic_block]],
|
|
||||||
(RegionName.granny_island, RegionName.badeline_tower_lower): [[ItemName.air_dash, ItemName.climb, ItemName.dash_refill]],
|
|
||||||
(RegionName.granny_island, RegionName.se_house_island): [[ItemName.air_dash, ItemName.climb, ItemName.double_dash_refill]],
|
|
||||||
|
|
||||||
(RegionName.highway_island, RegionName.granny_island): [[ItemName.traffic_block], [ItemName.air_dash, ItemName.dash_refill]],
|
|
||||||
(RegionName.highway_island, RegionName.ne_feathers_island): [[ItemName.feather]],
|
|
||||||
(RegionName.highway_island, RegionName.nw_girders_island): [[ItemName.cannot_access]],
|
|
||||||
|
|
||||||
(RegionName.nw_girders_island, RegionName.highway_island): [[ItemName.traffic_block]],
|
|
||||||
|
|
||||||
(RegionName.ne_feathers_island, RegionName.highway_island): [[ItemName.feather]],
|
|
||||||
(RegionName.ne_feathers_island, RegionName.badeline_tower_lower): [[ItemName.feather]],
|
|
||||||
(RegionName.ne_feathers_island, RegionName.badeline_tower_upper): [[ItemName.climb, ItemName.air_dash, ItemName.feather]],
|
|
||||||
|
|
||||||
(RegionName.se_house_island, RegionName.granny_island): [[ItemName.air_dash, ItemName.traffic_block, ItemName.double_dash_refill]],
|
|
||||||
(RegionName.se_house_island, RegionName.badeline_tower_lower): [[ItemName.air_dash, ItemName.double_dash_refill]],
|
|
||||||
|
|
||||||
(RegionName.badeline_tower_lower, RegionName.se_house_island): [[ItemName.cannot_access]],
|
|
||||||
(RegionName.badeline_tower_lower, RegionName.ne_feathers_island): [[ItemName.air_dash, ItemName.breakables, ItemName.feather]],
|
|
||||||
(RegionName.badeline_tower_lower, RegionName.granny_island): [[ItemName.cannot_access]],
|
|
||||||
(RegionName.badeline_tower_lower, RegionName.badeline_tower_upper): [[ItemName.cannot_access]],
|
|
||||||
|
|
||||||
(RegionName.badeline_tower_upper, RegionName.badeline_island): [[ItemName.air_dash, ItemName.climb, ItemName.double_dash_refill, ItemName.feather, ItemName.traffic_block, ItemName.breakables]],
|
|
||||||
(RegionName.badeline_tower_upper, RegionName.se_house_island): [[ItemName.air_dash], [ItemName.ground_dash]],
|
|
||||||
(RegionName.badeline_tower_upper, RegionName.ne_feathers_island): [[ItemName.air_dash], [ItemName.ground_dash]],
|
|
||||||
(RegionName.badeline_tower_upper, RegionName.granny_island): [[ItemName.dash_refill]],
|
|
||||||
|
|
||||||
(RegionName.badeline_island, RegionName.badeline_tower_upper): [[ItemName.air_dash], [ItemName.ground_dash]],
|
|
||||||
}
|
|
||||||
|
|
||||||
region_hard_moves_logic: Dict[Tuple[str], List[List[str]]] = {
|
|
||||||
(RegionName.forsaken_city, RegionName.granny_island): [[ItemName.checkpoint_2], [ItemName.checkpoint_3], [ItemName.checkpoint_4]],
|
|
||||||
(RegionName.forsaken_city, RegionName.highway_island): [[ItemName.checkpoint_5], [ItemName.checkpoint_6]],
|
|
||||||
(RegionName.forsaken_city, RegionName.ne_feathers_island): [[ItemName.checkpoint_7]],
|
|
||||||
(RegionName.forsaken_city, RegionName.se_house_island): [[ItemName.checkpoint_8]],
|
|
||||||
(RegionName.forsaken_city, RegionName.badeline_tower_upper): [[ItemName.checkpoint_9]],
|
|
||||||
(RegionName.forsaken_city, RegionName.badeline_island): [[ItemName.checkpoint_10]],
|
|
||||||
|
|
||||||
(RegionName.granny_island, RegionName.nw_girders_island): [[ItemName.traffic_block]],
|
|
||||||
(RegionName.granny_island, RegionName.badeline_tower_lower): [[ItemName.air_dash], [ItemName.ground_dash]],
|
|
||||||
(RegionName.granny_island, RegionName.se_house_island): [[ItemName.air_dash, ItemName.double_dash_refill], [ItemName.ground_dash]],
|
|
||||||
|
|
||||||
(RegionName.highway_island, RegionName.nw_girders_island): [[ItemName.air_dash, ItemName.ground_dash]],
|
|
||||||
|
|
||||||
(RegionName.nw_girders_island, RegionName.highway_island): [[ItemName.traffic_block], [ItemName.air_dash, ItemName.ground_dash]],
|
|
||||||
|
|
||||||
(RegionName.ne_feathers_island, RegionName.highway_island): [[ItemName.feather], [ItemName.air_dash], [ItemName.ground_dash], [ItemName.skid_jump]],
|
|
||||||
(RegionName.ne_feathers_island, RegionName.badeline_tower_lower): [[ItemName.feather], [ItemName.air_dash], [ItemName.ground_dash]],
|
|
||||||
(RegionName.ne_feathers_island, RegionName.badeline_tower_upper): [[ItemName.feather]],
|
|
||||||
|
|
||||||
(RegionName.se_house_island, RegionName.granny_island): [[ItemName.traffic_block]],
|
|
||||||
(RegionName.se_house_island, RegionName.badeline_tower_lower): [[ItemName.air_dash], [ItemName.ground_dash]],
|
|
||||||
|
|
||||||
(RegionName.badeline_tower_upper, RegionName.badeline_island): [[ItemName.air_dash, ItemName.climb, ItemName.feather, ItemName.traffic_block],
|
|
||||||
[ItemName.air_dash, ItemName.climb, ItemName.feather, ItemName.skid_jump],
|
|
||||||
[ItemName.air_dash, ItemName.climb, ItemName.ground_dash, ItemName.traffic_block],
|
|
||||||
[ItemName.air_dash, ItemName.climb, ItemName.ground_dash, ItemName.skid_jump]],
|
|
||||||
|
|
||||||
(RegionName.badeline_island, RegionName.badeline_tower_upper): [[ItemName.air_dash], [ItemName.ground_dash]],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def location_rule(state: CollectionState, world: Celeste64World, loc: str) -> bool:
|
def location_rule(state: CollectionState, world: Celeste64World, loc: str) -> bool:
|
||||||
|
|
||||||
if loc not in world.active_logic_mapping:
|
if loc not in world.active_logic_mapping:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -204,28 +332,12 @@ def location_rule(state: CollectionState, world: Celeste64World, loc: str) -> bo
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def region_connection_rule(state: CollectionState, world: Celeste64World, region_connection: Tuple[str]) -> bool:
|
|
||||||
if region_connection not in world.active_region_logic_mapping:
|
|
||||||
return True
|
|
||||||
|
|
||||||
for possible_access in world.active_region_logic_mapping[region_connection]:
|
|
||||||
if state.has_all(possible_access, world.player):
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
def goal_rule(state: CollectionState, world: Celeste64World) -> bool:
|
def goal_rule(state: CollectionState, world: Celeste64World) -> bool:
|
||||||
if not state.has(ItemName.strawberry, world.player, world.strawberries_required):
|
if not state.has(ItemName.strawberry, world.player, world.strawberries_required):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
goal_region: Region = world.multiworld.get_region(RegionName.badeline_island, world.player)
|
for possible_access in world.goal_logic_mapping:
|
||||||
return state.can_reach(goal_region)
|
if state.has_all(possible_access, world.player):
|
||||||
|
return True
|
||||||
|
|
||||||
def connect_region(world: Celeste64World, region: Region, dest_regions: List[str]):
|
return False
|
||||||
rules: Dict[str, Callable[[CollectionState], bool]] = {}
|
|
||||||
|
|
||||||
for dest_region in dest_regions:
|
|
||||||
region_connection: Tuple[str] = (region.name, dest_region)
|
|
||||||
rules[dest_region] = lambda state, region_connection=region_connection: region_connection_rule(state, world, region_connection)
|
|
||||||
|
|
||||||
region.add_exits(dest_regions, rules)
|
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from typing import Dict, List, Tuple
|
from typing import Dict, List
|
||||||
|
|
||||||
from BaseClasses import ItemClassification, Location, Region, Tutorial
|
from BaseClasses import ItemClassification, Location, Region, Tutorial
|
||||||
from worlds.AutoWorld import WebWorld, World
|
from worlds.AutoWorld import WebWorld, World
|
||||||
from .Items import Celeste64Item, unlockable_item_data_table, move_item_data_table, item_data_table,\
|
from .Items import Celeste64Item, unlockable_item_data_table, move_item_data_table, item_data_table, item_table
|
||||||
checkpoint_item_data_table, item_table
|
|
||||||
from .Locations import Celeste64Location, strawberry_location_data_table, friend_location_data_table,\
|
from .Locations import Celeste64Location, strawberry_location_data_table, friend_location_data_table,\
|
||||||
sign_location_data_table, car_location_data_table, checkpoint_location_data_table,\
|
sign_location_data_table, car_location_data_table, location_table
|
||||||
location_table
|
|
||||||
from .Names import ItemName, LocationName
|
from .Names import ItemName, LocationName
|
||||||
from .Options import Celeste64Options, celeste_64_option_groups, resolve_options
|
from .Options import Celeste64Options, celeste_64_option_groups
|
||||||
|
|
||||||
|
|
||||||
class Celeste64WebWorld(WebWorld):
|
class Celeste64WebWorld(WebWorld):
|
||||||
@@ -44,15 +42,8 @@ class Celeste64World(World):
|
|||||||
# Instance Data
|
# Instance Data
|
||||||
strawberries_required: int
|
strawberries_required: int
|
||||||
active_logic_mapping: Dict[str, List[List[str]]]
|
active_logic_mapping: Dict[str, List[List[str]]]
|
||||||
active_region_logic_mapping: Dict[Tuple[str], List[List[str]]]
|
goal_logic_mapping: Dict[str, List[List[str]]]
|
||||||
|
|
||||||
madeline_one_dash_hair_color: int
|
|
||||||
madeline_two_dash_hair_color: int
|
|
||||||
madeline_no_dash_hair_color: int
|
|
||||||
madeline_feather_hair_color: int
|
|
||||||
|
|
||||||
def generate_early(self) -> None:
|
|
||||||
resolve_options(self)
|
|
||||||
|
|
||||||
def create_item(self, name: str) -> Celeste64Item:
|
def create_item(self, name: str) -> Celeste64Item:
|
||||||
# Only make required amount of strawberries be Progression
|
# Only make required amount of strawberries be Progression
|
||||||
@@ -85,49 +76,25 @@ class Celeste64World(World):
|
|||||||
for name in unlockable_item_data_table.keys()
|
for name in unlockable_item_data_table.keys()
|
||||||
if name not in self.options.start_inventory]
|
if name not in self.options.start_inventory]
|
||||||
|
|
||||||
chosen_start_item: str = ""
|
|
||||||
|
|
||||||
if self.options.move_shuffle:
|
if self.options.move_shuffle:
|
||||||
|
move_items_for_itempool: List[str] = deepcopy(list(move_item_data_table.keys()))
|
||||||
|
|
||||||
if self.options.logic_difficulty == "standard":
|
if self.options.logic_difficulty == "standard":
|
||||||
possible_unwalls: List[str] = [name for name in move_item_data_table.keys()
|
# If the start_inventory already includes a move, don't worry about giving it one
|
||||||
if name != ItemName.skid_jump]
|
if not [move for move in move_items_for_itempool if move in self.options.start_inventory]:
|
||||||
|
chosen_start_move = self.random.choice(move_items_for_itempool)
|
||||||
if self.options.checkpointsanity:
|
move_items_for_itempool.remove(chosen_start_move)
|
||||||
possible_unwalls.extend([name for name in checkpoint_item_data_table.keys()
|
|
||||||
if name != ItemName.checkpoint_1 and name != ItemName.checkpoint_10])
|
|
||||||
|
|
||||||
# If the start_inventory already includes a move or checkpoint, don't worry about giving it one
|
|
||||||
if not [item for item in possible_unwalls if item in self.multiworld.precollected_items[self.player]]:
|
|
||||||
chosen_start_item = self.random.choice(possible_unwalls)
|
|
||||||
|
|
||||||
if self.options.carsanity:
|
if self.options.carsanity:
|
||||||
intro_car_loc: Location = self.multiworld.get_location(LocationName.car_1, self.player)
|
intro_car_loc: Location = self.multiworld.get_location(LocationName.car_1, self.player)
|
||||||
intro_car_loc.place_locked_item(self.create_item(chosen_start_item))
|
intro_car_loc.place_locked_item(self.create_item(chosen_start_move))
|
||||||
location_count -= 1
|
location_count -= 1
|
||||||
else:
|
else:
|
||||||
self.multiworld.push_precollected(self.create_item(chosen_start_item))
|
self.multiworld.push_precollected(self.create_item(chosen_start_move))
|
||||||
|
|
||||||
item_pool += [self.create_item(name)
|
item_pool += [self.create_item(name)
|
||||||
for name in move_item_data_table.keys()
|
for name in move_items_for_itempool
|
||||||
if name not in self.multiworld.precollected_items[self.player]
|
if name not in self.options.start_inventory]
|
||||||
and name != chosen_start_item]
|
|
||||||
else:
|
|
||||||
for start_move in move_item_data_table.keys():
|
|
||||||
self.multiworld.push_precollected(self.create_item(start_move))
|
|
||||||
|
|
||||||
if self.options.checkpointsanity:
|
|
||||||
location_count += 9
|
|
||||||
goal_checkpoint_loc: Location = self.multiworld.get_location(LocationName.checkpoint_10, self.player)
|
|
||||||
goal_checkpoint_loc.place_locked_item(self.create_item(ItemName.checkpoint_10))
|
|
||||||
item_pool += [self.create_item(name)
|
|
||||||
for name in checkpoint_item_data_table.keys()
|
|
||||||
if name not in self.multiworld.precollected_items[self.player]
|
|
||||||
and name != ItemName.checkpoint_10
|
|
||||||
and name != chosen_start_item]
|
|
||||||
else:
|
|
||||||
for item_name in checkpoint_item_data_table.keys():
|
|
||||||
checkpoint_loc: Location = self.multiworld.get_location(item_name, self.player)
|
|
||||||
checkpoint_loc.place_locked_item(self.create_item(item_name))
|
|
||||||
|
|
||||||
real_total_strawberries: int = min(self.options.total_strawberries.value, location_count - len(item_pool))
|
real_total_strawberries: int = min(self.options.total_strawberries.value, location_count - len(item_pool))
|
||||||
self.strawberries_required = int(real_total_strawberries * (self.options.strawberries_required_percentage / 100))
|
self.strawberries_required = int(real_total_strawberries * (self.options.strawberries_required_percentage / 100))
|
||||||
@@ -173,23 +140,18 @@ class Celeste64World(World):
|
|||||||
if location_data.region == region_name
|
if location_data.region == region_name
|
||||||
}, Celeste64Location)
|
}, Celeste64Location)
|
||||||
|
|
||||||
region.add_locations({
|
region.add_exits(region_data_table[region_name].connecting_regions)
|
||||||
location_name: location_data.address for location_name, location_data in checkpoint_location_data_table.items()
|
|
||||||
if location_data.region == region_name
|
|
||||||
}, Celeste64Location)
|
|
||||||
|
|
||||||
from .Rules import connect_region
|
|
||||||
connect_region(self, region, region_data_table[region_name].connecting_regions)
|
|
||||||
|
|
||||||
# Have to do this here because of other games using State in a way that's bad
|
|
||||||
from .Rules import set_rules
|
|
||||||
set_rules(self)
|
|
||||||
|
|
||||||
|
|
||||||
def get_filler_item_name(self) -> str:
|
def get_filler_item_name(self) -> str:
|
||||||
return ItemName.raspberry
|
return ItemName.raspberry
|
||||||
|
|
||||||
|
|
||||||
|
def set_rules(self) -> None:
|
||||||
|
from .Rules import set_rules
|
||||||
|
set_rules(self)
|
||||||
|
|
||||||
|
|
||||||
def fill_slot_data(self):
|
def fill_slot_data(self):
|
||||||
return {
|
return {
|
||||||
"death_link": self.options.death_link.value,
|
"death_link": self.options.death_link.value,
|
||||||
@@ -199,11 +161,6 @@ class Celeste64World(World):
|
|||||||
"friendsanity": self.options.friendsanity.value,
|
"friendsanity": self.options.friendsanity.value,
|
||||||
"signsanity": self.options.signsanity.value,
|
"signsanity": self.options.signsanity.value,
|
||||||
"carsanity": self.options.carsanity.value,
|
"carsanity": self.options.carsanity.value,
|
||||||
"checkpointsanity": self.options.checkpointsanity.value,
|
|
||||||
"madeline_one_dash_hair_color": self.madeline_one_dash_hair_color,
|
|
||||||
"madeline_two_dash_hair_color": self.madeline_two_dash_hair_color,
|
|
||||||
"madeline_no_dash_hair_color": self.madeline_no_dash_hair_color,
|
|
||||||
"madeline_feather_hair_color": self.madeline_feather_hair_color,
|
|
||||||
"badeline_chaser_source": self.options.badeline_chaser_source.value,
|
"badeline_chaser_source": self.options.badeline_chaser_source.value,
|
||||||
"badeline_chaser_frequency": self.options.badeline_chaser_frequency.value,
|
"badeline_chaser_frequency": self.options.badeline_chaser_frequency.value,
|
||||||
"badeline_chaser_speed": self.options.badeline_chaser_speed.value,
|
"badeline_chaser_speed": self.options.badeline_chaser_speed.value,
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
import os
|
import os
|
||||||
import io
|
|
||||||
from typing import TYPE_CHECKING, Dict, List, Optional, cast
|
from typing import TYPE_CHECKING, Dict, List, Optional, cast
|
||||||
import zipfile
|
import zipfile
|
||||||
from BaseClasses import Location
|
from BaseClasses import Location
|
||||||
from worlds.Files import APContainer, AutoPatchRegister
|
from worlds.Files import APContainer
|
||||||
|
|
||||||
from .Enum import CivVICheckType
|
from .Enum import CivVICheckType
|
||||||
from .Locations import CivVILocation, CivVILocationData
|
from .Locations import CivVILocation, CivVILocationData
|
||||||
@@ -26,32 +25,24 @@ class CivTreeItem:
|
|||||||
ui_tree_row: int
|
ui_tree_row: int
|
||||||
|
|
||||||
|
|
||||||
class CivVIContainer(APContainer, metaclass=AutoPatchRegister):
|
class CivVIContainer(APContainer):
|
||||||
"""
|
"""
|
||||||
Responsible for generating the dynamic mod files for the Civ VI multiworld
|
Responsible for generating the dynamic mod files for the Civ VI multiworld
|
||||||
"""
|
"""
|
||||||
game: Optional[str] = "Civilization VI"
|
game: Optional[str] = "Civilization VI"
|
||||||
patch_file_ending = ".apcivvi"
|
|
||||||
|
|
||||||
def __init__(self, patch_data: Dict[str, str] | io.BytesIO, base_path: str = "", output_directory: str = "",
|
def __init__(self, patch_data: Dict[str, str], base_path: str, output_directory: str,
|
||||||
player: Optional[int] = None, player_name: str = "", server: str = ""):
|
player: Optional[int] = None, player_name: str = "", server: str = ""):
|
||||||
if isinstance(patch_data, io.BytesIO):
|
self.patch_data = patch_data
|
||||||
super().__init__(patch_data, player, player_name, server)
|
self.file_path = base_path
|
||||||
else:
|
container_path = os.path.join(output_directory, base_path + ".apcivvi")
|
||||||
self.patch_data = patch_data
|
super().__init__(container_path, player, player_name, server)
|
||||||
self.file_path = base_path
|
|
||||||
container_path = os.path.join(output_directory, base_path + ".apcivvi")
|
|
||||||
super().__init__(container_path, player, player_name, server)
|
|
||||||
|
|
||||||
def write_contents(self, opened_zipfile: zipfile.ZipFile) -> None:
|
def write_contents(self, opened_zipfile: zipfile.ZipFile) -> None:
|
||||||
for filename, yml in self.patch_data.items():
|
for filename, yml in self.patch_data.items():
|
||||||
opened_zipfile.writestr(filename, yml)
|
opened_zipfile.writestr(filename, yml)
|
||||||
super().write_contents(opened_zipfile)
|
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:
|
def get_cost(world: 'CivVIWorld', location: CivVILocationData) -> int:
|
||||||
"""
|
"""
|
||||||
@@ -67,7 +58,7 @@ def get_formatted_player_name(world: 'CivVIWorld', player: int) -> str:
|
|||||||
Returns the name of the player in the world
|
Returns the name of the player in the world
|
||||||
"""
|
"""
|
||||||
if player != world.player:
|
if player != world.player:
|
||||||
return sanitize_value(f"{world.multiworld.player_name[player]}{apo}s")
|
return f"{world.multiworld.player_name[player]}{apo}s"
|
||||||
return "Your"
|
return "Your"
|
||||||
|
|
||||||
|
|
||||||
@@ -110,7 +101,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!"/>
|
<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}" '
|
{"".join([f'{tab}<Row TechnologyType="{location.name}" '
|
||||||
f'Name="{get_formatted_player_name(world, location.item.player)} '
|
f'Name="{get_formatted_player_name(world, location.item.player)} '
|
||||||
f'{sanitize_value(location.item.name)}" '
|
f'{location.item.name}" '
|
||||||
f'EraType="{world.location_table[location.name].era_type}" '
|
f'EraType="{world.location_table[location.name].era_type}" '
|
||||||
f'UITreeRow="{world.location_table[location.name].uiTreeRow}" '
|
f'UITreeRow="{world.location_table[location.name].uiTreeRow}" '
|
||||||
f'Cost="{get_cost(world, world.location_table[location.name])}" '
|
f'Cost="{get_cost(world, world.location_table[location.name])}" '
|
||||||
@@ -126,7 +117,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!"/>
|
<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}" '
|
{"".join([f'{tab}<Row CivicType="{location.name}" '
|
||||||
f'Name="{get_formatted_player_name(world, location.item.player)} '
|
f'Name="{get_formatted_player_name(world, location.item.player)} '
|
||||||
f'{sanitize_value(location.item.name)}" '
|
f'{location.item.name}" '
|
||||||
f'EraType="{world.location_table[location.name].era_type}" '
|
f'EraType="{world.location_table[location.name].era_type}" '
|
||||||
f'UITreeRow="{world.location_table[location.name].uiTreeRow}" '
|
f'UITreeRow="{world.location_table[location.name].uiTreeRow}" '
|
||||||
f'Cost="{get_cost(world, world.location_table[location.name])}" '
|
f'Cost="{get_cost(world, world.location_table[location.name])}" '
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ class CliqueWebWorld(WebWorld):
|
|||||||
)
|
)
|
||||||
|
|
||||||
tutorials = [setup_en, setup_de]
|
tutorials = [setup_en, setup_de]
|
||||||
game_info_languages = ["en", "de"]
|
|
||||||
|
|
||||||
|
|
||||||
class CliqueWorld(World):
|
class CliqueWorld(World):
|
||||||
|
|||||||
@@ -644,9 +644,6 @@ class CV64PatchExtensions(APPatchExtension):
|
|||||||
# Replace the PowerUp in the Forest Special1 Bridge 3HB rock with an L jewel if 3HBs aren't randomized
|
# 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"]:
|
if not options["multi_hit_breakables"]:
|
||||||
rom_data.write_byte(0x10C7A1, 0x03)
|
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
|
# Change the appearance of the Pot-Pourri to that of a larger PowerUp regardless of the above setting, so other
|
||||||
# game PermaUps are distinguishable.
|
# game PermaUps are distinguishable.
|
||||||
rom_data.write_int32s(0xEE558, [0x06005F08, 0x3FB00000, 0xFFFFFF00])
|
rom_data.write_int32s(0xEE558, [0x06005F08, 0x3FB00000, 0xFFFFFF00])
|
||||||
@@ -717,11 +714,7 @@ class CV64PatchExtensions(APPatchExtension):
|
|||||||
rom_data.write_int32(0x10CF38, 0x8000FF4D) # CT final room door slab
|
rom_data.write_int32(0x10CF38, 0x8000FF4D) # CT final room door slab
|
||||||
rom_data.write_int32(0x10CF44, 0x1000FF4D) # CT Renon slab
|
rom_data.write_int32(0x10CF44, 0x1000FF4D) # CT Renon slab
|
||||||
rom_data.write_int32(0x10C908, 0x0008FF4D) # Villa foyer chandelier
|
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
|
# Once-per-frame gameplay checks
|
||||||
rom_data.write_int32(0x6C848, 0x080FF40D) # J 0x803FD034
|
rom_data.write_int32(0x6C848, 0x080FF40D) # J 0x803FD034
|
||||||
@@ -1007,7 +1000,6 @@ def write_patch(world: "CV64World", patch: CV64ProcedurePatch, offset_data: Dict
|
|||||||
"multi_hit_breakables": world.options.multi_hit_breakables.value,
|
"multi_hit_breakables": world.options.multi_hit_breakables.value,
|
||||||
"drop_previous_sub_weapon": world.options.drop_previous_sub_weapon.value,
|
"drop_previous_sub_weapon": world.options.drop_previous_sub_weapon.value,
|
||||||
"countdown": world.options.countdown.value,
|
"countdown": world.options.countdown.value,
|
||||||
"lizard_locker_items": world.options.lizard_locker_items.value,
|
|
||||||
"shopsanity": world.options.shopsanity.value,
|
"shopsanity": world.options.shopsanity.value,
|
||||||
"panther_dash": world.options.panther_dash.value,
|
"panther_dash": world.options.panther_dash.value,
|
||||||
"big_toss": world.options.big_toss.value,
|
"big_toss": world.options.big_toss.value,
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ from worlds.AutoWorld import WebWorld, World
|
|||||||
|
|
||||||
from .aesthetics import shuffle_sub_weapons, get_location_data, get_countdown_flags, populate_enemy_drops, \
|
from .aesthetics import shuffle_sub_weapons, get_location_data, get_countdown_flags, populate_enemy_drops, \
|
||||||
get_start_inventory_data
|
get_start_inventory_data
|
||||||
from .rom import RomData, patch_rom, get_base_rom_path, CVCotMProcedurePatch, CVCOTM_CT_US_HASH, CVCOTM_AC_US_HASH
|
from .rom import RomData, patch_rom, get_base_rom_path, CVCotMProcedurePatch, CVCOTM_CT_US_HASH, CVCOTM_AC_US_HASH, \
|
||||||
# CVCOTM_VC_US_HASH
|
CVCOTM_VC_US_HASH
|
||||||
from .client import CastlevaniaCotMClient
|
from .client import CastlevaniaCotMClient
|
||||||
|
|
||||||
|
|
||||||
@@ -29,8 +29,7 @@ class CVCotMSettings(settings.Group):
|
|||||||
"""File name of the Castlevania CotM US rom"""
|
"""File name of the Castlevania CotM US rom"""
|
||||||
copy_to = "Castlevania - Circle of the Moon (USA).gba"
|
copy_to = "Castlevania - Circle of the Moon (USA).gba"
|
||||||
description = "Castlevania CotM (US) ROM File"
|
description = "Castlevania CotM (US) ROM File"
|
||||||
# md5s = [CVCOTM_CT_US_HASH, CVCOTM_AC_US_HASH, CVCOTM_VC_US_HASH]
|
md5s = [CVCOTM_CT_US_HASH, CVCOTM_AC_US_HASH, CVCOTM_VC_US_HASH]
|
||||||
md5s = [CVCOTM_CT_US_HASH, CVCOTM_AC_US_HASH]
|
|
||||||
|
|
||||||
rom_file: RomFile = RomFile(RomFile.copy_to)
|
rom_file: RomFile = RomFile(RomFile.copy_to)
|
||||||
|
|
||||||
|
|||||||
@@ -153,10 +153,11 @@ Advance Collection ROM; most notably the fact that the audio does not function w
|
|||||||
which is currently a requirement to connect to a multiworld. This happens because all audio code was stripped
|
which is currently a requirement to connect to a multiworld. This happens because all audio code was stripped
|
||||||
from the ROM, and all sound is instead played by the collection through external means.
|
from the ROM, and all sound is instead played by the collection through external means.
|
||||||
|
|
||||||
The Wii U Virtual Console version does not work due to changes in the code in that version.
|
For this reason, it is most recommended to obtain the ROM by dumping it from an original cartridge of the game that you legally own.
|
||||||
|
Though, the Advance Collection *can* still technically be an option if you cannot do that and don't mind the lack of sound.
|
||||||
|
|
||||||
Due to the reasons mentioned above, it is most recommended to obtain the ROM by dumping it from an original cartridge of the
|
The Wii U Virtual Console version is currently untested. If you happen to have purchased it before the Wii U eShop shut down, you can try
|
||||||
game that you legally own. However, the Advance Collection *is* an option if you cannot do that and don't mind the lack of sound.
|
dumping and playing with it. However, at the moment, we cannot guarantee that it will work well due to it being untested.
|
||||||
|
|
||||||
Regardless of which released ROM you intend to try playing with, the US version of the game is required.
|
Regardless of which released ROM you intend to try playing with, the US version of the game is required.
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
- [Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases/latest).
|
- [Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases/latest).
|
||||||
- A Castlevania: Circle of the Moon ROM of the US version specifically. The Archipelago community cannot provide this.
|
- A Castlevania: Circle of the Moon ROM of the US version specifically. The Archipelago community cannot provide this.
|
||||||
The Castlevania Advance Collection ROM can be used, but it has no audio. The Wii U Virtual Console ROM does not work.
|
The Castlevania Advance Collection ROM can technically be used, but it has no audio. The Wii U Virtual Console ROM is untested.
|
||||||
- [BizHawk](https://tasvideos.org/BizHawk/ReleaseHistory) 2.7 or later.
|
- [BizHawk](https://tasvideos.org/BizHawk/ReleaseHistory) 2.7 or later.
|
||||||
|
|
||||||
### Configuring BizHawk
|
### Configuring BizHawk
|
||||||
|
|||||||
@@ -22,9 +22,11 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
CVCOTM_CT_US_HASH = "50a1089600603a94e15ecf287f8d5a1f" # Original GBA cartridge ROM
|
CVCOTM_CT_US_HASH = "50a1089600603a94e15ecf287f8d5a1f" # Original GBA cartridge ROM
|
||||||
CVCOTM_AC_US_HASH = "87a1bd6577b6702f97a60fc55772ad74" # Castlevania Advance Collection ROM
|
CVCOTM_AC_US_HASH = "87a1bd6577b6702f97a60fc55772ad74" # Castlevania Advance Collection ROM
|
||||||
# CVCOTM_VC_US_HASH = "2cc38305f62b337281663bad8c901cf9" # Wii U Virtual Console ROM
|
CVCOTM_VC_US_HASH = "2cc38305f62b337281663bad8c901cf9" # Wii U Virtual Console ROM
|
||||||
|
|
||||||
# The Wii U VC version is not currently supported. See the Game Page for more info.
|
# NOTE: The Wii U VC version is untested as of when this comment was written. I am only including its hash in case it
|
||||||
|
# does work. If someone who has it can confirm it does indeed work, this comment should be removed. If it doesn't, the
|
||||||
|
# hash should be removed in addition. See the Game Page for more information about supported versions.
|
||||||
|
|
||||||
ARCHIPELAGO_IDENTIFIER_START = 0x7FFF00
|
ARCHIPELAGO_IDENTIFIER_START = 0x7FFF00
|
||||||
ARCHIPELAGO_IDENTIFIER = "ARCHIPELAG03"
|
ARCHIPELAGO_IDENTIFIER = "ARCHIPELAG03"
|
||||||
@@ -516,8 +518,7 @@ class CVCotMPatchExtensions(APPatchExtension):
|
|||||||
|
|
||||||
|
|
||||||
class CVCotMProcedurePatch(APProcedurePatch, APTokenMixin):
|
class CVCotMProcedurePatch(APProcedurePatch, APTokenMixin):
|
||||||
# hash = [CVCOTM_CT_US_HASH, CVCOTM_AC_US_HASH, CVCOTM_VC_US_HASH]
|
hash = [CVCOTM_CT_US_HASH, CVCOTM_AC_US_HASH, CVCOTM_VC_US_HASH]
|
||||||
hash = [CVCOTM_CT_US_HASH, CVCOTM_AC_US_HASH]
|
|
||||||
patch_file_ending: str = ".apcvcotm"
|
patch_file_ending: str = ".apcvcotm"
|
||||||
result_file_ending: str = ".gba"
|
result_file_ending: str = ".gba"
|
||||||
|
|
||||||
@@ -584,8 +585,7 @@ def get_base_rom_bytes(file_name: str = "") -> bytes:
|
|||||||
|
|
||||||
basemd5 = hashlib.md5()
|
basemd5 = hashlib.md5()
|
||||||
basemd5.update(base_rom_bytes)
|
basemd5.update(base_rom_bytes)
|
||||||
# if basemd5.hexdigest() not in [CVCOTM_CT_US_HASH, CVCOTM_AC_US_HASH, CVCOTM_VC_US_HASH]:
|
if basemd5.hexdigest() not in [CVCOTM_CT_US_HASH, CVCOTM_AC_US_HASH, CVCOTM_VC_US_HASH]:
|
||||||
if basemd5.hexdigest() not in [CVCOTM_CT_US_HASH, CVCOTM_AC_US_HASH]:
|
|
||||||
raise Exception("Supplied Base ROM does not match known MD5s for Castlevania: Circle of the Moon USA."
|
raise Exception("Supplied Base ROM does not match known MD5s for Castlevania: Circle of the Moon USA."
|
||||||
"Get the correct game and version, then dump it.")
|
"Get the correct game and version, then dump it.")
|
||||||
setattr(get_base_rom_bytes, "base_rom_bytes", base_rom_bytes)
|
setattr(get_base_rom_bytes, "base_rom_bytes", base_rom_bytes)
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ class DLCqwebworld(WebWorld):
|
|||||||
["Deoxis"]
|
["Deoxis"]
|
||||||
)
|
)
|
||||||
tutorials = [setup_en, setup_fr]
|
tutorials = [setup_en, setup_fr]
|
||||||
game_info_languages = ["en", "fr"]
|
|
||||||
|
|
||||||
|
|
||||||
class DLCqworld(World):
|
class DLCqworld(World):
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 3,
|
'map': 3,
|
||||||
'index': 64,
|
'index': 64,
|
||||||
'doom_type': 2001,
|
'doom_type': 2001,
|
||||||
'region': "Toxin Refinery (E1M3) Start"},
|
'region': "Toxin Refinery (E1M3) Main"},
|
||||||
351019: {'name': 'Toxin Refinery (E1M3) - Shotgun 2',
|
351019: {'name': 'Toxin Refinery (E1M3) - Shotgun 2',
|
||||||
'episode': 1,
|
'episode': 1,
|
||||||
'map': 3,
|
'map': 3,
|
||||||
@@ -234,7 +234,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 4,
|
'map': 4,
|
||||||
'index': 107,
|
'index': 107,
|
||||||
'doom_type': 8,
|
'doom_type': 8,
|
||||||
'region': "Command Control (E1M4) Start"},
|
'region': "Command Control (E1M4) Main"},
|
||||||
351037: {'name': 'Command Control (E1M4) - Shotgun',
|
351037: {'name': 'Command Control (E1M4) - Shotgun',
|
||||||
'episode': 1,
|
'episode': 1,
|
||||||
'map': 4,
|
'map': 4,
|
||||||
@@ -504,7 +504,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 7,
|
'map': 7,
|
||||||
'index': 122,
|
'index': 122,
|
||||||
'doom_type': 2001,
|
'doom_type': 2001,
|
||||||
'region': "Computer Station (E1M7) Start"},
|
'region': "Computer Station (E1M7) Main"},
|
||||||
351082: {'name': 'Computer Station (E1M7) - Rocket launcher',
|
351082: {'name': 'Computer Station (E1M7) - Rocket launcher',
|
||||||
'episode': 1,
|
'episode': 1,
|
||||||
'map': 7,
|
'map': 7,
|
||||||
@@ -912,7 +912,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 4,
|
'map': 4,
|
||||||
'index': 109,
|
'index': 109,
|
||||||
'doom_type': 2001,
|
'doom_type': 2001,
|
||||||
'region': "Deimos Lab (E2M4) Start"},
|
'region': "Deimos Lab (E2M4) Main"},
|
||||||
351150: {'name': 'Deimos Lab (E2M4) - Mega Armor',
|
351150: {'name': 'Deimos Lab (E2M4) - Mega Armor',
|
||||||
'episode': 2,
|
'episode': 2,
|
||||||
'map': 4,
|
'map': 4,
|
||||||
@@ -1242,7 +1242,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 8,
|
'map': 8,
|
||||||
'index': 36,
|
'index': 36,
|
||||||
'doom_type': 2019,
|
'doom_type': 2019,
|
||||||
'region': "Tower of Babel (E2M8) Start"},
|
'region': "Tower of Babel (E2M8) Main"},
|
||||||
351205: {'name': 'Fortress of Mystery (E2M9) - Supercharge',
|
351205: {'name': 'Fortress of Mystery (E2M9) - Supercharge',
|
||||||
'episode': 2,
|
'episode': 2,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
@@ -1638,7 +1638,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 5,
|
'map': 5,
|
||||||
'index': 187,
|
'index': 187,
|
||||||
'doom_type': 2001,
|
'doom_type': 2001,
|
||||||
'region': "Unholy Cathedral (E3M5) Start"},
|
'region': "Unholy Cathedral (E3M5) Main"},
|
||||||
351271: {'name': 'Unholy Cathedral (E3M5) - Shotgun 2',
|
351271: {'name': 'Unholy Cathedral (E3M5) - Shotgun 2',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 5,
|
'map': 5,
|
||||||
|
|||||||
@@ -33,11 +33,9 @@ regions:List[RegionDict] = [
|
|||||||
|
|
||||||
# Toxin Refinery (E1M3)
|
# Toxin Refinery (E1M3)
|
||||||
{"name":"Toxin Refinery (E1M3) Main",
|
{"name":"Toxin Refinery (E1M3) Main",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":True,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
"connections":[
|
"connections":[{"target":"Toxin Refinery (E1M3) Blue","pro":False}]},
|
||||||
{"target":"Toxin Refinery (E1M3) Blue","pro":False},
|
|
||||||
{"target":"Toxin Refinery (E1M3) Start","pro":False}]},
|
|
||||||
{"name":"Toxin Refinery (E1M3) Blue",
|
{"name":"Toxin Refinery (E1M3) Blue",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
@@ -48,20 +46,15 @@ regions:List[RegionDict] = [
|
|||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
"connections":[{"target":"Toxin Refinery (E1M3) Blue","pro":False}]},
|
"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)
|
# Command Control (E1M4)
|
||||||
{"name":"Command Control (E1M4) Main",
|
{"name":"Command Control (E1M4) Main",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":True,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
"connections":[
|
"connections":[
|
||||||
{"target":"Command Control (E1M4) Blue","pro":False},
|
{"target":"Command Control (E1M4) Blue","pro":False},
|
||||||
{"target":"Command Control (E1M4) Yellow","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",
|
{"name":"Command Control (E1M4) Blue",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
@@ -79,10 +72,6 @@ regions:List[RegionDict] = [
|
|||||||
{"target":"Command Control (E1M4) Main","pro":False},
|
{"target":"Command Control (E1M4) Main","pro":False},
|
||||||
{"target":"Command Control (E1M4) Blue","pro":False},
|
{"target":"Command Control (E1M4) Blue","pro":False},
|
||||||
{"target":"Command Control (E1M4) Yellow","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)
|
# Phobos Lab (E1M5)
|
||||||
{"name":"Phobos Lab (E1M5) Main",
|
{"name":"Phobos Lab (E1M5) Main",
|
||||||
@@ -137,12 +126,11 @@ regions:List[RegionDict] = [
|
|||||||
|
|
||||||
# Computer Station (E1M7)
|
# Computer Station (E1M7)
|
||||||
{"name":"Computer Station (E1M7) Main",
|
{"name":"Computer Station (E1M7) Main",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":True,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
"connections":[
|
"connections":[
|
||||||
{"target":"Computer Station (E1M7) Red","pro":False},
|
{"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",
|
{"name":"Computer Station (E1M7) Blue",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
@@ -162,10 +150,6 @@ regions:List[RegionDict] = [
|
|||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
"connections":[{"target":"Computer Station (E1M7) Yellow","pro":False}]},
|
"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)
|
# Phobos Anomaly (E1M8)
|
||||||
{"name":"Phobos Anomaly (E1M8) Main",
|
{"name":"Phobos Anomaly (E1M8) Main",
|
||||||
@@ -254,11 +238,9 @@ regions:List[RegionDict] = [
|
|||||||
|
|
||||||
# Deimos Lab (E2M4)
|
# Deimos Lab (E2M4)
|
||||||
{"name":"Deimos Lab (E2M4) Main",
|
{"name":"Deimos Lab (E2M4) Main",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":True,
|
||||||
"episode":2,
|
"episode":2,
|
||||||
"connections":[
|
"connections":[{"target":"Deimos Lab (E2M4) Blue","pro":False}]},
|
||||||
{"target":"Deimos Lab (E2M4) Blue","pro":False},
|
|
||||||
{"target":"Deimos Lab (E2M4) Start","pro":False}]},
|
|
||||||
{"name":"Deimos Lab (E2M4) Blue",
|
{"name":"Deimos Lab (E2M4) Blue",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":2,
|
"episode":2,
|
||||||
@@ -269,10 +251,6 @@ regions:List[RegionDict] = [
|
|||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":2,
|
"episode":2,
|
||||||
"connections":[{"target":"Deimos Lab (E2M4) Blue","pro":False}]},
|
"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)
|
# Command Center (E2M5)
|
||||||
{"name":"Command Center (E2M5) Main",
|
{"name":"Command Center (E2M5) Main",
|
||||||
@@ -336,13 +314,9 @@ regions:List[RegionDict] = [
|
|||||||
|
|
||||||
# Tower of Babel (E2M8)
|
# Tower of Babel (E2M8)
|
||||||
{"name":"Tower of Babel (E2M8) Main",
|
{"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,
|
"connects_to_hub":True,
|
||||||
"episode":2,
|
"episode":2,
|
||||||
"connections":[{"target":"Tower of Babel (E2M8) Main","pro":False}]},
|
"connections":[]},
|
||||||
|
|
||||||
# Fortress of Mystery (E2M9)
|
# Fortress of Mystery (E2M9)
|
||||||
{"name":"Fortress of Mystery (E2M9) Main",
|
{"name":"Fortress of Mystery (E2M9) Main",
|
||||||
@@ -418,12 +392,11 @@ regions:List[RegionDict] = [
|
|||||||
|
|
||||||
# Unholy Cathedral (E3M5)
|
# Unholy Cathedral (E3M5)
|
||||||
{"name":"Unholy Cathedral (E3M5) Main",
|
{"name":"Unholy Cathedral (E3M5) Main",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":True,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[
|
"connections":[
|
||||||
{"target":"Unholy Cathedral (E3M5) Yellow","pro":False},
|
{"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",
|
{"name":"Unholy Cathedral (E3M5) Blue",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
@@ -432,10 +405,6 @@ regions:List[RegionDict] = [
|
|||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[{"target":"Unholy Cathedral (E3M5) Main","pro":False}]},
|
"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)
|
# Mt. Erebus (E3M6)
|
||||||
{"name":"Mt. Erebus (E3M6) Main",
|
{"name":"Mt. Erebus (E3M6) Main",
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ def set_episode1_rules(player, multiworld, pro):
|
|||||||
state.has("Nuclear Plant (E1M2) - Red keycard", player, 1))
|
state.has("Nuclear Plant (E1M2) - Red keycard", player, 1))
|
||||||
|
|
||||||
# Toxin Refinery (E1M3)
|
# 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:
|
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))
|
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:
|
set_rule(multiworld.get_entrance("Toxin Refinery (E1M3) Blue -> Toxin Refinery (E1M3) Yellow", player), lambda state:
|
||||||
@@ -31,13 +35,12 @@ def set_episode1_rules(player, multiworld, pro):
|
|||||||
state.has("Toxin Refinery (E1M3) - Blue keycard", player, 1))
|
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:
|
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))
|
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)
|
# 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:
|
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) - Blue keycard", player, 1) or
|
||||||
state.has("Command Control (E1M4) - Yellow keycard", player, 1))
|
state.has("Command Control (E1M4) - Yellow keycard", player, 1))
|
||||||
@@ -47,11 +50,6 @@ def set_episode1_rules(player, multiworld, pro):
|
|||||||
set_rule(multiworld.get_entrance("Command Control (E1M4) Blue -> Command Control (E1M4) Main", player), lambda state:
|
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) - Yellow keycard", player, 1) or
|
||||||
state.has("Command Control (E1M4) - Blue keycard", player, 1))
|
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)
|
# Phobos Lab (E1M5)
|
||||||
set_rule(multiworld.get_entrance("Hub -> Phobos Lab (E1M5) Main", player), lambda state:
|
set_rule(multiworld.get_entrance("Hub -> Phobos Lab (E1M5) Main", player), lambda state:
|
||||||
@@ -85,6 +83,11 @@ def set_episode1_rules(player, multiworld, pro):
|
|||||||
state.has("Central Processing (E1M6) - Yellow keycard", player, 1))
|
state.has("Central Processing (E1M6) - Yellow keycard", player, 1))
|
||||||
|
|
||||||
# Computer Station (E1M7)
|
# 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:
|
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))
|
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:
|
set_rule(multiworld.get_entrance("Computer Station (E1M7) Main -> Computer Station (E1M7) Yellow", player), lambda state:
|
||||||
@@ -100,12 +103,6 @@ def set_episode1_rules(player, multiworld, pro):
|
|||||||
state.has("Computer Station (E1M7) - Red keycard", player, 1))
|
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:
|
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))
|
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)
|
# Phobos Anomaly (E1M8)
|
||||||
set_rule(multiworld.get_entrance("Hub -> Phobos Anomaly (E1M8) Start", player), lambda state:
|
set_rule(multiworld.get_entrance("Hub -> Phobos Anomaly (E1M8) Start", player), lambda state:
|
||||||
@@ -175,16 +172,15 @@ def set_episode2_rules(player, multiworld, pro):
|
|||||||
state.has("Refinery (E2M3) - Blue keycard", player, 1))
|
state.has("Refinery (E2M3) - Blue keycard", player, 1))
|
||||||
|
|
||||||
# Deimos Lab (E2M4)
|
# 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:
|
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))
|
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:
|
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))
|
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)
|
# Command Center (E2M5)
|
||||||
set_rule(multiworld.get_entrance("Hub -> Command Center (E2M5) Main", player), lambda state:
|
set_rule(multiworld.get_entrance("Hub -> Command Center (E2M5) Main", player), lambda state:
|
||||||
@@ -242,11 +238,11 @@ def set_episode2_rules(player, multiworld, pro):
|
|||||||
state.has("Spawning Vats (E2M7) - Red keycard", player, 1))
|
state.has("Spawning Vats (E2M7) - Red keycard", player, 1))
|
||||||
|
|
||||||
# Tower of Babel (E2M8)
|
# Tower of Babel (E2M8)
|
||||||
set_rule(multiworld.get_entrance("Hub -> Tower of Babel (E2M8) Start", player), lambda state:
|
set_rule(multiworld.get_entrance("Hub -> Tower of Babel (E2M8) Main", player), lambda state:
|
||||||
state.has("Tower of Babel (E2M8)", player, 1))
|
(state.has("Tower of Babel (E2M8)", player, 1) and
|
||||||
set_rule(multiworld.get_entrance("Tower of Babel (E2M8) Start -> Tower of Babel (E2M8) Main", player), lambda state:
|
state.has("Shotgun", player, 1) and
|
||||||
(state.has("Chaingun", player, 1) and
|
state.has("Chaingun", player, 1)) and
|
||||||
state.has("Shotgun", player, 1)) and (state.has("Rocket launcher", player, 1) or
|
(state.has("Rocket launcher", player, 1) or
|
||||||
state.has("Plasma gun", player, 1) or
|
state.has("Plasma gun", player, 1) or
|
||||||
state.has("BFG9000", player, 1)))
|
state.has("BFG9000", player, 1)))
|
||||||
|
|
||||||
@@ -325,6 +321,13 @@ def set_episode3_rules(player, multiworld, pro):
|
|||||||
state.has("House of Pain (E3M4) - Yellow skull key", player, 1))
|
state.has("House of Pain (E3M4) - Yellow skull key", player, 1))
|
||||||
|
|
||||||
# Unholy Cathedral (E3M5)
|
# 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:
|
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))
|
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:
|
set_rule(multiworld.get_entrance("Unholy Cathedral (E3M5) Main -> Unholy Cathedral (E3M5) Blue", player), lambda state:
|
||||||
@@ -333,13 +336,6 @@ def set_episode3_rules(player, multiworld, pro):
|
|||||||
state.has("Unholy Cathedral (E3M5) - Blue skull key", player, 1))
|
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:
|
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))
|
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)
|
# Mt. Erebus (E3M6)
|
||||||
set_rule(multiworld.get_entrance("Hub -> Mt. Erebus (E3M6) Main", player), lambda state:
|
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_to_id = {data["name"]: loc_id for loc_id, data in Locations.location_table.items()}
|
||||||
location_name_groups = Locations.location_name_groups
|
location_name_groups = Locations.location_name_groups
|
||||||
|
|
||||||
starting_level_for_episode: Dict[int, str] = {
|
starting_level_for_episode: List[str] = [
|
||||||
1: "Hangar (E1M1)",
|
"Hangar (E1M1)",
|
||||||
2: "Deimos Anomaly (E2M1)",
|
"Deimos Anomaly (E2M1)",
|
||||||
3: "Hell Keep (E3M1)",
|
"Hell Keep (E3M1)",
|
||||||
4: "Hell Beneath (E4M1)"
|
"Hell Beneath (E4M1)"
|
||||||
}
|
]
|
||||||
|
|
||||||
all_boss_levels: List[str] = [
|
boss_level_for_espidoes: List[str] = [
|
||||||
"Phobos Anomaly (E1M8)",
|
"Phobos Anomaly (E1M8)",
|
||||||
"Tower of Babel (E2M8)",
|
"Tower of Babel (E2M8)",
|
||||||
"Dis (E3M8)",
|
"Dis (E3M8)",
|
||||||
@@ -82,7 +82,6 @@ class DOOM1993World(World):
|
|||||||
def __init__(self, multiworld: MultiWorld, player: int):
|
def __init__(self, multiworld: MultiWorld, player: int):
|
||||||
self.included_episodes = [1, 1, 1, 0]
|
self.included_episodes = [1, 1, 1, 0]
|
||||||
self.location_count = 0
|
self.location_count = 0
|
||||||
self.starting_levels = []
|
|
||||||
|
|
||||||
super().__init__(multiworld, player)
|
super().__init__(multiworld, player)
|
||||||
|
|
||||||
@@ -100,16 +99,6 @@ class DOOM1993World(World):
|
|||||||
if self.get_episode_count() == 0:
|
if self.get_episode_count() == 0:
|
||||||
self.included_episodes[0] = 1
|
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):
|
def create_regions(self):
|
||||||
pro = self.options.pro.value
|
pro = self.options.pro.value
|
||||||
|
|
||||||
@@ -163,7 +152,7 @@ class DOOM1993World(World):
|
|||||||
def completion_rule(self, state: CollectionState):
|
def completion_rule(self, state: CollectionState):
|
||||||
goal_levels = Maps.map_names
|
goal_levels = Maps.map_names
|
||||||
if self.options.goal.value:
|
if self.options.goal.value:
|
||||||
goal_levels = self.all_boss_levels
|
goal_levels = self.boss_level_for_espidoes
|
||||||
|
|
||||||
for map_name in goal_levels:
|
for map_name in goal_levels:
|
||||||
if map_name + " - Exit" not in self.location_name_to_id:
|
if map_name + " - Exit" not in self.location_name_to_id:
|
||||||
@@ -212,7 +201,7 @@ class DOOM1993World(World):
|
|||||||
if item["episode"] != -1 and not self.included_episodes[item["episode"] - 1]:
|
if item["episode"] != -1 and not self.included_episodes[item["episode"] - 1]:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
count = item["count"] if item["name"] not in self.starting_levels else item["count"] - 1
|
count = item["count"] if item["name"] not in self.starting_level_for_episode else item["count"] - 1
|
||||||
itempool += [self.create_item(item["name"]) for _ in range(count)]
|
itempool += [self.create_item(item["name"]) for _ in range(count)]
|
||||||
|
|
||||||
# Backpack(s) based on options
|
# Backpack(s) based on options
|
||||||
@@ -243,8 +232,9 @@ class DOOM1993World(World):
|
|||||||
self.location_count -= 1
|
self.location_count -= 1
|
||||||
|
|
||||||
# Give starting levels right away
|
# Give starting levels right away
|
||||||
for map_name in self.starting_levels:
|
for i in range(len(self.included_episodes)):
|
||||||
self.multiworld.push_precollected(self.create_item(map_name))
|
if self.included_episodes[i]:
|
||||||
|
self.multiworld.push_precollected(self.create_item(self.starting_level_for_episode[i]))
|
||||||
|
|
||||||
# Give Computer area maps if option selected
|
# Give Computer area maps if option selected
|
||||||
if self.options.start_with_computer_area_maps.value:
|
if self.options.start_with_computer_area_maps.value:
|
||||||
|
|||||||
@@ -412,7 +412,7 @@ item_table: Dict[int, ItemDict] = {
|
|||||||
'map': 2},
|
'map': 2},
|
||||||
360246: {'classification': ItemClassification.progression,
|
360246: {'classification': ItemClassification.progression,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': "Barrels o' Fun (MAP23) - Yellow skull key",
|
'name': 'Barrels o Fun (MAP23) - Yellow skull key',
|
||||||
'doom_type': 39,
|
'doom_type': 39,
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 3},
|
'map': 3},
|
||||||
@@ -880,19 +880,19 @@ item_table: Dict[int, ItemDict] = {
|
|||||||
'map': 2},
|
'map': 2},
|
||||||
360466: {'classification': ItemClassification.progression,
|
360466: {'classification': ItemClassification.progression,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': "Barrels o' Fun (MAP23)",
|
'name': 'Barrels o Fun (MAP23)',
|
||||||
'doom_type': -1,
|
'doom_type': -1,
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 3},
|
'map': 3},
|
||||||
360467: {'classification': ItemClassification.progression,
|
360467: {'classification': ItemClassification.progression,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': "Barrels o' Fun (MAP23) - Complete",
|
'name': 'Barrels o Fun (MAP23) - Complete',
|
||||||
'doom_type': -2,
|
'doom_type': -2,
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 3},
|
'map': 3},
|
||||||
360468: {'classification': ItemClassification.filler,
|
360468: {'classification': ItemClassification.filler,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': "Barrels o' Fun (MAP23) - Computer area map",
|
'name': 'Barrels o Fun (MAP23) - Computer area map',
|
||||||
'doom_type': 2026,
|
'doom_type': 2026,
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 3},
|
'map': 3},
|
||||||
@@ -1024,37 +1024,37 @@ item_table: Dict[int, ItemDict] = {
|
|||||||
'map': 10},
|
'map': 10},
|
||||||
360490: {'classification': ItemClassification.progression,
|
360490: {'classification': ItemClassification.progression,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': 'Wolfenstein (MAP31)',
|
'name': 'Wolfenstein2 (MAP31)',
|
||||||
'doom_type': -1,
|
'doom_type': -1,
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 1},
|
'map': 1},
|
||||||
360491: {'classification': ItemClassification.progression,
|
360491: {'classification': ItemClassification.progression,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': 'Wolfenstein (MAP31) - Complete',
|
'name': 'Wolfenstein2 (MAP31) - Complete',
|
||||||
'doom_type': -2,
|
'doom_type': -2,
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 1},
|
'map': 1},
|
||||||
360492: {'classification': ItemClassification.filler,
|
360492: {'classification': ItemClassification.filler,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': 'Wolfenstein (MAP31) - Computer area map',
|
'name': 'Wolfenstein2 (MAP31) - Computer area map',
|
||||||
'doom_type': 2026,
|
'doom_type': 2026,
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 1},
|
'map': 1},
|
||||||
360493: {'classification': ItemClassification.progression,
|
360493: {'classification': ItemClassification.progression,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': 'Grosse (MAP32)',
|
'name': 'Grosse2 (MAP32)',
|
||||||
'doom_type': -1,
|
'doom_type': -1,
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 2},
|
'map': 2},
|
||||||
360494: {'classification': ItemClassification.progression,
|
360494: {'classification': ItemClassification.progression,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': 'Grosse (MAP32) - Complete',
|
'name': 'Grosse2 (MAP32) - Complete',
|
||||||
'doom_type': -2,
|
'doom_type': -2,
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 2},
|
'map': 2},
|
||||||
360495: {'classification': ItemClassification.filler,
|
360495: {'classification': ItemClassification.filler,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': 'Grosse (MAP32) - Computer area map',
|
'name': 'Grosse2 (MAP32) - Computer area map',
|
||||||
'doom_type': 2026,
|
'doom_type': 2026,
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 2},
|
'map': 2},
|
||||||
@@ -1087,9 +1087,9 @@ item_table: Dict[int, ItemDict] = {
|
|||||||
|
|
||||||
item_name_groups: Dict[str, Set[str]] = {
|
item_name_groups: Dict[str, Set[str]] = {
|
||||||
'Ammos': {'Box of bullets', 'Box of rockets', 'Box of shotgun shells', 'Energy cell pack', },
|
'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', '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', },
|
'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', },
|
'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)', },
|
'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)', },
|
||||||
'Powerups': {'Armor', 'Berserk', 'Invulnerability', 'Mega Armor', 'Megasphere', 'Partial invisibility', 'Supercharge', },
|
'Powerups': {'Armor', 'Berserk', 'Invulnerability', 'Mega Armor', 'Megasphere', 'Partial invisibility', 'Supercharge', },
|
||||||
'Weapons': {'BFG9000', 'Chaingun', 'Chainsaw', 'Plasma gun', 'Rocket launcher', 'Shotgun', 'Super Shotgun', },
|
'Weapons': {'BFG9000', 'Chaingun', 'Chainsaw', 'Plasma gun', 'Rocket launcher', 'Shotgun', 'Super Shotgun', },
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 5,
|
'map': 5,
|
||||||
'index': 46,
|
'index': 46,
|
||||||
'doom_type': 82,
|
'doom_type': 82,
|
||||||
'region': "The Waste Tunnels (MAP05) Start"},
|
'region': "The Waste Tunnels (MAP05) Main"},
|
||||||
361028: {'name': 'The Waste Tunnels (MAP05) - Blue keycard',
|
361028: {'name': 'The Waste Tunnels (MAP05) - Blue keycard',
|
||||||
'episode': 1,
|
'episode': 1,
|
||||||
'map': 5,
|
'map': 5,
|
||||||
@@ -234,7 +234,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 5,
|
'map': 5,
|
||||||
'index': 202,
|
'index': 202,
|
||||||
'doom_type': 2001,
|
'doom_type': 2001,
|
||||||
'region': "The Waste Tunnels (MAP05) Start"},
|
'region': "The Waste Tunnels (MAP05) Main"},
|
||||||
361037: {'name': 'The Waste Tunnels (MAP05) - Berserk',
|
361037: {'name': 'The Waste Tunnels (MAP05) - Berserk',
|
||||||
'episode': 1,
|
'episode': 1,
|
||||||
'map': 5,
|
'map': 5,
|
||||||
@@ -360,7 +360,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 7,
|
'map': 7,
|
||||||
'index': 8,
|
'index': 8,
|
||||||
'doom_type': 82,
|
'doom_type': 82,
|
||||||
'region': "Dead Simple (MAP07) Start"},
|
'region': "Dead Simple (MAP07) Main"},
|
||||||
361058: {'name': 'Dead Simple (MAP07) - Chaingun',
|
361058: {'name': 'Dead Simple (MAP07) - Chaingun',
|
||||||
'episode': 1,
|
'episode': 1,
|
||||||
'map': 7,
|
'map': 7,
|
||||||
@@ -378,7 +378,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 7,
|
'map': 7,
|
||||||
'index': 43,
|
'index': 43,
|
||||||
'doom_type': 8,
|
'doom_type': 8,
|
||||||
'region': "Dead Simple (MAP07) Start"},
|
'region': "Dead Simple (MAP07) Main"},
|
||||||
361061: {'name': 'Dead Simple (MAP07) - Berserk',
|
361061: {'name': 'Dead Simple (MAP07) - Berserk',
|
||||||
'episode': 1,
|
'episode': 1,
|
||||||
'map': 7,
|
'map': 7,
|
||||||
@@ -570,7 +570,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 26,
|
'index': 26,
|
||||||
'doom_type': 2019,
|
'doom_type': 2019,
|
||||||
'region': "The Pit (MAP09) Start"},
|
'region': "The Pit (MAP09) Main"},
|
||||||
361093: {'name': 'The Pit (MAP09) - Supercharge',
|
361093: {'name': 'The Pit (MAP09) - Supercharge',
|
||||||
'episode': 1,
|
'episode': 1,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
@@ -678,7 +678,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 10,
|
'map': 10,
|
||||||
'index': 99,
|
'index': 99,
|
||||||
'doom_type': 2001,
|
'doom_type': 2001,
|
||||||
'region': "Refueling Base (MAP10) Start"},
|
'region': "Refueling Base (MAP10) Main"},
|
||||||
361111: {'name': 'Refueling Base (MAP10) - Chaingun',
|
361111: {'name': 'Refueling Base (MAP10) - Chaingun',
|
||||||
'episode': 1,
|
'episode': 1,
|
||||||
'map': 10,
|
'map': 10,
|
||||||
@@ -846,31 +846,31 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 11,
|
'map': 11,
|
||||||
'index': 88,
|
'index': 88,
|
||||||
'doom_type': 8,
|
'doom_type': 8,
|
||||||
'region': "Circle of Death (MAP11) Ending"},
|
'region': "Circle of Death (MAP11) Red"},
|
||||||
361139: {'name': 'Circle of Death (MAP11) - Supercharge 2',
|
361139: {'name': 'Circle of Death (MAP11) - Supercharge 2',
|
||||||
'episode': 1,
|
'episode': 1,
|
||||||
'map': 11,
|
'map': 11,
|
||||||
'index': 108,
|
'index': 108,
|
||||||
'doom_type': 2013,
|
'doom_type': 2013,
|
||||||
'region': "Circle of Death (MAP11) Ending"},
|
'region': "Circle of Death (MAP11) Red"},
|
||||||
361140: {'name': 'Circle of Death (MAP11) - BFG9000',
|
361140: {'name': 'Circle of Death (MAP11) - BFG9000',
|
||||||
'episode': 1,
|
'episode': 1,
|
||||||
'map': 11,
|
'map': 11,
|
||||||
'index': 110,
|
'index': 110,
|
||||||
'doom_type': 2006,
|
'doom_type': 2006,
|
||||||
'region': "Circle of Death (MAP11) Ending"},
|
'region': "Circle of Death (MAP11) Red"},
|
||||||
361141: {'name': 'Circle of Death (MAP11) - Exit',
|
361141: {'name': 'Circle of Death (MAP11) - Exit',
|
||||||
'episode': 1,
|
'episode': 1,
|
||||||
'map': 11,
|
'map': 11,
|
||||||
'index': -1,
|
'index': -1,
|
||||||
'doom_type': -1,
|
'doom_type': -1,
|
||||||
'region': "Circle of Death (MAP11) Ending"},
|
'region': "Circle of Death (MAP11) Red"},
|
||||||
361142: {'name': 'The Factory (MAP12) - Shotgun',
|
361142: {'name': 'The Factory (MAP12) - Shotgun',
|
||||||
'episode': 2,
|
'episode': 2,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 14,
|
'index': 14,
|
||||||
'doom_type': 2001,
|
'doom_type': 2001,
|
||||||
'region': "The Factory (MAP12) Outdoors"},
|
'region': "The Factory (MAP12) Main"},
|
||||||
361143: {'name': 'The Factory (MAP12) - Berserk',
|
361143: {'name': 'The Factory (MAP12) - Berserk',
|
||||||
'episode': 2,
|
'episode': 2,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
@@ -888,13 +888,13 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 52,
|
'index': 52,
|
||||||
'doom_type': 2013,
|
'doom_type': 2013,
|
||||||
'region': "The Factory (MAP12) Indoors"},
|
'region': "The Factory (MAP12) Main"},
|
||||||
361146: {'name': 'The Factory (MAP12) - Blue keycard',
|
361146: {'name': 'The Factory (MAP12) - Blue keycard',
|
||||||
'episode': 2,
|
'episode': 2,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 54,
|
'index': 54,
|
||||||
'doom_type': 5,
|
'doom_type': 5,
|
||||||
'region': "The Factory (MAP12) Indoors"},
|
'region': "The Factory (MAP12) Main"},
|
||||||
361147: {'name': 'The Factory (MAP12) - Armor',
|
361147: {'name': 'The Factory (MAP12) - Armor',
|
||||||
'episode': 2,
|
'episode': 2,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
@@ -912,31 +912,31 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 83,
|
'index': 83,
|
||||||
'doom_type': 2013,
|
'doom_type': 2013,
|
||||||
'region': "The Factory (MAP12) Indoors"},
|
'region': "The Factory (MAP12) Main"},
|
||||||
361150: {'name': 'The Factory (MAP12) - Armor 2',
|
361150: {'name': 'The Factory (MAP12) - Armor 2',
|
||||||
'episode': 2,
|
'episode': 2,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 92,
|
'index': 92,
|
||||||
'doom_type': 2018,
|
'doom_type': 2018,
|
||||||
'region': "The Factory (MAP12) Outdoors"},
|
'region': "The Factory (MAP12) Main"},
|
||||||
361151: {'name': 'The Factory (MAP12) - Partial invisibility',
|
361151: {'name': 'The Factory (MAP12) - Partial invisibility',
|
||||||
'episode': 2,
|
'episode': 2,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 93,
|
'index': 93,
|
||||||
'doom_type': 2024,
|
'doom_type': 2024,
|
||||||
'region': "The Factory (MAP12) Outdoors"},
|
'region': "The Factory (MAP12) Main"},
|
||||||
361152: {'name': 'The Factory (MAP12) - Berserk 2',
|
361152: {'name': 'The Factory (MAP12) - Berserk 2',
|
||||||
'episode': 2,
|
'episode': 2,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 107,
|
'index': 107,
|
||||||
'doom_type': 2023,
|
'doom_type': 2023,
|
||||||
'region': "The Factory (MAP12) Indoors"},
|
'region': "The Factory (MAP12) Main"},
|
||||||
361153: {'name': 'The Factory (MAP12) - Yellow keycard',
|
361153: {'name': 'The Factory (MAP12) - Yellow keycard',
|
||||||
'episode': 2,
|
'episode': 2,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 123,
|
'index': 123,
|
||||||
'doom_type': 6,
|
'doom_type': 6,
|
||||||
'region': "The Factory (MAP12) Indoors"},
|
'region': "The Factory (MAP12) Main"},
|
||||||
361154: {'name': 'The Factory (MAP12) - BFG9000',
|
361154: {'name': 'The Factory (MAP12) - BFG9000',
|
||||||
'episode': 2,
|
'episode': 2,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
@@ -954,7 +954,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 192,
|
'index': 192,
|
||||||
'doom_type': 82,
|
'doom_type': 82,
|
||||||
'region': "The Factory (MAP12) Indoors"},
|
'region': "The Factory (MAP12) Main"},
|
||||||
361157: {'name': 'The Factory (MAP12) - Exit',
|
361157: {'name': 'The Factory (MAP12) - Exit',
|
||||||
'episode': 2,
|
'episode': 2,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
@@ -1812,7 +1812,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 70,
|
'index': 70,
|
||||||
'doom_type': 82,
|
'doom_type': 82,
|
||||||
'region': "Nirvana (MAP21) Start"},
|
'region': "Nirvana (MAP21) Main"},
|
||||||
361300: {'name': 'Nirvana (MAP21) - Rocket launcher',
|
361300: {'name': 'Nirvana (MAP21) - Rocket launcher',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
@@ -1884,7 +1884,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 2,
|
'map': 2,
|
||||||
'index': 28,
|
'index': 28,
|
||||||
'doom_type': 2001,
|
'doom_type': 2001,
|
||||||
'region': "The Catacombs (MAP22) Early"},
|
'region': "The Catacombs (MAP22) Main"},
|
||||||
361312: {'name': 'The Catacombs (MAP22) - Berserk',
|
361312: {'name': 'The Catacombs (MAP22) - Berserk',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 2,
|
'map': 2,
|
||||||
@@ -1896,103 +1896,103 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 2,
|
'map': 2,
|
||||||
'index': 83,
|
'index': 83,
|
||||||
'doom_type': 2004,
|
'doom_type': 2004,
|
||||||
'region': "The Catacombs (MAP22) Early"},
|
'region': "The Catacombs (MAP22) Main"},
|
||||||
361314: {'name': 'The Catacombs (MAP22) - Supercharge',
|
361314: {'name': 'The Catacombs (MAP22) - Supercharge',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 2,
|
'map': 2,
|
||||||
'index': 118,
|
'index': 118,
|
||||||
'doom_type': 2013,
|
'doom_type': 2013,
|
||||||
'region': "The Catacombs (MAP22) Early"},
|
'region': "The Catacombs (MAP22) Main"},
|
||||||
361315: {'name': 'The Catacombs (MAP22) - Armor',
|
361315: {'name': 'The Catacombs (MAP22) - Armor',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 2,
|
'map': 2,
|
||||||
'index': 119,
|
'index': 119,
|
||||||
'doom_type': 2018,
|
'doom_type': 2018,
|
||||||
'region': "The Catacombs (MAP22) Early"},
|
'region': "The Catacombs (MAP22) Main"},
|
||||||
361316: {'name': 'The Catacombs (MAP22) - Exit',
|
361316: {'name': 'The Catacombs (MAP22) - Exit',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 2,
|
'map': 2,
|
||||||
'index': -1,
|
'index': -1,
|
||||||
'doom_type': -1,
|
'doom_type': -1,
|
||||||
'region': "The Catacombs (MAP22) Red"},
|
'region': "The Catacombs (MAP22) Red"},
|
||||||
361317: {'name': "Barrels o' Fun (MAP23) - Shotgun",
|
361317: {'name': 'Barrels o Fun (MAP23) - Shotgun',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 3,
|
'map': 3,
|
||||||
'index': 136,
|
'index': 136,
|
||||||
'doom_type': 2001,
|
'doom_type': 2001,
|
||||||
'region': "Barrels o' Fun (MAP23) Main"},
|
'region': "Barrels o Fun (MAP23) Main"},
|
||||||
361318: {'name': "Barrels o' Fun (MAP23) - Berserk",
|
361318: {'name': 'Barrels o Fun (MAP23) - Berserk',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 3,
|
'map': 3,
|
||||||
'index': 222,
|
'index': 222,
|
||||||
'doom_type': 2023,
|
'doom_type': 2023,
|
||||||
'region': "Barrels o' Fun (MAP23) Main"},
|
'region': "Barrels o Fun (MAP23) Main"},
|
||||||
361319: {'name': "Barrels o' Fun (MAP23) - Backpack",
|
361319: {'name': 'Barrels o Fun (MAP23) - Backpack',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 3,
|
'map': 3,
|
||||||
'index': 223,
|
'index': 223,
|
||||||
'doom_type': 8,
|
'doom_type': 8,
|
||||||
'region': "Barrels o' Fun (MAP23) Main"},
|
'region': "Barrels o Fun (MAP23) Main"},
|
||||||
361320: {'name': "Barrels o' Fun (MAP23) - Computer area map",
|
361320: {'name': 'Barrels o Fun (MAP23) - Computer area map',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 3,
|
'map': 3,
|
||||||
'index': 224,
|
'index': 224,
|
||||||
'doom_type': 2026,
|
'doom_type': 2026,
|
||||||
'region': "Barrels o' Fun (MAP23) Main"},
|
'region': "Barrels o Fun (MAP23) Main"},
|
||||||
361321: {'name': "Barrels o' Fun (MAP23) - Armor",
|
361321: {'name': 'Barrels o Fun (MAP23) - Armor',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 3,
|
'map': 3,
|
||||||
'index': 249,
|
'index': 249,
|
||||||
'doom_type': 2018,
|
'doom_type': 2018,
|
||||||
'region': "Barrels o' Fun (MAP23) Main"},
|
'region': "Barrels o Fun (MAP23) Main"},
|
||||||
361322: {'name': "Barrels o' Fun (MAP23) - Rocket launcher",
|
361322: {'name': 'Barrels o Fun (MAP23) - Rocket launcher',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 3,
|
'map': 3,
|
||||||
'index': 264,
|
'index': 264,
|
||||||
'doom_type': 2003,
|
'doom_type': 2003,
|
||||||
'region': "Barrels o' Fun (MAP23) Main"},
|
'region': "Barrels o Fun (MAP23) Main"},
|
||||||
361323: {'name': "Barrels o' Fun (MAP23) - Megasphere",
|
361323: {'name': 'Barrels o Fun (MAP23) - Megasphere',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 3,
|
'map': 3,
|
||||||
'index': 266,
|
'index': 266,
|
||||||
'doom_type': 83,
|
'doom_type': 83,
|
||||||
'region': "Barrels o' Fun (MAP23) Main"},
|
'region': "Barrels o Fun (MAP23) Main"},
|
||||||
361324: {'name': "Barrels o' Fun (MAP23) - Supercharge",
|
361324: {'name': 'Barrels o Fun (MAP23) - Supercharge',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 3,
|
'map': 3,
|
||||||
'index': 277,
|
'index': 277,
|
||||||
'doom_type': 2013,
|
'doom_type': 2013,
|
||||||
'region': "Barrels o' Fun (MAP23) Main"},
|
'region': "Barrels o Fun (MAP23) Main"},
|
||||||
361325: {'name': "Barrels o' Fun (MAP23) - Backpack 2",
|
361325: {'name': 'Barrels o Fun (MAP23) - Backpack 2',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 3,
|
'map': 3,
|
||||||
'index': 301,
|
'index': 301,
|
||||||
'doom_type': 8,
|
'doom_type': 8,
|
||||||
'region': "Barrels o' Fun (MAP23) Main"},
|
'region': "Barrels o Fun (MAP23) Main"},
|
||||||
361326: {'name': "Barrels o' Fun (MAP23) - Yellow skull key",
|
361326: {'name': 'Barrels o Fun (MAP23) - Yellow skull key',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 3,
|
'map': 3,
|
||||||
'index': 307,
|
'index': 307,
|
||||||
'doom_type': 39,
|
'doom_type': 39,
|
||||||
'region': "Barrels o' Fun (MAP23) Main"},
|
'region': "Barrels o Fun (MAP23) Main"},
|
||||||
361327: {'name': "Barrels o' Fun (MAP23) - BFG9000",
|
361327: {'name': 'Barrels o Fun (MAP23) - BFG9000',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 3,
|
'map': 3,
|
||||||
'index': 342,
|
'index': 342,
|
||||||
'doom_type': 2006,
|
'doom_type': 2006,
|
||||||
'region': "Barrels o' Fun (MAP23) Main"},
|
'region': "Barrels o Fun (MAP23) Main"},
|
||||||
361328: {'name': "Barrels o' Fun (MAP23) - Exit",
|
361328: {'name': 'Barrels o Fun (MAP23) - Exit',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 3,
|
'map': 3,
|
||||||
'index': -1,
|
'index': -1,
|
||||||
'doom_type': -1,
|
'doom_type': -1,
|
||||||
'region': "Barrels o' Fun (MAP23) Yellow"},
|
'region': "Barrels o Fun (MAP23) Yellow"},
|
||||||
361329: {'name': 'The Chasm (MAP24) - Plasma gun',
|
361329: {'name': 'The Chasm (MAP24) - Plasma gun',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 4,
|
'map': 4,
|
||||||
'index': 5,
|
'index': 5,
|
||||||
'doom_type': 2004,
|
'doom_type': 2004,
|
||||||
'region': "The Chasm (MAP24) Blue"},
|
'region': "The Chasm (MAP24) Main"},
|
||||||
361330: {'name': 'The Chasm (MAP24) - Shotgun',
|
361330: {'name': 'The Chasm (MAP24) - Shotgun',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 4,
|
'map': 4,
|
||||||
@@ -2004,7 +2004,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 4,
|
'map': 4,
|
||||||
'index': 12,
|
'index': 12,
|
||||||
'doom_type': 2022,
|
'doom_type': 2022,
|
||||||
'region': "The Chasm (MAP24) Blue"},
|
'region': "The Chasm (MAP24) Main"},
|
||||||
361332: {'name': 'The Chasm (MAP24) - Rocket launcher',
|
361332: {'name': 'The Chasm (MAP24) - Rocket launcher',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 4,
|
'map': 4,
|
||||||
@@ -2022,7 +2022,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 4,
|
'map': 4,
|
||||||
'index': 31,
|
'index': 31,
|
||||||
'doom_type': 8,
|
'doom_type': 8,
|
||||||
'region': "The Chasm (MAP24) Blue"},
|
'region': "The Chasm (MAP24) Main"},
|
||||||
361335: {'name': 'The Chasm (MAP24) - Berserk',
|
361335: {'name': 'The Chasm (MAP24) - Berserk',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 4,
|
'map': 4,
|
||||||
@@ -2034,19 +2034,19 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 4,
|
'map': 4,
|
||||||
'index': 155,
|
'index': 155,
|
||||||
'doom_type': 2023,
|
'doom_type': 2023,
|
||||||
'region': "The Chasm (MAP24) Blue"},
|
'region': "The Chasm (MAP24) Main"},
|
||||||
361337: {'name': 'The Chasm (MAP24) - Armor',
|
361337: {'name': 'The Chasm (MAP24) - Armor',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 4,
|
'map': 4,
|
||||||
'index': 169,
|
'index': 169,
|
||||||
'doom_type': 2018,
|
'doom_type': 2018,
|
||||||
'region': "The Chasm (MAP24) Blue"},
|
'region': "The Chasm (MAP24) Main"},
|
||||||
361338: {'name': 'The Chasm (MAP24) - Red keycard',
|
361338: {'name': 'The Chasm (MAP24) - Red keycard',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 4,
|
'map': 4,
|
||||||
'index': 261,
|
'index': 261,
|
||||||
'doom_type': 13,
|
'doom_type': 13,
|
||||||
'region': "The Chasm (MAP24) Blue"},
|
'region': "The Chasm (MAP24) Main"},
|
||||||
361339: {'name': 'The Chasm (MAP24) - BFG9000',
|
361339: {'name': 'The Chasm (MAP24) - BFG9000',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 4,
|
'map': 4,
|
||||||
@@ -2064,7 +2064,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 4,
|
'map': 4,
|
||||||
'index': 355,
|
'index': 355,
|
||||||
'doom_type': 83,
|
'doom_type': 83,
|
||||||
'region': "The Chasm (MAP24) Blue"},
|
'region': "The Chasm (MAP24) Main"},
|
||||||
361342: {'name': 'The Chasm (MAP24) - Megasphere 2',
|
361342: {'name': 'The Chasm (MAP24) - Megasphere 2',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 4,
|
'map': 4,
|
||||||
@@ -2082,7 +2082,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 5,
|
'map': 5,
|
||||||
'index': 6,
|
'index': 6,
|
||||||
'doom_type': 82,
|
'doom_type': 82,
|
||||||
'region': "Bloodfalls (MAP25) Start"},
|
'region': "Bloodfalls (MAP25) Main"},
|
||||||
361345: {'name': 'Bloodfalls (MAP25) - Partial invisibility',
|
361345: {'name': 'Bloodfalls (MAP25) - Partial invisibility',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 5,
|
'map': 5,
|
||||||
@@ -2664,55 +2664,55 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 10,
|
'map': 10,
|
||||||
'index': 40,
|
'index': 40,
|
||||||
'doom_type': 2006,
|
'doom_type': 2006,
|
||||||
'region': "Icon of Sin (MAP30) Start"},
|
'region': "Icon of Sin (MAP30) Main"},
|
||||||
361442: {'name': 'Icon of Sin (MAP30) - Chaingun',
|
361442: {'name': 'Icon of Sin (MAP30) - Chaingun',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 10,
|
'map': 10,
|
||||||
'index': 41,
|
'index': 41,
|
||||||
'doom_type': 2002,
|
'doom_type': 2002,
|
||||||
'region': "Icon of Sin (MAP30) Start"},
|
'region': "Icon of Sin (MAP30) Main"},
|
||||||
361443: {'name': 'Icon of Sin (MAP30) - Chainsaw',
|
361443: {'name': 'Icon of Sin (MAP30) - Chainsaw',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 10,
|
'map': 10,
|
||||||
'index': 42,
|
'index': 42,
|
||||||
'doom_type': 2005,
|
'doom_type': 2005,
|
||||||
'region': "Icon of Sin (MAP30) Start"},
|
'region': "Icon of Sin (MAP30) Main"},
|
||||||
361444: {'name': 'Icon of Sin (MAP30) - Plasma gun',
|
361444: {'name': 'Icon of Sin (MAP30) - Plasma gun',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 10,
|
'map': 10,
|
||||||
'index': 43,
|
'index': 43,
|
||||||
'doom_type': 2004,
|
'doom_type': 2004,
|
||||||
'region': "Icon of Sin (MAP30) Start"},
|
'region': "Icon of Sin (MAP30) Main"},
|
||||||
361445: {'name': 'Icon of Sin (MAP30) - Rocket launcher',
|
361445: {'name': 'Icon of Sin (MAP30) - Rocket launcher',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 10,
|
'map': 10,
|
||||||
'index': 44,
|
'index': 44,
|
||||||
'doom_type': 2003,
|
'doom_type': 2003,
|
||||||
'region': "Icon of Sin (MAP30) Start"},
|
'region': "Icon of Sin (MAP30) Main"},
|
||||||
361446: {'name': 'Icon of Sin (MAP30) - Shotgun',
|
361446: {'name': 'Icon of Sin (MAP30) - Shotgun',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 10,
|
'map': 10,
|
||||||
'index': 45,
|
'index': 45,
|
||||||
'doom_type': 2001,
|
'doom_type': 2001,
|
||||||
'region': "Icon of Sin (MAP30) Start"},
|
'region': "Icon of Sin (MAP30) Main"},
|
||||||
361447: {'name': 'Icon of Sin (MAP30) - Super Shotgun',
|
361447: {'name': 'Icon of Sin (MAP30) - Super Shotgun',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 10,
|
'map': 10,
|
||||||
'index': 46,
|
'index': 46,
|
||||||
'doom_type': 82,
|
'doom_type': 82,
|
||||||
'region': "Icon of Sin (MAP30) Start"},
|
'region': "Icon of Sin (MAP30) Main"},
|
||||||
361448: {'name': 'Icon of Sin (MAP30) - Backpack',
|
361448: {'name': 'Icon of Sin (MAP30) - Backpack',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 10,
|
'map': 10,
|
||||||
'index': 47,
|
'index': 47,
|
||||||
'doom_type': 8,
|
'doom_type': 8,
|
||||||
'region': "Icon of Sin (MAP30) Start"},
|
'region': "Icon of Sin (MAP30) Main"},
|
||||||
361449: {'name': 'Icon of Sin (MAP30) - Megasphere',
|
361449: {'name': 'Icon of Sin (MAP30) - Megasphere',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 10,
|
'map': 10,
|
||||||
'index': 64,
|
'index': 64,
|
||||||
'doom_type': 83,
|
'doom_type': 83,
|
||||||
'region': "Icon of Sin (MAP30) Start"},
|
'region': "Icon of Sin (MAP30) Main"},
|
||||||
361450: {'name': 'Icon of Sin (MAP30) - Megasphere 2',
|
361450: {'name': 'Icon of Sin (MAP30) - Megasphere 2',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 10,
|
'map': 10,
|
||||||
@@ -2731,179 +2731,179 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'index': -1,
|
'index': -1,
|
||||||
'doom_type': -1,
|
'doom_type': -1,
|
||||||
'region': "Icon of Sin (MAP30) Main"},
|
'region': "Icon of Sin (MAP30) Main"},
|
||||||
361453: {'name': 'Wolfenstein (MAP31) - Rocket launcher',
|
361453: {'name': 'Wolfenstein2 (MAP31) - Rocket launcher',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 110,
|
'index': 110,
|
||||||
'doom_type': 2003,
|
'doom_type': 2003,
|
||||||
'region': "Wolfenstein (MAP31) Main"},
|
'region': "Wolfenstein2 (MAP31) Main"},
|
||||||
361454: {'name': 'Wolfenstein (MAP31) - Shotgun',
|
361454: {'name': 'Wolfenstein2 (MAP31) - Shotgun',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 139,
|
'index': 139,
|
||||||
'doom_type': 2001,
|
'doom_type': 2001,
|
||||||
'region': "Wolfenstein (MAP31) Main"},
|
'region': "Wolfenstein2 (MAP31) Main"},
|
||||||
361455: {'name': 'Wolfenstein (MAP31) - Berserk',
|
361455: {'name': 'Wolfenstein2 (MAP31) - Berserk',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 263,
|
'index': 263,
|
||||||
'doom_type': 2023,
|
'doom_type': 2023,
|
||||||
'region': "Wolfenstein (MAP31) Main"},
|
'region': "Wolfenstein2 (MAP31) Main"},
|
||||||
361456: {'name': 'Wolfenstein (MAP31) - Supercharge',
|
361456: {'name': 'Wolfenstein2 (MAP31) - Supercharge',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 278,
|
'index': 278,
|
||||||
'doom_type': 2013,
|
'doom_type': 2013,
|
||||||
'region': "Wolfenstein (MAP31) Main"},
|
'region': "Wolfenstein2 (MAP31) Main"},
|
||||||
361457: {'name': 'Wolfenstein (MAP31) - Chaingun',
|
361457: {'name': 'Wolfenstein2 (MAP31) - Chaingun',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 305,
|
'index': 305,
|
||||||
'doom_type': 2002,
|
'doom_type': 2002,
|
||||||
'region': "Wolfenstein (MAP31) Main"},
|
'region': "Wolfenstein2 (MAP31) Main"},
|
||||||
361458: {'name': 'Wolfenstein (MAP31) - Super Shotgun',
|
361458: {'name': 'Wolfenstein2 (MAP31) - Super Shotgun',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 308,
|
'index': 308,
|
||||||
'doom_type': 82,
|
'doom_type': 82,
|
||||||
'region': "Wolfenstein (MAP31) Main"},
|
'region': "Wolfenstein2 (MAP31) Main"},
|
||||||
361459: {'name': 'Wolfenstein (MAP31) - Partial invisibility',
|
361459: {'name': 'Wolfenstein2 (MAP31) - Partial invisibility',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 309,
|
'index': 309,
|
||||||
'doom_type': 2024,
|
'doom_type': 2024,
|
||||||
'region': "Wolfenstein (MAP31) Main"},
|
'region': "Wolfenstein2 (MAP31) Main"},
|
||||||
361460: {'name': 'Wolfenstein (MAP31) - Megasphere',
|
361460: {'name': 'Wolfenstein2 (MAP31) - Megasphere',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 310,
|
'index': 310,
|
||||||
'doom_type': 83,
|
'doom_type': 83,
|
||||||
'region': "Wolfenstein (MAP31) Main"},
|
'region': "Wolfenstein2 (MAP31) Main"},
|
||||||
361461: {'name': 'Wolfenstein (MAP31) - Backpack',
|
361461: {'name': 'Wolfenstein2 (MAP31) - Backpack',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 311,
|
'index': 311,
|
||||||
'doom_type': 8,
|
'doom_type': 8,
|
||||||
'region': "Wolfenstein (MAP31) Main"},
|
'region': "Wolfenstein2 (MAP31) Main"},
|
||||||
361462: {'name': 'Wolfenstein (MAP31) - Backpack 2',
|
361462: {'name': 'Wolfenstein2 (MAP31) - Backpack 2',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 312,
|
'index': 312,
|
||||||
'doom_type': 8,
|
'doom_type': 8,
|
||||||
'region': "Wolfenstein (MAP31) Main"},
|
'region': "Wolfenstein2 (MAP31) Main"},
|
||||||
361463: {'name': 'Wolfenstein (MAP31) - Backpack 3',
|
361463: {'name': 'Wolfenstein2 (MAP31) - Backpack 3',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 313,
|
'index': 313,
|
||||||
'doom_type': 8,
|
'doom_type': 8,
|
||||||
'region': "Wolfenstein (MAP31) Main"},
|
'region': "Wolfenstein2 (MAP31) Main"},
|
||||||
361464: {'name': 'Wolfenstein (MAP31) - Backpack 4',
|
361464: {'name': 'Wolfenstein2 (MAP31) - Backpack 4',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 314,
|
'index': 314,
|
||||||
'doom_type': 8,
|
'doom_type': 8,
|
||||||
'region': "Wolfenstein (MAP31) Main"},
|
'region': "Wolfenstein2 (MAP31) Main"},
|
||||||
361465: {'name': 'Wolfenstein (MAP31) - BFG9000',
|
361465: {'name': 'Wolfenstein2 (MAP31) - BFG9000',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 315,
|
'index': 315,
|
||||||
'doom_type': 2006,
|
'doom_type': 2006,
|
||||||
'region': "Wolfenstein (MAP31) Main"},
|
'region': "Wolfenstein2 (MAP31) Main"},
|
||||||
361466: {'name': 'Wolfenstein (MAP31) - Plasma gun',
|
361466: {'name': 'Wolfenstein2 (MAP31) - Plasma gun',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': 316,
|
'index': 316,
|
||||||
'doom_type': 2004,
|
'doom_type': 2004,
|
||||||
'region': "Wolfenstein (MAP31) Main"},
|
'region': "Wolfenstein2 (MAP31) Main"},
|
||||||
361467: {'name': 'Wolfenstein (MAP31) - Exit',
|
361467: {'name': 'Wolfenstein2 (MAP31) - Exit',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 1,
|
'map': 1,
|
||||||
'index': -1,
|
'index': -1,
|
||||||
'doom_type': -1,
|
'doom_type': -1,
|
||||||
'region': "Wolfenstein (MAP31) Main"},
|
'region': "Wolfenstein2 (MAP31) Main"},
|
||||||
361468: {'name': 'Grosse (MAP32) - Plasma gun',
|
361468: {'name': 'Grosse2 (MAP32) - Plasma gun',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 2,
|
'map': 2,
|
||||||
'index': 33,
|
'index': 33,
|
||||||
'doom_type': 2004,
|
'doom_type': 2004,
|
||||||
'region': "Grosse (MAP32) Main"},
|
'region': "Grosse2 (MAP32) Main"},
|
||||||
361469: {'name': 'Grosse (MAP32) - Rocket launcher',
|
361469: {'name': 'Grosse2 (MAP32) - Rocket launcher',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 2,
|
'map': 2,
|
||||||
'index': 57,
|
'index': 57,
|
||||||
'doom_type': 2003,
|
'doom_type': 2003,
|
||||||
'region': "Grosse (MAP32) Start"},
|
'region': "Grosse2 (MAP32) Main"},
|
||||||
361470: {'name': 'Grosse (MAP32) - Invulnerability',
|
361470: {'name': 'Grosse2 (MAP32) - Invulnerability',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 2,
|
'map': 2,
|
||||||
'index': 70,
|
'index': 70,
|
||||||
'doom_type': 2022,
|
'doom_type': 2022,
|
||||||
'region': "Grosse (MAP32) Main"},
|
'region': "Grosse2 (MAP32) Main"},
|
||||||
361471: {'name': 'Grosse (MAP32) - Super Shotgun',
|
361471: {'name': 'Grosse2 (MAP32) - Super Shotgun',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 2,
|
'map': 2,
|
||||||
'index': 74,
|
'index': 74,
|
||||||
'doom_type': 82,
|
'doom_type': 82,
|
||||||
'region': "Grosse (MAP32) Main"},
|
'region': "Grosse2 (MAP32) Main"},
|
||||||
361472: {'name': 'Grosse (MAP32) - BFG9000',
|
361472: {'name': 'Grosse2 (MAP32) - BFG9000',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 2,
|
'map': 2,
|
||||||
'index': 75,
|
'index': 75,
|
||||||
'doom_type': 2006,
|
'doom_type': 2006,
|
||||||
'region': "Grosse (MAP32) Main"},
|
'region': "Grosse2 (MAP32) Main"},
|
||||||
361473: {'name': 'Grosse (MAP32) - Megasphere',
|
361473: {'name': 'Grosse2 (MAP32) - Megasphere',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 2,
|
'map': 2,
|
||||||
'index': 78,
|
'index': 78,
|
||||||
'doom_type': 83,
|
'doom_type': 83,
|
||||||
'region': "Grosse (MAP32) Main"},
|
'region': "Grosse2 (MAP32) Main"},
|
||||||
361474: {'name': 'Grosse (MAP32) - Chaingun',
|
361474: {'name': 'Grosse2 (MAP32) - Chaingun',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 2,
|
'map': 2,
|
||||||
'index': 79,
|
'index': 79,
|
||||||
'doom_type': 2002,
|
'doom_type': 2002,
|
||||||
'region': "Grosse (MAP32) Main"},
|
'region': "Grosse2 (MAP32) Main"},
|
||||||
361475: {'name': 'Grosse (MAP32) - Chaingun 2',
|
361475: {'name': 'Grosse2 (MAP32) - Chaingun 2',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 2,
|
'map': 2,
|
||||||
'index': 80,
|
'index': 80,
|
||||||
'doom_type': 2002,
|
'doom_type': 2002,
|
||||||
'region': "Grosse (MAP32) Main"},
|
'region': "Grosse2 (MAP32) Main"},
|
||||||
361476: {'name': 'Grosse (MAP32) - Chaingun 3',
|
361476: {'name': 'Grosse2 (MAP32) - Chaingun 3',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 2,
|
'map': 2,
|
||||||
'index': 81,
|
'index': 81,
|
||||||
'doom_type': 2002,
|
'doom_type': 2002,
|
||||||
'region': "Grosse (MAP32) Main"},
|
'region': "Grosse2 (MAP32) Main"},
|
||||||
361477: {'name': 'Grosse (MAP32) - Berserk',
|
361477: {'name': 'Grosse2 (MAP32) - Berserk',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 2,
|
'map': 2,
|
||||||
'index': 82,
|
'index': 82,
|
||||||
'doom_type': 2023,
|
'doom_type': 2023,
|
||||||
'region': "Grosse (MAP32) Start"},
|
'region': "Grosse2 (MAP32) Main"},
|
||||||
361478: {'name': 'Grosse (MAP32) - Exit',
|
361478: {'name': 'Grosse2 (MAP32) - Exit',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'map': 2,
|
'map': 2,
|
||||||
'index': -1,
|
'index': -1,
|
||||||
'doom_type': -1,
|
'doom_type': -1,
|
||||||
'region': "Grosse (MAP32) Main"},
|
'region': "Grosse2 (MAP32) Main"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
location_name_groups: Dict[str, Set[str]] = {
|
location_name_groups: Dict[str, Set[str]] = {
|
||||||
"Barrels o' Fun (MAP23)": {
|
'Barrels o Fun (MAP23)': {
|
||||||
"Barrels o' Fun (MAP23) - Armor",
|
'Barrels o Fun (MAP23) - Armor',
|
||||||
"Barrels o' Fun (MAP23) - BFG9000",
|
'Barrels o Fun (MAP23) - BFG9000',
|
||||||
"Barrels o' Fun (MAP23) - Backpack",
|
'Barrels o Fun (MAP23) - Backpack',
|
||||||
"Barrels o' Fun (MAP23) - Backpack 2",
|
'Barrels o Fun (MAP23) - Backpack 2',
|
||||||
"Barrels o' Fun (MAP23) - Berserk",
|
'Barrels o Fun (MAP23) - Berserk',
|
||||||
"Barrels o' Fun (MAP23) - Computer area map",
|
'Barrels o Fun (MAP23) - Computer area map',
|
||||||
"Barrels o' Fun (MAP23) - Exit",
|
'Barrels o Fun (MAP23) - Exit',
|
||||||
"Barrels o' Fun (MAP23) - Megasphere",
|
'Barrels o Fun (MAP23) - Megasphere',
|
||||||
"Barrels o' Fun (MAP23) - Rocket launcher",
|
'Barrels o Fun (MAP23) - Rocket launcher',
|
||||||
"Barrels o' Fun (MAP23) - Shotgun",
|
'Barrels o Fun (MAP23) - Shotgun',
|
||||||
"Barrels o' Fun (MAP23) - Supercharge",
|
'Barrels o Fun (MAP23) - Supercharge',
|
||||||
"Barrels o' Fun (MAP23) - Yellow skull key",
|
'Barrels o Fun (MAP23) - Yellow skull key',
|
||||||
},
|
},
|
||||||
'Bloodfalls (MAP25)': {
|
'Bloodfalls (MAP25)': {
|
||||||
'Bloodfalls (MAP25) - Armor',
|
'Bloodfalls (MAP25) - Armor',
|
||||||
@@ -2998,18 +2998,18 @@ location_name_groups: Dict[str, Set[str]] = {
|
|||||||
'Gotcha! (MAP20) - Supercharge 3',
|
'Gotcha! (MAP20) - Supercharge 3',
|
||||||
'Gotcha! (MAP20) - Supercharge 4',
|
'Gotcha! (MAP20) - Supercharge 4',
|
||||||
},
|
},
|
||||||
'Grosse (MAP32)': {
|
'Grosse2 (MAP32)': {
|
||||||
'Grosse (MAP32) - BFG9000',
|
'Grosse2 (MAP32) - BFG9000',
|
||||||
'Grosse (MAP32) - Berserk',
|
'Grosse2 (MAP32) - Berserk',
|
||||||
'Grosse (MAP32) - Chaingun',
|
'Grosse2 (MAP32) - Chaingun',
|
||||||
'Grosse (MAP32) - Chaingun 2',
|
'Grosse2 (MAP32) - Chaingun 2',
|
||||||
'Grosse (MAP32) - Chaingun 3',
|
'Grosse2 (MAP32) - Chaingun 3',
|
||||||
'Grosse (MAP32) - Exit',
|
'Grosse2 (MAP32) - Exit',
|
||||||
'Grosse (MAP32) - Invulnerability',
|
'Grosse2 (MAP32) - Invulnerability',
|
||||||
'Grosse (MAP32) - Megasphere',
|
'Grosse2 (MAP32) - Megasphere',
|
||||||
'Grosse (MAP32) - Plasma gun',
|
'Grosse2 (MAP32) - Plasma gun',
|
||||||
'Grosse (MAP32) - Rocket launcher',
|
'Grosse2 (MAP32) - Rocket launcher',
|
||||||
'Grosse (MAP32) - Super Shotgun',
|
'Grosse2 (MAP32) - Super Shotgun',
|
||||||
},
|
},
|
||||||
'Icon of Sin (MAP30)': {
|
'Icon of Sin (MAP30)': {
|
||||||
'Icon of Sin (MAP30) - BFG9000',
|
'Icon of Sin (MAP30) - BFG9000',
|
||||||
@@ -3417,22 +3417,22 @@ location_name_groups: Dict[str, Set[str]] = {
|
|||||||
'Underhalls (MAP02) - Red keycard',
|
'Underhalls (MAP02) - Red keycard',
|
||||||
'Underhalls (MAP02) - Super Shotgun',
|
'Underhalls (MAP02) - Super Shotgun',
|
||||||
},
|
},
|
||||||
'Wolfenstein (MAP31)': {
|
'Wolfenstein2 (MAP31)': {
|
||||||
'Wolfenstein (MAP31) - BFG9000',
|
'Wolfenstein2 (MAP31) - BFG9000',
|
||||||
'Wolfenstein (MAP31) - Backpack',
|
'Wolfenstein2 (MAP31) - Backpack',
|
||||||
'Wolfenstein (MAP31) - Backpack 2',
|
'Wolfenstein2 (MAP31) - Backpack 2',
|
||||||
'Wolfenstein (MAP31) - Backpack 3',
|
'Wolfenstein2 (MAP31) - Backpack 3',
|
||||||
'Wolfenstein (MAP31) - Backpack 4',
|
'Wolfenstein2 (MAP31) - Backpack 4',
|
||||||
'Wolfenstein (MAP31) - Berserk',
|
'Wolfenstein2 (MAP31) - Berserk',
|
||||||
'Wolfenstein (MAP31) - Chaingun',
|
'Wolfenstein2 (MAP31) - Chaingun',
|
||||||
'Wolfenstein (MAP31) - Exit',
|
'Wolfenstein2 (MAP31) - Exit',
|
||||||
'Wolfenstein (MAP31) - Megasphere',
|
'Wolfenstein2 (MAP31) - Megasphere',
|
||||||
'Wolfenstein (MAP31) - Partial invisibility',
|
'Wolfenstein2 (MAP31) - Partial invisibility',
|
||||||
'Wolfenstein (MAP31) - Plasma gun',
|
'Wolfenstein2 (MAP31) - Plasma gun',
|
||||||
'Wolfenstein (MAP31) - Rocket launcher',
|
'Wolfenstein2 (MAP31) - Rocket launcher',
|
||||||
'Wolfenstein (MAP31) - Shotgun',
|
'Wolfenstein2 (MAP31) - Shotgun',
|
||||||
'Wolfenstein (MAP31) - Super Shotgun',
|
'Wolfenstein2 (MAP31) - Super Shotgun',
|
||||||
'Wolfenstein (MAP31) - Supercharge',
|
'Wolfenstein2 (MAP31) - Supercharge',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ map_names: List[str] = [
|
|||||||
'Gotcha! (MAP20)',
|
'Gotcha! (MAP20)',
|
||||||
'Nirvana (MAP21)',
|
'Nirvana (MAP21)',
|
||||||
'The Catacombs (MAP22)',
|
'The Catacombs (MAP22)',
|
||||||
"Barrels o' Fun (MAP23)",
|
'Barrels o Fun (MAP23)',
|
||||||
'The Chasm (MAP24)',
|
'The Chasm (MAP24)',
|
||||||
'Bloodfalls (MAP25)',
|
'Bloodfalls (MAP25)',
|
||||||
'The Abandoned Mines (MAP26)',
|
'The Abandoned Mines (MAP26)',
|
||||||
@@ -34,6 +34,6 @@ map_names: List[str] = [
|
|||||||
'The Spirit World (MAP28)',
|
'The Spirit World (MAP28)',
|
||||||
'The Living End (MAP29)',
|
'The Living End (MAP29)',
|
||||||
'Icon of Sin (MAP30)',
|
'Icon of Sin (MAP30)',
|
||||||
'Wolfenstein (MAP31)',
|
'Wolfenstein2 (MAP31)',
|
||||||
'Grosse (MAP32)',
|
'Grosse2 (MAP32)',
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -84,12 +84,11 @@ regions:List[RegionDict] = [
|
|||||||
|
|
||||||
# The Waste Tunnels (MAP05)
|
# The Waste Tunnels (MAP05)
|
||||||
{"name":"The Waste Tunnels (MAP05) Main",
|
{"name":"The Waste Tunnels (MAP05) Main",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":True,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
"connections":[
|
"connections":[
|
||||||
{"target":"The Waste Tunnels (MAP05) Red","pro":False},
|
{"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",
|
{"name":"The Waste Tunnels (MAP05) Blue",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
@@ -104,10 +103,6 @@ regions:List[RegionDict] = [
|
|||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
"connections":[{"target":"The Waste Tunnels (MAP05) Main","pro":False}]},
|
"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)
|
# The Crusher (MAP06)
|
||||||
{"name":"The Crusher (MAP06) Main",
|
{"name":"The Crusher (MAP06) Main",
|
||||||
@@ -134,13 +129,9 @@ regions:List[RegionDict] = [
|
|||||||
|
|
||||||
# Dead Simple (MAP07)
|
# Dead Simple (MAP07)
|
||||||
{"name":"Dead Simple (MAP07) Main",
|
{"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,
|
"connects_to_hub":True,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
"connections":[{"target":"Dead Simple (MAP07) Main","pro":False}]},
|
"connections":[]},
|
||||||
|
|
||||||
# Tricks and Traps (MAP08)
|
# Tricks and Traps (MAP08)
|
||||||
{"name":"Tricks and Traps (MAP08) Main",
|
{"name":"Tricks and Traps (MAP08) Main",
|
||||||
@@ -160,12 +151,11 @@ regions:List[RegionDict] = [
|
|||||||
|
|
||||||
# The Pit (MAP09)
|
# The Pit (MAP09)
|
||||||
{"name":"The Pit (MAP09) Main",
|
{"name":"The Pit (MAP09) Main",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":True,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
"connections":[
|
"connections":[
|
||||||
{"target":"The Pit (MAP09) Yellow","pro":False},
|
{"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",
|
{"name":"The Pit (MAP09) Blue",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
@@ -174,18 +164,12 @@ regions:List[RegionDict] = [
|
|||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
"connections":[{"target":"The Pit (MAP09) Main","pro":False}]},
|
"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)
|
# Refueling Base (MAP10)
|
||||||
{"name":"Refueling Base (MAP10) Main",
|
{"name":"Refueling Base (MAP10) Main",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":True,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
"connections":[
|
"connections":[{"target":"Refueling Base (MAP10) Yellow","pro":False}]},
|
||||||
{"target":"Refueling Base (MAP10) Yellow","pro":False},
|
|
||||||
{"target":"Refueling Base (MAP10) Start","pro":False}]},
|
|
||||||
{"name":"Refueling Base (MAP10) Yellow",
|
{"name":"Refueling Base (MAP10) Yellow",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
@@ -196,10 +180,6 @@ regions:List[RegionDict] = [
|
|||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
"connections":[{"target":"Refueling Base (MAP10) Yellow","pro":False}]},
|
"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)
|
# Circle of Death (MAP11)
|
||||||
{"name":"Circle of Death (MAP11) Main",
|
{"name":"Circle of Death (MAP11) Main",
|
||||||
@@ -207,49 +187,31 @@ regions:List[RegionDict] = [
|
|||||||
"episode":1,
|
"episode":1,
|
||||||
"connections":[
|
"connections":[
|
||||||
{"target":"Circle of Death (MAP11) Blue","pro":False},
|
{"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",
|
{"name":"Circle of Death (MAP11) Blue",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
"connections":[{"target":"Circle of Death (MAP11) Main","pro":False}]},
|
"connections":[{"target":"Circle of Death (MAP11) Main","pro":False}]},
|
||||||
{"name":"Circle of Death (MAP11) Red",
|
{"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,
|
"connects_to_hub":False,
|
||||||
"episode":1,
|
"episode":1,
|
||||||
"connections":[{"target":"Circle of Death (MAP11) Main","pro":False}]},
|
"connections":[{"target":"Circle of Death (MAP11) Main","pro":False}]},
|
||||||
|
|
||||||
# The Factory (MAP12)
|
# The Factory (MAP12)
|
||||||
{"name":"The Factory (MAP12) Indoors",
|
{"name":"The Factory (MAP12) Main",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":True,
|
||||||
"episode":2,
|
"episode":2,
|
||||||
"connections":[
|
"connections":[
|
||||||
{"target":"The Factory (MAP12) Yellow","pro":False},
|
{"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",
|
{"name":"The Factory (MAP12) Blue",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":2,
|
"episode":2,
|
||||||
"connections":[{"target":"The Factory (MAP12) Indoors","pro":False}]},
|
"connections":[{"target":"The Factory (MAP12) Main","pro":False}]},
|
||||||
{"name":"The Factory (MAP12) Yellow",
|
{"name":"The Factory (MAP12) Yellow",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":2,
|
"episode":2,
|
||||||
"connections":[]},
|
"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)
|
# Downtown (MAP13)
|
||||||
{"name":"Downtown (MAP13) Main",
|
{"name":"Downtown (MAP13) Main",
|
||||||
@@ -329,8 +291,7 @@ regions:List[RegionDict] = [
|
|||||||
"episode":2,
|
"episode":2,
|
||||||
"connections":[
|
"connections":[
|
||||||
{"target":"Suburbs (MAP16) Red","pro":False},
|
{"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",
|
{"name":"Suburbs (MAP16) Blue",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":2,
|
"episode":2,
|
||||||
@@ -338,13 +299,7 @@ regions:List[RegionDict] = [
|
|||||||
{"name":"Suburbs (MAP16) Red",
|
{"name":"Suburbs (MAP16) Red",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":2,
|
"episode":2,
|
||||||
"connections":[
|
"connections":[{"target":"Suburbs (MAP16) Main","pro":False}]},
|
||||||
{"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)
|
# Tenements (MAP17)
|
||||||
{"name":"Tenements (MAP17) Main",
|
{"name":"Tenements (MAP17) Main",
|
||||||
@@ -403,7 +358,7 @@ regions:List[RegionDict] = [
|
|||||||
|
|
||||||
# Nirvana (MAP21)
|
# Nirvana (MAP21)
|
||||||
{"name":"Nirvana (MAP21) Main",
|
{"name":"Nirvana (MAP21) Main",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":True,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[{"target":"Nirvana (MAP21) Yellow","pro":False}]},
|
"connections":[{"target":"Nirvana (MAP21) Yellow","pro":False}]},
|
||||||
{"name":"Nirvana (MAP21) Yellow",
|
{"name":"Nirvana (MAP21) Yellow",
|
||||||
@@ -411,31 +366,19 @@ regions:List[RegionDict] = [
|
|||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[
|
"connections":[
|
||||||
{"target":"Nirvana (MAP21) Main","pro":False},
|
{"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",
|
{"name":"Nirvana (MAP21) Magenta",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[
|
"connections":[{"target":"Nirvana (MAP21) Yellow","pro":False}]},
|
||||||
{"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)
|
# The Catacombs (MAP22)
|
||||||
{"name":"The Catacombs (MAP22) Main",
|
{"name":"The Catacombs (MAP22) Main",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":True,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[
|
"connections":[
|
||||||
{"target":"The Catacombs (MAP22) Blue","pro":False},
|
{"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",
|
{"name":"The Catacombs (MAP22) Blue",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
@@ -444,59 +387,36 @@ regions:List[RegionDict] = [
|
|||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[{"target":"The Catacombs (MAP22) Main","pro":False}]},
|
"connections":[{"target":"The Catacombs (MAP22) Main","pro":False}]},
|
||||||
{"name":"The Catacombs (MAP22) Early",
|
|
||||||
"connects_to_hub":True,
|
|
||||||
"episode":3,
|
|
||||||
"connections":[{"target":"The Catacombs (MAP22) Main","pro":False}]},
|
|
||||||
|
|
||||||
# Barrels o' Fun (MAP23)
|
# Barrels o Fun (MAP23)
|
||||||
{"name":"Barrels o' Fun (MAP23) Main",
|
{"name":"Barrels o Fun (MAP23) Main",
|
||||||
"connects_to_hub":True,
|
"connects_to_hub":True,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[{"target":"Barrels o' Fun (MAP23) Yellow","pro":False}]},
|
"connections":[{"target":"Barrels o Fun (MAP23) Yellow","pro":False}]},
|
||||||
{"name":"Barrels o' Fun (MAP23) Yellow",
|
{"name":"Barrels o Fun (MAP23) Yellow",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[{"target":"Barrels o' Fun (MAP23) Main","pro":False}]},
|
"connections":[{"target":"Barrels o Fun (MAP23) Main","pro":False}]},
|
||||||
|
|
||||||
# The Chasm (MAP24)
|
# The Chasm (MAP24)
|
||||||
{"name":"The Chasm (MAP24) Main",
|
{"name":"The Chasm (MAP24) Main",
|
||||||
"connects_to_hub":True,
|
"connects_to_hub":True,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[
|
"connections":[{"target":"The Chasm (MAP24) Red","pro":False}]},
|
||||||
{"target":"The Chasm (MAP24) Blue","pro":False},
|
|
||||||
{"target":"The Chasm (MAP24) Blue Pro","pro":True}]},
|
|
||||||
{"name":"The Chasm (MAP24) Red",
|
{"name":"The Chasm (MAP24) Red",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[{"target":"The Chasm (MAP24) Blue","pro":False}]},
|
"connections":[{"target":"The Chasm (MAP24) Main","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)
|
# Bloodfalls (MAP25)
|
||||||
{"name":"Bloodfalls (MAP25) Main",
|
{"name":"Bloodfalls (MAP25) Main",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":True,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[
|
"connections":[{"target":"Bloodfalls (MAP25) Blue","pro":False}]},
|
||||||
{"target":"Bloodfalls (MAP25) Blue","pro":False},
|
|
||||||
{"target":"Bloodfalls (MAP25) Start","pro":False}]},
|
|
||||||
{"name":"Bloodfalls (MAP25) Blue",
|
{"name":"Bloodfalls (MAP25) Blue",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[{"target":"Bloodfalls (MAP25) Main","pro":False}]},
|
"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)
|
# The Abandoned Mines (MAP26)
|
||||||
{"name":"The Abandoned Mines (MAP26) Main",
|
{"name":"The Abandoned Mines (MAP26) Main",
|
||||||
@@ -564,27 +484,19 @@ regions:List[RegionDict] = [
|
|||||||
|
|
||||||
# Icon of Sin (MAP30)
|
# Icon of Sin (MAP30)
|
||||||
{"name":"Icon of Sin (MAP30) Main",
|
{"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,
|
"connects_to_hub":True,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[{"target":"Icon of Sin (MAP30) Main","pro":False}]},
|
"connections":[]},
|
||||||
|
|
||||||
# Wolfenstein (MAP31)
|
# Wolfenstein2 (MAP31)
|
||||||
{"name":"Wolfenstein (MAP31) Main",
|
{"name":"Wolfenstein2 (MAP31) Main",
|
||||||
"connects_to_hub":True,
|
"connects_to_hub":True,
|
||||||
"episode":4,
|
"episode":4,
|
||||||
"connections":[]},
|
"connections":[]},
|
||||||
|
|
||||||
# Grosse (MAP32)
|
# Grosse2 (MAP32)
|
||||||
{"name":"Grosse (MAP32) Main",
|
{"name":"Grosse2 (MAP32) Main",
|
||||||
"connects_to_hub":False,
|
|
||||||
"episode":4,
|
|
||||||
"connections":[{"target":"Grosse (MAP32) Start","pro":False}]},
|
|
||||||
{"name":"Grosse (MAP32) Start",
|
|
||||||
"connects_to_hub":True,
|
"connects_to_hub":True,
|
||||||
"episode":4,
|
"episode":4,
|
||||||
"connections":[{"target":"Grosse (MAP32) Main","pro":False}]},
|
"connections":[]},
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -53,6 +53,14 @@ def set_episode1_rules(player, multiworld, pro):
|
|||||||
state.has("The Focus (MAP04) - Red keycard", player, 1))
|
state.has("The Focus (MAP04) - Red keycard", player, 1))
|
||||||
|
|
||||||
# The Waste Tunnels (MAP05)
|
# 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:
|
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))
|
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:
|
set_rule(multiworld.get_entrance("The Waste Tunnels (MAP05) Main -> The Waste Tunnels (MAP05) Blue", player), lambda state:
|
||||||
@@ -63,22 +71,18 @@ def set_episode1_rules(player, multiworld, pro):
|
|||||||
state.has("The Waste Tunnels (MAP05) - Blue keycard", player, 1))
|
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:
|
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))
|
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)
|
# The Crusher (MAP06)
|
||||||
set_rule(multiworld.get_entrance("Hub -> The Crusher (MAP06) Main", player), lambda state:
|
set_rule(multiworld.get_entrance("Hub -> The Crusher (MAP06) Main", player), lambda state:
|
||||||
(state.has("The Crusher (MAP06)", player, 1) and
|
(state.has("The Crusher (MAP06)", player, 1) and
|
||||||
state.has("Shotgun", player, 1)) and
|
state.has("Shotgun", player, 1) and
|
||||||
(state.has("Plasma gun", player, 1) or
|
state.has("Chaingun", player, 1) and
|
||||||
state.has("Chaingun", player, 1)))
|
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 Crusher (MAP06) Main -> The Crusher (MAP06) Blue", player), lambda state:
|
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) and
|
state.has("The Crusher (MAP06) - Blue keycard", player, 1))
|
||||||
state.has("Super Shotgun", player, 1))
|
|
||||||
set_rule(multiworld.get_entrance("The Crusher (MAP06) Blue -> The Crusher (MAP06) Red", player), lambda state:
|
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))
|
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:
|
set_rule(multiworld.get_entrance("The Crusher (MAP06) Blue -> The Crusher (MAP06) Main", player), lambda state:
|
||||||
@@ -91,14 +95,14 @@ def set_episode1_rules(player, multiworld, pro):
|
|||||||
state.has("The Crusher (MAP06) - Red keycard", player, 1))
|
state.has("The Crusher (MAP06) - Red keycard", player, 1))
|
||||||
|
|
||||||
# Dead Simple (MAP07)
|
# Dead Simple (MAP07)
|
||||||
set_rule(multiworld.get_entrance("Hub -> Dead Simple (MAP07) Start", player), lambda state:
|
set_rule(multiworld.get_entrance("Hub -> Dead Simple (MAP07) Main", player), lambda state:
|
||||||
state.has("Dead Simple (MAP07)", player, 1))
|
(state.has("Dead Simple (MAP07)", player, 1) and
|
||||||
set_rule(multiworld.get_entrance("Dead Simple (MAP07) Start -> Dead Simple (MAP07) Main", player), lambda state:
|
state.has("Shotgun", player, 1) and
|
||||||
(state.has("Shotgun", player, 1) and
|
|
||||||
state.has("Chaingun", player, 1) and
|
state.has("Chaingun", player, 1) and
|
||||||
state.has("Super Shotgun", player, 1)) and (state.has("BFG9000", player, 1) or
|
state.has("Super Shotgun", player, 1)) and
|
||||||
|
(state.has("Rocket launcher", player, 1) or
|
||||||
state.has("Plasma gun", player, 1) or
|
state.has("Plasma gun", player, 1) or
|
||||||
state.has("Rocket launcher", player, 1)))
|
state.has("BFG9000", player, 1)))
|
||||||
|
|
||||||
# Tricks and Traps (MAP08)
|
# Tricks and Traps (MAP08)
|
||||||
set_rule(multiworld.get_entrance("Hub -> Tricks and Traps (MAP08) Main", player), lambda state:
|
set_rule(multiworld.get_entrance("Hub -> Tricks and Traps (MAP08) Main", player), lambda state:
|
||||||
@@ -115,34 +119,34 @@ def set_episode1_rules(player, multiworld, pro):
|
|||||||
state.has("Tricks and Traps (MAP08) - Yellow skull key", player, 1))
|
state.has("Tricks and Traps (MAP08) - Yellow skull key", player, 1))
|
||||||
|
|
||||||
# The Pit (MAP09)
|
# 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:
|
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))
|
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:
|
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))
|
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:
|
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))
|
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)
|
# 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:
|
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))
|
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:
|
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))
|
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)
|
# Circle of Death (MAP11)
|
||||||
set_rule(multiworld.get_entrance("Hub -> Circle of Death (MAP11) Main", player), lambda state:
|
set_rule(multiworld.get_entrance("Hub -> Circle of Death (MAP11) Main", player), lambda state:
|
||||||
@@ -161,19 +165,18 @@ def set_episode1_rules(player, multiworld, pro):
|
|||||||
|
|
||||||
def set_episode2_rules(player, multiworld, pro):
|
def set_episode2_rules(player, multiworld, pro):
|
||||||
# The Factory (MAP12)
|
# The Factory (MAP12)
|
||||||
set_rule(multiworld.get_entrance("The Factory (MAP12) Indoors -> The Factory (MAP12) Yellow", player), lambda state:
|
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:
|
||||||
state.has("The Factory (MAP12) - Yellow keycard", player, 1))
|
state.has("The Factory (MAP12) - Yellow keycard", player, 1))
|
||||||
set_rule(multiworld.get_entrance("The Factory (MAP12) Indoors -> The Factory (MAP12) Blue", player), lambda state:
|
set_rule(multiworld.get_entrance("The Factory (MAP12) Main -> The Factory (MAP12) Blue", player), lambda state:
|
||||||
state.has("The Factory (MAP12) - Blue keycard", player, 1))
|
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)
|
# Downtown (MAP13)
|
||||||
set_rule(multiworld.get_entrance("Hub -> Downtown (MAP13) Main", player), lambda state:
|
set_rule(multiworld.get_entrance("Hub -> Downtown (MAP13) Main", player), lambda state:
|
||||||
@@ -304,56 +307,54 @@ def set_episode2_rules(player, multiworld, pro):
|
|||||||
|
|
||||||
def set_episode3_rules(player, multiworld, pro):
|
def set_episode3_rules(player, multiworld, pro):
|
||||||
# Nirvana (MAP21)
|
# Nirvana (MAP21)
|
||||||
set_rule(multiworld.get_entrance("Nirvana (MAP21) Main -> Nirvana (MAP21) Yellow", player), lambda state:
|
set_rule(multiworld.get_entrance("Hub -> Nirvana (MAP21) Main", player), lambda state:
|
||||||
(state.has("Super Shotgun", player, 1) and
|
(state.has("Nirvana (MAP21)", 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("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("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
|
|
||||||
state.has("Shotgun", player, 1) and
|
state.has("Shotgun", player, 1) and
|
||||||
state.has("Chaingun", player, 1) and
|
state.has("Chaingun", player, 1) and
|
||||||
state.has("Super Shotgun", player, 1)) and
|
state.has("Super Shotgun", player, 1)) and
|
||||||
(state.has("Rocket launcher", player, 1) or
|
(state.has("Rocket launcher", player, 1) or
|
||||||
state.has("Plasma gun", player, 1) or
|
state.has("Plasma gun", player, 1) or
|
||||||
state.has("BFG9000", player, 1)))
|
state.has("BFG9000", player, 1)))
|
||||||
set_rule(multiworld.get_entrance("Barrels o' Fun (MAP23) Main -> Barrels o' Fun (MAP23) Yellow", player), lambda state:
|
set_rule(multiworld.get_entrance("Nirvana (MAP21) Main -> Nirvana (MAP21) Yellow", player), lambda state:
|
||||||
state.has("Barrels o' Fun (MAP23) - Yellow skull key", player, 1))
|
state.has("Nirvana (MAP21) - Yellow skull key", player, 1))
|
||||||
set_rule(multiworld.get_entrance("Barrels o' Fun (MAP23) Yellow -> Barrels o' Fun (MAP23) Main", player), lambda state:
|
set_rule(multiworld.get_entrance("Nirvana (MAP21) Yellow -> Nirvana (MAP21) Main", player), lambda state:
|
||||||
state.has("Barrels o' Fun (MAP23) - Yellow skull key", player, 1))
|
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))
|
||||||
|
|
||||||
|
# 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))
|
||||||
|
|
||||||
|
# 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))
|
||||||
|
|
||||||
# The Chasm (MAP24)
|
# The Chasm (MAP24)
|
||||||
set_rule(multiworld.get_entrance("Hub -> The Chasm (MAP24) Main", player), lambda state:
|
set_rule(multiworld.get_entrance("Hub -> The Chasm (MAP24) Main", player), lambda state:
|
||||||
@@ -364,26 +365,24 @@ def set_episode3_rules(player, multiworld, pro):
|
|||||||
state.has("Plasma gun", player, 1) and
|
state.has("Plasma gun", player, 1) and
|
||||||
state.has("BFG9000", player, 1) and
|
state.has("BFG9000", player, 1) and
|
||||||
state.has("Super Shotgun", player, 1))
|
state.has("Super Shotgun", player, 1))
|
||||||
set_rule(multiworld.get_entrance("The Chasm (MAP24) Main -> The Chasm (MAP24) Blue", player), lambda state:
|
set_rule(multiworld.get_entrance("The Chasm (MAP24) Main -> The Chasm (MAP24) Red", 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))
|
state.has("The Chasm (MAP24) - Red keycard", player, 1))
|
||||||
set_rule(multiworld.get_entrance("The Chasm (MAP24) Blue -> The Chasm (MAP24) Red", player), lambda state:
|
set_rule(multiworld.get_entrance("The Chasm (MAP24) Red -> The Chasm (MAP24) Main", player), lambda state:
|
||||||
state.has("The Chasm (MAP24) - Red keycard", player, 1))
|
state.has("The Chasm (MAP24) - Red keycard", player, 1))
|
||||||
|
|
||||||
# Bloodfalls (MAP25)
|
# 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:
|
set_rule(multiworld.get_entrance("Bloodfalls (MAP25) Main -> Bloodfalls (MAP25) Blue", player), lambda state:
|
||||||
(state.has("Bloodfalls (MAP25) - Blue skull key", player, 1)) and (state.has("Rocket launcher", player, 1) or
|
state.has("Bloodfalls (MAP25) - Blue skull key", player, 1))
|
||||||
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:
|
set_rule(multiworld.get_entrance("Bloodfalls (MAP25) Blue -> Bloodfalls (MAP25) Main", player), lambda state:
|
||||||
state.has("Bloodfalls (MAP25) - Blue skull key", player, 1))
|
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)
|
# The Abandoned Mines (MAP26)
|
||||||
set_rule(multiworld.get_entrance("Hub -> The Abandoned Mines (MAP26) Main", player), lambda state:
|
set_rule(multiworld.get_entrance("Hub -> The Abandoned Mines (MAP26) Main", player), lambda state:
|
||||||
@@ -452,34 +451,36 @@ def set_episode3_rules(player, multiworld, pro):
|
|||||||
state.has("Super Shotgun", player, 1))
|
state.has("Super Shotgun", player, 1))
|
||||||
|
|
||||||
# Icon of Sin (MAP30)
|
# Icon of Sin (MAP30)
|
||||||
set_rule(multiworld.get_entrance("Hub -> Icon of Sin (MAP30) Start", player), lambda state:
|
set_rule(multiworld.get_entrance("Hub -> Icon of Sin (MAP30) Main", player), lambda state:
|
||||||
state.has("Icon of Sin (MAP30)", player, 1))
|
state.has("Icon of Sin (MAP30)", player, 1) and
|
||||||
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("Rocket launcher", player, 1) and
|
state.has("Rocket launcher", player, 1) and
|
||||||
state.has("Plasma gun", player, 1) and
|
state.has("Shotgun", player, 1) and
|
||||||
state.has("Chaingun", player, 1) and
|
state.has("Chaingun", player, 1) and
|
||||||
|
state.has("Plasma gun", player, 1) and
|
||||||
state.has("BFG9000", player, 1) and
|
state.has("BFG9000", player, 1) and
|
||||||
state.has("Super Shotgun", player, 1))
|
state.has("Super Shotgun", player, 1))
|
||||||
|
|
||||||
|
|
||||||
def set_episode4_rules(player, multiworld, pro):
|
def set_episode4_rules(player, multiworld, pro):
|
||||||
# Wolfenstein (MAP31)
|
# Wolfenstein2 (MAP31)
|
||||||
set_rule(multiworld.get_entrance("Hub -> Wolfenstein (MAP31) Main", player), lambda state:
|
set_rule(multiworld.get_entrance("Hub -> Wolfenstein2 (MAP31) Main", player), lambda state:
|
||||||
(state.has("Wolfenstein (MAP31)", player, 1) and
|
(state.has("Wolfenstein2 (MAP31)", player, 1) and
|
||||||
state.has("Chaingun", player, 1)) and
|
state.has("Shotgun", player, 1) and
|
||||||
(state.has("Shotgun", player, 1) or
|
|
||||||
state.has("Super Shotgun", player, 1)))
|
|
||||||
|
|
||||||
# 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("Chaingun", player, 1) and
|
||||||
state.has("Super Shotgun", player, 1)) and (state.has("BFG9000", player, 1) or
|
state.has("Super Shotgun", player, 1)) and
|
||||||
|
(state.has("Rocket launcher", player, 1) or
|
||||||
state.has("Plasma gun", player, 1) or
|
state.has("Plasma gun", player, 1) or
|
||||||
state.has("Rocket launcher", player, 1)))
|
state.has("BFG9000", 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
|
||||||
|
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)))
|
||||||
|
|
||||||
|
|
||||||
def set_rules(doom_ii_world: "DOOM2World", included_episodes, pro):
|
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_to_id = {data["name"]: loc_id for loc_id, data in Locations.location_table.items()}
|
||||||
location_name_groups = Locations.location_name_groups
|
location_name_groups = Locations.location_name_groups
|
||||||
|
|
||||||
starting_level_for_episode: Dict[int, str] = {
|
starting_level_for_episode: List[str] = [
|
||||||
1: "Entryway (MAP01)",
|
"Entryway (MAP01)",
|
||||||
2: "The Factory (MAP12)",
|
"The Factory (MAP12)",
|
||||||
3: "Nirvana (MAP21)"
|
"Nirvana (MAP21)"
|
||||||
}
|
]
|
||||||
|
|
||||||
# Item ratio that scales depending on episode count. These are the ratio for 3 episode. In DOOM1.
|
# 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.
|
# The ratio have been tweaked seem, and feel good.
|
||||||
@@ -77,7 +77,6 @@ class DOOM2World(World):
|
|||||||
def __init__(self, multiworld: MultiWorld, player: int):
|
def __init__(self, multiworld: MultiWorld, player: int):
|
||||||
self.included_episodes = [1, 1, 1, 0]
|
self.included_episodes = [1, 1, 1, 0]
|
||||||
self.location_count = 0
|
self.location_count = 0
|
||||||
self.starting_levels = []
|
|
||||||
|
|
||||||
super().__init__(multiworld, player)
|
super().__init__(multiworld, player)
|
||||||
|
|
||||||
@@ -96,14 +95,6 @@ class DOOM2World(World):
|
|||||||
if self.get_episode_count() == 0:
|
if self.get_episode_count() == 0:
|
||||||
self.included_episodes[0] = 1
|
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):
|
def create_regions(self):
|
||||||
pro = self.options.pro.value
|
pro = self.options.pro.value
|
||||||
|
|
||||||
@@ -202,7 +193,7 @@ class DOOM2World(World):
|
|||||||
if item["episode"] != -1 and not self.included_episodes[item["episode"] - 1]:
|
if item["episode"] != -1 and not self.included_episodes[item["episode"] - 1]:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
count = item["count"] if item["name"] not in self.starting_levels else item["count"] - 1
|
count = item["count"] if item["name"] not in self.starting_level_for_episode else item["count"] - 1
|
||||||
itempool += [self.create_item(item["name"]) for _ in range(count)]
|
itempool += [self.create_item(item["name"]) for _ in range(count)]
|
||||||
|
|
||||||
# Backpack(s) based on options
|
# Backpack(s) based on options
|
||||||
@@ -233,8 +224,9 @@ class DOOM2World(World):
|
|||||||
self.location_count -= 1
|
self.location_count -= 1
|
||||||
|
|
||||||
# Give starting levels right away
|
# Give starting levels right away
|
||||||
for map_name in self.starting_levels:
|
for i in range(len(self.starting_level_for_episode)):
|
||||||
self.multiworld.push_precollected(self.create_item(map_name))
|
if self.included_episodes[i]:
|
||||||
|
self.multiworld.push_precollected(self.create_item(self.starting_level_for_episode[i]))
|
||||||
|
|
||||||
# Give Computer area maps if option selected
|
# Give Computer area maps if option selected
|
||||||
if start_with_computer_area_maps:
|
if start_with_computer_area_maps:
|
||||||
|
|||||||
@@ -255,8 +255,7 @@ async def game_watcher(ctx: FactorioContext):
|
|||||||
if "DeathLink" in ctx.tags:
|
if "DeathLink" in ctx.tags:
|
||||||
async_start(ctx.send_death())
|
async_start(ctx.send_death())
|
||||||
if ctx.energy_link_increment:
|
if ctx.energy_link_increment:
|
||||||
# 1 + quality * 0.3 for each bridge
|
in_world_bridges = data["energy_bridges"]
|
||||||
in_world_bridges: float = data["energy_bridges"]
|
|
||||||
if in_world_bridges:
|
if in_world_bridges:
|
||||||
in_world_energy = data["energy"]
|
in_world_energy = data["energy"]
|
||||||
if in_world_energy < (ctx.energy_link_increment * in_world_bridges):
|
if in_world_energy < (ctx.energy_link_increment * in_world_bridges):
|
||||||
@@ -264,14 +263,14 @@ async def game_watcher(ctx: FactorioContext):
|
|||||||
ctx.last_deplete = time.time()
|
ctx.last_deplete = time.time()
|
||||||
async_start(ctx.send_msgs([{
|
async_start(ctx.send_msgs([{
|
||||||
"cmd": "Set", "key": ctx.energylink_key, "operations":
|
"cmd": "Set", "key": ctx.energylink_key, "operations":
|
||||||
[{"operation": "add", "value": int(-ctx.energy_link_increment * in_world_bridges)},
|
[{"operation": "add", "value": -ctx.energy_link_increment * in_world_bridges},
|
||||||
{"operation": "max", "value": 0}],
|
{"operation": "max", "value": 0}],
|
||||||
"last_deplete": ctx.last_deplete
|
"last_deplete": ctx.last_deplete
|
||||||
}]))
|
}]))
|
||||||
# Above Capacity - (len(Bridges) * ENERGY_INCREMENT)
|
# Above Capacity - (len(Bridges) * ENERGY_INCREMENT)
|
||||||
elif in_world_energy > (in_world_bridges * ctx.energy_link_increment * 5) - \
|
elif in_world_energy > (in_world_bridges * ctx.energy_link_increment * 5) - \
|
||||||
ctx.energy_link_increment * in_world_bridges:
|
ctx.energy_link_increment * in_world_bridges:
|
||||||
value = int(ctx.energy_link_increment * in_world_bridges)
|
value = ctx.energy_link_increment * in_world_bridges
|
||||||
async_start(ctx.send_msgs([{
|
async_start(ctx.send_msgs([{
|
||||||
"cmd": "Set", "key": ctx.energylink_key, "operations":
|
"cmd": "Set", "key": ctx.energylink_key, "operations":
|
||||||
[{"operation": "add", "value": value}]
|
[{"operation": "add", "value": value}]
|
||||||
@@ -407,7 +406,7 @@ async def get_info(ctx: FactorioContext, rcon_client: factorio_rcon.RCONClient):
|
|||||||
ctx.auth = info["slot_name"]
|
ctx.auth = info["slot_name"]
|
||||||
ctx.seed_name = info["seed_name"]
|
ctx.seed_name = info["seed_name"]
|
||||||
death_link = info["death_link"]
|
death_link = info["death_link"]
|
||||||
ctx.energy_link_increment = int(info.get("energy_link", 0))
|
ctx.energy_link_increment = info.get("energy_link", 0)
|
||||||
logger.debug(f"Energy Link Increment: {ctx.energy_link_increment}")
|
logger.debug(f"Energy Link Increment: {ctx.energy_link_increment}")
|
||||||
if ctx.energy_link_increment and ctx.ui:
|
if ctx.energy_link_increment and ctx.ui:
|
||||||
ctx.ui.enable_energy_link()
|
ctx.ui.enable_energy_link()
|
||||||
@@ -531,7 +530,7 @@ server_args = ("--rcon-port", rcon_port, "--rcon-password", rcon_password)
|
|||||||
def launch():
|
def launch():
|
||||||
import colorama
|
import colorama
|
||||||
global executable, server_settings, server_args
|
global executable, server_settings, server_args
|
||||||
colorama.just_fix_windows_console()
|
colorama.init()
|
||||||
|
|
||||||
if server_settings:
|
if server_settings:
|
||||||
server_settings = os.path.abspath(server_settings)
|
server_settings = os.path.abspath(server_settings)
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ class Factorio(World):
|
|||||||
item_name_groups = {
|
item_name_groups = {
|
||||||
"Progressive": set(progressive_tech_table.keys()),
|
"Progressive": set(progressive_tech_table.keys()),
|
||||||
}
|
}
|
||||||
required_client_version = (0, 6, 0)
|
required_client_version = (0, 5, 1)
|
||||||
if Utils.version_tuple < required_client_version:
|
if Utils.version_tuple < required_client_version:
|
||||||
raise Exception(f"Update Archipelago to use this world ({game}).")
|
raise Exception(f"Update Archipelago to use this world ({game}).")
|
||||||
ordered_science_packs: typing.List[str] = MaxSciencePack.get_ordered_science_packs()
|
ordered_science_packs: typing.List[str] = MaxSciencePack.get_ordered_science_packs()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import settings
|
|||||||
import base64
|
import base64
|
||||||
import threading
|
import threading
|
||||||
import requests
|
import requests
|
||||||
|
import yaml
|
||||||
from worlds.AutoWorld import World, WebWorld
|
from worlds.AutoWorld import World, WebWorld
|
||||||
from BaseClasses import Tutorial
|
from BaseClasses import Tutorial
|
||||||
from .Regions import create_regions, location_table, set_rules, stage_set_rules, rooms, non_dead_end_crest_rooms,\
|
from .Regions import create_regions, location_table, set_rules, stage_set_rules, rooms, non_dead_end_crest_rooms,\
|
||||||
@@ -43,7 +44,6 @@ class FFMQWebWorld(WebWorld):
|
|||||||
)
|
)
|
||||||
|
|
||||||
tutorials = [setup_en, setup_fr]
|
tutorials = [setup_en, setup_fr]
|
||||||
game_info_languages = ["en", "fr"]
|
|
||||||
|
|
||||||
|
|
||||||
class FFMQWorld(World):
|
class FFMQWorld(World):
|
||||||
@@ -134,7 +134,7 @@ class FFMQWorld(World):
|
|||||||
errors.append([api_url, err])
|
errors.append([api_url, err])
|
||||||
else:
|
else:
|
||||||
if response.ok:
|
if response.ok:
|
||||||
world.rooms = rooms_data[query] = Utils.parse_yaml(response.text)
|
world.rooms = rooms_data[query] = yaml.load(response.text, yaml.Loader)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
api_urls.remove(api_url)
|
api_urls.remove(api_url)
|
||||||
|
|||||||
@@ -514,19 +514,19 @@ item_table: Dict[int, ItemDict] = {
|
|||||||
'map': 7},
|
'map': 7},
|
||||||
370259: {'classification': ItemClassification.progression,
|
370259: {'classification': ItemClassification.progression,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': 'The Aquifer (E3M9) - Blue key',
|
'name': 'The Aquifier (E3M9) - Blue key',
|
||||||
'doom_type': 79,
|
'doom_type': 79,
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 9},
|
'map': 9},
|
||||||
370260: {'classification': ItemClassification.progression,
|
370260: {'classification': ItemClassification.progression,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': 'The Aquifer (E3M9) - Green key',
|
'name': 'The Aquifier (E3M9) - Green key',
|
||||||
'doom_type': 73,
|
'doom_type': 73,
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 9},
|
'map': 9},
|
||||||
370261: {'classification': ItemClassification.progression,
|
370261: {'classification': ItemClassification.progression,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': 'The Aquifer (E3M9) - Yellow key',
|
'name': 'The Aquifier (E3M9) - Yellow key',
|
||||||
'doom_type': 80,
|
'doom_type': 80,
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 9},
|
'map': 9},
|
||||||
@@ -1234,37 +1234,37 @@ item_table: Dict[int, ItemDict] = {
|
|||||||
'map': 7},
|
'map': 7},
|
||||||
370475: {'classification': ItemClassification.progression,
|
370475: {'classification': ItemClassification.progression,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': "D'Sparil's Keep (E3M8)",
|
'name': "D'Sparil'S Keep (E3M8)",
|
||||||
'doom_type': -1,
|
'doom_type': -1,
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 8},
|
'map': 8},
|
||||||
370476: {'classification': ItemClassification.progression,
|
370476: {'classification': ItemClassification.progression,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': "D'Sparil's Keep (E3M8) - Complete",
|
'name': "D'Sparil'S Keep (E3M8) - Complete",
|
||||||
'doom_type': -2,
|
'doom_type': -2,
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 8},
|
'map': 8},
|
||||||
370477: {'classification': ItemClassification.filler,
|
370477: {'classification': ItemClassification.filler,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': "D'Sparil's Keep (E3M8) - Map Scroll",
|
'name': "D'Sparil'S Keep (E3M8) - Map Scroll",
|
||||||
'doom_type': 35,
|
'doom_type': 35,
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 8},
|
'map': 8},
|
||||||
370478: {'classification': ItemClassification.progression,
|
370478: {'classification': ItemClassification.progression,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': 'The Aquifer (E3M9)',
|
'name': 'The Aquifier (E3M9)',
|
||||||
'doom_type': -1,
|
'doom_type': -1,
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 9},
|
'map': 9},
|
||||||
370479: {'classification': ItemClassification.progression,
|
370479: {'classification': ItemClassification.progression,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': 'The Aquifer (E3M9) - Complete',
|
'name': 'The Aquifier (E3M9) - Complete',
|
||||||
'doom_type': -2,
|
'doom_type': -2,
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 9},
|
'map': 9},
|
||||||
370480: {'classification': ItemClassification.filler,
|
370480: {'classification': ItemClassification.filler,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'name': 'The Aquifer (E3M9) - Map Scroll',
|
'name': 'The Aquifier (E3M9) - Map Scroll',
|
||||||
'doom_type': 35,
|
'doom_type': 35,
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'map': 9},
|
'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', },
|
'Ammos': {'Crystal Geode', 'Energy Orb', 'Greater Runes', 'Inferno Orb', 'Pile of Mace Spheres', 'Quiver of Ethereal Arrows', },
|
||||||
'Armors': {'Enchanted Shield', 'Silver Shield', },
|
'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', },
|
'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 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', },
|
'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 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)', },
|
'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 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', },
|
'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', },
|
||||||
'Weapons': {'Dragon Claw', 'Ethereal Crossbow', 'Firemace', 'Gauntlets of the Necromancer', 'Hellstaff', 'Phoenix Rod', },
|
'Weapons': {'Dragon Claw', 'Ethereal Crossbow', 'Firemace', 'Gauntlets of the Necromancer', 'Hellstaff', 'Phoenix Rod', },
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3633,300 +3633,300 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'index': -1,
|
'index': -1,
|
||||||
'doom_type': -1,
|
'doom_type': -1,
|
||||||
'region': "The Chasm (E3M7) Blue"},
|
'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,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 8,
|
'map': 8,
|
||||||
'index': 55,
|
'index': 55,
|
||||||
'doom_type': 2003,
|
'doom_type': 2003,
|
||||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||||
371518: {'name': "D'Sparil's Keep (E3M8) - Ethereal Crossbow",
|
371518: {'name': "D'Sparil'S Keep (E3M8) - Ethereal Crossbow",
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': True,
|
'check_sanity': True,
|
||||||
'map': 8,
|
'map': 8,
|
||||||
'index': 56,
|
'index': 56,
|
||||||
'doom_type': 2001,
|
'doom_type': 2001,
|
||||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||||
371519: {'name': "D'Sparil's Keep (E3M8) - Dragon Claw",
|
371519: {'name': "D'Sparil'S Keep (E3M8) - Dragon Claw",
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 8,
|
'map': 8,
|
||||||
'index': 57,
|
'index': 57,
|
||||||
'doom_type': 53,
|
'doom_type': 53,
|
||||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||||
371520: {'name': "D'Sparil's Keep (E3M8) - Gauntlets of the Necromancer",
|
371520: {'name': "D'Sparil'S Keep (E3M8) - Gauntlets of the Necromancer",
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 8,
|
'map': 8,
|
||||||
'index': 58,
|
'index': 58,
|
||||||
'doom_type': 2005,
|
'doom_type': 2005,
|
||||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||||
371521: {'name': "D'Sparil's Keep (E3M8) - Hellstaff",
|
371521: {'name': "D'Sparil'S Keep (E3M8) - Hellstaff",
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 8,
|
'map': 8,
|
||||||
'index': 59,
|
'index': 59,
|
||||||
'doom_type': 2004,
|
'doom_type': 2004,
|
||||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||||
371522: {'name': "D'Sparil's Keep (E3M8) - Bag of Holding",
|
371522: {'name': "D'Sparil'S Keep (E3M8) - Bag of Holding",
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 8,
|
'map': 8,
|
||||||
'index': 63,
|
'index': 63,
|
||||||
'doom_type': 8,
|
'doom_type': 8,
|
||||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||||
371523: {'name': "D'Sparil's Keep (E3M8) - Mystic Urn",
|
371523: {'name': "D'Sparil'S Keep (E3M8) - Mystic Urn",
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 8,
|
'map': 8,
|
||||||
'index': 64,
|
'index': 64,
|
||||||
'doom_type': 32,
|
'doom_type': 32,
|
||||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||||
371524: {'name': "D'Sparil's Keep (E3M8) - Ring of Invincibility",
|
371524: {'name': "D'Sparil'S Keep (E3M8) - Ring of Invincibility",
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 8,
|
'map': 8,
|
||||||
'index': 65,
|
'index': 65,
|
||||||
'doom_type': 84,
|
'doom_type': 84,
|
||||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||||
371525: {'name': "D'Sparil's Keep (E3M8) - Shadowsphere",
|
371525: {'name': "D'Sparil'S Keep (E3M8) - Shadowsphere",
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 8,
|
'map': 8,
|
||||||
'index': 66,
|
'index': 66,
|
||||||
'doom_type': 75,
|
'doom_type': 75,
|
||||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||||
371526: {'name': "D'Sparil's Keep (E3M8) - Silver Shield",
|
371526: {'name': "D'Sparil'S Keep (E3M8) - Silver Shield",
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 8,
|
'map': 8,
|
||||||
'index': 67,
|
'index': 67,
|
||||||
'doom_type': 85,
|
'doom_type': 85,
|
||||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||||
371527: {'name': "D'Sparil's Keep (E3M8) - Enchanted Shield",
|
371527: {'name': "D'Sparil'S Keep (E3M8) - Enchanted Shield",
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 8,
|
'map': 8,
|
||||||
'index': 68,
|
'index': 68,
|
||||||
'doom_type': 31,
|
'doom_type': 31,
|
||||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||||
371528: {'name': "D'Sparil's Keep (E3M8) - Tome of Power",
|
371528: {'name': "D'Sparil'S Keep (E3M8) - Tome of Power",
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 8,
|
'map': 8,
|
||||||
'index': 69,
|
'index': 69,
|
||||||
'doom_type': 86,
|
'doom_type': 86,
|
||||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||||
371529: {'name': "D'Sparil's Keep (E3M8) - Tome of Power 2",
|
371529: {'name': "D'Sparil'S Keep (E3M8) - Tome of Power 2",
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': True,
|
'check_sanity': True,
|
||||||
'map': 8,
|
'map': 8,
|
||||||
'index': 70,
|
'index': 70,
|
||||||
'doom_type': 86,
|
'doom_type': 86,
|
||||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||||
371530: {'name': "D'Sparil's Keep (E3M8) - Chaos Device",
|
371530: {'name': "D'Sparil'S Keep (E3M8) - Chaos Device",
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': True,
|
'check_sanity': True,
|
||||||
'map': 8,
|
'map': 8,
|
||||||
'index': 71,
|
'index': 71,
|
||||||
'doom_type': 36,
|
'doom_type': 36,
|
||||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||||
371531: {'name': "D'Sparil's Keep (E3M8) - Tome of Power 3",
|
371531: {'name': "D'Sparil'S Keep (E3M8) - Tome of Power 3",
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': True,
|
'check_sanity': True,
|
||||||
'map': 8,
|
'map': 8,
|
||||||
'index': 245,
|
'index': 245,
|
||||||
'doom_type': 86,
|
'doom_type': 86,
|
||||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||||
371532: {'name': "D'Sparil's Keep (E3M8) - Exit",
|
371532: {'name': "D'Sparil'S Keep (E3M8) - Exit",
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 8,
|
'map': 8,
|
||||||
'index': -1,
|
'index': -1,
|
||||||
'doom_type': -1,
|
'doom_type': -1,
|
||||||
'region': "D'Sparil's Keep (E3M8) Main"},
|
'region': "D'Sparil'S Keep (E3M8) Main"},
|
||||||
371533: {'name': 'The Aquifer (E3M9) - Blue key',
|
371533: {'name': 'The Aquifier (E3M9) - Blue key',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 12,
|
'index': 12,
|
||||||
'doom_type': 79,
|
'doom_type': 79,
|
||||||
'region': "The Aquifer (E3M9) Green"},
|
'region': "The Aquifier (E3M9) Green"},
|
||||||
371534: {'name': 'The Aquifer (E3M9) - Green key',
|
371534: {'name': 'The Aquifier (E3M9) - Green key',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 13,
|
'index': 13,
|
||||||
'doom_type': 73,
|
'doom_type': 73,
|
||||||
'region': "The Aquifer (E3M9) Yellow"},
|
'region': "The Aquifier (E3M9) Yellow"},
|
||||||
371535: {'name': 'The Aquifer (E3M9) - Yellow key',
|
371535: {'name': 'The Aquifier (E3M9) - Yellow key',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': True,
|
'check_sanity': True,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 14,
|
'index': 14,
|
||||||
'doom_type': 80,
|
'doom_type': 80,
|
||||||
'region': "The Aquifer (E3M9) Main"},
|
'region': "The Aquifier (E3M9) Main"},
|
||||||
371536: {'name': 'The Aquifer (E3M9) - Ethereal Crossbow',
|
371536: {'name': 'The Aquifier (E3M9) - Ethereal Crossbow',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 141,
|
'index': 141,
|
||||||
'doom_type': 2001,
|
'doom_type': 2001,
|
||||||
'region': "The Aquifer (E3M9) Main"},
|
'region': "The Aquifier (E3M9) Main"},
|
||||||
371537: {'name': 'The Aquifer (E3M9) - Phoenix Rod',
|
371537: {'name': 'The Aquifier (E3M9) - Phoenix Rod',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 142,
|
'index': 142,
|
||||||
'doom_type': 2003,
|
'doom_type': 2003,
|
||||||
'region': "The Aquifer (E3M9) Yellow"},
|
'region': "The Aquifier (E3M9) Yellow"},
|
||||||
371538: {'name': 'The Aquifer (E3M9) - Dragon Claw',
|
371538: {'name': 'The Aquifier (E3M9) - Dragon Claw',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 143,
|
'index': 143,
|
||||||
'doom_type': 53,
|
'doom_type': 53,
|
||||||
'region': "The Aquifer (E3M9) Green"},
|
'region': "The Aquifier (E3M9) Green"},
|
||||||
371539: {'name': 'The Aquifer (E3M9) - Hellstaff',
|
371539: {'name': 'The Aquifier (E3M9) - Hellstaff',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 144,
|
'index': 144,
|
||||||
'doom_type': 2004,
|
'doom_type': 2004,
|
||||||
'region': "The Aquifer (E3M9) Green"},
|
'region': "The Aquifier (E3M9) Green"},
|
||||||
371540: {'name': 'The Aquifer (E3M9) - Gauntlets of the Necromancer',
|
371540: {'name': 'The Aquifier (E3M9) - Gauntlets of the Necromancer',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 145,
|
'index': 145,
|
||||||
'doom_type': 2005,
|
'doom_type': 2005,
|
||||||
'region': "The Aquifer (E3M9) Green"},
|
'region': "The Aquifier (E3M9) Green"},
|
||||||
371541: {'name': 'The Aquifer (E3M9) - Ring of Invincibility',
|
371541: {'name': 'The Aquifier (E3M9) - Ring of Invincibility',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 148,
|
'index': 148,
|
||||||
'doom_type': 84,
|
'doom_type': 84,
|
||||||
'region': "The Aquifer (E3M9) Yellow"},
|
'region': "The Aquifier (E3M9) Yellow"},
|
||||||
371542: {'name': 'The Aquifer (E3M9) - Mystic Urn',
|
371542: {'name': 'The Aquifier (E3M9) - Mystic Urn',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 149,
|
'index': 149,
|
||||||
'doom_type': 32,
|
'doom_type': 32,
|
||||||
'region': "The Aquifer (E3M9) Green"},
|
'region': "The Aquifier (E3M9) Green"},
|
||||||
371543: {'name': 'The Aquifer (E3M9) - Silver Shield',
|
371543: {'name': 'The Aquifier (E3M9) - Silver Shield',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 151,
|
'index': 151,
|
||||||
'doom_type': 85,
|
'doom_type': 85,
|
||||||
'region': "The Aquifer (E3M9) Main"},
|
'region': "The Aquifier (E3M9) Main"},
|
||||||
371544: {'name': 'The Aquifer (E3M9) - Tome of Power',
|
371544: {'name': 'The Aquifier (E3M9) - Tome of Power',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 152,
|
'index': 152,
|
||||||
'doom_type': 86,
|
'doom_type': 86,
|
||||||
'region': "The Aquifer (E3M9) Main"},
|
'region': "The Aquifier (E3M9) Main"},
|
||||||
371545: {'name': 'The Aquifer (E3M9) - Bag of Holding',
|
371545: {'name': 'The Aquifier (E3M9) - Bag of Holding',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 153,
|
'index': 153,
|
||||||
'doom_type': 8,
|
'doom_type': 8,
|
||||||
'region': "The Aquifer (E3M9) Yellow"},
|
'region': "The Aquifier (E3M9) Yellow"},
|
||||||
371546: {'name': 'The Aquifer (E3M9) - Morph Ovum',
|
371546: {'name': 'The Aquifier (E3M9) - Morph Ovum',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 154,
|
'index': 154,
|
||||||
'doom_type': 30,
|
'doom_type': 30,
|
||||||
'region': "The Aquifer (E3M9) Green"},
|
'region': "The Aquifier (E3M9) Green"},
|
||||||
371547: {'name': 'The Aquifer (E3M9) - Map Scroll',
|
371547: {'name': 'The Aquifier (E3M9) - Map Scroll',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': True,
|
'check_sanity': True,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 155,
|
'index': 155,
|
||||||
'doom_type': 35,
|
'doom_type': 35,
|
||||||
'region': "The Aquifer (E3M9) Green"},
|
'region': "The Aquifier (E3M9) Green"},
|
||||||
371548: {'name': 'The Aquifer (E3M9) - Chaos Device',
|
371548: {'name': 'The Aquifier (E3M9) - Chaos Device',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 156,
|
'index': 156,
|
||||||
'doom_type': 36,
|
'doom_type': 36,
|
||||||
'region': "The Aquifer (E3M9) Yellow"},
|
'region': "The Aquifier (E3M9) Yellow"},
|
||||||
371549: {'name': 'The Aquifer (E3M9) - Enchanted Shield',
|
371549: {'name': 'The Aquifier (E3M9) - Enchanted Shield',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 157,
|
'index': 157,
|
||||||
'doom_type': 31,
|
'doom_type': 31,
|
||||||
'region': "The Aquifer (E3M9) Green"},
|
'region': "The Aquifier (E3M9) Green"},
|
||||||
371550: {'name': 'The Aquifer (E3M9) - Tome of Power 2',
|
371550: {'name': 'The Aquifier (E3M9) - Tome of Power 2',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 158,
|
'index': 158,
|
||||||
'doom_type': 86,
|
'doom_type': 86,
|
||||||
'region': "The Aquifer (E3M9) Green"},
|
'region': "The Aquifier (E3M9) Green"},
|
||||||
371551: {'name': 'The Aquifer (E3M9) - Torch',
|
371551: {'name': 'The Aquifier (E3M9) - Torch',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 159,
|
'index': 159,
|
||||||
'doom_type': 33,
|
'doom_type': 33,
|
||||||
'region': "The Aquifer (E3M9) Main"},
|
'region': "The Aquifier (E3M9) Main"},
|
||||||
371552: {'name': 'The Aquifer (E3M9) - Shadowsphere',
|
371552: {'name': 'The Aquifier (E3M9) - Shadowsphere',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 160,
|
'index': 160,
|
||||||
'doom_type': 75,
|
'doom_type': 75,
|
||||||
'region': "The Aquifer (E3M9) Green"},
|
'region': "The Aquifier (E3M9) Green"},
|
||||||
371553: {'name': 'The Aquifer (E3M9) - Silver Shield 2',
|
371553: {'name': 'The Aquifier (E3M9) - Silver Shield 2',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': True,
|
'check_sanity': True,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 374,
|
'index': 374,
|
||||||
'doom_type': 85,
|
'doom_type': 85,
|
||||||
'region': "The Aquifer (E3M9) Green"},
|
'region': "The Aquifier (E3M9) Green"},
|
||||||
371554: {'name': 'The Aquifer (E3M9) - Firemace',
|
371554: {'name': 'The Aquifier (E3M9) - Firemace',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 478,
|
'index': 478,
|
||||||
'doom_type': 2002,
|
'doom_type': 2002,
|
||||||
'region': "The Aquifer (E3M9) Green"},
|
'region': "The Aquifier (E3M9) Green"},
|
||||||
371555: {'name': 'The Aquifer (E3M9) - Firemace 2',
|
371555: {'name': 'The Aquifier (E3M9) - Firemace 2',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 526,
|
'index': 526,
|
||||||
'doom_type': 2002,
|
'doom_type': 2002,
|
||||||
'region': "The Aquifer (E3M9) Green"},
|
'region': "The Aquifier (E3M9) Green"},
|
||||||
371556: {'name': 'The Aquifer (E3M9) - Firemace 3',
|
371556: {'name': 'The Aquifier (E3M9) - Firemace 3',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 527,
|
'index': 527,
|
||||||
'doom_type': 2002,
|
'doom_type': 2002,
|
||||||
'region': "The Aquifer (E3M9) Green"},
|
'region': "The Aquifier (E3M9) Green"},
|
||||||
371557: {'name': 'The Aquifer (E3M9) - Firemace 4',
|
371557: {'name': 'The Aquifier (E3M9) - Firemace 4',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': True,
|
'check_sanity': True,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': 528,
|
'index': 528,
|
||||||
'doom_type': 2002,
|
'doom_type': 2002,
|
||||||
'region': "The Aquifer (E3M9) Yellow"},
|
'region': "The Aquifier (E3M9) Yellow"},
|
||||||
371558: {'name': 'The Aquifer (E3M9) - Exit',
|
371558: {'name': 'The Aquifier (E3M9) - Exit',
|
||||||
'episode': 3,
|
'episode': 3,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 9,
|
'map': 9,
|
||||||
'index': -1,
|
'index': -1,
|
||||||
'doom_type': -1,
|
'doom_type': -1,
|
||||||
'region': "The Aquifer (E3M9) Blue"},
|
'region': "The Aquifier (E3M9) Blue"},
|
||||||
371559: {'name': 'Catafalque (E4M1) - Yellow key',
|
371559: {'name': 'Catafalque (E4M1) - Yellow key',
|
||||||
'episode': 4,
|
'episode': 4,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
@@ -5963,7 +5963,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 3,
|
'map': 3,
|
||||||
'index': 213,
|
'index': 213,
|
||||||
'doom_type': 2005,
|
'doom_type': 2005,
|
||||||
'region': "Quay (E5M3) Blue"},
|
'region': "Quay (E5M3) Main"},
|
||||||
371850: {'name': 'Quay (E5M3) - Dragon Claw',
|
371850: {'name': 'Quay (E5M3) - Dragon Claw',
|
||||||
'episode': 5,
|
'episode': 5,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
@@ -6145,7 +6145,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 4,
|
'map': 4,
|
||||||
'index': 3,
|
'index': 3,
|
||||||
'doom_type': 79,
|
'doom_type': 79,
|
||||||
'region': "Courtyard (E5M4) Green"},
|
'region': "Courtyard (E5M4) Main"},
|
||||||
371876: {'name': 'Courtyard (E5M4) - Yellow key',
|
371876: {'name': 'Courtyard (E5M4) - Yellow key',
|
||||||
'episode': 5,
|
'episode': 5,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
@@ -6159,7 +6159,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 4,
|
'map': 4,
|
||||||
'index': 21,
|
'index': 21,
|
||||||
'doom_type': 73,
|
'doom_type': 73,
|
||||||
'region': "Courtyard (E5M4) Yellow"},
|
'region': "Courtyard (E5M4) Kakis"},
|
||||||
371878: {'name': 'Courtyard (E5M4) - Gauntlets of the Necromancer',
|
371878: {'name': 'Courtyard (E5M4) - Gauntlets of the Necromancer',
|
||||||
'episode': 5,
|
'episode': 5,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
@@ -6187,14 +6187,14 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 4,
|
'map': 4,
|
||||||
'index': 87,
|
'index': 87,
|
||||||
'doom_type': 2004,
|
'doom_type': 2004,
|
||||||
'region': "Courtyard (E5M4) Yellow"},
|
'region': "Courtyard (E5M4) Kakis"},
|
||||||
371882: {'name': 'Courtyard (E5M4) - Phoenix Rod',
|
371882: {'name': 'Courtyard (E5M4) - Phoenix Rod',
|
||||||
'episode': 5,
|
'episode': 5,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 4,
|
'map': 4,
|
||||||
'index': 88,
|
'index': 88,
|
||||||
'doom_type': 2003,
|
'doom_type': 2003,
|
||||||
'region': "Courtyard (E5M4) Green"},
|
'region': "Courtyard (E5M4) Main"},
|
||||||
371883: {'name': 'Courtyard (E5M4) - Morph Ovum',
|
371883: {'name': 'Courtyard (E5M4) - Morph Ovum',
|
||||||
'episode': 5,
|
'episode': 5,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
@@ -6229,7 +6229,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 4,
|
'map': 4,
|
||||||
'index': 104,
|
'index': 104,
|
||||||
'doom_type': 84,
|
'doom_type': 84,
|
||||||
'region': "Courtyard (E5M4) Yellow"},
|
'region': "Courtyard (E5M4) Kakis"},
|
||||||
371888: {'name': 'Courtyard (E5M4) - Shadowsphere',
|
371888: {'name': 'Courtyard (E5M4) - Shadowsphere',
|
||||||
'episode': 5,
|
'episode': 5,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
@@ -6250,14 +6250,14 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 4,
|
'map': 4,
|
||||||
'index': 107,
|
'index': 107,
|
||||||
'doom_type': 35,
|
'doom_type': 35,
|
||||||
'region': "Courtyard (E5M4) Yellow"},
|
'region': "Courtyard (E5M4) Kakis"},
|
||||||
371891: {'name': 'Courtyard (E5M4) - Chaos Device',
|
371891: {'name': 'Courtyard (E5M4) - Chaos Device',
|
||||||
'episode': 5,
|
'episode': 5,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
'map': 4,
|
'map': 4,
|
||||||
'index': 108,
|
'index': 108,
|
||||||
'doom_type': 36,
|
'doom_type': 36,
|
||||||
'region': "Courtyard (E5M4) Green"},
|
'region': "Courtyard (E5M4) Main"},
|
||||||
371892: {'name': 'Courtyard (E5M4) - Tome of Power',
|
371892: {'name': 'Courtyard (E5M4) - Tome of Power',
|
||||||
'episode': 5,
|
'episode': 5,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
@@ -6278,7 +6278,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 4,
|
'map': 4,
|
||||||
'index': 111,
|
'index': 111,
|
||||||
'doom_type': 86,
|
'doom_type': 86,
|
||||||
'region': "Courtyard (E5M4) Yellow"},
|
'region': "Courtyard (E5M4) Kakis"},
|
||||||
371895: {'name': 'Courtyard (E5M4) - Torch',
|
371895: {'name': 'Courtyard (E5M4) - Torch',
|
||||||
'episode': 5,
|
'episode': 5,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
@@ -6299,7 +6299,7 @@ location_table: Dict[int, LocationDict] = {
|
|||||||
'map': 4,
|
'map': 4,
|
||||||
'index': 219,
|
'index': 219,
|
||||||
'doom_type': 85,
|
'doom_type': 85,
|
||||||
'region': "Courtyard (E5M4) Yellow"},
|
'region': "Courtyard (E5M4) Kakis"},
|
||||||
371898: {'name': 'Courtyard (E5M4) - Bag of Holding 3',
|
371898: {'name': 'Courtyard (E5M4) - Bag of Holding 3',
|
||||||
'episode': 5,
|
'episode': 5,
|
||||||
'check_sanity': False,
|
'check_sanity': False,
|
||||||
@@ -7247,23 +7247,23 @@ location_name_groups: Dict[str, Set[str]] = {
|
|||||||
'Courtyard (E5M4) - Torch',
|
'Courtyard (E5M4) - Torch',
|
||||||
'Courtyard (E5M4) - Yellow key',
|
'Courtyard (E5M4) - Yellow key',
|
||||||
},
|
},
|
||||||
"D'Sparil's Keep (E3M8)": {
|
"D'Sparil'S Keep (E3M8)": {
|
||||||
"D'Sparil's Keep (E3M8) - Bag of Holding",
|
"D'Sparil'S Keep (E3M8) - Bag of Holding",
|
||||||
"D'Sparil's Keep (E3M8) - Chaos Device",
|
"D'Sparil'S Keep (E3M8) - Chaos Device",
|
||||||
"D'Sparil's Keep (E3M8) - Dragon Claw",
|
"D'Sparil'S Keep (E3M8) - Dragon Claw",
|
||||||
"D'Sparil's Keep (E3M8) - Enchanted Shield",
|
"D'Sparil'S Keep (E3M8) - Enchanted Shield",
|
||||||
"D'Sparil's Keep (E3M8) - Ethereal Crossbow",
|
"D'Sparil'S Keep (E3M8) - Ethereal Crossbow",
|
||||||
"D'Sparil's Keep (E3M8) - Exit",
|
"D'Sparil'S Keep (E3M8) - Exit",
|
||||||
"D'Sparil's Keep (E3M8) - Gauntlets of the Necromancer",
|
"D'Sparil'S Keep (E3M8) - Gauntlets of the Necromancer",
|
||||||
"D'Sparil's Keep (E3M8) - Hellstaff",
|
"D'Sparil'S Keep (E3M8) - Hellstaff",
|
||||||
"D'Sparil's Keep (E3M8) - Mystic Urn",
|
"D'Sparil'S Keep (E3M8) - Mystic Urn",
|
||||||
"D'Sparil's Keep (E3M8) - Phoenix Rod",
|
"D'Sparil'S Keep (E3M8) - Phoenix Rod",
|
||||||
"D'Sparil's Keep (E3M8) - Ring of Invincibility",
|
"D'Sparil'S Keep (E3M8) - Ring of Invincibility",
|
||||||
"D'Sparil's Keep (E3M8) - Shadowsphere",
|
"D'Sparil'S Keep (E3M8) - Shadowsphere",
|
||||||
"D'Sparil's Keep (E3M8) - Silver Shield",
|
"D'Sparil'S Keep (E3M8) - Silver Shield",
|
||||||
"D'Sparil's Keep (E3M8) - Tome of Power",
|
"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 2",
|
||||||
"D'Sparil's Keep (E3M8) - Tome of Power 3",
|
"D'Sparil'S Keep (E3M8) - Tome of Power 3",
|
||||||
},
|
},
|
||||||
'Field of Judgement (E5M8)': {
|
'Field of Judgement (E5M8)': {
|
||||||
'Field of Judgement (E5M8) - Bag of Holding',
|
'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) - Torch",
|
||||||
"Skein of D'Sparil (E5M9) - Yellow key",
|
"Skein of D'Sparil (E5M9) - Yellow key",
|
||||||
},
|
},
|
||||||
'The Aquifer (E3M9)': {
|
'The Aquifier (E3M9)': {
|
||||||
'The Aquifer (E3M9) - Bag of Holding',
|
'The Aquifier (E3M9) - Bag of Holding',
|
||||||
'The Aquifer (E3M9) - Blue key',
|
'The Aquifier (E3M9) - Blue key',
|
||||||
'The Aquifer (E3M9) - Chaos Device',
|
'The Aquifier (E3M9) - Chaos Device',
|
||||||
'The Aquifer (E3M9) - Dragon Claw',
|
'The Aquifier (E3M9) - Dragon Claw',
|
||||||
'The Aquifer (E3M9) - Enchanted Shield',
|
'The Aquifier (E3M9) - Enchanted Shield',
|
||||||
'The Aquifer (E3M9) - Ethereal Crossbow',
|
'The Aquifier (E3M9) - Ethereal Crossbow',
|
||||||
'The Aquifer (E3M9) - Exit',
|
'The Aquifier (E3M9) - Exit',
|
||||||
'The Aquifer (E3M9) - Firemace',
|
'The Aquifier (E3M9) - Firemace',
|
||||||
'The Aquifer (E3M9) - Firemace 2',
|
'The Aquifier (E3M9) - Firemace 2',
|
||||||
'The Aquifer (E3M9) - Firemace 3',
|
'The Aquifier (E3M9) - Firemace 3',
|
||||||
'The Aquifer (E3M9) - Firemace 4',
|
'The Aquifier (E3M9) - Firemace 4',
|
||||||
'The Aquifer (E3M9) - Gauntlets of the Necromancer',
|
'The Aquifier (E3M9) - Gauntlets of the Necromancer',
|
||||||
'The Aquifer (E3M9) - Green key',
|
'The Aquifier (E3M9) - Green key',
|
||||||
'The Aquifer (E3M9) - Hellstaff',
|
'The Aquifier (E3M9) - Hellstaff',
|
||||||
'The Aquifer (E3M9) - Map Scroll',
|
'The Aquifier (E3M9) - Map Scroll',
|
||||||
'The Aquifer (E3M9) - Morph Ovum',
|
'The Aquifier (E3M9) - Morph Ovum',
|
||||||
'The Aquifer (E3M9) - Mystic Urn',
|
'The Aquifier (E3M9) - Mystic Urn',
|
||||||
'The Aquifer (E3M9) - Phoenix Rod',
|
'The Aquifier (E3M9) - Phoenix Rod',
|
||||||
'The Aquifer (E3M9) - Ring of Invincibility',
|
'The Aquifier (E3M9) - Ring of Invincibility',
|
||||||
'The Aquifer (E3M9) - Shadowsphere',
|
'The Aquifier (E3M9) - Shadowsphere',
|
||||||
'The Aquifer (E3M9) - Silver Shield',
|
'The Aquifier (E3M9) - Silver Shield',
|
||||||
'The Aquifer (E3M9) - Silver Shield 2',
|
'The Aquifier (E3M9) - Silver Shield 2',
|
||||||
'The Aquifer (E3M9) - Tome of Power',
|
'The Aquifier (E3M9) - Tome of Power',
|
||||||
'The Aquifer (E3M9) - Tome of Power 2',
|
'The Aquifier (E3M9) - Tome of Power 2',
|
||||||
'The Aquifer (E3M9) - Torch',
|
'The Aquifier (E3M9) - Torch',
|
||||||
'The Aquifer (E3M9) - Yellow key',
|
'The Aquifier (E3M9) - Yellow key',
|
||||||
},
|
},
|
||||||
'The Azure Fortress (E3M4)': {
|
'The Azure Fortress (E3M4)': {
|
||||||
'The Azure Fortress (E3M4) - Bag of Holding',
|
'The Azure Fortress (E3M4) - Bag of Holding',
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ map_names: List[str] = [
|
|||||||
'The Ophidian Lair (E3M5)',
|
'The Ophidian Lair (E3M5)',
|
||||||
'The Halls of Fear (E3M6)',
|
'The Halls of Fear (E3M6)',
|
||||||
'The Chasm (E3M7)',
|
'The Chasm (E3M7)',
|
||||||
"D'Sparil's Keep (E3M8)",
|
"D'Sparil'S Keep (E3M8)",
|
||||||
'The Aquifer (E3M9)',
|
'The Aquifier (E3M9)',
|
||||||
'Catafalque (E4M1)',
|
'Catafalque (E4M1)',
|
||||||
'Blockhouse (E4M2)',
|
'Blockhouse (E4M2)',
|
||||||
'Ambulatory (E4M3)',
|
'Ambulatory (E4M3)',
|
||||||
|
|||||||
@@ -520,34 +520,34 @@ regions:List[RegionDict] = [
|
|||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[{"target":"The Chasm (E3M7) Yellow","pro":False}]},
|
"connections":[{"target":"The Chasm (E3M7) Yellow","pro":False}]},
|
||||||
|
|
||||||
# D'Sparil's Keep (E3M8)
|
# D'Sparil'S Keep (E3M8)
|
||||||
{"name":"D'Sparil's Keep (E3M8) Main",
|
{"name":"D'Sparil'S Keep (E3M8) Main",
|
||||||
"connects_to_hub":True,
|
"connects_to_hub":True,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[]},
|
"connections":[]},
|
||||||
|
|
||||||
# The Aquifer (E3M9)
|
# The Aquifier (E3M9)
|
||||||
{"name":"The Aquifer (E3M9) Main",
|
{"name":"The Aquifier (E3M9) Main",
|
||||||
"connects_to_hub":True,
|
"connects_to_hub":True,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[{"target":"The Aquifer (E3M9) Yellow","pro":False}]},
|
"connections":[{"target":"The Aquifier (E3M9) Yellow","pro":False}]},
|
||||||
{"name":"The Aquifer (E3M9) Blue",
|
{"name":"The Aquifier (E3M9) Blue",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[]},
|
"connections":[]},
|
||||||
{"name":"The Aquifer (E3M9) Yellow",
|
{"name":"The Aquifier (E3M9) Yellow",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[
|
"connections":[
|
||||||
{"target":"The Aquifer (E3M9) Green","pro":False},
|
{"target":"The Aquifier (E3M9) Green","pro":False},
|
||||||
{"target":"The Aquifer (E3M9) Main","pro":False}]},
|
{"target":"The Aquifier (E3M9) Main","pro":False}]},
|
||||||
{"name":"The Aquifer (E3M9) Green",
|
{"name":"The Aquifier (E3M9) Green",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":3,
|
"episode":3,
|
||||||
"connections":[
|
"connections":[
|
||||||
{"target":"The Aquifer (E3M9) Yellow","pro":False},
|
{"target":"The Aquifier (E3M9) Yellow","pro":False},
|
||||||
{"target":"The Aquifer (E3M9) Main","pro":False},
|
{"target":"The Aquifier (E3M9) Main","pro":False},
|
||||||
{"target":"The Aquifer (E3M9) Blue","pro":False}]},
|
{"target":"The Aquifier (E3M9) Blue","pro":False}]},
|
||||||
|
|
||||||
# Catafalque (E4M1)
|
# Catafalque (E4M1)
|
||||||
{"name":"Catafalque (E4M1) Main",
|
{"name":"Catafalque (E4M1) Main",
|
||||||
@@ -795,22 +795,16 @@ regions:List[RegionDict] = [
|
|||||||
"connects_to_hub":True,
|
"connects_to_hub":True,
|
||||||
"episode":5,
|
"episode":5,
|
||||||
"connections":[
|
"connections":[
|
||||||
{"target":"Courtyard (E5M4) Yellow","pro":False},
|
{"target":"Courtyard (E5M4) Kakis","pro":False},
|
||||||
{"target":"Courtyard (E5M4) Blue","pro":False}]},
|
{"target":"Courtyard (E5M4) Blue","pro":False}]},
|
||||||
{"name":"Courtyard (E5M4) Blue",
|
{"name":"Courtyard (E5M4) Blue",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":5,
|
"episode":5,
|
||||||
"connections":[{"target":"Courtyard (E5M4) Main","pro":False}]},
|
"connections":[{"target":"Courtyard (E5M4) Main","pro":False}]},
|
||||||
{"name":"Courtyard (E5M4) Yellow",
|
{"name":"Courtyard (E5M4) Kakis",
|
||||||
"connects_to_hub":False,
|
"connects_to_hub":False,
|
||||||
"episode":5,
|
"episode":5,
|
||||||
"connections":[
|
"connections":[{"target":"Courtyard (E5M4) Main","pro":False}]},
|
||||||
{"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)
|
# Hydratyr (E5M5)
|
||||||
{"name":"Hydratyr (E5M5) Main",
|
{"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:
|
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))
|
state.has("The Chasm (E3M7) - Green key", player, 1))
|
||||||
|
|
||||||
# D'Sparil's Keep (E3M8)
|
# D'Sparil'S Keep (E3M8)
|
||||||
set_rule(multiworld.get_entrance("Hub -> D'Sparil's Keep (E3M8) Main", player), lambda state:
|
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("D'Sparil'S Keep (E3M8)", player, 1) and
|
||||||
state.has("Gauntlets of the Necromancer", player, 1) and
|
state.has("Gauntlets of the Necromancer", player, 1) and
|
||||||
state.has("Ethereal Crossbow", player, 1) and
|
state.has("Ethereal Crossbow", player, 1) and
|
||||||
state.has("Dragon Claw", 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("Firemace", player, 1) and
|
||||||
state.has("Hellstaff", player, 1))
|
state.has("Hellstaff", player, 1))
|
||||||
|
|
||||||
# The Aquifer (E3M9)
|
# The Aquifier (E3M9)
|
||||||
set_rule(multiworld.get_entrance("Hub -> The Aquifer (E3M9) Main", player), lambda state:
|
set_rule(multiworld.get_entrance("Hub -> The Aquifier (E3M9) Main", player), lambda state:
|
||||||
state.has("The Aquifer (E3M9)", player, 1) and
|
state.has("The Aquifier (E3M9)", player, 1) and
|
||||||
state.has("Gauntlets of the Necromancer", player, 1) and
|
state.has("Gauntlets of the Necromancer", player, 1) and
|
||||||
state.has("Ethereal Crossbow", player, 1) and
|
state.has("Ethereal Crossbow", player, 1) and
|
||||||
state.has("Dragon Claw", player, 1) and
|
state.has("Dragon Claw", player, 1) and
|
||||||
state.has("Phoenix Rod", player, 1) and
|
state.has("Phoenix Rod", player, 1) and
|
||||||
state.has("Firemace", player, 1) and
|
state.has("Firemace", player, 1) and
|
||||||
state.has("Hellstaff", player, 1))
|
state.has("Hellstaff", player, 1))
|
||||||
set_rule(multiworld.get_entrance("The Aquifer (E3M9) Main -> The Aquifer (E3M9) Yellow", player), lambda state:
|
set_rule(multiworld.get_entrance("The Aquifier (E3M9) Main -> The Aquifier (E3M9) Yellow", player), lambda state:
|
||||||
state.has("The Aquifer (E3M9) - Yellow key", player, 1))
|
state.has("The Aquifier (E3M9) - Yellow key", player, 1))
|
||||||
set_rule(multiworld.get_entrance("The Aquifer (E3M9) Yellow -> The Aquifer (E3M9) Green", player), lambda state:
|
set_rule(multiworld.get_entrance("The Aquifier (E3M9) Yellow -> The Aquifier (E3M9) Green", player), lambda state:
|
||||||
state.has("The Aquifer (E3M9) - Green key", player, 1))
|
state.has("The Aquifier (E3M9) - Green key", player, 1))
|
||||||
set_rule(multiworld.get_entrance("The Aquifer (E3M9) Yellow -> The Aquifer (E3M9) Main", player), lambda state:
|
set_rule(multiworld.get_entrance("The Aquifier (E3M9) Yellow -> The Aquifier (E3M9) Main", player), lambda state:
|
||||||
state.has("The Aquifer (E3M9) - Yellow key", player, 1))
|
state.has("The Aquifier (E3M9) - Yellow key", player, 1))
|
||||||
set_rule(multiworld.get_entrance("The Aquifer (E3M9) Green -> The Aquifer (E3M9) Yellow", player), lambda state:
|
set_rule(multiworld.get_entrance("The Aquifier (E3M9) Green -> The Aquifier (E3M9) Yellow", player), lambda state:
|
||||||
state.has("The Aquifer (E3M9) - Green key", player, 1))
|
state.has("The Aquifier (E3M9) - Green key", player, 1))
|
||||||
|
|
||||||
|
|
||||||
def set_episode4_rules(player, multiworld, pro):
|
def set_episode4_rules(player, multiworld, pro):
|
||||||
@@ -623,17 +623,15 @@ def set_episode5_rules(player, multiworld, pro):
|
|||||||
(state.has("Phoenix Rod", player, 1) or
|
(state.has("Phoenix Rod", player, 1) or
|
||||||
state.has("Firemace", player, 1) or
|
state.has("Firemace", player, 1) or
|
||||||
state.has("Hellstaff", player, 1)))
|
state.has("Hellstaff", player, 1)))
|
||||||
set_rule(multiworld.get_entrance("Courtyard (E5M4) Main -> Courtyard (E5M4) Yellow", player), lambda state:
|
set_rule(multiworld.get_entrance("Courtyard (E5M4) Main -> Courtyard (E5M4) Kakis", player), lambda state:
|
||||||
state.has("Courtyard (E5M4) - Yellow key", player, 1))
|
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) Blue", player), lambda state:
|
set_rule(multiworld.get_entrance("Courtyard (E5M4) Main -> Courtyard (E5M4) Blue", player), lambda state:
|
||||||
state.has("Courtyard (E5M4) - Blue key", player, 1))
|
state.has("Courtyard (E5M4) - Blue key", player, 1))
|
||||||
set_rule(multiworld.get_entrance("Courtyard (E5M4) Blue -> Courtyard (E5M4) Main", player), lambda state:
|
set_rule(multiworld.get_entrance("Courtyard (E5M4) Blue -> Courtyard (E5M4) Main", player), lambda state:
|
||||||
state.has("Courtyard (E5M4) - Blue key", player, 1))
|
state.has("Courtyard (E5M4) - Blue key", player, 1))
|
||||||
set_rule(multiworld.get_entrance("Courtyard (E5M4) Yellow -> Courtyard (E5M4) Main", player), lambda state:
|
set_rule(multiworld.get_entrance("Courtyard (E5M4) Kakis -> Courtyard (E5M4) Main", player), lambda state:
|
||||||
state.has("Courtyard (E5M4) - Yellow key", player, 1))
|
state.has("Courtyard (E5M4) - Yellow key", player, 1) or
|
||||||
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))
|
state.has("Courtyard (E5M4) - Green key", player, 1))
|
||||||
|
|
||||||
# Hydratyr (E5M5)
|
# 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_to_id = {data["name"]: loc_id for loc_id, data in Locations.location_table.items()}
|
||||||
location_name_groups = Locations.location_name_groups
|
location_name_groups = Locations.location_name_groups
|
||||||
|
|
||||||
starting_level_for_episode: Dict[int, str] = {
|
starting_level_for_episode: List[str] = [
|
||||||
1: "The Docks (E1M1)",
|
"The Docks (E1M1)",
|
||||||
2: "The Crater (E2M1)",
|
"The Crater (E2M1)",
|
||||||
3: "The Storehouse (E3M1)",
|
"The Storehouse (E3M1)",
|
||||||
4: "Catafalque (E4M1)",
|
"Catafalque (E4M1)",
|
||||||
5: "Ochre Cliffs (E5M1)"
|
"Ochre Cliffs (E5M1)"
|
||||||
}
|
]
|
||||||
|
|
||||||
all_boss_levels: List[str] = [
|
boss_level_for_episode: List[str] = [
|
||||||
"Hell's Maw (E1M8)",
|
"Hell's Maw (E1M8)",
|
||||||
"The Portals of Chaos (E2M8)",
|
"The Portals of Chaos (E2M8)",
|
||||||
"D'Sparil's Keep (E3M8)",
|
"D'Sparil'S Keep (E3M8)",
|
||||||
"Shattered Bridge (E4M8)",
|
"Shattered Bridge (E4M8)",
|
||||||
"Field of Judgement (E5M8)"
|
"Field of Judgement (E5M8)"
|
||||||
]
|
]
|
||||||
@@ -82,7 +82,6 @@ class HereticWorld(World):
|
|||||||
def __init__(self, multiworld: MultiWorld, player: int):
|
def __init__(self, multiworld: MultiWorld, player: int):
|
||||||
self.included_episodes = [1, 1, 1, 0, 0]
|
self.included_episodes = [1, 1, 1, 0, 0]
|
||||||
self.location_count = 0
|
self.location_count = 0
|
||||||
self.starting_levels = []
|
|
||||||
|
|
||||||
super().__init__(multiworld, player)
|
super().__init__(multiworld, player)
|
||||||
|
|
||||||
@@ -101,14 +100,6 @@ class HereticWorld(World):
|
|||||||
if self.get_episode_count() == 0:
|
if self.get_episode_count() == 0:
|
||||||
self.included_episodes[0] = 1
|
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):
|
def create_regions(self):
|
||||||
pro = self.options.pro.value
|
pro = self.options.pro.value
|
||||||
check_sanity = self.options.check_sanity.value
|
check_sanity = self.options.check_sanity.value
|
||||||
@@ -163,7 +154,7 @@ class HereticWorld(World):
|
|||||||
def completion_rule(self, state: CollectionState):
|
def completion_rule(self, state: CollectionState):
|
||||||
goal_levels = Maps.map_names
|
goal_levels = Maps.map_names
|
||||||
if self.options.goal.value:
|
if self.options.goal.value:
|
||||||
goal_levels = self.all_boss_levels
|
goal_levels = self.boss_level_for_episode
|
||||||
|
|
||||||
for map_name in goal_levels:
|
for map_name in goal_levels:
|
||||||
if map_name + " - Exit" not in self.location_name_to_id:
|
if map_name + " - Exit" not in self.location_name_to_id:
|
||||||
@@ -212,7 +203,7 @@ class HereticWorld(World):
|
|||||||
if item["episode"] != -1 and not self.included_episodes[item["episode"] - 1]:
|
if item["episode"] != -1 and not self.included_episodes[item["episode"] - 1]:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
count = item["count"] if item["name"] not in self.starting_levels else item["count"] - 1
|
count = item["count"] if item["name"] not in self.starting_level_for_episode else item["count"] - 1
|
||||||
itempool += [self.create_item(item["name"]) for _ in range(count)]
|
itempool += [self.create_item(item["name"]) for _ in range(count)]
|
||||||
|
|
||||||
# Bag(s) of Holding based on options
|
# Bag(s) of Holding based on options
|
||||||
@@ -245,8 +236,9 @@ class HereticWorld(World):
|
|||||||
self.location_count -= 1
|
self.location_count -= 1
|
||||||
|
|
||||||
# Give starting levels right away
|
# Give starting levels right away
|
||||||
for map_name in self.starting_levels:
|
for i in range(len(self.included_episodes)):
|
||||||
self.multiworld.push_precollected(self.create_item(map_name))
|
if self.included_episodes[i]:
|
||||||
|
self.multiworld.push_precollected(self.create_item(self.starting_level_for_episode[i]))
|
||||||
|
|
||||||
# Give Computer area maps if option selected
|
# Give Computer area maps if option selected
|
||||||
if self.options.start_with_map_scrolls.value:
|
if self.options.start_with_map_scrolls.value:
|
||||||
|
|||||||
@@ -8,14 +8,8 @@
|
|||||||
|
|
||||||
## Installing the Archipelago Mod using Lumafly
|
## Installing the Archipelago Mod using Lumafly
|
||||||
1. Launch Lumafly and ensure it locates your Hollow Knight installation directory.
|
1. Launch Lumafly and ensure it locates your Hollow Knight installation directory.
|
||||||
2. Install the Archipelago mods by doing either of the following:
|
2. Click the "Install" button near the "Archipelago" mod entry.
|
||||||
* Click one of the links below to allow Lumafly to install the mods. Lumafly will prompt for confirmation.
|
* If desired, also install "Archipelago Map Mod" to use as an in-game tracker.
|
||||||
* [Archipelago and dependencies only](https://themulhima.github.io/Lumafly/commands/download/?mods=Archipelago)
|
|
||||||
* [Archipelago with rando essentials](https://themulhima.github.io/Lumafly/commands/download/?mods=Archipelago/Archipelago%20Map%20Mod/RecentItemsDisplay/DebugMod/RandoStats/Additional%20Timelines/CompassAlwaysOn/AdditionalMaps/)
|
|
||||||
(includes Archipelago Map Mod, RecentItemsDisplay, DebugMod, RandoStats, AdditionalTimelines, CompassAlwaysOn,
|
|
||||||
and AdditionalMaps).
|
|
||||||
* Click the "Install" button near the "Archipelago" mod entry. If desired, also install "Archipelago Map Mod"
|
|
||||||
to use as an in-game tracker.
|
|
||||||
3. Launch the game, you're all set!
|
3. Launch the game, you're all set!
|
||||||
|
|
||||||
### What to do if Lumafly fails to find your installation directory
|
### What to do if Lumafly fails to find your installation directory
|
||||||
|
|||||||
@@ -295,6 +295,6 @@ def launch():
|
|||||||
parser = get_base_parser(description="KH1 Client, for text interfacing.")
|
parser = get_base_parser(description="KH1 Client, for text interfacing.")
|
||||||
|
|
||||||
args, rest = parser.parse_known_args()
|
args, rest = parser.parse_known_args()
|
||||||
colorama.just_fix_windows_console()
|
colorama.init()
|
||||||
asyncio.run(main(args))
|
asyncio.run(main(args))
|
||||||
colorama.deinit()
|
colorama.deinit()
|
||||||
|
|||||||
@@ -981,6 +981,6 @@ def launch():
|
|||||||
parser = get_base_parser(description="KH2 Client, for text interfacing.")
|
parser = get_base_parser(description="KH2 Client, for text interfacing.")
|
||||||
|
|
||||||
args, rest = parser.parse_known_args()
|
args, rest = parser.parse_known_args()
|
||||||
colorama.just_fix_windows_console()
|
colorama.init()
|
||||||
asyncio.run(main(args))
|
asyncio.run(main(args))
|
||||||
colorama.deinit()
|
colorama.deinit()
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Pymem>=1.10.0
|
Pymem>=1.10.0
|
||||||
@@ -107,7 +107,6 @@ SYNONYMS = {
|
|||||||
'JUMP': 'FEATHER',
|
'JUMP': 'FEATHER',
|
||||||
'PLUME': 'FEATHER',
|
'PLUME': 'FEATHER',
|
||||||
'WING': 'FEATHER',
|
'WING': 'FEATHER',
|
||||||
"QUILL": "FEATHER",
|
|
||||||
|
|
||||||
# SHOVEL
|
# SHOVEL
|
||||||
'DIG': 'SHOVEL',
|
'DIG': 'SHOVEL',
|
||||||
@@ -344,8 +343,6 @@ SYNONYMS = {
|
|||||||
# TRADING_ITEM_LETTER
|
# TRADING_ITEM_LETTER
|
||||||
'CARD': 'TRADING_ITEM_LETTER',
|
'CARD': 'TRADING_ITEM_LETTER',
|
||||||
'MESSAGE': 'TRADING_ITEM_LETTER',
|
'MESSAGE': 'TRADING_ITEM_LETTER',
|
||||||
"TICKET": 'TRADING_ITEM_LETTER',
|
|
||||||
"PASS": 'TRADING_ITEM_LETTER',
|
|
||||||
|
|
||||||
# TRADING_ITEM_BROOM
|
# TRADING_ITEM_BROOM
|
||||||
'SWEEP': 'TRADING_ITEM_BROOM',
|
'SWEEP': 'TRADING_ITEM_BROOM',
|
||||||
@@ -368,8 +365,6 @@ SYNONYMS = {
|
|||||||
'MIRROR': 'TRADING_ITEM_MAGNIFYING_GLASS',
|
'MIRROR': 'TRADING_ITEM_MAGNIFYING_GLASS',
|
||||||
'SCOPE': 'TRADING_ITEM_MAGNIFYING_GLASS',
|
'SCOPE': 'TRADING_ITEM_MAGNIFYING_GLASS',
|
||||||
'XRAY': 'TRADING_ITEM_MAGNIFYING_GLASS',
|
'XRAY': 'TRADING_ITEM_MAGNIFYING_GLASS',
|
||||||
"DETECTOR": 'TRADING_ITEM_MAGNIFYING_GLASS',
|
|
||||||
"ITEMFINDER": 'TRADING_ITEM_MAGNIFYING_GLASS',
|
|
||||||
|
|
||||||
# PIECE_OF_POWER
|
# PIECE_OF_POWER
|
||||||
'TRIANGLE': 'PIECE_OF_POWER',
|
'TRIANGLE': 'PIECE_OF_POWER',
|
||||||
@@ -383,7 +378,6 @@ PHRASES = {
|
|||||||
'BOSS KEY': 'NIGHTMARE_KEY',
|
'BOSS KEY': 'NIGHTMARE_KEY',
|
||||||
'HEART PIECE': 'HEART_PIECE',
|
'HEART PIECE': 'HEART_PIECE',
|
||||||
'PIECE OF HEART': 'HEART_PIECE',
|
'PIECE OF HEART': 'HEART_PIECE',
|
||||||
"ROCK SMASH": 'BOMB',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# All following will only be used to match items for the specific game.
|
# All following will only be used to match items for the specific game.
|
||||||
@@ -410,16 +404,6 @@ GAME_SPECIFIC_PHRASES = {
|
|||||||
|
|
||||||
'Ocarina of Time': {
|
'Ocarina of Time': {
|
||||||
'COJIRO': 'ROOSTER',
|
'COJIRO': 'ROOSTER',
|
||||||
"Goron Tunic": "RED_TUNIC",
|
|
||||||
"Zora Tunic": "BLUE_TUNIC",
|
|
||||||
"Wallet": "MAGIC_POWDER",
|
|
||||||
"Medallion": "PIECE_OF_POWER",
|
|
||||||
"Kokiri Emerald": "RUPEES_500",
|
|
||||||
"Goron Ruby": "RUPEES_500",
|
|
||||||
"Zora Sapphire": "RUPEES_500",
|
|
||||||
"Dins Fire": "MAGIC_ROD", # Fire shield
|
|
||||||
"Nayrus Love": "MAGIC_ROD", # Protective barrier
|
|
||||||
"Farores Wind": "MAGIC_ROD", # Create/use warp point in dungeons
|
|
||||||
},
|
},
|
||||||
|
|
||||||
'SMZ3': {
|
'SMZ3': {
|
||||||
@@ -433,14 +417,10 @@ GAME_SPECIFIC_PHRASES = {
|
|||||||
|
|
||||||
'Sonic Adventure 2 Battle': {
|
'Sonic Adventure 2 Battle': {
|
||||||
'CHAOS EMERALD': 'PIECE_OF_POWER',
|
'CHAOS EMERALD': 'PIECE_OF_POWER',
|
||||||
"Rings": "RUPEES_20", # This should only affect filler Rings currency, not Flame Ring upgrade
|
|
||||||
"Grapes": "TRADING_ITEM_PINEAPPLE",
|
|
||||||
"Pick Nails": "SHOVEL", # Digging upgrade
|
|
||||||
},
|
},
|
||||||
|
|
||||||
'Super Mario 64': {
|
'Super Mario 64': {
|
||||||
'POWER STAR': 'PIECE_OF_POWER',
|
'POWER STAR': 'PIECE_OF_POWER',
|
||||||
"Key": "NIGHTMARE_KEY" # Affect 2nd Floor / Basement / Progressive keys
|
|
||||||
},
|
},
|
||||||
|
|
||||||
'Super Mario World': {
|
'Super Mario World': {
|
||||||
@@ -548,336 +528,4 @@ GAME_SPECIFIC_PHRASES = {
|
|||||||
'2500 Tokens': 'RUPEES_500',
|
'2500 Tokens': 'RUPEES_500',
|
||||||
'5000 Tokens': 'RUPEES_500',
|
'5000 Tokens': 'RUPEES_500',
|
||||||
},
|
},
|
||||||
|
|
||||||
"Donkey Kong Country 3": {
|
|
||||||
"Flupperius Petallus Pongus": "TRADING_ITEM_HIBISCUS", # It's a flower in the game
|
|
||||||
"Banana Bird": "ROOSTER", # Made sure this is a BIRD, not a BANANA
|
|
||||||
},
|
|
||||||
|
|
||||||
"Pokemon Red and Blue": {
|
|
||||||
|
|
||||||
# Key Items
|
|
||||||
|
|
||||||
"Old Amber": "STONE_BEAK", # Aerodactyl's fossil should still be a fossil
|
|
||||||
"Coin Case": "MAGIC_POWDER", # This shouldn't spawn as RUPEES
|
|
||||||
"Bike Voucher": "TRADING_ITEM_LETTER",
|
|
||||||
"Oak's Parcel": "TRADING_ITEM_LETTER",
|
|
||||||
|
|
||||||
# Drinks always get converted to MEDICINE
|
|
||||||
"Soda Pop": "MEDICINE",
|
|
||||||
"Fresh Water": "MEDICINE",
|
|
||||||
|
|
||||||
# Consumables
|
|
||||||
"Elixir": "MEDICINE",
|
|
||||||
"Ether": "MEDICINE",
|
|
||||||
"Antidote": "MEDICINE",
|
|
||||||
"Awakening": "MEDICINE",
|
|
||||||
"Burn Heal": "MEDICINE",
|
|
||||||
"Ice Heal": "MEDICINE",
|
|
||||||
"Paralyze Heal": "MEDICINE",
|
|
||||||
"Full Heal": "MEDICINE",
|
|
||||||
"Full Restore": "MEDICINE",
|
|
||||||
},
|
|
||||||
|
|
||||||
"Pokemon Emerald": {
|
|
||||||
|
|
||||||
"Coin Case": "MAGIC_POWDER", # This shouldn't spawn as RUPEES
|
|
||||||
|
|
||||||
# Drinks always get converted to MEDICINE
|
|
||||||
|
|
||||||
"Soda Pop": "MEDICINE",
|
|
||||||
"Fresh Water": "MEDICINE",
|
|
||||||
|
|
||||||
# Consumables
|
|
||||||
"Elixir": "MEDICINE",
|
|
||||||
"Ether": "MEDICINE",
|
|
||||||
"Antidote": "MEDICINE",
|
|
||||||
"Awakening": "MEDICINE",
|
|
||||||
"Burn Heal": "MEDICINE",
|
|
||||||
"Ice Heal": "MEDICINE",
|
|
||||||
"Paralyze Heal": "MEDICINE",
|
|
||||||
"Full Heal": "MEDICINE",
|
|
||||||
"Full Restore": "MEDICINE",
|
|
||||||
"Nanab Berry": "TRADING_ITEM_BANANAS", # Special exception for Nanab Berry, which look like bananas
|
|
||||||
"Berry": "TRADING_ITEM_PINEAPPLE",
|
|
||||||
"Mail": "TRADING_ITEM_LETTER", # Snail mail, not chain mail
|
|
||||||
},
|
|
||||||
|
|
||||||
"Mario & Luigi Superstar Saga": {
|
|
||||||
|
|
||||||
# Key Items
|
|
||||||
"Peach's Extra Dress": "RED_TUNIC",
|
|
||||||
"Peasley's Rose": "TRADING_ITEM_HIBISCUS",
|
|
||||||
"Beanstar": "PIECE_OF_POWER", # Hits both Fake Beanstar and pieces of the real Beanstar, hopefully
|
|
||||||
"Beanstone": "RUPEES_500", # They're gemstones
|
|
||||||
"Firebrand": "POWER_BRACELET", # Magic power that affects Mario/Luigi's hands, either this or MAGIC_ROD would be okay
|
|
||||||
"Thunderhand": "POWER_BRACELET", # Ditto
|
|
||||||
|
|
||||||
# 1-UP Super fix
|
|
||||||
"1-UP Super": "TOADSTOOL",
|
|
||||||
|
|
||||||
# Drinks --> medicine
|
|
||||||
|
|
||||||
# Syrup bottles
|
|
||||||
"Syrup": "MEDICINE",
|
|
||||||
|
|
||||||
# Coffee blends
|
|
||||||
"Hoolumbian": "MEDICINE",
|
|
||||||
"Chuckoccino": "MEDICINE",
|
|
||||||
"Teeheespresso": "MEDICINE",
|
|
||||||
"Blend": "MEDICINE", # for all coffee blends
|
|
||||||
|
|
||||||
# Secret Scrolls --> MESSAGE
|
|
||||||
"Secret Scroll": "TRADING_ITEM_LETTER",
|
|
||||||
|
|
||||||
# Goblets --> MEDICINE
|
|
||||||
"Goblet": "MEDICINE",
|
|
||||||
|
|
||||||
# Pearl Beans --> Fruit
|
|
||||||
"Pearl Bean": 'TRADING_ITEM_PINEAPPLE',
|
|
||||||
|
|
||||||
# Bros. Armor --> Blue Tunic
|
|
||||||
"Pants": "BLUE_TUNIC",
|
|
||||||
"Jeans": "BLUE_TUNIC",
|
|
||||||
"Trousers": "BLUE_TUNIC",
|
|
||||||
"Slacks": "BLUE_TUNIC",
|
|
||||||
"Casual Coral": "BLUE_TUNIC",
|
|
||||||
"Shroom Bells": "BLUE_TUNIC",
|
|
||||||
|
|
||||||
# Badges --> Ribbon
|
|
||||||
"Badge": "TRADING_ITEM_RIBBON",
|
|
||||||
"Soulful Bros.": "TRADING_ITEM_RIBBON",
|
|
||||||
"Bros. Rock": "TRADING_ITEM_RIBBON",
|
|
||||||
|
|
||||||
# Misc. Beans --> Acorns
|
|
||||||
"Hoo Bean": "GUARDIAN_ACORN", # Beans and nuts are similar enough, right?
|
|
||||||
"Chuckle Bean": "GUARDIAN_ACORN",
|
|
||||||
"Hee Bean": "GUARDIAN_ACORN",
|
|
||||||
"Woo Bean": "GUARDIAN_ACORN",
|
|
||||||
},
|
|
||||||
|
|
||||||
"DOOM 1993": {
|
|
||||||
"Keycard": "KEY",
|
|
||||||
"Computer area map": "MAP",
|
|
||||||
"Box of": "SINGLE_ARROW", # bullets, rockets, or shotgun shells
|
|
||||||
"Energy cell pack": "SINGLE_ARROW",
|
|
||||||
"Chainsaw": "SWORD",
|
|
||||||
"Medikit": "MEDICINE",
|
|
||||||
"Skull key": "NIGHTMARE_KEY",
|
|
||||||
},
|
|
||||||
|
|
||||||
"DOOM II": {
|
|
||||||
"Keycard": "KEY",
|
|
||||||
"Computer area map": "MAP",
|
|
||||||
"Box of": "SINGLE_ARROW", # bullets, rockets, or shotgun shells
|
|
||||||
"Energy cell pack": "SINGLE_ARROW",
|
|
||||||
"Chainsaw": "SWORD",
|
|
||||||
"Medikit": "MEDICINE",
|
|
||||||
"Skull key": "NIGHTMARE_KEY",
|
|
||||||
},
|
|
||||||
|
|
||||||
"Inscryption": {
|
|
||||||
"Extra Candle": "HEART_CONTAINER", # Candles act as extra health
|
|
||||||
"Magnificus Eye": "TRADING_ITEM_MAGNIFYING_GLASS", # Needed to see hidden drawings / messages
|
|
||||||
"Monocle": "TRADING_ITEM_MAGNIFYING_GLASS", # Ditto
|
|
||||||
"Pile Of Meat": "TRADING_ITEM_DOG_FOOD",
|
|
||||||
"Angler Hook": "TRADING_ITEM_FISHING_HOOK", # Good fish.
|
|
||||||
"Currency": "RUPEES_20",
|
|
||||||
},
|
|
||||||
|
|
||||||
"Minecraft": {
|
|
||||||
"Progressive Weapons": "SWORD",
|
|
||||||
"Progressive Tools": "SHOVEL",
|
|
||||||
"Archery": "BOW",
|
|
||||||
"Emerald": "RUPEES_20",
|
|
||||||
"Brewing": "MEDICINE",
|
|
||||||
"Spyglass": 'TRADING_ITEM_MAGNIFYING_GLASS',
|
|
||||||
"Porkchop": "TRADING_ITEM_DOG_FOOD"
|
|
||||||
},
|
|
||||||
"VVVVVV": {
|
|
||||||
"Trinket": "PIECE_OF_POWER",
|
|
||||||
},
|
|
||||||
|
|
||||||
"A Hat in Time": {
|
|
||||||
"Time Piece": "PIECE_OF_POWER",
|
|
||||||
"Metro Ticket": "TRADING_ITEM_LETTER",
|
|
||||||
"Snatcher's Contract": "TRADING_ITEM_LETTER",
|
|
||||||
"Pon": "RUPEES_20",
|
|
||||||
},
|
|
||||||
|
|
||||||
"Kingdom Hearts 2": {
|
|
||||||
# Goal items / Collectibles
|
|
||||||
"Proof of": "PIECE_OF_POWER",
|
|
||||||
"Lucky Emblem": "PIECE_OF_POWER",
|
|
||||||
"Secret Ansem's Report": "TRADING_ITEM_LETTER",
|
|
||||||
|
|
||||||
# Sora Keyblades
|
|
||||||
"Bond of Flame": "SWORD",
|
|
||||||
"Circle of Life": "SWORD",
|
|
||||||
"Decisive Pumpkin": "SWORD",
|
|
||||||
"Fatal Crest": "SWORD",
|
|
||||||
"Fenrir": "SWORD",
|
|
||||||
"Follow the Wind": "SWORD",
|
|
||||||
"Guardian Soul": "SWORD",
|
|
||||||
"Gull Wing": "SWORD",
|
|
||||||
"Hero's Crest": "SWORD",
|
|
||||||
"Hidden Dragon": "SWORD",
|
|
||||||
"Monochrome": "SWORD",
|
|
||||||
"Mysterious Abyss": "SWORD",
|
|
||||||
"Oathkeeper": "SWORD",
|
|
||||||
"Oblivion": "SWORD",
|
|
||||||
"Photon Debugger": "SWORD",
|
|
||||||
"Pureblood": "SWORD",
|
|
||||||
"Rumbling Rose": "SWORD",
|
|
||||||
"Sleeping Lion": "SWORD",
|
|
||||||
"Star Seeker": "SWORD",
|
|
||||||
"Sweet Memories": "SWORD",
|
|
||||||
"Two Become One": "SWORD",
|
|
||||||
"Ultima Weapon": "SWORD",
|
|
||||||
"Winner's Proof": "SWORD",
|
|
||||||
"Wishing Lamp": "SWORD",
|
|
||||||
|
|
||||||
# Donald Staves
|
|
||||||
"Centurion+": "MAGIC_ROD",
|
|
||||||
"Nobody Lance": "MAGIC_ROD",
|
|
||||||
"Precious Mushroom": "MAGIC_ROD",
|
|
||||||
"Precious Mushroom+": "MAGIC_ROD",
|
|
||||||
"Premium Mushroom": "MAGIC_ROD",
|
|
||||||
"Rising Dragon": "MAGIC_ROD",
|
|
||||||
"Save The Queen+": "MAGIC_ROD",
|
|
||||||
"Shaman's Relic": "MAGIC_ROD",
|
|
||||||
"Victory Bell": "MAGIC_ROD",
|
|
||||||
|
|
||||||
# Goofy Shields
|
|
||||||
"Akashic Record": "SHIELD",
|
|
||||||
"Frozen Pride+": "SHIELD",
|
|
||||||
"Majestic Mushroom": "SHIELD",
|
|
||||||
"Majestic Mushroom+": "SHIELD",
|
|
||||||
"Nobody Guard": "SHIELD",
|
|
||||||
"Ogre Shield": "SHIELD",
|
|
||||||
"Save The King+": "SHIELD",
|
|
||||||
"Ultimate Mushroom": "SHIELD",
|
|
||||||
|
|
||||||
# Accessories as RIBBON
|
|
||||||
"Star Charm": "TRADING_ITEM_RIBBON",
|
|
||||||
"Ring": "TRADING_ITEM_RIBBON",
|
|
||||||
"Earring": "TRADING_ITEM_RIBBON",
|
|
||||||
"Shadow Archive": "TRADING_ITEM_RIBBON",
|
|
||||||
"Shadow Archive+": "TRADING_ITEM_RIBBON",
|
|
||||||
"Full Bloom": "TRADING_ITEM_RIBBON",
|
|
||||||
"Full Bloom+": "TRADING_ITEM_RIBBON",
|
|
||||||
|
|
||||||
# Armor as BLUE_TUNIC
|
|
||||||
"Bandanna": "BLUE_TUNIC",
|
|
||||||
"Belt": "BLUE_TUNIC",
|
|
||||||
"Band": "BLUE_TUNIC",
|
|
||||||
"Bangle": "BLUE_TUNIC",
|
|
||||||
"Armlet": "BLUE_TUNIC",
|
|
||||||
"Trinket": "BLUE_TUNIC",
|
|
||||||
"Charm": "BLUE_TUNIC",
|
|
||||||
"Anklet": "BLUE_TUNIC",
|
|
||||||
"Chain": "BLUE_TUNIC",
|
|
||||||
"Acrisius": "BLUE_TUNIC",
|
|
||||||
"Ribbon": "BLUE_TUNIC",
|
|
||||||
|
|
||||||
# Magic
|
|
||||||
"Element": "MAGIC_ROD",
|
|
||||||
|
|
||||||
# Other
|
|
||||||
"Munny Pouch": "MAGIC_POWDER",
|
|
||||||
"Ether": "MEDICINE",
|
|
||||||
"Elixir": "MEDICINE",
|
|
||||||
"Megalixir": "MEDICINE",
|
|
||||||
},
|
|
||||||
|
|
||||||
"Kingdom Hearts": {
|
|
||||||
# Goal/collectible items
|
|
||||||
"Ansem's Report": "TRADING_ITEM_LETTER",
|
|
||||||
|
|
||||||
# Dalmatian puppies
|
|
||||||
"Puppy": "BOWWOW",
|
|
||||||
"Puppies": "BOWWOW",
|
|
||||||
|
|
||||||
# Sora Keyblades
|
|
||||||
"Jungle King": "SWORD",
|
|
||||||
"Three Wishes": "SWORD",
|
|
||||||
"Fairy Harp": "SWORD",
|
|
||||||
"Pumpkinhead": "SWORD",
|
|
||||||
"Crabclaw": "SWORD",
|
|
||||||
"Divine Rose": "SWORD",
|
|
||||||
"Spellbinder": "SWORD",
|
|
||||||
"Olympia": "SWORD",
|
|
||||||
"Lionheart": "SWORD",
|
|
||||||
"Metal Chocobo": "SWORD",
|
|
||||||
"Oathkeeper": "SWORD",
|
|
||||||
"Oblivion": "SWORD",
|
|
||||||
"Lady Luck": "SWORD",
|
|
||||||
"Wishing Star": "SWORD",
|
|
||||||
"Ultima Weapon": "SWORD",
|
|
||||||
"Diamond Dust": "SWORD",
|
|
||||||
"One-Winged Angel": "SWORD",
|
|
||||||
|
|
||||||
# Donald Staves
|
|
||||||
"Morning Star": "MAGIC_ROD",
|
|
||||||
"Shooting Star": "MAGIC_ROD",
|
|
||||||
"Warhammer": "MAGIC_ROD",
|
|
||||||
"Silver Mallet": "MAGIC_ROD",
|
|
||||||
"Grand Mallet": "MAGIC_ROD",
|
|
||||||
"Lord Fortune": "MAGIC_ROD",
|
|
||||||
"Violetta": "MAGIC_ROD",
|
|
||||||
"Save the Queen": "MAGIC_ROD",
|
|
||||||
"Wizard's Relic": "MAGIC_ROD",
|
|
||||||
"Meteor Strike": "MAGIC_ROD",
|
|
||||||
"Fantasista": "MAGIC_ROD",
|
|
||||||
|
|
||||||
# Goofy Shields
|
|
||||||
"Smasher": "SHIELD",
|
|
||||||
"Gigas Fist": "SHIELD",
|
|
||||||
"Save the King": "SHIELD",
|
|
||||||
"Defender": "SHIELD",
|
|
||||||
"Seven Elements": "SHIELD",
|
|
||||||
|
|
||||||
# Magic
|
|
||||||
"Progressive Fire": "MAGIC_ROD",
|
|
||||||
"Progressive Blizzard": "MAGIC_ROD",
|
|
||||||
"Progressive Thunder": "MAGIC_ROD",
|
|
||||||
"Progressive Cure": "MAGIC_ROD",
|
|
||||||
"Progressive Gravity": "MAGIC_ROD",
|
|
||||||
"Progressive Stop": "MAGIC_ROD",
|
|
||||||
"Progressive Aero": "MAGIC_ROD",
|
|
||||||
|
|
||||||
# Accessories / armor (Let's go with BLUE_TUNIC for these, these items are closer to RPG armor anyways)
|
|
||||||
"Chain": "BLUE_TUNIC",
|
|
||||||
"Ring": "BLUE_TUNIC",
|
|
||||||
"Band": "BLUE_TUNIC",
|
|
||||||
"Three Stars": "BLUE_TUNIC",
|
|
||||||
"Stud": "BLUE_TUNIC",
|
|
||||||
"Earring": "BLUE_TUNIC",
|
|
||||||
"Bangle": "BLUE_TUNIC",
|
|
||||||
"Armlet": "BLUE_TUNIC",
|
|
||||||
"Moogle Badge": "BLUE_TUNIC",
|
|
||||||
"Cosmic Arts": "BLUE_TUNIC",
|
|
||||||
"Heartguard": "BLUE_TUNIC",
|
|
||||||
"Crystal Crown": "BLUE_TUNIC",
|
|
||||||
"Ribbon": "BLUE_TUNIC",
|
|
||||||
"Brave Warrior": "BLUE_TUNIC",
|
|
||||||
"Ifrit's Horn": "BLUE_TUNIC",
|
|
||||||
"White Fang": "BLUE_TUNIC",
|
|
||||||
"Ray of Light": "BLUE_TUNIC",
|
|
||||||
"Circlet": "BLUE_TUNIC",
|
|
||||||
"Raven's Claw": "BLUE_TUNIC",
|
|
||||||
"Omega Arts": "BLUE_TUNIC",
|
|
||||||
"Royal Crown": "BLUE_TUNIC",
|
|
||||||
"Prime Cap": "BLUE_TUNIC",
|
|
||||||
"Belt": "BLUE_TUNIC",
|
|
||||||
"EXP Bracelet": "BLUE_TUNIC",
|
|
||||||
"EXP Necklace": "BLUE_TUNIC",
|
|
||||||
|
|
||||||
# Other
|
|
||||||
"Glide": "FEATHER",
|
|
||||||
"Ether": "MEDICINE",
|
|
||||||
"Elixir": "MEDICINE",
|
|
||||||
"Megalixir": "MEDICINE",
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user