ALTTP: Updates to player-specific game tracker. (#3133)

This commit is contained in:
Zach Parks 2024-04-20 13:18:06 -05:00 committed by GitHub
parent a4acdb6ddf
commit 0a1ce5b7d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 489 additions and 499 deletions

View File

@ -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)
});

View File

@ -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;
}

View File

@ -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;
}

View File

@ -1,86 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{ player_name }}&apos;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>

View File

@ -1,73 +1,89 @@
{%- set icons = { {% set icons = {
"Blue Shield": "https://www.zeldadungeon.net/wiki/images/8/85/Fighters-Shield.png", "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/5/55/Fire-Shield.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/8/84/Mirror-Shield.png", "Mirror Shield": "https://www.zeldadungeon.net/wiki/images/thumb/e/e3/MirrorShield-ALttP-Sprite.png/105px-MirrorShield-ALttP-Sprite.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", "Fighter Sword": "https://upload.wikimedia.org/wikibooks/en/8/8e/Zelda_ALttP_item_L-1_Sword.png",
"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", "Master Sword": "https://upload.wikimedia.org/wikibooks/en/8/87/BS_Zelda_AST_item_L-2_Sword.png",
"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", "Tempered Sword": "https://upload.wikimedia.org/wikibooks/en/c/cc/BS_Zelda_AST_item_L-3_Sword.png",
"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", "Golden Sword": "https://upload.wikimedia.org/wikibooks/en/4/40/BS_Zelda_AST_item_L-4_Sword.png",
"Bow": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/b/bc/ALttP_Bow_%26_Arrows_Sprite.png?version=5f85a70e6366bf473544ef93b274f74c", "Bow": "https://www.zeldadungeon.net/wiki/images/thumb/8/8c/BowArrows-ALttP-Sprite.png/120px-BowArrows-ALttP-Sprite.png",
"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", "Silver Bow": "https://upload.wikimedia.org/wikibooks/en/6/69/Zelda_ALttP_item_Silver_Arrows.png",
"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", "Green Mail": "https://upload.wikimedia.org/wikibooks/en/d/dd/Zelda_ALttP_item_Green_Mail.png",
"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", "Blue Mail": "https://upload.wikimedia.org/wikibooks/en/b/b5/Zelda_ALttP_item_Blue_Mail.png",
"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", "Red Mail": "https://upload.wikimedia.org/wikibooks/en/d/db/Zelda_ALttP_item_Red_Mail.png",
"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", "Power Glove": "https://www.zeldadungeon.net/wiki/images/thumb/4/41/PowerGlove-ALttP-Sprite.png/105px-PowerGlove-ALttP-Sprite.png",
"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", "Titan Mitts": "https://www.zeldadungeon.net/wiki/images/thumb/7/75/TitanMitt-ALttP-Sprite.png/105px-TitanMitt-ALttP-Sprite.png",
"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",
"Pegasus Boots": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/ed/ALttP_Pegasus_Shoes_Sprite.png?version=405f42f97240c9dcd2b71ffc4bebc7f9", "Flippers": "https://www.zeldadungeon.net/wiki/images/thumb/b/bc/ZoraFlippers-ALttP-Sprite.png/112px-ZoraFlippers-ALttP-Sprite.png",
"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", "Moon Pearl": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/6/63/ALttP_Moon_Pearl_Sprite.png",
"Flippers": "https://oyster.ignimgs.com/mediawiki/apis.ign.com/the-legend-of-zelda-a-link-to-the-past/4/4c/ZoraFlippers.png?width=1920", "Blue Boomerang": "https://www.zeldadungeon.net/wiki/images/thumb/f/f0/Boomerang-ALttP-Sprite.png/86px-Boomerang-ALttP-Sprite.png",
"Moon Pearl": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/6/63/ALttP_Moon_Pearl_Sprite.png?version=d601542d5abcc3e006ee163254bea77e", "Red Boomerang": "https://www.zeldadungeon.net/wiki/images/thumb/3/3c/MagicalBoomerang-ALttP-Sprite.png/86px-MagicalBoomerang-ALttP-Sprite.png",
"Progressive Bow": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/b/bc/ALttP_Bow_%26_Arrows_Sprite.png?version=cfb7648b3714cccc80e2b17b2adf00ed", "Hookshot": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/2/24/Hookshot.png",
"Blue Boomerang": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/c/c3/ALttP_Boomerang_Sprite.png?version=96127d163759395eb510b81a556d500e", "Mushroom": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/3/35/ALttP_Mushroom_Sprite.png",
"Red Boomerang": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/b/b9/ALttP_Magical_Boomerang_Sprite.png?version=47cddce7a07bc3e4c2c10727b491f400", "Magic Powder": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/e5/ALttP_Magic_Powder_Sprite.png",
"Hookshot": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/2/24/Hookshot.png?version=c90bc8e07a52e8090377bd6ef854c18b", "Fire Rod": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/d6/FireRod.png",
"Mushroom": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/3/35/ALttP_Mushroom_Sprite.png?version=1f1acb30d71bd96b60a3491e54bbfe59", "Ice Rod": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/d7/ALttP_Ice_Rod_Sprite.png",
"Magic Powder": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/e5/ALttP_Magic_Powder_Sprite.png?version=c24e38effbd4f80496d35830ce8ff4ec", "Bombos": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/8/8c/ALttP_Bombos_Medallion_Sprite.png",
"Fire Rod": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/d6/FireRod.png?version=6eabc9f24d25697e2c4cd43ddc8207c0", "Ether": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/3/3c/Ether.png",
"Ice Rod": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/d7/ALttP_Ice_Rod_Sprite.png?version=1f944148223d91cfc6a615c92286c3bc", "Quake": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/5/56/ALttP_Quake_Medallion_Sprite.png",
"Bombos": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/8/8c/ALttP_Bombos_Medallion_Sprite.png?version=f4d6aba47fb69375e090178f0fc33b26", "Lamp": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/6/63/ALttP_Lantern_Sprite.png",
"Ether": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/3/3c/Ether.png?version=34027651a5565fcc5a83189178ab17b5", "Hammer": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/d1/ALttP_Hammer_Sprite.png",
"Quake": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/5/56/ALttP_Quake_Medallion_Sprite.png?version=efd64d451b1831bd59f7b7d6b61b5879", "Shovel": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/c/c4/ALttP_Shovel_Sprite.png",
"Lamp": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/6/63/ALttP_Lantern_Sprite.png?version=e76eaa1ec509c9a5efb2916698d5a4ce", "Flute": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/db/Flute.png",
"Hammer": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/d1/ALttP_Hammer_Sprite.png?version=e0adec227193818dcaedf587eba34500", "Bug Catching Net": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/5/54/Bug-CatchingNet.png",
"Shovel": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/c/c4/ALttP_Shovel_Sprite.png?version=e73d1ce0115c2c70eaca15b014bd6f05", "Book of Mudora": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/2/22/ALttP_Book_of_Mudora_Sprite.png",
"Flute": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/db/Flute.png?version=ec4982b31c56da2c0c010905c5c60390", "Bottles": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/ef/ALttP_Magic_Bottle_Sprite.png",
"Bug Catching Net": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/5/54/Bug-CatchingNet.png?version=4d40e0ee015b687ff75b333b968d8be6", "Cane of Somaria": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/e1/ALttP_Cane_of_Somaria_Sprite.png",
"Book of Mudora": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/2/22/ALttP_Book_of_Mudora_Sprite.png?version=11e4632bba54f6b9bf921df06ac93744", "Cane of Byrna": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/b/bc/ALttP_Cane_of_Byrna_Sprite.png",
"Bottle": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/ef/ALttP_Magic_Bottle_Sprite.png?version=fd98ab04db775270cbe79fce0235777b", "Cape": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/1/1c/ALttP_Magic_Cape_Sprite.png",
"Cane of Somaria": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/e1/ALttP_Cane_of_Somaria_Sprite.png?version=8cc1900dfd887890badffc903bb87943", "Magic Mirror": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/e5/ALttP_Magic_Mirror_Sprite.png",
"Cane of Byrna": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/b/bc/ALttP_Cane_of_Byrna_Sprite.png?version=758b607c8cbe2cf1900d42a0b3d0fb54", "Triforce": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/4/4e/TriforceALttPTitle.png",
"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",
"Triforce Piece": "https://www.zeldadungeon.net/wiki/images/thumb/5/54/Triforce_Fragment_-_BS_Zelda.png/62px-Triforce_Fragment_-_BS_Zelda.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", "Bombs": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/3/38/ALttP_Bomb_Sprite.png",
"Big Key": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/3/33/ALttP_Big_Key_Sprite.png?version=136dfa418ba76c8b4e270f466fc12f4d", "Small Key": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/f/f1/ALttP_Small_Key_Sprite.png",
"Chest": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/7/73/ALttP_Treasure_Chest_Sprite.png?version=5f530ecd98dcb22251e146e8049c0dda", "Big Key": "https://gamepedia.cursecdn.com/zelda_gamepedia_en/3/33/ALttP_Big_Key_Sprite.png",
"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",
} -%}
<!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"> <html lang="en">
<head> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ player_name }}&apos;s Tracker</title> <title>{{ player_name }}&apos;s Tracker</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename="styles/lttp-tracker.css") }}"/> <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles/tracker__ALinkToThePast.css') }}">
<script type="application/ecmascript" src="{{ url_for('static', filename="assets/lttp-tracker.js") }}"></script>
</head> </head>
<body> <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> <a href="{{ url_for("get_generic_game_tracker", tracker=room.tracker, tracked_team=team, tracked_player=player) }}">Switch To Generic Tracker</a>
</div> </div>
<div id="player-tracker-wrapper" data-tracker="{{ room.tracker|suuid }}"> <div class="tracker-container">
<table id="inventory-table"> {# Inventory Grid #}
<tr> <div class="inventory-grid">
<td><img src="{{ icons[bow_icon] }}" class="{{ 'acquired' if bow_acquired }}" /></td> {% for item in inventory_order %}
<td><img src="{{ icons["Blue Boomerang"] }}" class="{{ 'acquired' if 'Blue Boomerang' in acquired_items }}" /></td> {% if item in progressive_order %}
<td><img src="{{ icons["Red Boomerang"] }}" class="{{ 'acquired' if 'Red Boomerang' in acquired_items }}" /></td> {% set non_prog_item = progressive_order[item][inventory[item]] %}
<td><img src="{{ icons["Hookshot"] }}" class="{{ 'acquired' if 'Hookshot' in acquired_items }}" /></td> <div class="item">
<td><img src="{{ icons["Magic Powder"] }}" class="powder-fix {{ 'acquired' if 'Magic Powder' in acquired_items }}" /></td> <img
</tr> src="{{ icons[non_prog_item] }}"
<tr> alt="{{ non_prog_item }}"
<td><img src="{{ icons["Fire Rod"] }}" class="{{ 'acquired' if "Fire Rod" in acquired_items }}" /></td> title="{{ non_prog_item }}"
<td><img src="{{ icons["Ice Rod"] }}" class="{{ 'acquired' if "Ice Rod" in acquired_items }}" /></td> {# Progressive Mail gets a special exception, since it starts displaying green mail. #}
<td><img src="{{ icons["Bombos"] }}" class="{{ 'acquired' if "Bombos" in acquired_items }}" /></td> class="{{ 'missing' if (item not in inventory or inventory[item] == 0) and item != 'Progressive Mail' }}"
<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> </div>
</tr> {% elif item == "Boomerangs" %}
<tr> <div class="dual-item">
<td><img src="{{ icons["Lamp"] }}" class="{{ 'acquired' if "Lamp" in acquired_items }}" /></td> <img
<td><img src="{{ icons["Hammer"] }}" class="{{ 'acquired' if "Hammer" in acquired_items }}" /></td> src="{{ icons['Blue Boomerang'] }}"
<td><img src="{{ icons["Flute"] }}" class="{{ 'acquired' if "Flute" in acquired_items }}" /></td> alt="Blue Boomerang"
<td><img src="{{ icons["Bug Catching Net"] }}" class="{{ 'acquired' if "Bug Catching Net" in acquired_items }}" /></td> title="Blue Boomerang"
<td><img src="{{ icons["Book of Mudora"] }}" class="{{ 'acquired' if "Book of Mudora" in acquired_items }}" /></td> class="{{ 'missing' if 'Blue Boomerang' not in inventory }}"
</tr> >
<tr> <img
<td><img src="{{ icons["Bottle"] }}" class="{{ 'acquired' if "Bottle" in acquired_items }}" /></td> src="{{ icons['Red Boomerang'] }}"
<td><img src="{{ icons["Cane of Somaria"] }}" class="{{ 'acquired' if "Cane of Somaria" in acquired_items }}" /></td> alt="Red Boomerang"
<td><img src="{{ icons["Cane of Byrna"] }}" class="{{ 'acquired' if "Cane of Byrna" in acquired_items }}" /></td> title="Red Boomerang"
<td><img src="{{ icons["Cape"] }}" class="{{ 'acquired' if "Cape" in acquired_items }}" /></td> class="{{ 'missing' if 'Red Boomerang' not in inventory }}"
<td><img src="{{ icons["Magic Mirror"] }}" class="{{ 'acquired' if "Magic Mirror" in acquired_items }}" /></td> >
</tr> </div>
<tr> {% else %}
<td><img src="{{ icons["Pegasus Boots"] }}" class="{{ 'acquired' if "Pegasus Boots" in acquired_items }}" /></td> <div class="item {{ 'hidden' if item == 'Triforce Piece' and inventory['Triforce Piece'] == 0 }}">
<td><img src="{{ icons[glove_icon] }}" class="{{ 'acquired' if glove_acquired }}" /></td> <img
<td><img src="{{ icons["Flippers"] }}" class="{{ 'acquired' if "Flippers" in acquired_items }}" /></td> src="{{ icons[item] }}"
<td><img src="{{ icons["Moon Pearl"] }}" class="{{ 'acquired' if "Moon Pearl" in acquired_items }}" /></td> alt="{{ item }}"
<td><img src="{{ icons["Mushroom"] }}" class="{{ 'acquired' if "Mushroom" in acquired_items }}" /></td> title="{{ item }}"
</tr> class="{{ 'missing' if item not in inventory or inventory[item] == 0 }}"
<tr> >
<td><img src="{{ icons[sword_icon] }}" class="{{ 'acquired' if sword_acquired }}" /></td> {% if item == "Bottles" or item == "Triforce Piece" %}
<td><img src="{{ icons[shield_icon] }}" class="{{ 'acquired' if shield_acquired }}" /></td> <div class="quantity">{{ inventory[item] }}</div>
<td><img src="{{ icons[mail_icon] }}" class="acquired" /></td> {% endif %}
<td><img src="{{ icons["Shovel"] }}" class="{{ 'acquired' if "Shovel" in acquired_items }}" /></td> </div>
<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 %} {% 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 %} {% 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" %}
&mdash;
{% 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>&mdash;</span>
<span>&mdash;</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> </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> </body>
</html> </html>

View File

@ -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: def render_ALinkToThePast_tracker(tracker_data: TrackerData, team: int, player: int) -> str:
# Helper objects. inventory = collections.Counter({
alttp_id_lookup = tracker_data.item_name_to_id["A Link to the Past"] 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 = { # Mapping from non-progressive item to progressive name and max level.
"Bow": "Progressive Bow", non_progressive_items = {
"Silver Arrows": "Progressive Bow", "Fighter Sword": ("Progressive Sword", 1),
"Silver Bow": "Progressive Bow", "Master Sword": ("Progressive Sword", 2),
"Progressive Bow (Alt)": "Progressive Bow", "Tempered Sword": ("Progressive Sword", 3),
"Bottle (Red Potion)": "Bottle", "Golden Sword": ("Progressive Sword", 4),
"Bottle (Green Potion)": "Bottle", "Power Glove": ("Progressive Glove", 1),
"Bottle (Blue Potion)": "Bottle", "Titans Mitts": ("Progressive Glove", 2),
"Bottle (Fairy)": "Bottle", "Bow": ("Progressive Bow", 1),
"Bottle (Bee)": "Bottle", "Silver Bow": ("Progressive Bow", 2),
"Bottle (Good Bee)": "Bottle", "Blue Mail": ("Progressive Mail", 1),
"Fighter Sword": "Progressive Sword", "Red Mail": ("Progressive Mail", 2),
"Master Sword": "Progressive Sword", "Blue Shield": ("Progressive Shield", 1),
"Tempered Sword": "Progressive Sword", "Red Shield": ("Progressive Shield", 2),
"Golden Sword": "Progressive Sword", "Mirror Shield": ("Progressive Shield", 3),
"Power Glove": "Progressive Glove",
"Titans Mitts": "Progressive Glove",
} }
links = {alttp_id_lookup[key]: alttp_id_lookup[value] for key, value in links.items()}
levels = { progressive_item_max = {
"Fighter Sword": 1, "Progressive Sword": 4,
"Master Sword": 2, "Progressive Glove": 2,
"Tempered Sword": 3, "Progressive Bow": 2,
"Golden Sword": 4, "Progressive Mail": 2,
"Power Glove": 1, "Progressive Shield": 3,
"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", bottle_items = [
"Pegasus Boots", "Progressive Glove", "Flippers", "Moon Pearl", "Blue Boomerang", "Red Boomerang", "Bottle",
"Bug Catching Net", "Cape", "Shovel", "Lamp", "Mushroom", "Magic Powder", "Cane of Somaria", "Bottle (Bee)",
"Cane of Byrna", "Fire Rod", "Ice Rod", "Bombos", "Ether", "Quake", "Bottle", "Triforce Piece", "Triforce", "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": { "Light World": {
1572864, 1572865, 60034, 1572867, 1572868, 60037, 1572869, 1572866, 60040, 59788, 60046, 60175, 0x180013, 0x02eb18, 0x18014a, 0x180145, 0x033d68, 0x00eb0f, 0x00eb12, 0x00eb15, 0x00eb18, 0x00eb1b,
1572880, 60049, 60178, 1572883, 60052, 60181, 1572885, 60055, 60184, 191256, 60058, 60187, 1572884, 0x02df45, 0x00e971, 0x0ee1c3, 0x180149, 0x00e9b0, 0x00e9d1, 0x00e97a, 0x00e98c, 0x00e9bc, 0x00e9ce,
1572886, 1572887, 1572906, 60202, 60205, 59824, 166320, 1010170, 60208, 60211, 60214, 60217, 59836, 0x00e9e9, 0x00e9f2, 0x00ea82, 0x00ea85, 0x00ea88, 0x02f1fc, 0x00ea8e, 0x00ea91, 0x00ea94, 0x00ea97,
60220, 60223, 59839, 1573184, 60226, 975299, 1573188, 1573189, 188229, 60229, 60232, 1573193, 0x00ea9a, 0x18002a, 0x180015, 0x0339cf, 0x033e7d, 0x180000, 0x180001, 0x180003, 0x180004, 0x180005,
1573194, 60235, 1573187, 59845, 59854, 211407, 60238, 59857, 1573185, 1573186, 1572882, 212328, 0x00eb42, 0x00eb45, 0x00eb48, 0x00eb4b, 0x180010, 0x00eb4e, 0x00eb3f, 0x180012, 0x180014, 0x180144,
59881, 59761, 59890, 59770, 193020, 212605 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": { "Dark World": {
59776, 59779, 975237, 1572870, 60043, 1572881, 60190, 60193, 60196, 60199, 60840, 1573190, 209095, 0x180147, 0x0ee185, 0x0330c7, 0x180148, 0x00eb1e, 0x00eb21, 0x00eb24, 0x00eb27, 0x180011, 0x180006,
1573192, 1573191, 60241, 60244, 60247, 60250, 59884, 59887, 60019, 60022, 60028, 60031 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": { "Palace of Darkness": {
59968, 59971, 59974, 59977, 59980, 59983, 59986, 1573203, 59989, 59959, 59992, 59962, 59995, 0x00ea5b, 0x00ea3d, 0x00ea49, 0x00ea37, 0x00ea3a, 0x00ea52, 0x00ea43, 0x00ea4c, 0x00ea4f, 0x00ea55,
59965 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": { "Ganons Tower": {
60160, 60163, 60166, 60088, 60091, 60094, 60097, 60100, 60103, 60106, 60109, 60112, 60115, 60118, 0x180161, 0x00ead9, 0x00eadc, 0x00eae2, 0x00eae5, 0x00eae8, 0x00eaeb, 0x00eaee, 0x00eab8, 0x00eabb,
60121, 60124, 60127, 1573217, 60130, 60133, 60136, 60139, 60142, 60145, 60148, 60151, 60157 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(), regions = {
"Dark World": set(), "Light World": {"checked": 0, "locations": []},
"Desert Palace": {0x140031, 0x14002b, 0x140061, 0x140028}, "Dark World": {"checked": 0, "locations": []},
"Eastern Palace": {0x14005b, 0x140049}, "Hyrule Castle": {"checked": 0, "locations": []},
"Hyrule Castle": {0x140037, 0x140034, 0x14000d, 0x14003d}, "Agahnims Tower": {"checked": 0, "locations": []},
"Agahnims Tower": {0x140061, 0x140052}, "Eastern Palace": {"checked": 0, "locations": []},
"Tower of Hera": set(), "Desert Palace": {"checked": 0, "locations": []},
"Swamp Palace": {0x140019, 0x140016, 0x140013, 0x140010, 0x14000a}, "Tower of Hera": {"checked": 0, "locations": []},
"Thieves Town": {0x14005e, 0x14004f}, "Palace of Darkness": {"checked": 0, "locations": []},
"Skull Woods": {0x14002e, 0x14001c}, "Skull Woods": {"checked": 0, "locations": []},
"Ice Palace": {0x140004, 0x140022, 0x140025, 0x140046}, "Thieves' Town": {"checked": 0, "locations": []},
"Misery Mire": {0x140055, 0x14004c, 0x140064}, "Swamp Palace": {"checked": 0, "locations": []},
"Turtle Rock": {0x140058, 0x140007}, "Ice Palace": {"checked": 0, "locations": []},
"Palace of Darkness": set(), "Misery Mire": {"checked": 0, "locations": []},
"Ganons Tower": {0x140040, 0x140043, 0x14003a, 0x14001f}, "Turtle Rock": {"checked": 0, "locations": []},
"Total": set() "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()} for location in tracker_data.get_player_locations(team, player):
checks_in_area["Total"] = 216 location_name = tracker_data.location_id_to_name["A Link to the Past"][location]
ordered_areas = ( location_checked = location in tracker_data.get_player_checked_locations(team, player)
"Light World", "Dark World", "Hyrule Castle", "Agahnims Tower", "Eastern Palace", "Desert Palace", for region, region_locations in known_regions.items():
"Tower of Hera", "Palace of Darkness", "Swamp Palace", "Skull Woods", "Thieves Town", "Ice Palace", if location in region_locations:
"Misery Mire", "Turtle Rock", "Ganons Tower", "Total" regions[region]["locations"].append((location_name, location_checked))
) regions[region]["checked"] += 1 if location_checked else 0
break
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])
else: 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(): # Sort locations in regions by name
if item_id in ids_big_key: for region in regions:
player_big_key_locations.add(ids_big_key[item_id]) regions[region]["locations"].sort()
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]
return render_template( return render_template(
template_name_or_list="tracker__ALinkToThePast.html", template_name_or_list="tracker__ALinkToThePast.html",
@ -893,15 +866,7 @@ if "A Link to the Past" in network_data_package["games"]:
player=player, player=player,
inventory=inventory, inventory=inventory,
player_name=tracker_data.get_player_name(team, player), player_name=tracker_data.get_player_name(team, player),
checks_done=checks_done, regions=regions,
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,
) )
_multiworld_trackers["A Link to the Past"] = render_ALinkToThePast_multiworld_tracker _multiworld_trackers["A Link to the Past"] = render_ALinkToThePast_multiworld_tracker