LttP: free core of checks_in_area (#1798)

This commit is contained in:
Fabian Dill 2023-07-02 13:00:05 +02:00 committed by GitHub
parent a6ba185c55
commit ee40312384
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 112 additions and 132 deletions

42
Main.py
View File

@ -7,7 +7,7 @@ import tempfile
import time import time
import zipfile import zipfile
import zlib import zlib
from typing import Dict, List, Optional, Set, Tuple from typing import Dict, List, Optional, Set, Tuple, Union
import worlds import worlds
from BaseClasses import CollectionState, Item, Location, LocationProgressType, MultiWorld, Region 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 Options import StartInventoryPool
from Utils import __version__, get_options, output_path, version_tuple from Utils import __version__, get_options, output_path, version_tuple
from worlds import AutoWorld 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 from worlds.generic.Rules import exclusion_rules, locality_rules
__all__ = ["main"] __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): def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = None):
if not baked_server_options: 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]] = {} er_hint_data: Dict[int, Dict[int, str]] = {}
AutoWorld.call_all(world, 'extend_hint_information', er_hint_data) 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(): def write_multidata():
import NetUtils import NetUtils
slot_data = {} 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() for game_world in world.worlds.values()
} }
checks_in_area: Dict[int, Dict[str, Union[int, List[int]]]] = {}
multidata = { multidata = {
"slot_data": slot_data, "slot_data": slot_data,
"slot_info": slot_info, "slot_info": slot_info,

View File

@ -0,0 +1,28 @@
{% for team, hints in hints.items() %}
<div class="table-wrapper">
<table id="hints-table" class="table non-unique-item-table" data-order='[[5, "asc"], [0, "asc"]]'>
<thead>
<tr>
<th>Finder</th>
<th>Receiver</th>
<th>Item</th>
<th>Location</th>
<th>Entrance</th>
<th>Found</th>
</tr>
</thead>
<tbody>
{%- for hint in hints -%}
<tr>
<td>{{ long_player_names[team, hint.finding_player] }}</td>
<td>{{ long_player_names[team, hint.receiving_player] }}</td>
<td>{{ hint.item|item_name }}</td>
<td>{{ hint.location|location_name }}</td>
<td>{% if hint.entrance %}{{ hint.entrance }}{% else %}Vanilla{% endif %}</td>
<td>{% if hint.found %}✔{% endif %}</td>
</tr>
{%- endfor -%}
</tbody>
</table>
</div>
{% endfor %}

View File

@ -128,20 +128,30 @@
tracked_team=team, tracked_player=player)}}">{{ loop.index }}</a></td> tracked_team=team, tracked_player=player)}}">{{ loop.index }}</a></td>
<td>{{ player_names[(team, loop.index)]|e }}</td> <td>{{ player_names[(team, loop.index)]|e }}</td>
{%- for area in ordered_areas -%} {%- for area in ordered_areas -%}
{%- set checks_done = checks[area] -%} {% if player in checks_in_area and area in checks_in_area[player] %}
{%- set checks_total = checks_in_area[player][area] -%} {%- set checks_done = checks[area] -%}
{%- if checks_done == checks_total -%} {%- set checks_total = checks_in_area[player][area] -%}
<td class="item-acquired center-column"> {%- if checks_done == checks_total -%}
{{ checks_done }}/{{ checks_total }}</td> <td class="item-acquired center-column">
{%- else -%} {{ checks_done }}/{{ checks_total }}</td>
<td class="center-column">{{ checks_done }}/{{ checks_total }}</td> {%- else -%}
{%- endif -%} <td class="center-column">{{ checks_done }}/{{ checks_total }}</td>
{%- if area in key_locations -%} {%- endif -%}
<td class="center-column">{{ inventory[team][player][small_key_ids[area]] }}</td> {%- if area in key_locations -%}
{%- endif -%} <td class="center-column">{{ inventory[team][player][small_key_ids[area]] }}</td>
{%- if area in big_key_locations -%} {%- endif -%}
<td class="center-column">{% if inventory[team][player][big_key_ids[area]] %}✔️{% endif %}</td> {%- if area in big_key_locations -%}
{%- endif -%} <td class="center-column">{% if inventory[team][player][big_key_ids[area]] %}✔️{% endif %}</td>
{%- endif -%}
{% else %}
<td class="center-column"></td>
{%- if area in key_locations -%}
<td class="center-column"></td>
{%- endif -%}
{%- if area in big_key_locations -%}
<td class="center-column"></td>
{%- endif -%}
{% endif %}
{%- endfor -%} {%- endfor -%}
<td class="center-column">{{ percent_total_checks_done[team][player] }}</td> <td class="center-column">{{ percent_total_checks_done[team][player] }}</td>
{%- if activity_timers[(team, player)] -%} {%- if activity_timers[(team, player)] -%}
@ -155,34 +165,7 @@
</table> </table>
</div> </div>
{% endfor %} {% endfor %}
{% for team, hints in hints.items() %} {% include "hintTable.html" with context %}
<div class="table-wrapper">
<table id="hints-table" class="table non-unique-item-table" data-order='[[5, "asc"], [0, "asc"]]'>
<thead>
<tr>
<th>Finder</th>
<th>Receiver</th>
<th>Item</th>
<th>Location</th>
<th>Entrance</th>
<th>Found</th>
</tr>
</thead>
<tbody>
{%- for hint in hints -%}
<tr>
<td>{{ long_player_names[team, hint.finding_player] }}</td>
<td>{{ long_player_names[team, hint.receiving_player] }}</td>
<td>{{ hint.item|item_name }}</td>
<td>{{ hint.location|location_name }}</td>
<td>{% if hint.entrance %}{{ hint.entrance }}{% else %}Vanilla{% endif %}</td>
<td>{% if hint.found %}✔{% endif %}</td>
</tr>
{%- endfor -%}
</tbody>
</table>
</div>
{% endfor %}
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -53,7 +53,7 @@
{# implement this block in game-specific multi trackers #} {# implement this block in game-specific multi trackers #}
{% endblock %} {% endblock %}
<td class="center-column" data-sort="{{ checks["Total"] }}"> <td class="center-column" data-sort="{{ checks["Total"] }}">
{{ checks["Total"] }}/{{ checks_in_area[player]["Total"] }} {{ checks["Total"] }}/{{ locations[player] | length }}
</td> </td>
<td class="center-column">{{ percent_total_checks_done[team][player] }}</td> <td class="center-column">{{ percent_total_checks_done[team][player] }}</td>
{%- if activity_timers[team, player] -%} {%- if activity_timers[team, player] -%}
@ -67,34 +67,7 @@
</table> </table>
</div> </div>
{% endfor %} {% endfor %}
{% for team, hints in hints.items() %} {% include "hintTable.html" with context %}
<div class="table-wrapper">
<table id="hints-table" class="table non-unique-item-table" data-order='[[5, "asc"], [0, "asc"]]'>
<thead>
<tr>
<th>Finder</th>
<th>Receiver</th>
<th>Item</th>
<th>Location</th>
<th>Entrance</th>
<th>Found</th>
</tr>
</thead>
<tbody>
{%- for hint in hints -%}
<tr>
<td>{{ long_player_names[team, hint.finding_player] }}</td>
<td>{{ long_player_names[team, hint.receiving_player] }}</td>
<td>{{ hint.item|item_name }}</td>
<td>{{ hint.location|location_name }}</td>
<td>{% if hint.entrance %}{{ hint.entrance }}{% else %}Vanilla{% endif %}</td>
<td>{% if hint.found %}✔{% endif %}</td>
</tr>
{%- endfor -%}
</tbody>
</table>
</div>
{% endfor %}
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -305,11 +305,9 @@ def get_static_room_data(room: Room):
player_checks_in_area = {playernumber: {areaname: len(multidata["checks_in_area"][playernumber][areaname]) player_checks_in_area = {playernumber: {areaname: len(multidata["checks_in_area"][playernumber][areaname])
if areaname != "Total" else multidata["checks_in_area"][playernumber]["Total"] if areaname != "Total" else multidata["checks_in_area"][playernumber]["Total"]
for areaname in ordered_areas} for areaname in ordered_areas}
for playernumber in range(1, len(names[0]) + 1) for playernumber in multidata["checks_in_area"]}
if playernumber not in groups}
player_location_to_area = {playernumber: get_location_table(multidata["checks_in_area"][playernumber]) player_location_to_area = {playernumber: get_location_table(multidata["checks_in_area"][playernumber])
for playernumber in range(1, len(names[0]) + 1) for playernumber in multidata["checks_in_area"]}
if playernumber not in groups}
saving_second = get_saving_second(multidata["seed_name"]) saving_second = get_saving_second(multidata["seed_name"])
result = locations, names, use_door_tracker, player_checks_in_area, player_location_to_area, \ result = locations, names, use_door_tracker, player_checks_in_area, player_location_to_area, \
multidata["precollected_items"], games, multidata["slot_data"], groups, saving_second, \ 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) specific_tracker = game_specific_trackers.get(games[tracked_player], None)
if specific_tracker and not want_generic: if specific_tracker and not want_generic:
tracker = specific_tracker(multisave, room, locations, inventory, tracked_team, tracked_player, player_name, 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: else:
tracker = __renderGenericTracker(multisave, room, locations, inventory, tracked_team, tracked_player, player_name, tracker = __renderGenericTracker(multisave, room, locations, inventory, tracked_team, tracked_player,
seed_checks_in_area, checks_done, saving_second, custom_locations, custom_items) 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 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: if player in groups:
continue continue
player_locations = locations[player] 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"] / percent_total_checks_done[team][player] = int(checks_done[team][player]["Total"] /
checks_in_area[player]["Total"] * 100) \ len(player_locations) * 100) \
if checks_in_area[player]["Total"] else 100 if player_locations else 100
activity_timers = {} activity_timers = {}
now = datetime.datetime.utcnow() now = datetime.datetime.utcnow()

View File

@ -172,6 +172,7 @@ def FillDisabledShopSlots(world):
shop: Shop = location.parent_region.shop shop: Shop = location.parent_region.shop
location.item = ItemFactory(shop.inventory[location.shop_slot]['item'], location.player) 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.item_rule = lambda item: item.name == location.item.name and item.player == location.player
location.locked = True
def ShopSlotFill(multiworld): def ShopSlotFill(multiworld):
@ -278,6 +279,8 @@ def ShopSlotFill(multiworld):
if 'P' in multiworld.shop_shuffle[location.player]: if 'P' in multiworld.shop_shuffle[location.player]:
price_to_funny_price(multiworld, shop.inventory[location.shop_slot], location.player) price_to_funny_price(multiworld, shop.inventory[location.shop_slot], location.player)
FillDisabledShopSlots(multiworld)
def create_shops(world, player: int): def create_shops(world, player: int):
option = world.shop_shuffle[player] option = world.shop_shuffle[player]

View File

@ -544,6 +544,44 @@ class ALTTPWorld(World):
er_hint_data[region.player][location.address] = main_entrance.name er_hint_data[region.player][location.address] = main_entrance.name
hint_data.update(er_hint_data) 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): def modify_multidata(self, multidata: dict):
import base64 import base64
# wait for self.rom_name to be available. # wait for self.rom_name to be available.

View File

@ -1,14 +1,10 @@
from argparse import Namespace from argparse import Namespace
from BaseClasses import MultiWorld from BaseClasses import MultiWorld
from worlds.alttp.Dungeons import create_dungeons, get_dungeon_item_pool from worlds.alttp.Dungeons import get_dungeon_item_pool
from worlds.alttp.EntranceShuffle import link_entrances
from worlds.alttp.InvertedRegions import mark_dark_world_regions 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.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 test.TestBase import TestBase
from worlds import AutoWorld from worlds import AutoWorld

View File

@ -1,14 +1,10 @@
from argparse import Namespace from argparse import Namespace
from BaseClasses import MultiWorld from BaseClasses import MultiWorld
from worlds.alttp.Dungeons import create_dungeons, get_dungeon_item_pool from worlds.alttp.Dungeons import get_dungeon_item_pool
from worlds.alttp.EntranceShuffle import link_entrances
from worlds.alttp.InvertedRegions import mark_dark_world_regions 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.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 test.TestBase import TestBase
from worlds import AutoWorld from worlds import AutoWorld