ALTTP: Updates to player-specific game tracker. (#3133)
This commit is contained in:
		
							parent
							
								
									a4acdb6ddf
								
							
						
					
					
						commit
						0a1ce5b7d8
					
				| 
						 | 
				
			
			@ -1,20 +0,0 @@
 | 
			
		|||
window.addEventListener('load', () => {
 | 
			
		||||
  const url = window.location;
 | 
			
		||||
  setInterval(() => {
 | 
			
		||||
    const ajax = new XMLHttpRequest();
 | 
			
		||||
    ajax.onreadystatechange = () => {
 | 
			
		||||
      if (ajax.readyState !== 4) { return; }
 | 
			
		||||
 | 
			
		||||
      // Create a fake DOM using the returned HTML
 | 
			
		||||
      const domParser = new DOMParser();
 | 
			
		||||
      const fakeDOM = domParser.parseFromString(ajax.responseText, 'text/html');
 | 
			
		||||
 | 
			
		||||
      // Update item and location trackers
 | 
			
		||||
      document.getElementById('inventory-table').innerHTML = fakeDOM.getElementById('inventory-table').innerHTML;
 | 
			
		||||
      document.getElementById('location-table').innerHTML = fakeDOM.getElementById('location-table').innerHTML;
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
    ajax.open('GET', url);
 | 
			
		||||
    ajax.send();
 | 
			
		||||
  }, 15000)
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -1,75 +0,0 @@
 | 
			
		|||
#player-tracker-wrapper{
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    font-family: LexendDeca-Light, sans-serif;
 | 
			
		||||
    color: white;
 | 
			
		||||
    font-size: 14px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#inventory-table{
 | 
			
		||||
    border-top: 2px solid #000000;
 | 
			
		||||
    border-left: 2px solid #000000;
 | 
			
		||||
    border-right: 2px solid #000000;
 | 
			
		||||
    border-top-left-radius: 4px;
 | 
			
		||||
    border-top-right-radius: 4px;
 | 
			
		||||
    padding: 3px 3px 10px;
 | 
			
		||||
    width: 284px;
 | 
			
		||||
    background-color: #42b149;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#inventory-table td{
 | 
			
		||||
    width: 40px;
 | 
			
		||||
    height: 40px;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#inventory-table img{
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    max-width: 40px;
 | 
			
		||||
    max-height: 40px;
 | 
			
		||||
    filter: grayscale(100%) contrast(75%) brightness(75%);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#inventory-table img.acquired{
 | 
			
		||||
    filter: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#inventory-table img.powder-fix{
 | 
			
		||||
    width: 35px;
 | 
			
		||||
    height: 35px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#location-table{
 | 
			
		||||
    width: 284px;
 | 
			
		||||
    border-left: 2px solid #000000;
 | 
			
		||||
    border-right: 2px solid #000000;
 | 
			
		||||
    border-bottom: 2px solid #000000;
 | 
			
		||||
    border-bottom-left-radius: 4px;
 | 
			
		||||
    border-bottom-right-radius: 4px;
 | 
			
		||||
    background-color: #42b149;
 | 
			
		||||
    padding: 0 3px 3px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#location-table th{
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    padding-right: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#location-table td{
 | 
			
		||||
    padding-top: 2px;
 | 
			
		||||
    padding-bottom: 2px;
 | 
			
		||||
    padding-right: 5px;
 | 
			
		||||
    line-height: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#location-table td.counter{
 | 
			
		||||
    padding-right: 8px;
 | 
			
		||||
    text-align: right;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#location-table img{
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    max-width: 30px;
 | 
			
		||||
    max-height: 30px;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,142 @@
 | 
			
		|||
@import url('https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@100..900&display=swap');
 | 
			
		||||
 | 
			
		||||
.tracker-container {
 | 
			
		||||
    width: 440px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    font-family: "Lexend Deca", Arial, Helvetica, sans-serif;
 | 
			
		||||
    border: 2px solid black;
 | 
			
		||||
    border-radius: 4px;
 | 
			
		||||
    resize: both;
 | 
			
		||||
 | 
			
		||||
    background-color: #42b149;
 | 
			
		||||
    color: white;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.hidden {
 | 
			
		||||
    visibility: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Inventory Grid ****************************************************************************************************/
 | 
			
		||||
.inventory-grid {
 | 
			
		||||
    display: grid;
 | 
			
		||||
    grid-template-columns: repeat(6, minmax(0, 1fr));
 | 
			
		||||
    padding: 1rem;
 | 
			
		||||
    gap: 1rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.inventory-grid .item {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    height: 48px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.inventory-grid .dual-item {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.inventory-grid .missing {
 | 
			
		||||
    /* Missing items will be in full grayscale to signify "uncollected". */
 | 
			
		||||
    filter: grayscale(100%) contrast(75%) brightness(75%);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.inventory-grid .item img,
 | 
			
		||||
.inventory-grid .dual-item img {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    font-size: 0.8rem;
 | 
			
		||||
    text-shadow: 0 1px 2px black;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    image-rendering: crisp-edges;
 | 
			
		||||
    background-size: contain;
 | 
			
		||||
    background-repeat: no-repeat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.inventory-grid .dual-item img {
 | 
			
		||||
    height: 48px;
 | 
			
		||||
    margin: 0 -4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.inventory-grid .dual-item img:first-child {
 | 
			
		||||
    align-self: flex-end;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.inventory-grid .item .quantity {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    right: 0;
 | 
			
		||||
    text-align: right;
 | 
			
		||||
    font-weight: 600;
 | 
			
		||||
    font-size: 1.75rem;
 | 
			
		||||
    line-height: 1.75rem;
 | 
			
		||||
    text-shadow:
 | 
			
		||||
        -1px -1px 0 #000,
 | 
			
		||||
         1px -1px 0 #000,
 | 
			
		||||
        -1px 1px 0 #000,
 | 
			
		||||
         1px 1px 0 #000;
 | 
			
		||||
    user-select: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Regions List ******************************************************************************************************/
 | 
			
		||||
.regions-list {
 | 
			
		||||
    padding: 1rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.regions-list summary {
 | 
			
		||||
    list-style: none;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    gap: 0.5rem;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.regions-list summary::before {
 | 
			
		||||
    content: "⯈";
 | 
			
		||||
    width: 1em;
 | 
			
		||||
    flex-shrink: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.regions-list details {
 | 
			
		||||
    font-weight: 300;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.regions-list details[open] > summary::before {
 | 
			
		||||
    content: "⯆";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.regions-list .region {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    display: grid;
 | 
			
		||||
    grid-template-columns: 20fr 8fr 2fr 2fr;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    gap: 4px;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    font-weight: 300;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.regions-list .region :first-child {
 | 
			
		||||
    text-align: left;
 | 
			
		||||
    font-weight: 500;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.regions-list .region.region-header {
 | 
			
		||||
    margin-left: 24px;
 | 
			
		||||
    width: calc(100% - 24px);
 | 
			
		||||
    padding: 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.regions-list .location-rows {
 | 
			
		||||
    border-top: 1px solid white;
 | 
			
		||||
    display: grid;
 | 
			
		||||
    grid-template-columns: auto 32px;
 | 
			
		||||
    font-weight: 300;
 | 
			
		||||
    padding: 2px 8px;
 | 
			
		||||
    margin-top: 4px;
 | 
			
		||||
    font-size: 0.8rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.regions-list .location-rows :nth-child(even) {
 | 
			
		||||
    text-align: right;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,86 +0,0 @@
 | 
			
		|||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
<head>
 | 
			
		||||
    <title>{{ player_name }}'s Tracker</title>
 | 
			
		||||
    <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename="styles/globalStyles.css") }}"/>
 | 
			
		||||
    <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename="styles/lttp-tracker.css") }}"/>
 | 
			
		||||
    <script type="application/ecmascript" src="{{ url_for('static', filename="assets/lttp-tracker.js") }}"></script>
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
    <div id="player-tracker-wrapper" data-tracker="{{ room.tracker|suuid }}">
 | 
			
		||||
        <table id="inventory-table">
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td><img src="{{ bow_url }}" class="{{ 'acquired' if bow_acquired }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Blue Boomerang"] }}" class="{{ 'acquired' if 'Blue Boomerang' in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Red Boomerang"] }}" class="{{ 'acquired' if 'Red Boomerang' in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Hookshot"] }}" class="{{ 'acquired' if 'Hookshot' in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Magic Powder"] }}" class="powder-fix {{ 'acquired' if 'Magic Powder' in acquired_items }}" /></td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td><img src="{{ icons["Fire Rod"] }}" class="{{ 'acquired' if "Fire Rod" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Ice Rod"] }}" class="{{ 'acquired' if "Ice Rod" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Bombos"] }}" class="{{ 'acquired' if "Bombos" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Ether"] }}" class="{{ 'acquired' if "Ether" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Quake"] }}" class="{{ 'acquired' if "Quake" in acquired_items }}" /></td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td><img src="{{ icons["Lamp"] }}" class="{{ 'acquired' if "Lamp" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Hammer"] }}" class="{{ 'acquired' if "Hammer" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Flute"] }}" class="{{ 'acquired' if "Flute" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Bug Catching Net"] }}" class="{{ 'acquired' if "Bug Catching Net" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Book of Mudora"] }}" class="{{ 'acquired' if "Book of Mudora" in acquired_items }}" /></td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td><img src="{{ icons["Bottle"] }}" class="{{ 'acquired' if "Bottle" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Cane of Somaria"] }}" class="{{ 'acquired' if "Cane of Somaria" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Cane of Byrna"] }}" class="{{ 'acquired' if "Cane of Byrna" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Cape"] }}" class="{{ 'acquired' if "Cape" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Magic Mirror"] }}" class="{{ 'acquired' if "Magic Mirror" in acquired_items }}" /></td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td><img src="{{ icons["Pegasus Boots"] }}" class="{{ 'acquired' if "Pegasus Boots" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ glove_url }}" class="{{ 'acquired' if glove_acquired }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Flippers"] }}" class="{{ 'acquired' if "Flippers" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Moon Pearl"] }}" class="{{ 'acquired' if "Moon Pearl" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Mushroom"] }}" class="{{ 'acquired' if "Mushroom" in acquired_items }}" /></td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td><img src="{{ sword_url }}" class="{{ 'acquired' if sword_acquired }}" /></td>
 | 
			
		||||
                <td><img src="{{ shield_url }}" class="{{ 'acquired' if shield_acquired }}" /></td>
 | 
			
		||||
                <td><img src="{{ mail_url }}" class="acquired" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Shovel"] }}" class="{{ 'acquired' if "Shovel" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Triforce"] }}" class="{{ 'acquired' if "Triforce" in acquired_items }}" /></td>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </table>
 | 
			
		||||
        <table id="location-table">
 | 
			
		||||
            <tr>
 | 
			
		||||
                <th></th>
 | 
			
		||||
                <th class="counter"><img src="{{ icons["Chest"] }}" /></th>
 | 
			
		||||
                {% if key_locations and "Universal" not in key_locations %}
 | 
			
		||||
                    <th class="counter"><img src="{{ icons["Small Key"] }}" /></th>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
                {% if big_key_locations %}
 | 
			
		||||
                    <th><img src="{{ icons["Big Key"] }}" /></th>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
            </tr>
 | 
			
		||||
            {% for area in sp_areas %}
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <td>{{ area }}</td>
 | 
			
		||||
                    <td class="counter">{{ checks_done[area] }} / {{ checks_in_area[area] }}</td>
 | 
			
		||||
                    {% if key_locations and "Universal" not in key_locations %}
 | 
			
		||||
                        <td class="counter">
 | 
			
		||||
                            {{ inventory[small_key_ids[area]] if area in key_locations else '—' }}
 | 
			
		||||
                        </td>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                    {% if big_key_locations %}
 | 
			
		||||
                        <td>
 | 
			
		||||
                            {{ '✔' if area in big_key_locations and inventory[big_key_ids[area]] else ('—' if area not in big_key_locations else '') }}
 | 
			
		||||
                        </td>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                </tr>
 | 
			
		||||
            {% endfor %}
 | 
			
		||||
        </table>
 | 
			
		||||
    </div>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,73 +1,89 @@
 | 
			
		|||
{%- 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://gamepedia.cursecdn.com/zelda_gamepedia_en/e/e5/ALttP_Magic_Powder_Sprite.png?version=c24e38effbd4f80496d35830ce8ff4ec",
 | 
			
		||||
    "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",
 | 
			
		||||
    "Fighter Sword": "https://upload.wikimedia.org/wikibooks/en/8/8e/Zelda_ALttP_item_L-1_Sword.png",
 | 
			
		||||
    "Master Sword": "https://upload.wikimedia.org/wikibooks/en/8/87/BS_Zelda_AST_item_L-2_Sword.png",
 | 
			
		||||
    "Tempered Sword": "https://upload.wikimedia.org/wikibooks/en/c/cc/BS_Zelda_AST_item_L-3_Sword.png",
 | 
			
		||||
    "Golden Sword": "https://upload.wikimedia.org/wikibooks/en/4/40/BS_Zelda_AST_item_L-4_Sword.png",
 | 
			
		||||
    "Bow": "https://www.zeldadungeon.net/wiki/images/thumb/8/8c/BowArrows-ALttP-Sprite.png/120px-BowArrows-ALttP-Sprite.png",
 | 
			
		||||
    "Silver Bow": "https://upload.wikimedia.org/wikibooks/en/6/69/Zelda_ALttP_item_Silver_Arrows.png",
 | 
			
		||||
    "Green Mail": "https://upload.wikimedia.org/wikibooks/en/d/dd/Zelda_ALttP_item_Green_Mail.png",
 | 
			
		||||
    "Blue Mail": "https://upload.wikimedia.org/wikibooks/en/b/b5/Zelda_ALttP_item_Blue_Mail.png",
 | 
			
		||||
    "Red Mail": "https://upload.wikimedia.org/wikibooks/en/d/db/Zelda_ALttP_item_Red_Mail.png",
 | 
			
		||||
    "Power Glove": "https://www.zeldadungeon.net/wiki/images/thumb/4/41/PowerGlove-ALttP-Sprite.png/105px-PowerGlove-ALttP-Sprite.png",
 | 
			
		||||
    "Titan Mitts": "https://www.zeldadungeon.net/wiki/images/thumb/7/75/TitanMitt-ALttP-Sprite.png/105px-TitanMitt-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",
 | 
			
		||||
    "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",
 | 
			
		||||
    "Hyrule Castle": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/d3/ALttP_Ball_and_Chain_Trooper_Sprite.png?version=1768a87c06d29cc8e7ddd80b9fa516be",
 | 
			
		||||
    "Agahnims Tower": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/1/1e/ALttP_Agahnim_Sprite.png?version=365956e61b0c2191eae4eddbe591dab5",
 | 
			
		||||
    "Desert Palace": "https://www.zeldadungeon.net/wiki/images/2/25/Lanmola-ALTTP-Sprite.png",
 | 
			
		||||
    "Eastern Palace": "https://www.zeldadungeon.net/wiki/images/d/dc/RedArmosKnight.png",
 | 
			
		||||
    "Tower of Hera": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/3/3c/ALttP_Moldorm_Sprite.png?version=c588257bdc2543468e008a6b30f262a7",
 | 
			
		||||
    "Palace of Darkness": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/ed/ALttP_Helmasaur_King_Sprite.png?version=ab8a4a1cfd91d4fc43466c56cba30022",
 | 
			
		||||
    "Swamp Palace": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/7/73/ALttP_Arrghus_Sprite.png?version=b098be3122e53f751b74f4a5ef9184b5",
 | 
			
		||||
    "Skull Woods": "https://alttp-wiki.net/images/6/6a/Mothula.png",
 | 
			
		||||
    "Thieves Town": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/8/86/ALttP_Blind_the_Thief_Sprite.png?version=3833021bfcd112be54e7390679047222",
 | 
			
		||||
    "Ice Palace": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/3/33/ALttP_Kholdstare_Sprite.png?version=e5a1b0e8b2298e550d85f90bf97045c0",
 | 
			
		||||
    "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",
 | 
			
		||||
} -%}
 | 
			
		||||
    "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",
 | 
			
		||||
} %}
 | 
			
		||||
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
{% set inventory_order = [
 | 
			
		||||
    "Progressive Bow", "Boomerangs",      "Hookshot",          "Bombs",            "Mushroom",       "Magic Powder",
 | 
			
		||||
    "Fire Rod",        "Ice Rod",         "Bombos",            "Ether",            "Quake",          "Progressive Mail",
 | 
			
		||||
    "Lamp",            "Hammer",          "Flute",             "Bug Catching Net", "Book of Mudora", "Progressive Shield",
 | 
			
		||||
    "Bottles",         "Cane of Somaria", "Cane of Byrna",     "Cape",             "Magic Mirror",   "Progressive Sword",
 | 
			
		||||
    "Shovel",          "Pegasus Boots",   "Progressive Glove", "Flippers",         "Moon Pearl",     "Triforce Piece",
 | 
			
		||||
] %}
 | 
			
		||||
 | 
			
		||||
{# Most have a duplicated 0th entry for when we have none of that item to still load the correct icon/name. #}
 | 
			
		||||
{% set progressive_order = {
 | 
			
		||||
    "Progressive Bow":    ["Bow", "Bow", "Silver Bow"],
 | 
			
		||||
    "Progressive Mail":   ["Green Mail", "Blue Mail", "Red Mail"],
 | 
			
		||||
    "Progressive Shield": ["Blue Shield", "Blue Shield", "Red Shield", "Mirror Shield"],
 | 
			
		||||
    "Progressive Sword":  ["Fighter Sword", "Fighter Sword", "Master Sword", "Tempered Sword", "Golden Sword"],
 | 
			
		||||
    "Progressive Glove":  ["Power Glove", "Power Glove", "Titan Mitts"],
 | 
			
		||||
} %}
 | 
			
		||||
 | 
			
		||||
{% 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)"),
 | 
			
		||||
} %}
 | 
			
		||||
 | 
			
		||||
<!doctype html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="UTF-8">
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
			
		||||
    <title>{{ player_name }}'s Tracker</title>
 | 
			
		||||
    <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename="styles/lttp-tracker.css") }}"/>
 | 
			
		||||
    <script type="application/ecmascript" src="{{ url_for('static', filename="assets/lttp-tracker.js") }}"></script>
 | 
			
		||||
    <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles/tracker__ALinkToThePast.css') }}">
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
| 
						 | 
				
			
			@ -76,79 +92,127 @@
 | 
			
		|||
        <a href="{{ url_for("get_generic_game_tracker", tracker=room.tracker, tracked_team=team, tracked_player=player) }}">Switch To Generic Tracker</a>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div id="player-tracker-wrapper" data-tracker="{{ room.tracker|suuid }}">
 | 
			
		||||
        <table id="inventory-table">
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td><img src="{{ icons[bow_icon] }}" class="{{ 'acquired' if bow_acquired }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Blue Boomerang"] }}" class="{{ 'acquired' if 'Blue Boomerang' in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Red Boomerang"] }}" class="{{ 'acquired' if 'Red Boomerang' in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Hookshot"] }}" class="{{ 'acquired' if 'Hookshot' in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Magic Powder"] }}" class="powder-fix {{ 'acquired' if 'Magic Powder' in acquired_items }}" /></td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td><img src="{{ icons["Fire Rod"] }}" class="{{ 'acquired' if "Fire Rod" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Ice Rod"] }}" class="{{ 'acquired' if "Ice Rod" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Bombos"] }}" class="{{ 'acquired' if "Bombos" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Ether"] }}" class="{{ 'acquired' if "Ether" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Quake"] }}" class="{{ 'acquired' if "Quake" in acquired_items }}" /></td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td><img src="{{ icons["Lamp"] }}" class="{{ 'acquired' if "Lamp" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Hammer"] }}" class="{{ 'acquired' if "Hammer" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Flute"] }}" class="{{ 'acquired' if "Flute" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Bug Catching Net"] }}" class="{{ 'acquired' if "Bug Catching Net" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Book of Mudora"] }}" class="{{ 'acquired' if "Book of Mudora" in acquired_items }}" /></td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td><img src="{{ icons["Bottle"] }}" class="{{ 'acquired' if "Bottle" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Cane of Somaria"] }}" class="{{ 'acquired' if "Cane of Somaria" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Cane of Byrna"] }}" class="{{ 'acquired' if "Cane of Byrna" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Cape"] }}" class="{{ 'acquired' if "Cape" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Magic Mirror"] }}" class="{{ 'acquired' if "Magic Mirror" in acquired_items }}" /></td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td><img src="{{ icons["Pegasus Boots"] }}" class="{{ 'acquired' if "Pegasus Boots" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons[glove_icon] }}" class="{{ 'acquired' if glove_acquired }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Flippers"] }}" class="{{ 'acquired' if "Flippers" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Moon Pearl"] }}" class="{{ 'acquired' if "Moon Pearl" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Mushroom"] }}" class="{{ 'acquired' if "Mushroom" in acquired_items }}" /></td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td><img src="{{ icons[sword_icon] }}" class="{{ 'acquired' if sword_acquired }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons[shield_icon] }}" class="{{ 'acquired' if shield_acquired }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons[mail_icon] }}" class="acquired" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Shovel"] }}" class="{{ 'acquired' if "Shovel" in acquired_items }}" /></td>
 | 
			
		||||
                <td><img src="{{ icons["Triforce"] }}" class="{{ 'acquired' if "Triforce" in acquired_items }}" /></td>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </table>
 | 
			
		||||
        <table id="location-table">
 | 
			
		||||
            <tr>
 | 
			
		||||
                <th></th>
 | 
			
		||||
                <th class="counter"><img src="{{ icons["Chest"] }}" /></th>
 | 
			
		||||
                {% if key_locations and "Universal" not in key_locations %}
 | 
			
		||||
                    <th class="counter"><img src="{{ icons["Small Key"] }}" /></th>
 | 
			
		||||
    <div class="tracker-container">
 | 
			
		||||
        {# Inventory Grid #}
 | 
			
		||||
        <div class="inventory-grid">
 | 
			
		||||
            {% for item in inventory_order %}
 | 
			
		||||
                {% if item in progressive_order %}
 | 
			
		||||
                    {% set non_prog_item = progressive_order[item][inventory[item]] %}
 | 
			
		||||
                    <div class="item">
 | 
			
		||||
                        <img
 | 
			
		||||
                            src="{{ icons[non_prog_item] }}"
 | 
			
		||||
                            alt="{{ non_prog_item }}"
 | 
			
		||||
                            title="{{ non_prog_item }}"
 | 
			
		||||
                            {# Progressive Mail gets a special exception, since it starts displaying green mail. #}
 | 
			
		||||
                            class="{{ 'missing' if (item not in inventory or inventory[item] == 0) and item != 'Progressive Mail' }}"
 | 
			
		||||
                        >
 | 
			
		||||
                    </div>
 | 
			
		||||
                {% elif item == "Boomerangs" %}
 | 
			
		||||
                    <div class="dual-item">
 | 
			
		||||
                        <img
 | 
			
		||||
                            src="{{ icons['Blue Boomerang'] }}"
 | 
			
		||||
                            alt="Blue Boomerang"
 | 
			
		||||
                            title="Blue Boomerang"
 | 
			
		||||
                            class="{{ 'missing' if 'Blue Boomerang' not in inventory }}"
 | 
			
		||||
                        >
 | 
			
		||||
                        <img
 | 
			
		||||
                            src="{{ icons['Red Boomerang'] }}"
 | 
			
		||||
                            alt="Red Boomerang"
 | 
			
		||||
                            title="Red Boomerang"
 | 
			
		||||
                            class="{{ 'missing' if 'Red Boomerang' not in inventory }}"
 | 
			
		||||
                        >
 | 
			
		||||
                    </div>
 | 
			
		||||
                {% else %}
 | 
			
		||||
                    <div class="item {{ 'hidden' if item == 'Triforce Piece' and inventory['Triforce Piece'] == 0 }}">
 | 
			
		||||
                        <img
 | 
			
		||||
                            src="{{ icons[item] }}"
 | 
			
		||||
                            alt="{{ item }}"
 | 
			
		||||
                            title="{{ item }}"
 | 
			
		||||
                            class="{{ 'missing' if item not in inventory or inventory[item] == 0 }}"
 | 
			
		||||
                        >
 | 
			
		||||
                        {% if item == "Bottles" or item == "Triforce Piece" %}
 | 
			
		||||
                            <div class="quantity">{{ inventory[item] }}</div>
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                    </div>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
                {% if big_key_locations %}
 | 
			
		||||
                    <th><img src="{{ icons["Big Key"] }}" /></th>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
            </tr>
 | 
			
		||||
            {% for area in sp_areas %}
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <td>{{ area }}</td>
 | 
			
		||||
                    <td class="counter">{{ checks_done[area] }} / {{ checks_in_area[area] }}</td>
 | 
			
		||||
                    {% if key_locations and "Universal" not in key_locations %}
 | 
			
		||||
                        <td class="counter">
 | 
			
		||||
                            {{ inventory[small_key_ids[area]] if area in key_locations else '—' }}
 | 
			
		||||
                        </td>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                    {% if big_key_locations %}
 | 
			
		||||
                        <td>
 | 
			
		||||
                            {{ '✔' if area in big_key_locations and inventory[big_key_ids[area]] else ('—' if area not in big_key_locations else '') }}
 | 
			
		||||
                        </td>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                </tr>
 | 
			
		||||
            {% endfor %}
 | 
			
		||||
        </table>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="regions-list">
 | 
			
		||||
            <div class="region region-header">
 | 
			
		||||
                <div></div>
 | 
			
		||||
                <div></div>
 | 
			
		||||
                <div><img src="{{ icons['Small Key'] }}" alt="SK" title="Small Keys"></div>
 | 
			
		||||
                <div><img src="{{ icons['Big Key'] }}" alt="BK" title="Big Keys"></div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            {% for region_name, region_data in regions.items() %}
 | 
			
		||||
                {% if region_data["locations"] | length > 0 %}
 | 
			
		||||
                    <details class="region-details">
 | 
			
		||||
                        <summary>
 | 
			
		||||
                            {% if region_name in dungeon_keys %}
 | 
			
		||||
                                <div class="region">
 | 
			
		||||
                                    <span>{{ region_name }}</span>
 | 
			
		||||
                                    <span>{{ region_data["checked"] }} / {{ region_data["locations"] | length }}</span>
 | 
			
		||||
                                    <span>{{ inventory[dungeon_keys[region_name][0]] }}</span>
 | 
			
		||||
                                    <span>
 | 
			
		||||
                                        {% if region_name == "Agahnims Tower" %}
 | 
			
		||||
                                            —
 | 
			
		||||
                                        {% elif inventory[dungeon_keys[region_name][1]] %}
 | 
			
		||||
                                            ✔
 | 
			
		||||
                                        {% endif %}
 | 
			
		||||
                                    </span>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            {% else %}
 | 
			
		||||
                                <div class="region">
 | 
			
		||||
                                    <span>{{ region_name }}</span>
 | 
			
		||||
                                    <span>{{ region_data["checked"] }} / {{ region_data["locations"] | length }}</span>
 | 
			
		||||
                                    <span>—</span>
 | 
			
		||||
                                    <span>—</span>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            {% endif %}
 | 
			
		||||
                        </summary>
 | 
			
		||||
 | 
			
		||||
                        <div class="location-rows">
 | 
			
		||||
                            {% for location, checked in region_data["locations"] %}
 | 
			
		||||
                                <div>{{ location }}</div>
 | 
			
		||||
                                <div>{% if checked %}✔{% endif %}</div>
 | 
			
		||||
                            {% endfor %}
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </details>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
            {% endfor %}
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <script>
 | 
			
		||||
        const parser = new DOMParser();
 | 
			
		||||
        const interval = 15_000;
 | 
			
		||||
 | 
			
		||||
        window.addEventListener("load", () => {
 | 
			
		||||
            setInterval(() => updateTracker()
 | 
			
		||||
                .then(() => console.log("Refreshed tracker."))
 | 
			
		||||
                .catch(console.error), interval);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        async function updateTracker() {
 | 
			
		||||
            const response = await fetch(`${window.location}`);
 | 
			
		||||
            if (!response.ok) {
 | 
			
		||||
                throw new Error(`Failed to fetch tracker update from ${window.location}. Received response: ${response.statusText}`);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const fakeDOM = parser.parseFromString(await response.text(), "text/html");
 | 
			
		||||
            document.querySelector(".inventory-grid").innerHTML = fakeDOM.querySelector(".inventory-grid").innerHTML;
 | 
			
		||||
 | 
			
		||||
            const regionDetailElements = document.querySelectorAll(".region-details");
 | 
			
		||||
            const fakeDetailElements = fakeDOM.querySelectorAll(".region-details");
 | 
			
		||||
 | 
			
		||||
            for (let i = 0; i < regionDetailElements.length; ++i) {
 | 
			
		||||
                const isOpen = regionDetailElements[i].open;
 | 
			
		||||
                regionDetailElements[i].innerHTML = fakeDetailElements[i].innerHTML;
 | 
			
		||||
                regionDetailElements[i].open = isOpen;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    </script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -695,196 +695,169 @@ if "A Link to the Past" in network_data_package["games"]:
 | 
			
		|||
        )
 | 
			
		||||
 | 
			
		||||
    def render_ALinkToThePast_tracker(tracker_data: TrackerData, team: int, player: int) -> str:
 | 
			
		||||
        # Helper objects.
 | 
			
		||||
        alttp_id_lookup = tracker_data.item_name_to_id["A Link to the Past"]
 | 
			
		||||
        inventory = 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()
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        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",
 | 
			
		||||
        # 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),
 | 
			
		||||
        }
 | 
			
		||||
        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,
 | 
			
		||||
 | 
			
		||||
        progressive_item_max = {
 | 
			
		||||
            "Progressive Sword":  4,
 | 
			
		||||
            "Progressive Glove":  2,
 | 
			
		||||
            "Progressive Bow":    2,
 | 
			
		||||
            "Progressive Mail":   2,
 | 
			
		||||
            "Progressive Shield": 3,
 | 
			
		||||
        }
 | 
			
		||||
        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",
 | 
			
		||||
 | 
			
		||||
        bottle_items = [
 | 
			
		||||
            "Bottle",
 | 
			
		||||
            "Bottle (Bee)",
 | 
			
		||||
            "Bottle (Blue Potion)",
 | 
			
		||||
            "Bottle (Fairy)",
 | 
			
		||||
            "Bottle (Good Bee)",
 | 
			
		||||
            "Bottle (Green Potion)",
 | 
			
		||||
            "Bottle (Red Potion)",
 | 
			
		||||
        ]
 | 
			
		||||
        default_locations = {
 | 
			
		||||
 | 
			
		||||
        # 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": {
 | 
			
		||||
                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
 | 
			
		||||
                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": {
 | 
			
		||||
                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
 | 
			
		||||
                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
 | 
			
		||||
            },
 | 
			
		||||
            "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
 | 
			
		||||
                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": {
 | 
			
		||||
                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
 | 
			
		||||
                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,
 | 
			
		||||
            },
 | 
			
		||||
            "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()
 | 
			
		||||
 | 
			
		||||
        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": []},
 | 
			
		||||
        }
 | 
			
		||||
        location_to_area = {}
 | 
			
		||||
        for area, locations in default_locations.items():
 | 
			
		||||
            for checked_location in locations:
 | 
			
		||||
                location_to_area[checked_location] = area
 | 
			
		||||
        for area, locations in key_only_locations.items():
 | 
			
		||||
            for checked_location in locations:
 | 
			
		||||
                location_to_area[checked_location] = area
 | 
			
		||||
 | 
			
		||||
        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"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
        inventory = collections.Counter()
 | 
			
		||||
        checks_done = {loc_name: 0 for loc_name in default_locations}
 | 
			
		||||
        player_big_key_locations = set()
 | 
			
		||||
        player_small_key_locations = set()
 | 
			
		||||
 | 
			
		||||
        player_locations = tracker_data.get_player_locations(team, player)
 | 
			
		||||
        for checked_location in tracker_data.get_player_checked_locations(team, player):
 | 
			
		||||
            if checked_location in player_locations:
 | 
			
		||||
                area_name = location_to_area.get(checked_location, None)
 | 
			
		||||
                if area_name:
 | 
			
		||||
                    checks_done[area_name] += 1
 | 
			
		||||
 | 
			
		||||
                checks_done["Total"] += 1
 | 
			
		||||
 | 
			
		||||
        for received_item in tracker_data.get_player_received_items(team, player):
 | 
			
		||||
            target_item = links.get(received_item.item, received_item.item)
 | 
			
		||||
            if received_item.item in levels:  # non-progressive
 | 
			
		||||
                inventory[target_item] = max(inventory[target_item], levels[received_item.item])
 | 
			
		||||
        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:
 | 
			
		||||
                inventory[target_item] += 1
 | 
			
		||||
                # 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
 | 
			
		||||
 | 
			
		||||
        for location, (item_id, _, _) in player_locations.items():
 | 
			
		||||
            if item_id in ids_big_key:
 | 
			
		||||
                player_big_key_locations.add(ids_big_key[item_id])
 | 
			
		||||
            elif item_id in ids_small_key:
 | 
			
		||||
                player_small_key_locations.add(ids_small_key[item_id])
 | 
			
		||||
 | 
			
		||||
        # Note the presence of the triforce item
 | 
			
		||||
        if tracker_data.get_player_client_status(team, player) == ClientStatus.CLIENT_GOAL:
 | 
			
		||||
            inventory[106] = 1  # Triforce
 | 
			
		||||
 | 
			
		||||
        # Progressive items need special handling for icons and class
 | 
			
		||||
        progressive_items = {
 | 
			
		||||
            "Progressive Sword":  94,
 | 
			
		||||
            "Progressive Glove":  97,
 | 
			
		||||
            "Progressive Bow":    100,
 | 
			
		||||
            "Progressive Mail":   96,
 | 
			
		||||
            "Progressive Shield": 95,
 | 
			
		||||
        }
 | 
			
		||||
        progressive_names = {
 | 
			
		||||
            "Progressive Sword":  [None, "Fighter Sword", "Master Sword", "Tempered Sword", "Golden Sword"],
 | 
			
		||||
            "Progressive Glove":  [None, "Power Glove", "Titan Mitts"],
 | 
			
		||||
            "Progressive Bow":    [None, "Bow", "Silver Bow"],
 | 
			
		||||
            "Progressive Mail":   ["Green Mail", "Blue Mail", "Red Mail"],
 | 
			
		||||
            "Progressive Shield": [None, "Blue Shield", "Red Shield", "Mirror Shield"]
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        # Determine which icon to use
 | 
			
		||||
        display_data = {}
 | 
			
		||||
        for item_name, item_id in progressive_items.items():
 | 
			
		||||
            level = min(inventory[item_id], len(progressive_names[item_name]) - 1)
 | 
			
		||||
            display_name = progressive_names[item_name][level]
 | 
			
		||||
            acquired = True
 | 
			
		||||
            if not display_name:
 | 
			
		||||
                acquired = False
 | 
			
		||||
                display_name = progressive_names[item_name][level + 1]
 | 
			
		||||
            base_name = item_name.split(maxsplit=1)[1].lower()
 | 
			
		||||
            display_data[base_name + "_acquired"] = acquired
 | 
			
		||||
            display_data[base_name + "_icon"] = display_name
 | 
			
		||||
 | 
			
		||||
        # The single player tracker doesn't care about overworld, underworld, and total checks. Maybe it should?
 | 
			
		||||
        sp_areas = ordered_areas[2:15]
 | 
			
		||||
        # Sort locations in regions by name
 | 
			
		||||
        for region in regions:
 | 
			
		||||
            regions[region]["locations"].sort()
 | 
			
		||||
 | 
			
		||||
        return render_template(
 | 
			
		||||
            template_name_or_list="tracker__ALinkToThePast.html",
 | 
			
		||||
| 
						 | 
				
			
			@ -893,15 +866,7 @@ if "A Link to the Past" in network_data_package["games"]:
 | 
			
		|||
            player=player,
 | 
			
		||||
            inventory=inventory,
 | 
			
		||||
            player_name=tracker_data.get_player_name(team, player),
 | 
			
		||||
            checks_done=checks_done,
 | 
			
		||||
            checks_in_area=checks_in_area,
 | 
			
		||||
            acquired_items={tracker_data.item_id_to_name["A Link to the Past"][id] for id in inventory},
 | 
			
		||||
            sp_areas=sp_areas,
 | 
			
		||||
            small_key_ids=small_key_ids,
 | 
			
		||||
            key_locations=player_small_key_locations,
 | 
			
		||||
            big_key_ids=big_key_ids,
 | 
			
		||||
            big_key_locations=player_big_key_locations,
 | 
			
		||||
            **display_data,
 | 
			
		||||
            regions=regions,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    _multiworld_trackers["A Link to the Past"] = render_ALinkToThePast_multiworld_tracker
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue