mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-04-08 16:58:23 -07:00
Compare commits
9 Commits
0.6.1
...
NewSoupVi-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6ffff674c | ||
|
|
507e051a5a | ||
|
|
b5bf9ed1d7 | ||
|
|
215eb7e473 | ||
|
|
f42233699a | ||
|
|
1bec68df4d | ||
|
|
7b21121df1 | ||
|
|
0fdc481082 | ||
|
|
92ca11b729 |
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,22 +279,30 @@ 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 SafeDict(dict):
|
class SafeFormatter(string.Formatter):
|
||||||
def __missing__(self, key):
|
def get_value(self, key, args, kwargs):
|
||||||
return '{' + key + '}'
|
if isinstance(key, int):
|
||||||
|
if key < len(args):
|
||||||
|
return args[key]
|
||||||
|
else:
|
||||||
|
return "{" + str(key) + "}"
|
||||||
|
else:
|
||||||
|
return kwargs.get(key, "{" + key + "}")
|
||||||
|
|
||||||
|
|
||||||
def handle_name(name: str, player: int, name_counter: Counter):
|
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,
|
|
||||||
NUMBER=(number if number > 1 else ''),
|
new_name = SafeFormatter().vformat(new_name, (), {"number": number,
|
||||||
player=player,
|
"NUMBER": (number if number > 1 else ''),
|
||||||
PLAYER=(player if player > 1 else '')))
|
"player": player,
|
||||||
|
"PLAYER": (player if player > 1 else '')})
|
||||||
# Run .strip twice for edge case where after the initial .slice new_name has a leading whitespace.
|
# 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
|
||||||
|
|||||||
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.1"
|
__version__ = "0.6.2"
|
||||||
version_tuple = tuplize_version(__version__)
|
version_tuple = tuplize_version(__version__)
|
||||||
|
|
||||||
is_linux = sys.platform.startswith("linux")
|
is_linux = sys.platform.startswith("linux")
|
||||||
|
|||||||
@@ -35,6 +35,12 @@ 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))
|
||||||
|
|
||||||
|
|
||||||
@@ -52,6 +58,12 @@ 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
|
from flask import redirect, render_template, request, Response, abort
|
||||||
|
|
||||||
import Options
|
import Options
|
||||||
from Utils import local_path
|
from Utils import local_path
|
||||||
@@ -142,7 +142,10 @@ 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):
|
||||||
return render_options_page("weightedOptions/weightedOptions.html", game, is_complex=True)
|
try:
|
||||||
|
return render_options_page("weightedOptions/weightedOptions.html", game, is_complex=True)
|
||||||
|
except KeyError:
|
||||||
|
return abort(404)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/games/<string:game>/generate-weighted-yaml", methods=["POST"])
|
@app.route("/games/<string:game>/generate-weighted-yaml", methods=["POST"])
|
||||||
@@ -197,7 +200,10 @@ def generate_weighted_yaml(game: str):
|
|||||||
@app.route("/games/<string:game>/player-options")
|
@app.route("/games/<string:game>/player-options")
|
||||||
@cache.cached()
|
@cache.cached()
|
||||||
def player_options(game: str):
|
def player_options(game: str):
|
||||||
return render_options_page("playerOptions/playerOptions.html", game, is_complex=False)
|
try:
|
||||||
|
return render_options_page("playerOptions/playerOptions.html", game, is_complex=False)
|
||||||
|
except KeyError:
|
||||||
|
return abort(404)
|
||||||
|
|
||||||
|
|
||||||
# YAML generator for player-options
|
# YAML generator for player-options
|
||||||
|
|||||||
@@ -42,10 +42,5 @@ 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,10 +49,5 @@ 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>`;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -110,6 +110,16 @@ class AutoLogicRegister(type):
|
|||||||
elif not item_name.startswith("__"):
|
elif not item_name.startswith("__"):
|
||||||
if hasattr(CollectionState, item_name):
|
if hasattr(CollectionState, item_name):
|
||||||
raise Exception(f"Name conflict on Logic Mixin {name} trying to overwrite {item_name}")
|
raise Exception(f"Name conflict on Logic Mixin {name} trying to overwrite {item_name}")
|
||||||
|
|
||||||
|
assert callable(function) or "init_mixin" in dct, (
|
||||||
|
f"{name} defined class variable {item_name} without also having init_mixin.\n\n"
|
||||||
|
"Explanation:\n"
|
||||||
|
"Class variables that will be mutated need to be inintialized as instance variables in init_mixin.\n"
|
||||||
|
"If your LogicMixin variables aren't actually mutable / you don't intend to mutate them, "
|
||||||
|
"there is no point in using LogixMixin.\n"
|
||||||
|
"LogicMixin exists to track custom state variables that change when items are collected/removed."
|
||||||
|
)
|
||||||
|
|
||||||
setattr(CollectionState, item_name, function)
|
setattr(CollectionState, item_name, function)
|
||||||
return new_class
|
return new_class
|
||||||
|
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ 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):
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ class AquariaWeb(WebWorld):
|
|||||||
)
|
)
|
||||||
|
|
||||||
tutorials = [setup, setup_fr]
|
tutorials = [setup, setup_fr]
|
||||||
|
game_info_languages = ["en", "fr"]
|
||||||
|
|
||||||
|
|
||||||
class AquariaWorld(World):
|
class AquariaWorld(World):
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class CliqueWebWorld(WebWorld):
|
|||||||
)
|
)
|
||||||
|
|
||||||
tutorials = [setup_en, setup_de]
|
tutorials = [setup_en, setup_de]
|
||||||
|
game_info_languages = ["en", "de"]
|
||||||
|
|
||||||
|
|
||||||
class CliqueWorld(World):
|
class CliqueWorld(World):
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ 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):
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ class FFMQWebWorld(WebWorld):
|
|||||||
)
|
)
|
||||||
|
|
||||||
tutorials = [setup_en, setup_fr]
|
tutorials = [setup_en, setup_fr]
|
||||||
|
game_info_languages = ["en", "fr"]
|
||||||
|
|
||||||
|
|
||||||
class FFMQWorld(World):
|
class FFMQWorld(World):
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ class OOTWeb(WebWorld):
|
|||||||
|
|
||||||
tutorials = [setup, setup_fr, setup_de]
|
tutorials = [setup, setup_fr, setup_de]
|
||||||
option_groups = oot_option_groups
|
option_groups = oot_option_groups
|
||||||
|
game_info_languages = ["en", "de"]
|
||||||
|
|
||||||
|
|
||||||
class OOTWorld(World):
|
class OOTWorld(World):
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ class Starcraft2WebWorld(WebWorld):
|
|||||||
)
|
)
|
||||||
|
|
||||||
tutorials = [setup_en, setup_fr]
|
tutorials = [setup_en, setup_fr]
|
||||||
|
game_info_languages = ["en", "fr"]
|
||||||
|
|
||||||
|
|
||||||
class SC2World(World):
|
class SC2World(World):
|
||||||
|
|||||||
@@ -330,7 +330,11 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal
|
|||||||
else:
|
else:
|
||||||
if not portal2:
|
if not portal2:
|
||||||
raise Exception(f"Could not find entrance named {p_exit} for "
|
raise Exception(f"Could not find entrance named {p_exit} for "
|
||||||
f"plando connections in {player_name}'s YAML.")
|
f"plando connections in {player_name}'s YAML.\n"
|
||||||
|
f"If you are using Universal Tracker, the most likely reason for this error "
|
||||||
|
f"is that the host generated with a newer version of the APWorld.\n"
|
||||||
|
f"Please check the TUNIC Randomizer Github and place the newest APWorld in your "
|
||||||
|
f"custom_worlds folder, and remove the one in lib/worlds if there is one there.")
|
||||||
dead_ends.remove(portal2)
|
dead_ends.remove(portal2)
|
||||||
|
|
||||||
# update the traversal chart to say you can get from portal1's region to portal2's and vice versa
|
# update the traversal chart to say you can get from portal1's region to portal2's and vice versa
|
||||||
|
|||||||
Reference in New Issue
Block a user