ALTTP: Updates and refactors to multi-tracker and player tracker. (#3183)

* ALTTP: Massive game tracker update.

* Adds dropdowns separated by region for each location and its checked status.
* Adds Bombs for bombless start seeds.
* Adds Triforce Pieces to track.
* Update icon image URLs to match in-game closer.
* Fix issue with grouped progressive items.

* Couple missed points.

* Another edge case with details being refreshed.

* Remove old commented out CSS

* Consolidate a table and move an erroneous location in wrong region.

* ALTTP: Updates and refactors to multi-tracker and player tracker.

* Removed some missed commented out code.

* Add triforce to prepare inventory logic.
This commit is contained in:
Zach Parks 2024-04-20 17:29:41 -05:00 committed by GitHub
parent 0a1ce5b7d8
commit 532cff1334
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 318 additions and 515 deletions

View File

@ -6,52 +6,42 @@
{% endblock %}
{# List all tracker-relevant icons. Format: (Name, Image URL) #}
{%- set icons = {
"Blue Shield": "https://www.zeldadungeon.net/wiki/images/8/85/Fighters-Shield.png",
"Red Shield": "https://www.zeldadungeon.net/wiki/images/5/55/Fire-Shield.png",
"Mirror Shield": "https://www.zeldadungeon.net/wiki/images/8/84/Mirror-Shield.png",
"Fighter Sword": "https://oyster.ignimgs.com/mediawiki/apis.ign.com/the-legend-of-zelda-a-link-to-the-past/4/40/SFighterSword.png?width=1920",
"Master Sword": "https://oyster.ignimgs.com/mediawiki/apis.ign.com/the-legend-of-zelda-a-link-to-the-past/6/65/SMasterSword.png?width=1920",
"Tempered Sword": "https://oyster.ignimgs.com/mediawiki/apis.ign.com/the-legend-of-zelda-a-link-to-the-past/9/92/STemperedSword.png?width=1920",
"Golden Sword": "https://oyster.ignimgs.com/mediawiki/apis.ign.com/the-legend-of-zelda-a-link-to-the-past/2/28/SGoldenSword.png?width=1920",
"Bow": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/b/bc/ALttP_Bow_%26_Arrows_Sprite.png?version=5f85a70e6366bf473544ef93b274f74c",
"Silver Bow": "https://oyster.ignimgs.com/mediawiki/apis.ign.com/the-legend-of-zelda-a-link-to-the-past/6/65/Bow.png?width=1920",
"Green Mail": "https://oyster.ignimgs.com/mediawiki/apis.ign.com/the-legend-of-zelda-a-link-to-the-past/c/c9/SGreenTunic.png?width=1920",
"Blue Mail": "https://oyster.ignimgs.com/mediawiki/apis.ign.com/the-legend-of-zelda-a-link-to-the-past/9/98/SBlueTunic.png?width=1920",
"Red Mail": "https://oyster.ignimgs.com/mediawiki/apis.ign.com/the-legend-of-zelda-a-link-to-the-past/7/74/SRedTunic.png?width=1920",
"Power Glove": "https://oyster.ignimgs.com/mediawiki/apis.ign.com/the-legend-of-zelda-a-link-to-the-past/f/f5/SPowerGlove.png?width=1920",
"Titan Mitts": "https://oyster.ignimgs.com/mediawiki/apis.ign.com/the-legend-of-zelda-a-link-to-the-past/c/c1/STitanMitt.png?width=1920",
"Progressive Sword": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/c/cc/ALttP_Master_Sword_Sprite.png?version=55869db2a20e157cd3b5c8f556097725",
"Pegasus Boots": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/ed/ALttP_Pegasus_Shoes_Sprite.png?version=405f42f97240c9dcd2b71ffc4bebc7f9",
"Progressive Glove": "https://oyster.ignimgs.com/mediawiki/apis.ign.com/the-legend-of-zelda-a-link-to-the-past/c/c1/STitanMitt.png?width=1920",
"Flippers": "https://oyster.ignimgs.com/mediawiki/apis.ign.com/the-legend-of-zelda-a-link-to-the-past/4/4c/ZoraFlippers.png?width=1920",
"Moon Pearl": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/6/63/ALttP_Moon_Pearl_Sprite.png?version=d601542d5abcc3e006ee163254bea77e",
"Progressive Bow": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/b/bc/ALttP_Bow_%26_Arrows_Sprite.png?version=cfb7648b3714cccc80e2b17b2adf00ed",
"Blue Boomerang": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/c/c3/ALttP_Boomerang_Sprite.png?version=96127d163759395eb510b81a556d500e",
"Red Boomerang": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/b/b9/ALttP_Magical_Boomerang_Sprite.png?version=47cddce7a07bc3e4c2c10727b491f400",
"Hookshot": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/2/24/Hookshot.png?version=c90bc8e07a52e8090377bd6ef854c18b",
"Mushroom": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/3/35/ALttP_Mushroom_Sprite.png?version=1f1acb30d71bd96b60a3491e54bbfe59",
"Magic Powder": "https://www.zeldadungeon.net/wiki/images/thumb/6/62/MagicPowder-ALttP-Sprite.png/86px-MagicPowder-ALttP-Sprite.png",
"Fire Rod": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/d6/FireRod.png?version=6eabc9f24d25697e2c4cd43ddc8207c0",
"Ice Rod": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/d7/ALttP_Ice_Rod_Sprite.png?version=1f944148223d91cfc6a615c92286c3bc",
"Bombos": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/8/8c/ALttP_Bombos_Medallion_Sprite.png?version=f4d6aba47fb69375e090178f0fc33b26",
"Ether": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/3/3c/Ether.png?version=34027651a5565fcc5a83189178ab17b5",
"Quake": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/5/56/ALttP_Quake_Medallion_Sprite.png?version=efd64d451b1831bd59f7b7d6b61b5879",
"Lamp": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/6/63/ALttP_Lantern_Sprite.png?version=e76eaa1ec509c9a5efb2916698d5a4ce",
"Hammer": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/d1/ALttP_Hammer_Sprite.png?version=e0adec227193818dcaedf587eba34500",
"Shovel": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/c/c4/ALttP_Shovel_Sprite.png?version=e73d1ce0115c2c70eaca15b014bd6f05",
"Flute": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/db/Flute.png?version=ec4982b31c56da2c0c010905c5c60390",
"Bug Catching Net": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/5/54/Bug-CatchingNet.png?version=4d40e0ee015b687ff75b333b968d8be6",
"Book of Mudora": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/2/22/ALttP_Book_of_Mudora_Sprite.png?version=11e4632bba54f6b9bf921df06ac93744",
"Bottle": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/ef/ALttP_Magic_Bottle_Sprite.png?version=fd98ab04db775270cbe79fce0235777b",
"Cane of Somaria": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/e1/ALttP_Cane_of_Somaria_Sprite.png?version=8cc1900dfd887890badffc903bb87943",
"Cane of Byrna": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/b/bc/ALttP_Cane_of_Byrna_Sprite.png?version=758b607c8cbe2cf1900d42a0b3d0fb54",
"Cape": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/1/1c/ALttP_Magic_Cape_Sprite.png?version=6b77f0d609aab0c751307fc124736832",
"Magic Mirror": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/e5/ALttP_Magic_Mirror_Sprite.png?version=e035dbc9cbe2a3bd44aa6d047762b0cc",
"Triforce": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/4/4e/TriforceALttPTitle.png?version=dc398e1293177581c16303e4f9d12a48",
{% set icons = {
"Blue Shield": "https://www.zeldadungeon.net/wiki/images/thumb/c/c3/FightersShield-ALttP-Sprite.png/100px-FightersShield-ALttP-Sprite.png",
"Red Shield": "https://www.zeldadungeon.net/wiki/images/thumb/9/9e/FireShield-ALttP-Sprite.png/111px-FireShield-ALttP-Sprite.png",
"Mirror Shield": "https://www.zeldadungeon.net/wiki/images/thumb/e/e3/MirrorShield-ALttP-Sprite.png/105px-MirrorShield-ALttP-Sprite.png",
"Progressive Sword": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/c/cc/ALttP_Master_Sword_Sprite.png",
"Progressive Bow": "https://www.zeldadungeon.net/wiki/images/thumb/8/8c/BowArrows-ALttP-Sprite.png/120px-BowArrows-ALttP-Sprite.png",
"Progressive Glove": "https://www.zeldadungeon.net/wiki/images/thumb/4/41/PowerGlove-ALttP-Sprite.png/105px-PowerGlove-ALttP-Sprite.png",
"Pegasus Boots": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/ed/ALttP_Pegasus_Shoes_Sprite.png",
"Flippers": "https://www.zeldadungeon.net/wiki/images/thumb/b/bc/ZoraFlippers-ALttP-Sprite.png/112px-ZoraFlippers-ALttP-Sprite.png",
"Moon Pearl": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/6/63/ALttP_Moon_Pearl_Sprite.png",
"Blue Boomerang": "https://www.zeldadungeon.net/wiki/images/thumb/f/f0/Boomerang-ALttP-Sprite.png/86px-Boomerang-ALttP-Sprite.png",
"Red Boomerang": "https://www.zeldadungeon.net/wiki/images/thumb/3/3c/MagicalBoomerang-ALttP-Sprite.png/86px-MagicalBoomerang-ALttP-Sprite.png",
"Hookshot": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/2/24/Hookshot.png",
"Mushroom": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/3/35/ALttP_Mushroom_Sprite.png",
"Magic Powder": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/e5/ALttP_Magic_Powder_Sprite.png",
"Fire Rod": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/d6/FireRod.png",
"Ice Rod": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/d7/ALttP_Ice_Rod_Sprite.png",
"Bombos": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/8/8c/ALttP_Bombos_Medallion_Sprite.png",
"Ether": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/3/3c/Ether.png",
"Quake": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/5/56/ALttP_Quake_Medallion_Sprite.png",
"Lamp": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/6/63/ALttP_Lantern_Sprite.png",
"Hammer": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/d1/ALttP_Hammer_Sprite.png",
"Shovel": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/c/c4/ALttP_Shovel_Sprite.png",
"Flute": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/db/Flute.png",
"Bug Catching Net": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/5/54/Bug-CatchingNet.png",
"Book of Mudora": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/2/22/ALttP_Book_of_Mudora_Sprite.png",
"Bottles": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/ef/ALttP_Magic_Bottle_Sprite.png",
"Cane of Somaria": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/e1/ALttP_Cane_of_Somaria_Sprite.png",
"Cane of Byrna": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/b/bc/ALttP_Cane_of_Byrna_Sprite.png",
"Cape": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/1/1c/ALttP_Magic_Cape_Sprite.png",
"Magic Mirror": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/e5/ALttP_Magic_Mirror_Sprite.png",
"Triforce": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/4/4e/TriforceALttPTitle.png",
"Triforce Piece": "https://www.zeldadungeon.net/wiki/images/thumb/5/54/Triforce_Fragment_-_BS_Zelda.png/62px-Triforce_Fragment_-_BS_Zelda.png",
"Small Key": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/f/f1/ALttP_Small_Key_Sprite.png?version=4f35d92842f0de39d969181eea03774e",
"Big Key": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/3/33/ALttP_Big_Key_Sprite.png?version=136dfa418ba76c8b4e270f466fc12f4d",
"Bombs": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/3/38/ALttP_Bomb_Sprite.png",
"Small Key": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/f/f1/ALttP_Small_Key_Sprite.png",
"Big Key": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/3/33/ALttP_Big_Key_Sprite.png",
"Chest": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/7/73/ALttP_Treasure_Chest_Sprite.png?version=5f530ecd98dcb22251e146e8049c0dda",
"Light World": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/e7/ALttP_Soldier_Green_Sprite.png?version=d650d417934cd707a47e496489c268a6",
"Dark World": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/9/94/ALttP_Moblin_Sprite.png?version=ebf50e33f4657c377d1606bcc0886ddc",
@ -68,33 +58,93 @@
"Misery Mire": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/8/85/ALttP_Vitreous_Sprite.png?version=92b2e9cb0aa63f831760f08041d8d8d8",
"Turtle Rock": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/9/91/ALttP_Trinexx_Sprite.png?version=0cc867d513952aa03edd155597a0c0be",
"Ganons Tower": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/b/b9/ALttP_Ganon_Sprite.png?version=956f51f054954dfff53c1a9d4f929c74",
} -%}
} %}
{% set inventory_order = [
"Progressive Sword",
"Progressive Bow",
"Blue Boomerang",
"Red Boomerang",
"Hookshot",
"Bombs",
"Mushroom",
"Magic Powder",
"Fire Rod",
"Ice Rod",
"Bombos",
"Ether",
"Quake",
"Lamp",
"Hammer",
"Flute",
"Bug Catching Net",
"Book of Mudora",
"Cane of Somaria",
"Cane of Byrna",
"Cape",
"Magic Mirror",
"Shovel",
"Pegasus Boots",
"Flippers",
"Progressive Glove",
"Moon Pearl",
"Bottles",
"Triforce Piece",
"Triforce",
] %}
{% set dungeon_keys = {
"Hyrule Castle": ("Small Key (Hyrule Castle)", "Big Key (Hyrule Castle)"),
"Agahnims Tower": ("Small Key (Agahnims Tower)", "Big Key (Agahnims Tower)"),
"Eastern Palace": ("Small Key (Eastern Palace)", "Big Key (Eastern Palace)"),
"Desert Palace": ("Small Key (Desert Palace)", "Big Key (Desert Palace)"),
"Tower of Hera": ("Small Key (Tower of Hera)", "Big Key (Tower of Hera)"),
"Palace of Darkness": ("Small Key (Palace of Darkness)", "Big Key (Palace of Darkness)"),
"Thieves Town": ("Small Key (Thieves Town)", "Big Key (Thieves Town)"),
"Skull Woods": ("Small Key (Skull Woods)", "Big Key (Skull Woods)"),
"Swamp Palace": ("Small Key (Swamp Palace)", "Big Key (Swamp Palace)"),
"Ice Palace": ("Small Key (Ice Palace)", "Big Key (Ice Palace)"),
"Misery Mire": ("Small Key (Misery Mire)", "Big Key (Misery Mire)"),
"Turtle Rock": ("Small Key (Turtle Rock)", "Big Key (Turtle Rock)"),
"Ganons Tower": ("Small Key (Ganons Tower)", "Big Key (Ganons Tower)"),
} %}
{% set multi_items = [
"Progressive Sword",
"Progressive Glove",
"Progressive Bow",
"Bottles",
"Triforce Piece",
] %}
{%- block custom_table_headers %}
{#- macro that creates a table header with display name and image -#}
{%- macro make_header(name, img_src) %}
<th class="center-column">
<img height="24" src="{{ img_src }}" title="{{ name }}" alt="{{ name }}" />
</th>
{% endmacro -%}
{#- call the macro to build the table header -#}
{%- for name in tracking_names %}
{%- if name in icons -%}
{#- macro that creates a table header with display name and image -#}
{%- macro make_header(name, img_src) %}
<th class="center-column">
<img class="icon-sprite" src="{{ icons[name] }}" alt="{{ name | e }}" title="{{ name | e }}" />
<img height="24" src="{{ img_src }}" title="{{ name }}" alt="{{ name }}">
</th>
{%- endif %}
{% endfor -%}
{% endmacro -%}
{#- call the macro to build the table header -#}
{%- for item in inventory_order %}
{%- if item in icons -%}
<th class="center-column">
<img class="icon-sprite" src="{{ icons[item] }}" alt="{{ item | e }}" title="{{ item | e }}">
</th>
{%- endif %}
{% endfor -%}
{% endblock %}
{# build each row of custom entries #}
{% block custom_table_row scoped %}
{%- for id in tracking_ids -%}
{# {{ checks }}#}
{%- if inventories[(team, player)][id] -%}
{%- for item in inventory_order -%}
{%- if inventories[(team, player)][item] -%}
<td class="center-column item-acquired">
{% if id in multi_items %}{{ inventories[(team, player)][id] }}{% else %}✔️{% endif %}
{% if item in multi_items %}
{{ inventories[(team, player)][item] }}
{% else %}
✔️
{% endif %}
</td>
{%- else -%}
<td></td>
@ -104,102 +154,95 @@
{% block custom_tables %}
{% for team, _ in total_team_locations.items() %}
<div class="table-wrapper">
<table id="area-table" class="table non-unique-item-table">
<thead>
<tr>
<th rowspan="2">#</th>
<th rowspan="2">Name</th>
{% for area in ordered_areas %}
{% set colspan = 1 %}
{% if area in key_locations %}
{% set colspan = colspan + 1 %}
{% endif %}
{% if area in big_key_locations %}
{% set colspan = colspan + 1 %}
{% endif %}
{% if area in icons %}
<th colspan="{{ colspan }}" class="center-column upper-row">
<img class="icon-sprite" src="{{ icons[area] }}" alt="{{ area }}" title="{{ area }}"></th>
{%- else -%}
<th colspan="{{ colspan }}" class="center-column">{{ area }}</th>
{%- endif -%}
{%- endfor -%}
<th rowspan="2" class="center-column">&percnt;</th>
<th rowspan="2" class="center-column hours">Last<br>Activity</th>
</tr>
<tr>
{% for area in ordered_areas %}
{% for team in total_team_locations %}
<div class="table-wrapper">
<table class="table non-unique-item-table">
<thead>
<tr>
<th rowspan="2">#</th>
<th rowspan="2">Name</th>
{% for region in known_regions %}
{% set colspan = 1 %}
{% if region == "Agahnims Tower" %}
{% set colspan = 2 %}
{% elif region in dungeon_keys %}
{% set colspan = 3 %}
{% endif %}
{% if region in icons %}
<th colspan="{{ colspan }}" class="center-column upper-row">
<img class="icon-sprite" src="{{ icons[region] }}" alt="{{ region }}" title="{{ region }}">
</th>
{% else %}
<th colspan="{{ colspan }}" class="center-column">{{ region }}</th>
{% endif %}
{% endfor %}
<th class="center-column">Total</th>
</tr>
<tr>
{% for region in known_regions %}
<th class="center-column lower-row fraction">
<img class="icon-sprite" src="{{ icons["Chest"] }}" alt="Checks" title="Checks Complete">
</th>
{% if region in dungeon_keys %}
<th class="center-column lower-row number">
<img class="icon-sprite" src="{{ icons["Small Key"] }}" alt="Small Key" title="Small Keys">
</th>
{# Special check just for Agahnims Tower, which has no big keys. #}
{% if region != "Agahnims Tower" %}
<th class="center-column lower-row number">
<img class="icon-sprite" src="{{ icons["Big Key"] }}" alt="Big Key" title="Big Keys">
</th>
{% endif %}
{% endif %}
{% endfor %}
{# For "total" checks #}
<th class="center-column lower-row fraction">
<img class="icon-sprite" src="{{ icons["Chest"] }}" alt="Checks" title="Checks Complete">
<img class="icon-sprite" src="{{ icons["Chest"] }}" alt="Checks" title="Total Checks Complete">
</th>
{% if area in key_locations %}
<th class="center-column lower-row number">
<img class="icon-sprite" src="{{ icons["Small Key"] }}" alt="Small Key" title="Small Keys">
</th>
{% endif %}
{% if area in big_key_locations %}
<th class="center-column lower-row number">
<img class="icon-sprite" src="{{ icons["Big Key"] }}" alt="Big Key" title="Big Keys">
</th>
{%- endif -%}
{%- endfor -%}
</tr>
</thead>
<tbody>
{%- for (checks_team, player), area_checks in checks_done.items() if games[(team, player)] == current_tracker and team == checks_team -%}
<tr>
<td><a href="{{ url_for("get_player_tracker", tracker=room.tracker,
tracked_team=team, tracked_player=player)}}">{{ player }}</a></td>
<td>{{ player_names_with_alias[(team, player)] | e }}</td>
{%- for area in ordered_areas -%}
{% if (team, player) in checks_in_area and area in checks_in_area[(team, player)] %}
{%- set checks_done = area_checks[area] -%}
{%- set checks_total = checks_in_area[(team, player)][area] -%}
{%- if checks_done == checks_total -%}
</tr>
</thead>
<tbody>
{% for (player_team, player), player_regions in regions.items() if team == player_team %}
<tr>
<td>
<a href="{{ url_for("get_player_tracker", tracker=room.tracker, tracked_team=team, tracked_player=player) }}">
{{ player }}
</a>
</td>
<td>{{ player_names_with_alias[(team, player)] | e }}</td>
{% for region, counts in player_regions.items() %}
<td class="item-acquired center-column">
{{ checks_done }}/{{ checks_total }}</td>
{%- else -%}
<td class="center-column">{{ checks_done }}/{{ checks_total }}</td>
{%- endif -%}
{%- if area in key_locations -%}
<td class="center-column">{{ inventories[(team, player)][small_key_ids[area]] }}</td>
{%- endif -%}
{%- if area in big_key_locations -%}
<td class="center-column">{% if inventories[(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 -%}
{{ counts.checked }}/{{ counts.total }}
</td>
<td class="center-column">
{% set location_count = locations[(team, player)] | length %}
{%- if locations[(team, player)] | length > 0 -%}
{% set percentage_of_completion = locations_complete[(team, player)] / location_count * 100 %}
{{ "{0:.2f}".format(percentage_of_completion) }}
{%- else -%}
100.00
{%- endif -%}
</td>
{% if region in dungeon_keys %}
<td class="center-column">
{{ inventories[(team, player)][dungeon_keys[region][0]] }}
</td>
{%- if activity_timers[(team, player)] -%}
<td class="center-column">{{ activity_timers[(team, player)].total_seconds() }}</td>
{%- else -%}
<td class="center-column">None</td>
{%- endif -%}
</tr>
{%- endfor -%}
</tbody>
</table>
</div>
{# Special check just for Agahnims Tower, which has no big keys. #}
{% if region != "Agahnims Tower" %}
<td class="center-column">
{% if inventories[(team, player)][dungeon_keys[region][1]] %}
✔️
{% endif %}
</td>
{% endif %}
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endfor %}
{% endblock %}

View File

@ -68,9 +68,9 @@
"Desert Palace": ("Small Key (Desert Palace)", "Big Key (Desert Palace)"),
"Tower of Hera": ("Small Key (Tower of Hera)", "Big Key (Tower of Hera)"),
"Palace of Darkness": ("Small Key (Palace of Darkness)", "Big Key (Palace of Darkness)"),
"Thieves' Town": ("Small Key (Thieves Town)", "Big Key (Thieves Town)"),
"Skull Woods": ("Small Key (Skull Woods)", "Big Key (Skull Woods)"),
"Swamp Palace": ("Small Key (Swamp Palace)", "Big Key (Swamp Palace)"),
"Thieves Town": ("Small Key (Thieves Town)", "Big Key (Thieves Town)"),
"Skull Woods": ("Small Key (Skull Woods)", "Big Key (Skull Woods)"),
"Ice Palace": ("Small Key (Ice Palace)", "Big Key (Ice Palace)"),
"Misery Mire": ("Small Key (Misery Mire)", "Big Key (Misery Mire)"),
"Turtle Rock": ("Small Key (Turtle Rock)", "Big Key (Turtle Rock)"),
@ -146,7 +146,8 @@
<div><img src="{{ icons['Big Key'] }}" alt="BK" title="Big Keys"></div>
</div>
{% for region_name, region_data in regions.items() %}
{% for region_name in known_regions %}
{% set region_data = regions[region_name] %}
{% if region_data["locations"] | length > 0 %}
<details class="region-details">
<summary>

View File

@ -1,7 +1,7 @@
import datetime
import collections
from dataclasses import dataclass
from typing import Any, Callable, Dict, List, Optional, Set, Tuple
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, NamedTuple
from uuid import UUID
from flask import render_template
@ -456,210 +456,111 @@ if "Factorio" in network_data_package["games"]:
_multiworld_trackers["Factorio"] = render_Factorio_multiworld_tracker
if "A Link to the Past" in network_data_package["games"]:
# Mapping from non-progressive item to progressive name and max level.
non_progressive_items = {
"Fighter Sword": ("Progressive Sword", 1),
"Master Sword": ("Progressive Sword", 2),
"Tempered Sword": ("Progressive Sword", 3),
"Golden Sword": ("Progressive Sword", 4),
"Power Glove": ("Progressive Glove", 1),
"Titans Mitts": ("Progressive Glove", 2),
"Bow": ("Progressive Bow", 1),
"Silver Bow": ("Progressive Bow", 2),
"Blue Mail": ("Progressive Mail", 1),
"Red Mail": ("Progressive Mail", 2),
"Blue Shield": ("Progressive Shield", 1),
"Red Shield": ("Progressive Shield", 2),
"Mirror Shield": ("Progressive Shield", 3),
}
progressive_item_max = {
"Progressive Sword": 4,
"Progressive Glove": 2,
"Progressive Bow": 2,
"Progressive Mail": 2,
"Progressive Shield": 3,
}
bottle_items = [
"Bottle",
"Bottle (Bee)",
"Bottle (Blue Potion)",
"Bottle (Fairy)",
"Bottle (Good Bee)",
"Bottle (Green Potion)",
"Bottle (Red Potion)",
]
known_regions = [
"Light World", "Dark World", "Hyrule Castle", "Agahnims Tower", "Eastern Palace", "Desert Palace",
"Tower of Hera", "Palace of Darkness", "Swamp Palace", "Thieves Town", "Skull Woods", "Ice Palace",
"Misery Mire", "Turtle Rock", "Ganons Tower"
]
class RegionCounts(NamedTuple):
total: int
checked: int
def prepare_inventories(team: int, player: int, inventory: collections.Counter[str], tracker_data: TrackerData):
for item, (prog_item, level) in non_progressive_items.items():
if item in inventory:
inventory[prog_item] = min(max(inventory[prog_item], level), progressive_item_max[prog_item])
for bottle in bottle_items:
inventory["Bottles"] = min(inventory["Bottles"] + inventory[bottle], 4)
if "Progressive Bow (Alt)" in inventory:
inventory["Progressive Bow"] += inventory["Progressive Bow (Alt)"]
inventory["Progressive Bow"] = min(inventory["Progressive Bow"], progressive_item_max["Progressive Bow"])
# Highlight 'bombs' if we received any bomb upgrades in bombless start.
# In race mode, we'll just assume bombless start for simplicity.
if tracker_data.get_slot_data(team, player).get("bombless_start", True):
inventory["Bombs"] = sum(count for item, count in inventory.items() if item.startswith("Bomb Upgrade"))
else:
inventory["Bombs"] = 1
# Triforce item if we meet goal.
if tracker_data.get_room_client_statuses()[team, player] == ClientStatus.CLIENT_GOAL:
inventory["Triforce"] = 1
def render_ALinkToThePast_multiworld_tracker(tracker_data: TrackerData, enabled_trackers: List[str]):
# Helper objects.
alttp_id_lookup = tracker_data.item_name_to_id["A Link to the Past"]
inventories: Dict[Tuple[int, int], collections.Counter[str]] = {
(team, player): collections.Counter({
tracker_data.item_id_to_name["A Link to the Past"][code]: count
for code, count in tracker_data.get_player_inventory_counts(team, player).items()
})
for team, players in tracker_data.get_all_players().items()
for player in players if tracker_data.get_slot_info(team, player).game == "A Link to the Past"
}
multi_items = {
alttp_id_lookup[name]
for name in ("Progressive Sword", "Progressive Bow", "Bottle", "Progressive Glove", "Triforce Piece")
}
links = {
"Bow": "Progressive Bow",
"Silver Arrows": "Progressive Bow",
"Silver Bow": "Progressive Bow",
"Progressive Bow (Alt)": "Progressive Bow",
"Bottle (Red Potion)": "Bottle",
"Bottle (Green Potion)": "Bottle",
"Bottle (Blue Potion)": "Bottle",
"Bottle (Fairy)": "Bottle",
"Bottle (Bee)": "Bottle",
"Bottle (Good Bee)": "Bottle",
"Fighter Sword": "Progressive Sword",
"Master Sword": "Progressive Sword",
"Tempered Sword": "Progressive Sword",
"Golden Sword": "Progressive Sword",
"Power Glove": "Progressive Glove",
"Titans Mitts": "Progressive Glove",
}
links = {alttp_id_lookup[key]: alttp_id_lookup[value] for key, value in links.items()}
levels = {
"Fighter Sword": 1,
"Master Sword": 2,
"Tempered Sword": 3,
"Golden Sword": 4,
"Power Glove": 1,
"Titans Mitts": 2,
"Bow": 1,
"Silver Bow": 2,
"Triforce Piece": 90,
}
tracking_names = [
"Progressive Sword", "Progressive Bow", "Book of Mudora", "Hammer", "Hookshot", "Magic Mirror", "Flute",
"Pegasus Boots", "Progressive Glove", "Flippers", "Moon Pearl", "Blue Boomerang", "Red Boomerang",
"Bug Catching Net", "Cape", "Shovel", "Lamp", "Mushroom", "Magic Powder", "Cane of Somaria",
"Cane of Byrna", "Fire Rod", "Ice Rod", "Bombos", "Ether", "Quake", "Bottle", "Triforce Piece", "Triforce",
]
default_locations = {
"Light World": {
1572864, 1572865, 60034, 1572867, 1572868, 60037, 1572869, 1572866, 60040, 59788, 60046, 60175,
1572880, 60049, 60178, 1572883, 60052, 60181, 1572885, 60055, 60184, 191256, 60058, 60187, 1572884,
1572886, 1572887, 1572906, 60202, 60205, 59824, 166320, 1010170, 60208, 60211, 60214, 60217, 59836,
60220, 60223, 59839, 1573184, 60226, 975299, 1573188, 1573189, 188229, 60229, 60232, 1573193,
1573194, 60235, 1573187, 59845, 59854, 211407, 60238, 59857, 1573185, 1573186, 1572882, 212328,
59881, 59761, 59890, 59770, 193020, 212605
},
"Dark World": {
59776, 59779, 975237, 1572870, 60043, 1572881, 60190, 60193, 60196, 60199, 60840, 1573190, 209095,
1573192, 1573191, 60241, 60244, 60247, 60250, 59884, 59887, 60019, 60022, 60028, 60031
},
"Desert Palace": {1573216, 59842, 59851, 59791, 1573201, 59830},
"Eastern Palace": {1573200, 59827, 59893, 59767, 59833, 59773},
"Hyrule Castle": {60256, 60259, 60169, 60172, 59758, 59764, 60025, 60253},
"Agahnims Tower": {60082, 60085},
"Tower of Hera": {1573218, 59878, 59821, 1573202, 59896, 59899},
"Swamp Palace": {60064, 60067, 60070, 59782, 59785, 60073, 60076, 60079, 1573204, 60061},
"Thieves Town": {59905, 59908, 59911, 59914, 59917, 59920, 59923, 1573206},
"Skull Woods": {59809, 59902, 59848, 59794, 1573205, 59800, 59803, 59806},
"Ice Palace": {59872, 59875, 59812, 59818, 59860, 59797, 1573207, 59869},
"Misery Mire": {60001, 60004, 60007, 60010, 60013, 1573208, 59866, 59998},
"Turtle Rock": {59938, 59941, 59944, 1573209, 59947, 59950, 59953, 59956, 59926, 59929, 59932, 59935},
"Palace of Darkness": {
59968, 59971, 59974, 59977, 59980, 59983, 59986, 1573203, 59989, 59959, 59992, 59962, 59995,
59965
},
"Ganons Tower": {
60160, 60163, 60166, 60088, 60091, 60094, 60097, 60100, 60103, 60106, 60109, 60112, 60115, 60118,
60121, 60124, 60127, 1573217, 60130, 60133, 60136, 60139, 60142, 60145, 60148, 60151, 60157
},
"Total": set()
}
key_only_locations = {
"Light World": set(),
"Dark World": set(),
"Desert Palace": {0x140031, 0x14002b, 0x140061, 0x140028},
"Eastern Palace": {0x14005b, 0x140049},
"Hyrule Castle": {0x140037, 0x140034, 0x14000d, 0x14003d},
"Agahnims Tower": {0x140061, 0x140052},
"Tower of Hera": set(),
"Swamp Palace": {0x140019, 0x140016, 0x140013, 0x140010, 0x14000a},
"Thieves Town": {0x14005e, 0x14004f},
"Skull Woods": {0x14002e, 0x14001c},
"Ice Palace": {0x140004, 0x140022, 0x140025, 0x140046},
"Misery Mire": {0x140055, 0x14004c, 0x140064},
"Turtle Rock": {0x140058, 0x140007},
"Palace of Darkness": set(),
"Ganons Tower": {0x140040, 0x140043, 0x14003a, 0x14001f},
"Total": set()
}
location_to_area = {}
for area, locations in default_locations.items():
for location in locations:
location_to_area[location] = area
for area, locations in key_only_locations.items():
for location in locations:
location_to_area[location] = area
# Translate non-progression items to progression items for tracker simplicity.
for (team, player), inventory in inventories.items():
prepare_inventories(team, player, inventory, tracker_data)
checks_in_area = {area: len(checks) for area, checks in default_locations.items()}
checks_in_area["Total"] = 216
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"
)
player_checks_in_area = {
regions: Dict[Tuple[int, int], Dict[str, RegionCounts]] = {
(team, player): {
area_name: len(tracker_data._multidata["checks_in_area"][player][area_name])
if area_name != "Total" else tracker_data._multidata["checks_in_area"][player]["Total"]
for area_name in ordered_areas
region_name: RegionCounts(
total=len(tracker_data._multidata["checks_in_area"][player][region_name]),
checked=sum(
1 for location in tracker_data._multidata["checks_in_area"][player][region_name]
if location in tracker_data.get_player_checked_locations(team, player)
),
)
for region_name in known_regions
}
for team, players in tracker_data.get_all_slots().items()
for player in players
if tracker_data.get_slot_info(team, player).type != SlotType.group and
tracker_data.get_slot_info(team, player).game == "A Link to the Past"
for team, players in tracker_data.get_all_players().items()
for player in players if tracker_data.get_slot_info(team, player).game == "A Link to the Past"
}
tracking_ids = []
for item in tracking_names:
tracking_ids.append(alttp_id_lookup[item])
# Can't wait to get this into the apworld. Oof.
from worlds.alttp import Items
small_key_ids = {}
big_key_ids = {}
ids_small_key = {}
ids_big_key = {}
for item_name, data in Items.item_table.items():
if "Key" in item_name:
area = item_name.split("(")[1][:-1]
if "Small" in item_name:
small_key_ids[area] = data[2]
ids_small_key[data[2]] = area
else:
big_key_ids[area] = data[2]
ids_big_key[data[2]] = area
def _get_location_table(checks_table: dict) -> dict:
loc_to_area = {}
for area, locations in checks_table.items():
if area == "Total":
continue
for location in locations:
loc_to_area[location] = area
return loc_to_area
player_location_to_area = {
(team, player): _get_location_table(tracker_data._multidata["checks_in_area"][player])
for team, players in tracker_data.get_all_slots().items()
for player in players
if tracker_data.get_slot_info(team, player).type != SlotType.group and
tracker_data.get_slot_info(team, player).game == "A Link to the Past"
}
checks_done: Dict[TeamPlayer, Dict[str: int]] = {
(team, player): {location_name: 0 for location_name in default_locations}
for team, players in tracker_data.get_all_slots().items()
for player in players
if tracker_data.get_slot_info(team, player).type != SlotType.group and
tracker_data.get_slot_info(team, player).game == "A Link to the Past"
}
inventories: Dict[TeamPlayer, Dict[int, int]] = {}
player_big_key_locations = {(player): set() for player in tracker_data.get_all_slots()[0]}
player_small_key_locations = {player: set() for player in tracker_data.get_all_slots()[0]}
group_big_key_locations = set()
group_key_locations = set()
for (team, player), locations in checks_done.items():
# Check if game complete.
if tracker_data.get_player_client_status(team, player) == ClientStatus.CLIENT_GOAL:
inventories[team, player][106] = 1 # Triforce
# Count number of locations checked.
for location in tracker_data.get_player_checked_locations(team, player):
checks_done[team, player][player_location_to_area[team, player][location]] += 1
checks_done[team, player]["Total"] += 1
# Count keys.
for location, (item, receiving, _) in tracker_data.get_player_locations(team, player).items():
if item in ids_big_key:
player_big_key_locations[receiving].add(ids_big_key[item])
elif item in ids_small_key:
player_small_key_locations[receiving].add(ids_small_key[item])
# Iterate over received items and build inventory/key counts.
inventories[team, player] = collections.Counter()
for network_item in tracker_data.get_player_received_items(team, player):
target_item = links.get(network_item.item, network_item.item)
if network_item.item in levels: # non-progressive
inventories[team, player][target_item] = (max(inventories[team, player][target_item], levels[network_item.item]))
else:
inventories[team, player][target_item] += 1
group_key_locations |= player_small_key_locations[player]
group_big_key_locations |= player_big_key_locations[player]
# Get a totals count.
for player, player_regions in regions.items():
total = 0
checked = 0
for region, region_counts in player_regions.items():
total += region_counts.total
checked += region_counts.checked
regions[player]["Total"] = RegionCounts(total, checked)
return render_template(
"multitracker__ALinkToThePast.html",
@ -682,16 +583,8 @@ if "A Link to the Past" in network_data_package["games"]:
item_id_to_name=tracker_data.item_id_to_name,
location_id_to_name=tracker_data.location_id_to_name,
inventories=inventories,
tracking_names=tracking_names,
tracking_ids=tracking_ids,
multi_items=multi_items,
checks_done=checks_done,
ordered_areas=ordered_areas,
checks_in_area=player_checks_in_area,
key_locations=group_key_locations,
big_key_locations=group_big_key_locations,
small_key_ids=small_key_ids,
big_key_ids=big_key_ids,
regions=regions,
known_regions=known_regions,
)
def render_ALinkToThePast_tracker(tracker_data: TrackerData, team: int, player: int) -> str:
@ -700,161 +593,26 @@ if "A Link to the Past" in network_data_package["games"]:
for code, count in tracker_data.get_player_inventory_counts(team, player).items()
})
# Mapping from non-progressive item to progressive name and max level.
non_progressive_items = {
"Fighter Sword": ("Progressive Sword", 1),
"Master Sword": ("Progressive Sword", 2),
"Tempered Sword": ("Progressive Sword", 3),
"Golden Sword": ("Progressive Sword", 4),
"Power Glove": ("Progressive Glove", 1),
"Titans Mitts": ("Progressive Glove", 2),
"Bow": ("Progressive Bow", 1),
"Silver Bow": ("Progressive Bow", 2),
"Blue Mail": ("Progressive Mail", 1),
"Red Mail": ("Progressive Mail", 2),
"Blue Shield": ("Progressive Shield", 1),
"Red Shield": ("Progressive Shield", 2),
"Mirror Shield": ("Progressive Shield", 3),
}
progressive_item_max = {
"Progressive Sword": 4,
"Progressive Glove": 2,
"Progressive Bow": 2,
"Progressive Mail": 2,
"Progressive Shield": 3,
}
bottle_items = [
"Bottle",
"Bottle (Bee)",
"Bottle (Blue Potion)",
"Bottle (Fairy)",
"Bottle (Good Bee)",
"Bottle (Green Potion)",
"Bottle (Red Potion)",
]
# Translate non-progression items to progression items for tracker simplicity.
for item, (prog_item, level) in non_progressive_items.items():
if item in inventory:
inventory[prog_item] = min(max(inventory[prog_item], level), progressive_item_max[prog_item])
for bottle in bottle_items:
inventory["Bottles"] = min(inventory["Bottles"] + inventory[bottle], 4)
if "Progressive Bow (Alt)" in inventory:
inventory["Progressive Bow"] += inventory["Progressive Bow (Alt)"]
inventory["Progressive Bow"] = min(inventory["Progressive Bow"], progressive_item_max["Progressive Bow"])
# Highlight 'bombs' if we received any bomb upgrades in bombless start.
# In race mode, we'll just assume bombless start for simplicity.
if tracker_data.get_slot_data(team, player).get("bombless_start", True):
inventory["Bombs"] = sum(count for item, count in inventory.items() if item.startswith("Bomb Upgrade"))
else:
inventory["Bombs"] = 1
known_regions = {
"Light World": {
0x180013, 0x02eb18, 0x18014a, 0x180145, 0x033d68, 0x00eb0f, 0x00eb12, 0x00eb15, 0x00eb18, 0x00eb1b,
0x02df45, 0x00e971, 0x0ee1c3, 0x180149, 0x00e9b0, 0x00e9d1, 0x00e97a, 0x00e98c, 0x00e9bc, 0x00e9ce,
0x00e9e9, 0x00e9f2, 0x00ea82, 0x00ea85, 0x00ea88, 0x02f1fc, 0x00ea8e, 0x00ea91, 0x00ea94, 0x00ea97,
0x00ea9a, 0x18002a, 0x180015, 0x0339cf, 0x033e7d, 0x180000, 0x180001, 0x180003, 0x180004, 0x180005,
0x00eb42, 0x00eb45, 0x00eb48, 0x00eb4b, 0x180010, 0x00eb4e, 0x00eb3f, 0x180012, 0x180014, 0x180144,
0x180142, 0x180143, 0x0289b0, 0x0f69fa, 0x180002, 0x00eb2a, 0x00eb2d, 0x00eb30, 0x00eb33, 0x00eb36,
0x00eb39, 0x00eb3c, 0x00e9bf, 0x180016, 0x180017, 0x180140, 0x180141, 0x00e9c5, 0x400018, 0x400019,
0x40001a, 0x400015, 0x400016, 0x400017, 0x400012, 0x400013, 0x400014, 0x40001b, 0x40001c, 0x40001d,
0x400022, 0x400023, 0x400024, 0x400025, 0x400021, 0x40001e, 0x40001f,
},
"Dark World": {
0x180147, 0x0ee185, 0x0330c7, 0x180148, 0x00eb1e, 0x00eb21, 0x00eb24, 0x00eb27, 0x180011, 0x180006,
0x00e980, 0x00e983, 0x00e9ec, 0x00e9ef, 0x00eda8, 0x180146, 0x00ea73, 0x00ea76, 0x00ea7c, 0x00ea7f,
0x00ea8b, 0x00eb51, 0x00eb54, 0x00eb5a, 0x00eb57, 0x400000, 0x400001, 0x400002, 0x400006, 0x400007,
0x400008, 0x400009, 0x40000a, 0x40000b, 0x40000f, 0x400010, 0x400011, 0x400003, 0x400004, 0x400005,
0x40000c, 0x40000d, 0x40000e,
},
"Hyrule Castle": {
0x00e974, 0x00eb0c, 0x00eb09, 0x00e96e, 0x00eb5d, 0x00eb60, 0x00eb63, 0x00ea79, 0x140037, 0x140034,
0x14000d, 0x14003d,
},
"Agahnims Tower": {
0x00eab5, 0x00eab2, 0x140061, 0x140052,
},
"Eastern Palace": {
0x00e977, 0x00e97d, 0x00e9b3, 0x00e9b9, 0x00e9f5, 0x180150, 0x14005b, 0x140049,
},
"Desert Palace": {
0x00e98f, 0x180160, 0x00e9b6, 0x00e9cb, 0x00e9c2, 0x180151, 0x140031, 0x14002b, 0x140028,
},
"Tower of Hera": {
0x180162, 0x00e9ad, 0x00e9e6, 0x00e9fb, 0x00e9f8, 0x180152
},
"Palace of Darkness": {
0x00ea5b, 0x00ea3d, 0x00ea49, 0x00ea37, 0x00ea3a, 0x00ea52, 0x00ea43, 0x00ea4c, 0x00ea4f, 0x00ea55,
0x00ea58, 0x00ea40, 0x00ea46, 0x180153,
},
"Swamp Palace": {
0x00ea9d, 0x00e986, 0x00e989, 0x00eaa0, 0x00eaa6, 0x00eaa3, 0x00eaa9, 0x00eaac, 0x00eaaf, 0x180154,
0x140019, 0x140016, 0x140013, 0x140010, 0x14000a,
},
"Thieves' Town": {
0x00ea04, 0x00ea01, 0x00ea07, 0x00ea0a, 0x00ea0d, 0x00ea10, 0x00ea13, 0x180156, 0x14005e, 0x14004f,
},
"Skull Woods": {
0x00e992, 0x00e99b, 0x00e998, 0x00e9a1, 0x00e9c8, 0x00e99e, 0x00e9fe, 0x180155, 0x14002e, 0x14001c,
},
"Ice Palace": {
0x00e9d4, 0x00e995, 0x00e9aa, 0x00e9e3, 0x00e9e0, 0x00e9a4, 0x00e9dd, 0x180157, 0x140004, 0x140022,
0x140025, 0x140046,
},
"Misery Mire": {
0x00ea67, 0x00ea6a, 0x00ea5e, 0x00ea61, 0x00e9da, 0x00ea64, 0x00ea6d, 0x180158, 0x140055, 0x14004c,
0x140064,
},
"Turtle Rock": {
0x00ea22, 0x00ea1c, 0x00ea1f, 0x00ea16, 0x00ea25, 0x00ea19, 0x00ea34, 0x00ea31, 0x00ea2e, 0x00ea2b,
0x00ea28, 0x180159, 0x140058, 0x140007,
},
"Ganons Tower": {
0x180161, 0x00ead9, 0x00eadc, 0x00eae2, 0x00eae5, 0x00eae8, 0x00eaeb, 0x00eaee, 0x00eab8, 0x00eabb,
0x00eabe, 0x00eac1, 0x00ead3, 0x00ead0, 0x00eac4, 0x00eac7, 0x00eaca, 0x00eacd, 0x00eadf, 0x00eadf,
0x00ead6, 0x00eaf4, 0x00eaf7, 0x00eaf1, 0x00eafd, 0x00eb00, 0x00eb03, 0x00eb06, 0x140040, 0x140043,
0x14003a, 0x14001f,
},
}
prepare_inventories(team, player, inventory, tracker_data)
regions = {
"Light World": {"checked": 0, "locations": []},
"Dark World": {"checked": 0, "locations": []},
"Hyrule Castle": {"checked": 0, "locations": []},
"Agahnims Tower": {"checked": 0, "locations": []},
"Eastern Palace": {"checked": 0, "locations": []},
"Desert Palace": {"checked": 0, "locations": []},
"Tower of Hera": {"checked": 0, "locations": []},
"Palace of Darkness": {"checked": 0, "locations": []},
"Skull Woods": {"checked": 0, "locations": []},
"Thieves' Town": {"checked": 0, "locations": []},
"Swamp Palace": {"checked": 0, "locations": []},
"Ice Palace": {"checked": 0, "locations": []},
"Misery Mire": {"checked": 0, "locations": []},
"Turtle Rock": {"checked": 0, "locations": []},
"Ganons Tower": {"checked": 0, "locations": []},
"Unknown": {"checked": 0, "locations": []},
region_name: {
"checked": sum(
1 for location in tracker_data._multidata["checks_in_area"][player][region_name]
if location in tracker_data.get_player_checked_locations(team, player)
),
"locations": [
(
tracker_data.location_id_to_name["A Link to the Past"][location],
location in tracker_data.get_player_checked_locations(team, player)
)
for location in tracker_data._multidata["checks_in_area"][player][region_name]
],
}
for region_name in known_regions
}
for location in tracker_data.get_player_locations(team, player):
location_name = tracker_data.location_id_to_name["A Link to the Past"][location]
location_checked = location in tracker_data.get_player_checked_locations(team, player)
for region, region_locations in known_regions.items():
if location in region_locations:
regions[region]["locations"].append((location_name, location_checked))
regions[region]["checked"] += 1 if location_checked else 0
break
else:
# New or missed location in the tables above. Add it to an "unknown region", so it's not forgotten.
regions["Unknown"]["locations"].append((location_name, location_checked))
regions["Unknown"]["checked"] += 1 if location_checked else 0
# Sort locations in regions by name
for region in regions:
regions[region]["locations"].sort()
@ -867,6 +625,7 @@ if "A Link to the Past" in network_data_package["games"]:
inventory=inventory,
player_name=tracker_data.get_player_name(team, player),
regions=regions,
known_regions=known_regions,
)
_multiworld_trackers["A Link to the Past"] = render_ALinkToThePast_multiworld_tracker