diff --git a/Main.py b/Main.py
index 78ae39e9..9804e6bd 100644
--- a/Main.py
+++ b/Main.py
@@ -7,7 +7,7 @@ import tempfile
import time
import zipfile
import zlib
-from typing import Dict, List, Optional, Set, Tuple
+from typing import Dict, List, Optional, Set, Tuple, Union
import worlds
from BaseClasses import CollectionState, Item, Location, LocationProgressType, MultiWorld, Region
@@ -15,19 +15,10 @@ from Fill import balance_multiworld_progression, distribute_items_restrictive, d
from Options import StartInventoryPool
from Utils import __version__, get_options, output_path, version_tuple
from worlds import AutoWorld
-from worlds.alttp.Regions import is_main_entrance
-from worlds.alttp.Shops import FillDisabledShopSlots
-from worlds.alttp.SubClasses import LTTPRegionType
from worlds.generic.Rules import exclusion_rules, locality_rules
__all__ = ["main"]
-ordered_areas = (
- 'Light World', 'Dark World', 'Hyrule Castle', 'Agahnims Tower', 'Eastern Palace', 'Desert Palace',
- 'Tower of Hera', 'Palace of Darkness', 'Swamp Palace', 'Skull Woods', 'Thieves Town', 'Ice Palace',
- 'Misery Mire', 'Turtle Rock', 'Ganons Tower', "Total"
-)
-
def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = None):
if not baked_server_options:
@@ -313,35 +304,6 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
er_hint_data: Dict[int, Dict[int, str]] = {}
AutoWorld.call_all(world, 'extend_hint_information', er_hint_data)
- checks_in_area = {player: {area: list() for area in ordered_areas}
- for player in range(1, world.players + 1)}
-
- for player in range(1, world.players + 1):
- checks_in_area[player]["Total"] = 0
-
- for location in world.get_filled_locations():
- if type(location.address) is int:
- if location.game != "A Link to the Past":
- checks_in_area[location.player]["Light World"].append(location.address)
- else:
- main_entrance = location.parent_region.get_connecting_entrance(is_main_entrance)
- if location.parent_region.dungeon:
- dungeonname = {'Inverted Agahnims Tower': 'Agahnims Tower',
- 'Inverted Ganons Tower': 'Ganons Tower'} \
- .get(location.parent_region.dungeon.name, location.parent_region.dungeon.name)
- checks_in_area[location.player][dungeonname].append(location.address)
- elif location.parent_region.type == LTTPRegionType.LightWorld:
- checks_in_area[location.player]["Light World"].append(location.address)
- elif location.parent_region.type == LTTPRegionType.DarkWorld:
- checks_in_area[location.player]["Dark World"].append(location.address)
- elif main_entrance.parent_region.type == LTTPRegionType.LightWorld:
- checks_in_area[location.player]["Light World"].append(location.address)
- elif main_entrance.parent_region.type == LTTPRegionType.DarkWorld:
- checks_in_area[location.player]["Dark World"].append(location.address)
- checks_in_area[location.player]["Total"] += 1
-
- FillDisabledShopSlots(world)
-
def write_multidata():
import NetUtils
slot_data = {}
@@ -401,6 +363,8 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
for game_world in world.worlds.values()
}
+ checks_in_area: Dict[int, Dict[str, Union[int, List[int]]]] = {}
+
multidata = {
"slot_data": slot_data,
"slot_info": slot_info,
diff --git a/WebHostLib/templates/hintTable.html b/WebHostLib/templates/hintTable.html
new file mode 100644
index 00000000..00b74111
--- /dev/null
+++ b/WebHostLib/templates/hintTable.html
@@ -0,0 +1,28 @@
+{% for team, hints in hints.items() %}
+
+
+
+
+ Finder |
+ Receiver |
+ Item |
+ Location |
+ Entrance |
+ Found |
+
+
+
+ {%- for hint in hints -%}
+
+ {{ long_player_names[team, hint.finding_player] }} |
+ {{ long_player_names[team, hint.receiving_player] }} |
+ {{ hint.item|item_name }} |
+ {{ hint.location|location_name }} |
+ {% if hint.entrance %}{{ hint.entrance }}{% else %}Vanilla{% endif %} |
+ {% if hint.found %}✔{% endif %} |
+
+ {%- endfor -%}
+
+
+
+{% endfor %}
\ No newline at end of file
diff --git a/WebHostLib/templates/lttpMultiTracker.html b/WebHostLib/templates/lttpMultiTracker.html
index 276e1de3..2b943a22 100644
--- a/WebHostLib/templates/lttpMultiTracker.html
+++ b/WebHostLib/templates/lttpMultiTracker.html
@@ -128,20 +128,30 @@
tracked_team=team, tracked_player=player)}}">{{ loop.index }}
{{ player_names[(team, loop.index)]|e }} |
{%- for area in ordered_areas -%}
- {%- set checks_done = checks[area] -%}
- {%- set checks_total = checks_in_area[player][area] -%}
- {%- if checks_done == checks_total -%}
-
- {{ checks_done }}/{{ checks_total }} |
- {%- else -%}
- {{ checks_done }}/{{ checks_total }} |
- {%- endif -%}
- {%- if area in key_locations -%}
- {{ inventory[team][player][small_key_ids[area]] }} |
- {%- endif -%}
- {%- if area in big_key_locations -%}
- {% if inventory[team][player][big_key_ids[area]] %}✔️{% endif %} |
- {%- endif -%}
+ {% if player in checks_in_area and area in checks_in_area[player] %}
+ {%- set checks_done = checks[area] -%}
+ {%- set checks_total = checks_in_area[player][area] -%}
+ {%- if checks_done == checks_total -%}
+
+ {{ checks_done }}/{{ checks_total }} |
+ {%- else -%}
+ {{ checks_done }}/{{ checks_total }} |
+ {%- endif -%}
+ {%- if area in key_locations -%}
+ {{ inventory[team][player][small_key_ids[area]] }} |
+ {%- endif -%}
+ {%- if area in big_key_locations -%}
+ {% if inventory[team][player][big_key_ids[area]] %}✔️{% endif %} |
+ {%- endif -%}
+ {% else %}
+ |
+ {%- if area in key_locations -%}
+ |
+ {%- endif -%}
+ {%- if area in big_key_locations -%}
+ |
+ {%- endif -%}
+ {% endif %}
{%- endfor -%}
{{ percent_total_checks_done[team][player] }} |
{%- if activity_timers[(team, player)] -%}
@@ -155,34 +165,7 @@
{% endfor %}
- {% for team, hints in hints.items() %}
-
-
-
-
- Finder |
- Receiver |
- Item |
- Location |
- Entrance |
- Found |
-
-
-
- {%- for hint in hints -%}
-
- {{ long_player_names[team, hint.finding_player] }} |
- {{ long_player_names[team, hint.receiving_player] }} |
- {{ hint.item|item_name }} |
- {{ hint.location|location_name }} |
- {% if hint.entrance %}{{ hint.entrance }}{% else %}Vanilla{% endif %} |
- {% if hint.found %}✔{% endif %} |
-
- {%- endfor -%}
-
-
-
- {% endfor %}
+ {% include "hintTable.html" with context %}
{% endblock %}
diff --git a/WebHostLib/templates/multiTracker.html b/WebHostLib/templates/multiTracker.html
index 8fc1a218..2232cd0f 100644
--- a/WebHostLib/templates/multiTracker.html
+++ b/WebHostLib/templates/multiTracker.html
@@ -53,7 +53,7 @@
{# implement this block in game-specific multi trackers #}
{% endblock %}
- {{ checks["Total"] }}/{{ checks_in_area[player]["Total"] }}
+ {{ checks["Total"] }}/{{ locations[player] | length }}
|
{{ percent_total_checks_done[team][player] }} |
{%- if activity_timers[team, player] -%}
@@ -67,34 +67,7 @@
{% endfor %}
- {% for team, hints in hints.items() %}
-
-
-
-
- Finder |
- Receiver |
- Item |
- Location |
- Entrance |
- Found |
-
-
-
- {%- for hint in hints -%}
-
- {{ long_player_names[team, hint.finding_player] }} |
- {{ long_player_names[team, hint.receiving_player] }} |
- {{ hint.item|item_name }} |
- {{ hint.location|location_name }} |
- {% if hint.entrance %}{{ hint.entrance }}{% else %}Vanilla{% endif %} |
- {% if hint.found %}✔{% endif %} |
-
- {%- endfor -%}
-
-
-
- {% endfor %}
+ {% include "hintTable.html" with context %}
{% endblock %}
diff --git a/WebHostLib/tracker.py b/WebHostLib/tracker.py
index 8f9fb148..decb3dd8 100644
--- a/WebHostLib/tracker.py
+++ b/WebHostLib/tracker.py
@@ -305,11 +305,9 @@ def get_static_room_data(room: Room):
player_checks_in_area = {playernumber: {areaname: len(multidata["checks_in_area"][playernumber][areaname])
if areaname != "Total" else multidata["checks_in_area"][playernumber]["Total"]
for areaname in ordered_areas}
- for playernumber in range(1, len(names[0]) + 1)
- if playernumber not in groups}
+ for playernumber in multidata["checks_in_area"]}
player_location_to_area = {playernumber: get_location_table(multidata["checks_in_area"][playernumber])
- for playernumber in range(1, len(names[0]) + 1)
- if playernumber not in groups}
+ for playernumber in multidata["checks_in_area"]}
saving_second = get_saving_second(multidata["seed_name"])
result = locations, names, use_door_tracker, player_checks_in_area, player_location_to_area, \
multidata["precollected_items"], games, multidata["slot_data"], groups, saving_second, \
@@ -380,10 +378,11 @@ def _get_player_tracker(tracker: UUID, tracked_team: int, tracked_player: int, w
specific_tracker = game_specific_trackers.get(games[tracked_player], None)
if specific_tracker and not want_generic:
tracker = specific_tracker(multisave, room, locations, inventory, tracked_team, tracked_player, player_name,
- seed_checks_in_area, checks_done, slot_data[tracked_player], saving_second)
+ seed_checks_in_area, checks_done, slot_data[tracked_player], saving_second)
else:
- tracker = __renderGenericTracker(multisave, room, locations, inventory, tracked_team, tracked_player, player_name,
- seed_checks_in_area, checks_done, saving_second, custom_locations, custom_items)
+ tracker = __renderGenericTracker(multisave, room, locations, inventory, tracked_team, tracked_player,
+ player_name, seed_checks_in_area, checks_done, saving_second,
+ custom_locations, custom_items)
return (saving_second - datetime.datetime.now().second) % 60 or 60, tracker
@@ -1373,10 +1372,10 @@ def _get_multiworld_tracker_data(tracker: UUID) -> typing.Optional[typing.Dict[s
if player in groups:
continue
player_locations = locations[player]
- checks_done[team][player]["Total"] = sum(1 for loc in locations_checked if loc in player_locations)
+ checks_done[team][player]["Total"] = len(locations_checked)
percent_total_checks_done[team][player] = int(checks_done[team][player]["Total"] /
- checks_in_area[player]["Total"] * 100) \
- if checks_in_area[player]["Total"] else 100
+ len(player_locations) * 100) \
+ if player_locations else 100
activity_timers = {}
now = datetime.datetime.utcnow()
diff --git a/worlds/alttp/Shops.py b/worlds/alttp/Shops.py
index 53a880d0..f17eb1ea 100644
--- a/worlds/alttp/Shops.py
+++ b/worlds/alttp/Shops.py
@@ -172,6 +172,7 @@ def FillDisabledShopSlots(world):
shop: Shop = location.parent_region.shop
location.item = ItemFactory(shop.inventory[location.shop_slot]['item'], location.player)
location.item_rule = lambda item: item.name == location.item.name and item.player == location.player
+ location.locked = True
def ShopSlotFill(multiworld):
@@ -278,6 +279,8 @@ def ShopSlotFill(multiworld):
if 'P' in multiworld.shop_shuffle[location.player]:
price_to_funny_price(multiworld, shop.inventory[location.shop_slot], location.player)
+ FillDisabledShopSlots(multiworld)
+
def create_shops(world, player: int):
option = world.shop_shuffle[player]
diff --git a/worlds/alttp/__init__.py b/worlds/alttp/__init__.py
index 3f68e34b..8f74a354 100644
--- a/worlds/alttp/__init__.py
+++ b/worlds/alttp/__init__.py
@@ -544,6 +544,44 @@ class ALTTPWorld(World):
er_hint_data[region.player][location.address] = main_entrance.name
hint_data.update(er_hint_data)
+ @classmethod
+ def stage_modify_multidata(cls, multiworld, multidata: dict):
+
+ ordered_areas = (
+ 'Light World', 'Dark World', 'Hyrule Castle', 'Agahnims Tower', 'Eastern Palace', 'Desert Palace',
+ 'Tower of Hera', 'Palace of Darkness', 'Swamp Palace', 'Skull Woods', 'Thieves Town', 'Ice Palace',
+ 'Misery Mire', 'Turtle Rock', 'Ganons Tower', "Total"
+ )
+
+ checks_in_area = {player: {area: list() for area in ordered_areas}
+ for player in multiworld.get_game_players(cls.game)}
+
+ for player in checks_in_area:
+ checks_in_area[player]["Total"] = 0
+
+ for location in multiworld.get_locations():
+ if location.game == cls.game and type(location.address) is int:
+ main_entrance = location.parent_region.get_connecting_entrance(is_main_entrance)
+ if location.parent_region.dungeon:
+ dungeonname = {'Inverted Agahnims Tower': 'Agahnims Tower',
+ 'Inverted Ganons Tower': 'Ganons Tower'} \
+ .get(location.parent_region.dungeon.name, location.parent_region.dungeon.name)
+ checks_in_area[location.player][dungeonname].append(location.address)
+ elif location.parent_region.type == LTTPRegionType.LightWorld:
+ checks_in_area[location.player]["Light World"].append(location.address)
+ elif location.parent_region.type == LTTPRegionType.DarkWorld:
+ checks_in_area[location.player]["Dark World"].append(location.address)
+ elif main_entrance.parent_region.type == LTTPRegionType.LightWorld:
+ checks_in_area[location.player]["Light World"].append(location.address)
+ elif main_entrance.parent_region.type == LTTPRegionType.DarkWorld:
+ checks_in_area[location.player]["Dark World"].append(location.address)
+ else:
+ assert False, "Unknown Location area."
+ # TODO: remove Total as it's duplicated data and breaks consistent typing
+ checks_in_area[location.player]["Total"] += 1
+
+ multidata["checks_in_area"].update(checks_in_area)
+
def modify_multidata(self, multidata: dict):
import base64
# wait for self.rom_name to be available.
diff --git a/worlds/alttp/test/owg/TestVanillaOWG.py b/worlds/alttp/test/owg/TestVanillaOWG.py
index 5b02666d..c0888aa3 100644
--- a/worlds/alttp/test/owg/TestVanillaOWG.py
+++ b/worlds/alttp/test/owg/TestVanillaOWG.py
@@ -1,14 +1,10 @@
from argparse import Namespace
from BaseClasses import MultiWorld
-from worlds.alttp.Dungeons import create_dungeons, get_dungeon_item_pool
-from worlds.alttp.EntranceShuffle import link_entrances
+from worlds.alttp.Dungeons import get_dungeon_item_pool
from worlds.alttp.InvertedRegions import mark_dark_world_regions
-from worlds.alttp.ItemPool import difficulties, generate_itempool
+from worlds.alttp.ItemPool import difficulties
from worlds.alttp.Items import ItemFactory
-from worlds.alttp.Regions import create_regions
-from worlds.alttp.Shops import create_shops
-from worlds.alttp.Rules import set_rules
from test.TestBase import TestBase
from worlds import AutoWorld
diff --git a/worlds/alttp/test/vanilla/TestVanilla.py b/worlds/alttp/test/vanilla/TestVanilla.py
index 92035c86..e338410d 100644
--- a/worlds/alttp/test/vanilla/TestVanilla.py
+++ b/worlds/alttp/test/vanilla/TestVanilla.py
@@ -1,14 +1,10 @@
from argparse import Namespace
from BaseClasses import MultiWorld
-from worlds.alttp.Dungeons import create_dungeons, get_dungeon_item_pool
-from worlds.alttp.EntranceShuffle import link_entrances
+from worlds.alttp.Dungeons import get_dungeon_item_pool
from worlds.alttp.InvertedRegions import mark_dark_world_regions
-from worlds.alttp.ItemPool import difficulties, generate_itempool
+from worlds.alttp.ItemPool import difficulties
from worlds.alttp.Items import ItemFactory
-from worlds.alttp.Regions import create_regions
-from worlds.alttp.Shops import create_shops
-from worlds.alttp.Rules import set_rules
from test.TestBase import TestBase
from worlds import AutoWorld