mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-07 15:13:52 -08:00
Compare commits
14 Commits
NewSoupVi-
...
player-tra
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f5fceba2d | ||
|
|
e9e5511583 | ||
|
|
c546dcd5ff | ||
|
|
053fb14495 | ||
|
|
ed77d14618 | ||
|
|
3fb287e82b | ||
|
|
32431cfe04 | ||
|
|
ca8f4c38ec | ||
|
|
eb52454ccc | ||
|
|
14e5f54f59 | ||
|
|
2052cc55af | ||
|
|
63a8436240 | ||
|
|
e60719a20a | ||
|
|
8742aadc72 |
@@ -46,4 +46,4 @@ def get_datapackage_versions():
|
||||
return version_package
|
||||
|
||||
|
||||
from . import generate, user # trigger registration
|
||||
from . import generate, user, tracker # trigger registration
|
||||
|
||||
50
WebHostLib/api/tracker.py
Normal file
50
WebHostLib/api/tracker.py
Normal file
@@ -0,0 +1,50 @@
|
||||
import collections
|
||||
|
||||
from flask import jsonify
|
||||
from typing import Optional, Dict, Any, Tuple, List
|
||||
from Utils import restricted_loads
|
||||
from uuid import UUID
|
||||
|
||||
from ..models import Room
|
||||
from . import api_endpoints
|
||||
from ..tracker import fill_tracker_data, get_static_room_data
|
||||
from worlds import lookup_any_item_id_to_name, lookup_any_location_id_to_name
|
||||
from WebHostLib import cache
|
||||
|
||||
|
||||
@api_endpoints.route('/tracker/<suuid:tracker>/<int:tracked_team>/<int:tracked_player>')
|
||||
@cache.memoize(timeout=60)
|
||||
def update_player_tracker(tracker: UUID, tracked_team: int, tracked_player: int):
|
||||
|
||||
room: Optional[Room] = Room.get(tracker=tracker)
|
||||
locations = get_static_room_data(room)[0]
|
||||
items_counter: Dict[int, collections.Counter] = get_item_names_counter(locations)
|
||||
player_tracker, multisave, inventory, seed_checks_in_area, lttp_checks_done, \
|
||||
slot_data, games, player_name, display_icons = fill_tracker_data(room, tracked_team, tracked_player)
|
||||
|
||||
# convert numbers to string
|
||||
for item in player_tracker.items_received:
|
||||
if items_counter[tracked_player][item] == 1:
|
||||
player_tracker.items_received[item] = '✔'
|
||||
else:
|
||||
player_tracker.items_received[item] = str(player_tracker.items_received[item])
|
||||
|
||||
return jsonify({
|
||||
"items_received": player_tracker.items_received,
|
||||
"checked_locations": list(sorted(player_tracker.checked_locations)),
|
||||
"icons": display_icons,
|
||||
"progressive_names": player_tracker.progressive_names
|
||||
})
|
||||
|
||||
|
||||
@cache.cached()
|
||||
def get_item_names_counter(locations: Dict[int, Dict[int, Tuple[int, int, int]]]):
|
||||
# create and fill dictionary of all progression items for players
|
||||
items_counters: Dict[int, collections.Counter] = {}
|
||||
for player in locations:
|
||||
for location in locations[player]:
|
||||
item, recipient, flags = locations[player][location]
|
||||
item_name = lookup_any_item_id_to_name[item]
|
||||
items_counters.setdefault(recipient, collections.Counter())[item_name] += 1
|
||||
|
||||
return items_counters
|
||||
@@ -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)
|
||||
});
|
||||
82
WebHostLib/static/assets/trackers/playerTracker.js
Normal file
82
WebHostLib/static/assets/trackers/playerTracker.js
Normal file
@@ -0,0 +1,82 @@
|
||||
window.addEventListener('load', () => {
|
||||
// Reload tracker
|
||||
const update = () => {
|
||||
const room = document.getElementById('tracker-wrapper').getAttribute('data-tracker');
|
||||
|
||||
const request = new Request('/api/tracker/' + room);
|
||||
|
||||
fetch(request)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
// update locations blocks
|
||||
for (const location of data.checked_locations) {
|
||||
document.getElementById(location).classList.add('acquired');
|
||||
}
|
||||
// update totals checks done
|
||||
let total_checks_ele = document.getElementById('total-checks');
|
||||
const total_checks = document.getElementsByClassName('location').length;
|
||||
let checks_done = data.checked_locations.length;
|
||||
total_checks_ele.innerText = 'Total Checks Done: ' + checks_done + '/' + total_checks;
|
||||
// update item and icons blocks
|
||||
// update icons block
|
||||
if (data.icons.length > 0) {
|
||||
for (let item in data.icons) {
|
||||
if (data.progressive_names.length > 0) {
|
||||
for (let item_category in data.progressive_names) {
|
||||
let i = 0;
|
||||
for (let current_item in current_name) {
|
||||
if (current_item === item) {
|
||||
let doc_item = document.getElementById(item_category)
|
||||
doc_item.children[0].src = data.icons[item];
|
||||
if (item in data.items_received) {
|
||||
doc_item.children[0].classList.add('acquired');
|
||||
doc_item.children[1].innerText = item_category;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (item in data.items_received) {
|
||||
let current_item = document.getElementById(item);
|
||||
current_item.children[0].classList.add('acquired');
|
||||
current_item.children[0].src = data.icons[item];
|
||||
current_item.children[1].innerText = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const item in data.items_received) {
|
||||
if (document.getElementById(item)) {
|
||||
let current_item = document.getElementById(item);
|
||||
current_item.innerText = item + data.items_received[item];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
update()
|
||||
setInterval(update, 30000);
|
||||
|
||||
|
||||
// Collapsible regions section
|
||||
const regions = document.getElementsByClassName('regions-column');
|
||||
for (let i = 0; i < regions.length; i++) {
|
||||
let region_name = regions[i].id;
|
||||
|
||||
const tab_header = document.getElementById(region_name+'-header');
|
||||
const locations = document.getElementById(region_name+'-locations');
|
||||
// toggle locations display
|
||||
regions[i].addEventListener('click', function(event) {
|
||||
if (tab_header.innerHTML.includes("▼")) {
|
||||
locations.classList.remove('hidden');
|
||||
// change header text
|
||||
tab_header.innerHTML = tab_header.innerHTML.replace('▼', '▲');
|
||||
} else {
|
||||
locations.classList.add('hidden');
|
||||
// change header text
|
||||
tab_header.innerHTML = tab_header.innerHTML.replace('▲', '▼');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
82
WebHostLib/static/assets/trackers/zeldaKeysTracker.js
Normal file
82
WebHostLib/static/assets/trackers/zeldaKeysTracker.js
Normal file
@@ -0,0 +1,82 @@
|
||||
window.addEventListener('load', () => {
|
||||
// Reload tracker
|
||||
const update = () => {
|
||||
const room = document.getElementById('tracker-wrapper').getAttribute('data-tracker');
|
||||
|
||||
const request = new Request('/api/tracker/' + room);
|
||||
|
||||
fetch(request)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
// update locations blocks
|
||||
for (const location of data.checked_locations) {
|
||||
document.getElementById(location).classList.add('acquired');
|
||||
}
|
||||
// update totals checks done
|
||||
let total_checks_ele = document.getElementById('total-checks');
|
||||
const total_checks = document.getElementsByClassName('location').length;
|
||||
let checks_done = data.checked_locations.length;
|
||||
total_checks_ele.innerText = 'Total Checks Done: ' + checks_done + '/' + total_checks;
|
||||
// update item and icons blocks
|
||||
// update icons block
|
||||
if (data.icons.length > 0) {
|
||||
for (let item in data.icons) {
|
||||
if (data.progressive_names.length > 0) {
|
||||
for (let item_category in data.progressive_names) {
|
||||
let i = 0;
|
||||
for (let current_item in current_name) {
|
||||
if (current_item === item) {
|
||||
let doc_item = document.getElementById(item_category)
|
||||
doc_item.children[0].src = data.icons[item];
|
||||
if (item in data.items_received) {
|
||||
doc_item.children[0].classList.add('acquired');
|
||||
doc_item.children[1].innerText = item_category;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (item in data.items_received) {
|
||||
let current_item = document.getElementById(item);
|
||||
current_item.children[0].classList.add('acquired');
|
||||
current_item.children[0].src = data.icons[item];
|
||||
current_item.children[1].innerText = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const item in data.items_received) {
|
||||
if (document.getElementById(item)) {
|
||||
let current_item = document.getElementById(item);
|
||||
current_item.innerText = item + data.items_received[item];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
update()
|
||||
setInterval(update, 30000);
|
||||
|
||||
|
||||
// Collapsible regions section
|
||||
const regions = document.getElementsByClassName('regions-column');
|
||||
for (let i = 0; i < regions.length; i++) {
|
||||
let region_name = regions[i].id;
|
||||
|
||||
const tab_header = document.getElementById(region_name+'-header');
|
||||
const locations = document.getElementById(region_name+'-locations');
|
||||
// toggle locations display
|
||||
regions[i].addEventListener('click', function(event) {
|
||||
if (tab_header.innerHTML.includes("▼")) {
|
||||
locations.classList.remove('hidden');
|
||||
// change header text
|
||||
tab_header.innerHTML = tab_header.innerHTML.replace('▼', '▲');
|
||||
} else {
|
||||
locations.classList.add('hidden');
|
||||
// change header text
|
||||
tab_header.innerHTML = tab_header.innerHTML.replace('▲', '▼');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
150
WebHostLib/static/styles/trackers/playerTracker.css
Normal file
150
WebHostLib/static/styles/trackers/playerTracker.css
Normal file
@@ -0,0 +1,150 @@
|
||||
/* CSS Overrides */
|
||||
.dirt-wrapper{
|
||||
background-color: #897249;
|
||||
}
|
||||
|
||||
.dirt-wrapper h1{}
|
||||
|
||||
.grass-wrapper{
|
||||
background-color: #3fb24a;
|
||||
}
|
||||
|
||||
.grass-wrapper h1{}
|
||||
|
||||
.grassFlowers-wrapper{
|
||||
background-color: #3fb24a;
|
||||
}
|
||||
|
||||
.grassFlowers-wrapper h1{}
|
||||
|
||||
.ice-wrapper{
|
||||
background-color: #afe0ef;
|
||||
}
|
||||
|
||||
.ice-wrapper h1{}
|
||||
|
||||
.jungle-wrapper{
|
||||
background-color: #2a7808;
|
||||
}
|
||||
|
||||
.jungle-wrapper h1{}
|
||||
|
||||
.ocean-wrapper{
|
||||
background-color: #3667b1;
|
||||
}
|
||||
|
||||
.ocean-wrapper h1{}
|
||||
|
||||
.partyTime-wrapper{
|
||||
background-color: #3a0f69;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.partyTime-wrapper h1{}
|
||||
|
||||
|
||||
/* Actual Styles */
|
||||
h1 {
|
||||
font-size: 20px;
|
||||
color: #ffffff;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
text-shadow: 1px 1px black;
|
||||
}
|
||||
|
||||
h2 {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
#player-keys-tracker{
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
#items-container{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-evenly;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#items-container div{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.image-container{
|
||||
display: absolute;
|
||||
height: 75px;
|
||||
width: 75px;
|
||||
}
|
||||
|
||||
.bottom-text{
|
||||
position: relative;
|
||||
align-items: bottom;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.icon{
|
||||
height: 100%;
|
||||
position: relative;
|
||||
left: 15px;
|
||||
max-width: 45px;
|
||||
max-height: 45px;
|
||||
filter: grayscale(100%) contrast(75%) brightness(40%);
|
||||
}
|
||||
|
||||
.icon.acquired{
|
||||
filter: none;
|
||||
}
|
||||
|
||||
.total-checks{
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.locations-container{
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 5px;
|
||||
margin-left: 50px;
|
||||
margin-right: 50px;
|
||||
}
|
||||
|
||||
.location.acquired{
|
||||
text-decoration: line-through;
|
||||
filter: none;
|
||||
}
|
||||
|
||||
.regions-container{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-evenly;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.regions-header{
|
||||
font-size: 18px;
|
||||
padding: 15px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hidden{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.button-link{
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
line-height: 30px;
|
||||
background-color: lightgrey;
|
||||
cursor: pointer;
|
||||
color: inherit;
|
||||
}
|
||||
@@ -51,6 +51,17 @@ table.dataTable{
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
table.dataTable img.icon{
|
||||
height: 100%;
|
||||
max-width: 60px;
|
||||
max-height: 60px;
|
||||
filter: grayscale(100%) contrast(75%) brightness(50%);
|
||||
}
|
||||
|
||||
table.dataTable img.acquired{
|
||||
filter: none;
|
||||
}
|
||||
|
||||
table.dataTable thead{
|
||||
font-family: LexendDeca-Regular, sans-serif;
|
||||
}
|
||||
@@ -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>
|
||||
@@ -50,7 +50,7 @@
|
||||
No file to download for this game.
|
||||
{% endif %}
|
||||
</td>
|
||||
<td><a href="{{ url_for("getPlayerTracker", tracker=room.tracker, tracked_team=0, tracked_player=patch.player_id) }}">Tracker</a></td>
|
||||
<td><a href="{{ url_for("get_player_tracker", tracker=room.tracker, tracked_team=0, tracked_player=patch.player_id) }}">Tracker</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
<title>{{ player_name }}'s Tracker</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename="styles/tracker.css") }}"/>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename="styles/trackers/tracker.css") }}"/>
|
||||
<script type="application/ecmascript" src="{{ url_for('static', filename="assets/jquery.scrollsync.js") }}"></script>
|
||||
<script type="application/ecmascript" src="{{ url_for('static', filename="assets/tracker.js") }}"></script>
|
||||
<script type="application/ecmascript" src="{{ url_for('static', filename="assets/trackers/tracker.js") }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
@@ -13,6 +13,9 @@
|
||||
<div id="tracker-header-bar">
|
||||
<input placeholder="Search" id="search"/>
|
||||
<span class="info">This tracker will automatically update itself periodically.</span>
|
||||
<a href="/tracker/{{ room.tracker|suuid }}/{{ team }}/{{ player }}" class="button-link">
|
||||
Go to Styled Tracker
|
||||
</a>
|
||||
</div>
|
||||
<div class="table-wrapper">
|
||||
<table class="table non-unique-item-table">
|
||||
@@ -2,8 +2,8 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{{ player_name }}'s Tracker</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles/minecraftTracker.css') }}"/>
|
||||
<script type="application/ecmascript" src="{{ url_for('static', filename='assets/minecraftTracker.js') }}"></script>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles/trackers/minecraftTracker.css') }}"/>
|
||||
<script type="application/ecmascript" src="{{ url_for('static', filename='assets/trackers/minecraftTracker.js') }}"></script>
|
||||
<link rel="stylesheet" media="screen" href="https://fontlibrary.org//face/minecraftia" type="text/css"/>
|
||||
</head>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
<title>Multiworld Tracker</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename="styles/tracker.css") }}"/>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename="styles/trackers/tracker.css") }}"/>
|
||||
<script type="application/ecmascript" src="{{ url_for('static', filename="assets/jquery.scrollsync.js") }}"></script>
|
||||
<script type="application/ecmascript" src="{{ url_for('static', filename="assets/tracker.js") }}"></script>
|
||||
<script type="application/ecmascript" src="{{ url_for('static', filename="assets/trackers/tracker.js") }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
@@ -44,7 +44,7 @@
|
||||
<tbody>
|
||||
{%- for player, items in players.items() -%}
|
||||
<tr>
|
||||
<td><a href="{{ url_for("getPlayerTracker", tracker=room.tracker,
|
||||
<td><a href="{{ url_for("get_player_tracker", tracker=room.tracker,
|
||||
tracked_team=team, tracked_player=player)}}">{{ loop.index }}</a></td>
|
||||
{%- if (team, loop.index) in video -%}
|
||||
{%- if video[(team, loop.index)][0] == "Twitch" -%}
|
||||
@@ -121,7 +121,7 @@
|
||||
<tbody>
|
||||
{%- for player, checks in players.items() -%}
|
||||
<tr>
|
||||
<td><a href="{{ url_for("getPlayerTracker", tracker=room.tracker,
|
||||
<td><a href="{{ url_for("get_player_tracker", tracker=room.tracker,
|
||||
tracked_team=team, tracked_player=player)}}">{{ loop.index }}</a></td>
|
||||
<td>{{ player_names[(team, loop.index)]|e }}</td>
|
||||
{%- for area in ordered_areas -%}
|
||||
99
WebHostLib/templates/trackers/playerTracker.html
Normal file
99
WebHostLib/templates/trackers/playerTracker.html
Normal file
@@ -0,0 +1,99 @@
|
||||
{% block head %}
|
||||
<!--suppress XmlDuplicatedId -->
|
||||
<title>{{ player_name }}'s Tracker</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles/trackers/playerTracker.css') }}"/>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles/tooltip.css') }}"/>
|
||||
<script type="application/ecmascript" src="{{ url_for('static', filename='assets/trackers/playerTracker.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div id="tracker-wrapper" class="{{ theme }}-wrapper" data-tracker="{{ room.tracker|suuid }}/{{ team }}/{{ player }}">
|
||||
<a href="/generic_tracker/{{ room.tracker|suuid }}/{{ team }}/{{ player }}" class="button-link">
|
||||
Go to Generic Tracker
|
||||
</a>
|
||||
|
||||
{% if icons %}
|
||||
|
||||
{% block icons_render %}
|
||||
|
||||
<h1>Items</h1>
|
||||
<div id="items-container">
|
||||
{%- for item in icons %}
|
||||
<div class="image-container tooltip" id="{{ item }}" data-tooltip="{{ item }}">
|
||||
<img
|
||||
src="{{ icons[item] }}"
|
||||
class="icon tooltip {{ 'acquired' if item in received_items }}"
|
||||
/>
|
||||
</div>
|
||||
{%- endfor %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% else %}
|
||||
|
||||
{% block item_names_render %}
|
||||
<h1 class="items-header">Items</h1>
|
||||
<div class="items-container">
|
||||
{%- for item in received_items|sort -%}
|
||||
<div class="item" id="{{ item }}">
|
||||
{{ item }}
|
||||
{% if all_progression_items[item] > 1 %}
|
||||
{{ received_items[item] }}
|
||||
{% else %}
|
||||
✔
|
||||
{% endif %}
|
||||
</div>
|
||||
{%- endfor -%}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
{# div for total checks done as percentage. Probably needs to be put somewhere else but I liked how it looked here #}
|
||||
<div class="total-checks" id="total-checks">
|
||||
Total Checks Done: {{ checked_locations|length }}/{{ locations|length }}
|
||||
</div>
|
||||
|
||||
|
||||
{% if regions %}
|
||||
|
||||
{% block regions_render %}
|
||||
|
||||
<div class="regions-container">
|
||||
{% for region in regions %}
|
||||
<div class="regions-column" id="{{ region }}">
|
||||
<h1 class="regions-header" id="{{ region }}-header">{{ region }} ▼ {{ checks_done[region]|length }} / {{ regions[region]|length }}</h1>
|
||||
<div class="location-column hidden" id="{{ region }}-locations">
|
||||
{%- for location in regions[region] %}
|
||||
<div class="location {{ 'acquired' if location in checked_locations }}" id="{{ location }}">{{ location }}</div>
|
||||
{%- endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% else %}
|
||||
|
||||
{% block locations_render %}
|
||||
|
||||
<h1>Locations</h1>
|
||||
<div class="locations-container" id="locations-container">
|
||||
{% for location in locations %}
|
||||
<div class="location {{ 'acquired' if name in checked_locations }}" id="{{ location }}">
|
||||
{{ location }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -2,8 +2,8 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{{ player_name }}'s Tracker</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles/supermetroidTracker.css') }}"/>
|
||||
<script type="application/ecmascript" src="{{ url_for('static', filename='assets/supermetroidTracker.js') }}"></script>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles/trackers/supermetroidTracker.css') }}"/>
|
||||
<script type="application/ecmascript" src="{{ url_for('static', filename='assets/trackers/supermetroidTracker.js') }}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -2,8 +2,8 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{{ player_name }}'s Tracker</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles/timespinnerTracker.css') }}"/>
|
||||
<script type="application/ecmascript" src="{{ url_for('static', filename='assets/timespinnerTracker.js') }}"></script>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles/trackers/timespinnerTracker.css') }}"/>
|
||||
<script type="application/ecmascript" src="{{ url_for('static', filename='assets/trackers/timespinnerTracker.js') }}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
77
WebHostLib/templates/trackers/zeldaKeysTracker.html
Normal file
77
WebHostLib/templates/trackers/zeldaKeysTracker.html
Normal file
@@ -0,0 +1,77 @@
|
||||
{% block head %}
|
||||
<!--suppress XmlDuplicatedId -->
|
||||
<title>{{ player_name }}'s Keys Tracker</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles/trackers/playerTracker.css') }}"/>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles/tooltip.css') }}" />
|
||||
<script type="application/ecmascript" src="{{ url_for('static', filename='assets/trackers/zeldaKeysTracker.js') }}"/></script>
|
||||
{% endblock %}
|
||||
|
||||
{# this tracker is mostly similar to the generic player tracker but
|
||||
also adds a table with the key and checks counts for each region in the middle #}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div id="tracker-wrapper" class="{{ theme }}-wrapper" data-tracker="{{ room.tracker|suuid }}/{{ team }}/{{ player }}">
|
||||
<a href="/generic_tracker/{{ room.tracker|suuid }}/{{ team }}/{{ player }}" class="button-link">
|
||||
Go to Generic Tracker
|
||||
</a>
|
||||
<h1>Items</h1>
|
||||
<div id="items-container">
|
||||
{% for item in icons %}
|
||||
{% if item not in ['Small Key', 'Big Key'] %}
|
||||
<div class="image-container tooltip" id="{{ item }}" data-tooltip="{{ item }}">
|
||||
<img
|
||||
src="{{ icons[item] }}"
|
||||
class="icon tooltip {{ 'acquired' if item in received_items }}"
|
||||
/>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="total-checks" id="total-checks">
|
||||
Total Checks Done: {{ checked_locations|length }}/{{ locations|length }}
|
||||
</div>
|
||||
|
||||
<table id="regions-column">
|
||||
<tr class="keys-icons">
|
||||
<td><img src="{{icons['Small Key']}}" class="icon tooltip acquired" id="small-key-icon"/></td>
|
||||
<td><img src="{{icons['Big Key']}}" class="icon tooltip acquired" id="big-key-icon"/></td>
|
||||
<td class="right-align">Total</td>
|
||||
</tr>
|
||||
{% for region in regions %}
|
||||
<tr class="regions-column" id="{{ region }}">
|
||||
<td id="{{ region }}-header">{{ region }} ▼</td>
|
||||
{% if region in region_keys %}
|
||||
{%- if region_keys[region]|length > 1 %}
|
||||
<td class="smallkeys">{{ received_items[region_keys[region][0]] if region_keys[region][0] in received_items else '-' }}</td>
|
||||
<td class="bigkeys">{{ received_items[region_keys[region][1]] if region_keys[region][1] in received_items else '-' }}</td>
|
||||
{%- else %}
|
||||
{% if 'Small Key' in region_keys[region][0] %}
|
||||
<td class="smallkeys">{{ received_items[region_keys[region][0]] if region_keys[region][0] in received_items else '-' }}</td>
|
||||
<td class="bigkeys">-</td>
|
||||
{% else %}
|
||||
<td class="smallkeys">-</td>
|
||||
<td class="bigkeys">{{ received_items[region_keys[region][0]] if region_keys[region][0] in received_items else '-' }}</td>
|
||||
{% endif %}
|
||||
{%- endif%}
|
||||
{% else %}
|
||||
<td class="smallkeys">-</td>
|
||||
<td class="bigkeys">-</td>
|
||||
{% endif %}
|
||||
<td class="counter">{{ checks_done[region]|length }} / {{ regions[region]|length }}</td>
|
||||
</tr>
|
||||
<tbody class="locations hidden" id="{{ region }}-locations">
|
||||
{% for location in regions[region] %}
|
||||
<tr>
|
||||
<td class="location {{ 'acquired' if location in checked_locations }}" id="{{ location }}">
|
||||
{{ location }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,6 +1,6 @@
|
||||
import collections
|
||||
import typing
|
||||
from typing import Counter, Optional, Dict, Any, Tuple
|
||||
from typing import Counter, Optional, Dict, Any, Tuple, Set, List, TYPE_CHECKING
|
||||
|
||||
from flask import render_template
|
||||
from werkzeug.exceptions import abort
|
||||
@@ -11,9 +11,53 @@ from worlds.alttp import Items
|
||||
from WebHostLib import app, cache, Room
|
||||
from Utils import restricted_loads
|
||||
from worlds import lookup_any_item_id_to_name, lookup_any_location_id_to_name
|
||||
from MultiServer import Context
|
||||
from worlds.AutoWorld import AutoWorldRegister
|
||||
from MultiServer import get_item_name_from_id, Context
|
||||
from NetUtils import SlotType
|
||||
|
||||
|
||||
class PlayerTracker:
|
||||
"""This class will create a basic 'prettier' tracker for each world using their themes automatically. This
|
||||
can be overridden to customize how it will appear. Can provide icons and custom regions. The html used is also
|
||||
a jinja template that can be overridden if you want your tracker to look different in certain aspects. To render
|
||||
icons and regions add dictionaries to the relevant attributes of the tracker_info. To customize the layout of
|
||||
your icons you can create a new html in your world and extend playerTracker.html and overwrite the icons_render
|
||||
block then change the tracker_info template attribute to your template."""
|
||||
|
||||
template: str = 'playerTracker.html'
|
||||
icons: Dict[str, str] = {}
|
||||
progressive_items: List[str] = []
|
||||
progressive_names: Dict[str, List[str]] = {}
|
||||
regions: Dict[str, List[str]] = {}
|
||||
checks_done: Dict[str, Set[str]] = {}
|
||||
room: Any
|
||||
team: int
|
||||
player: int
|
||||
name: str
|
||||
all_locations: Set[str]
|
||||
checked_locations: Set[str]
|
||||
all_prog_items: Counter[str]
|
||||
items_received: Counter[str]
|
||||
received_prog_items: Counter[str]
|
||||
slot_data: Dict[any, any]
|
||||
theme: str
|
||||
|
||||
region_keys: Dict[str, str] = {}
|
||||
|
||||
def __init__(self, room: Any, team: int, player: int, name: str, all_locations: Set[str],
|
||||
checked_locations: set, all_progression_items: Counter[str], items_received: Counter[str],
|
||||
slot_data: Dict[any, any]):
|
||||
self.room = room
|
||||
self.team = team
|
||||
self.player = player
|
||||
self.name = name
|
||||
self.all_locations = all_locations
|
||||
self.checked_locations = checked_locations
|
||||
self.all_prog_items = all_progression_items
|
||||
self.items_received = items_received
|
||||
self.slot_data = slot_data
|
||||
|
||||
|
||||
alttp_icons = {
|
||||
"Blue Shield": r"https://www.zeldadungeon.net/wiki/images/8/85/Fighters-Shield.png",
|
||||
"Red Shield": r"https://www.zeldadungeon.net/wiki/images/5/55/Fire-Shield.png",
|
||||
@@ -288,7 +332,7 @@ def get_static_room_data(room: Room):
|
||||
|
||||
@app.route('/tracker/<suuid:tracker>/<int:tracked_team>/<int:tracked_player>')
|
||||
@cache.memoize(timeout=60) # multisave is currently created at most every minute
|
||||
def getPlayerTracker(tracker: UUID, tracked_team: int, tracked_player: int, want_generic: bool = False):
|
||||
def get_player_tracker(tracker: UUID, tracked_team: int, tracked_player: int, want_generic: bool = False):
|
||||
# Team and player must be positive and greater than zero
|
||||
if tracked_team < 0 or tracked_player < 1:
|
||||
abort(404)
|
||||
@@ -297,13 +341,78 @@ def getPlayerTracker(tracker: UUID, tracked_team: int, tracked_player: int, want
|
||||
if not room:
|
||||
abort(404)
|
||||
|
||||
# Collect seed information and pare it down to a single player
|
||||
player_tracker, multisave, inventory, seed_checks_in_area, lttp_checks_done, \
|
||||
slot_data, games, player_name, display_icons = fill_tracker_data(room, tracked_team, tracked_player)
|
||||
|
||||
game_name = games[tracked_player]
|
||||
# TODO move all games in game_specific_trackers to new system
|
||||
if game_name in game_specific_trackers and not want_generic:
|
||||
specific_tracker = game_specific_trackers.get(game_name, None)
|
||||
return specific_tracker(multisave, room, player_tracker.all_locations, inventory, tracked_team, tracked_player,
|
||||
player_name, seed_checks_in_area, lttp_checks_done, slot_data[tracked_player])
|
||||
elif game_name in AutoWorldRegister.world_types and not want_generic:
|
||||
return render_template(
|
||||
"trackers/" + player_tracker.template,
|
||||
all_progression_items=player_tracker.all_prog_items,
|
||||
player=tracked_player,
|
||||
team=tracked_team,
|
||||
room=player_tracker.room,
|
||||
player_name=player_tracker.name,
|
||||
checked_locations=sorted(player_tracker.checked_locations),
|
||||
locations=sorted(player_tracker.all_locations),
|
||||
theme=player_tracker.theme,
|
||||
icons=display_icons,
|
||||
regions=player_tracker.regions,
|
||||
checks_done=player_tracker.checks_done,
|
||||
region_keys=player_tracker.region_keys
|
||||
)
|
||||
else:
|
||||
return __renderGenericTracker(multisave, room, player_tracker.all_locations, inventory, tracked_team, tracked_player, player_name, seed_checks_in_area, lttp_checks_done)
|
||||
|
||||
|
||||
@app.route('/generic_tracker/<suuid:tracker>/<int:tracked_team>/<int:tracked_player>')
|
||||
@cache.memoize(timeout=60)
|
||||
def get_generic_tracker(tracker: UUID, tracked_team: int, tracked_player: int):
|
||||
return get_player_tracker(tracker, tracked_team, tracked_player, True)
|
||||
|
||||
|
||||
def get_tracker_icons_and_regions(player_tracker: PlayerTracker) -> Dict[str, str]:
|
||||
"""this function allows multiple icons to be used for the same item but it does require the world to submit both
|
||||
a progressive_items list and the icons dict together"""
|
||||
display_icons: Dict[str, str] = {}
|
||||
if player_tracker.progressive_names and player_tracker.icons:
|
||||
for item in player_tracker.progressive_items:
|
||||
if item in player_tracker.progressive_names:
|
||||
level = min(player_tracker.items_received[item], len(player_tracker.progressive_names[item]) - 1)
|
||||
display_name = player_tracker.progressive_names[item][level]
|
||||
if display_name in player_tracker.icons:
|
||||
display_icons[item] = player_tracker.icons[display_name]
|
||||
else:
|
||||
display_icons[item] = player_tracker.icons[item]
|
||||
else:
|
||||
display_icons[item] = player_tracker.icons[item]
|
||||
else:
|
||||
if player_tracker.progressive_items and player_tracker.icons:
|
||||
for item in player_tracker.progressive_items:
|
||||
display_icons[item] = player_tracker.icons[item]
|
||||
|
||||
if player_tracker.regions:
|
||||
for region in player_tracker.regions:
|
||||
for location in region:
|
||||
if location in player_tracker.checked_locations:
|
||||
player_tracker.checks_done.setdefault(region, set()).add(location)
|
||||
|
||||
return display_icons
|
||||
|
||||
|
||||
def fill_tracker_data(room: Room, tracked_team: int, tracked_player: int) -> Tuple:
|
||||
"""Collect seed information and pare it down to a single player"""
|
||||
locations, names, use_door_tracker, seed_checks_in_area, player_location_to_area, \
|
||||
precollected_items, games, slot_data, groups = get_static_room_data(room)
|
||||
player_name = names[tracked_team][tracked_player - 1]
|
||||
location_to_area = player_location_to_area[tracked_player]
|
||||
inventory = collections.Counter()
|
||||
checks_done = {loc_name: 0 for loc_name in default_locations}
|
||||
lttp_checks_done = {loc_name: 0 for loc_name in default_locations}
|
||||
|
||||
# Add starting items to inventory
|
||||
starting_items = precollected_items[tracked_player]
|
||||
@@ -321,6 +430,7 @@ def getPlayerTracker(tracker: UUID, tracked_team: int, tracked_player: int, want
|
||||
if tracked_player in group_members:
|
||||
slots_aimed_at_player.add(group_id)
|
||||
|
||||
checked_locations = set()
|
||||
# Add items to player inventory
|
||||
for (ms_team, ms_player), locations_checked in multisave.get("location_checks", {}).items():
|
||||
# Skip teams and players not matching the request
|
||||
@@ -332,383 +442,52 @@ def getPlayerTracker(tracker: UUID, tracked_team: int, tracked_player: int, want
|
||||
item, recipient, flags = player_locations[location]
|
||||
if recipient in slots_aimed_at_player: # a check done for the tracked player
|
||||
attribute_item_solo(inventory, item)
|
||||
|
||||
if ms_player == tracked_player: # a check done by the tracked player
|
||||
checks_done[location_to_area[location]] += 1
|
||||
checks_done["Total"] += 1
|
||||
specific_tracker = game_specific_trackers.get(games[tracked_player], None)
|
||||
if specific_tracker and not want_generic:
|
||||
return specific_tracker(multisave, room, locations, inventory, tracked_team, tracked_player, player_name,
|
||||
seed_checks_in_area, checks_done, slot_data[tracked_player])
|
||||
else:
|
||||
return __renderGenericTracker(multisave, room, locations, inventory, tracked_team, tracked_player, player_name,
|
||||
seed_checks_in_area, checks_done)
|
||||
lttp_checks_done[location_to_area[location]] += 1
|
||||
lttp_checks_done["Total"] += 1
|
||||
checked_locations.add(lookup_any_location_id_to_name[location])
|
||||
|
||||
prog_items = collections.Counter
|
||||
all_location_names = set()
|
||||
|
||||
all_location_names = {lookup_any_location_id_to_name[id] for id in locations[tracked_player]}
|
||||
prog_items = collections.Counter()
|
||||
for player in locations:
|
||||
for location in locations[player]:
|
||||
item, recipient, flags = locations[player][location]
|
||||
if recipient == player:
|
||||
if flags & 1:
|
||||
item_name = lookup_any_item_id_to_name[item]
|
||||
prog_items[item_name] += 1
|
||||
|
||||
items_received = collections.Counter()
|
||||
for id in inventory:
|
||||
items_received[lookup_any_item_id_to_name[id]] = inventory[id]
|
||||
|
||||
player_tracker = PlayerTracker(
|
||||
room,
|
||||
tracked_team,
|
||||
tracked_player,
|
||||
player_name,
|
||||
all_location_names,
|
||||
checked_locations,
|
||||
prog_items,
|
||||
items_received,
|
||||
slot_data[tracked_player]
|
||||
)
|
||||
|
||||
# grab webworld and apply its theme to the tracker
|
||||
webworld = AutoWorldRegister.world_types[games[tracked_player]].web
|
||||
player_tracker.theme = webworld.theme
|
||||
# allow the world to add information to the tracker class
|
||||
webworld.modify_tracker(player_tracker)
|
||||
display_icons = get_tracker_icons_and_regions(player_tracker)
|
||||
|
||||
return player_tracker, multisave, inventory, seed_checks_in_area, lttp_checks_done, slot_data, games, player_name, display_icons
|
||||
|
||||
|
||||
@app.route('/generic_tracker/<suuid:tracker>/<int:tracked_team>/<int:tracked_player>')
|
||||
def get_generic_tracker(tracker: UUID, tracked_team: int, tracked_player: int):
|
||||
return getPlayerTracker(tracker, tracked_team, tracked_player, True)
|
||||
|
||||
|
||||
def __renderAlttpTracker(multisave: Dict[str, Any], room: Room, locations: Dict[int, Dict[int, Tuple[int, int, int]]],
|
||||
inventory: Counter, team: int, player: int, player_name: str,
|
||||
seed_checks_in_area: Dict[int, Dict[str, int]], checks_done: Dict[str, int], slot_data: Dict) -> str:
|
||||
|
||||
# Note the presence of the triforce item
|
||||
game_state = multisave.get("client_game_state", {}).get((team, player), 0)
|
||||
if game_state == 30:
|
||||
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 + "_url"] = alttp_icons[display_name]
|
||||
|
||||
# The single player tracker doesn't care about overworld, underworld, and total checks. Maybe it should?
|
||||
sp_areas = ordered_areas[2:15]
|
||||
|
||||
player_big_key_locations = set()
|
||||
player_small_key_locations = set()
|
||||
for loc_data in locations.values():
|
||||
for values in loc_data.values():
|
||||
item_id, item_player, flags = values
|
||||
if item_player == player:
|
||||
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])
|
||||
|
||||
return render_template("lttpTracker.html", inventory=inventory,
|
||||
player_name=player_name, room=room, icons=alttp_icons, checks_done=checks_done,
|
||||
checks_in_area=seed_checks_in_area[player],
|
||||
acquired_items={lookup_any_item_id_to_name[id] for id in inventory},
|
||||
small_key_ids=small_key_ids, big_key_ids=big_key_ids, sp_areas=sp_areas,
|
||||
key_locations=player_small_key_locations,
|
||||
big_key_locations=player_big_key_locations,
|
||||
**display_data)
|
||||
|
||||
|
||||
def __renderMinecraftTracker(multisave: Dict[str, Any], room: Room, locations: Dict[int, Dict[int, Tuple[int, int, int]]],
|
||||
inventory: Counter, team: int, player: int, playerName: str,
|
||||
seed_checks_in_area: Dict[int, Dict[str, int]], checks_done: Dict[str, int], slot_data: Dict) -> str:
|
||||
|
||||
icons = {
|
||||
"Wooden Pickaxe": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/d/d2/Wooden_Pickaxe_JE3_BE3.png",
|
||||
"Stone Pickaxe": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/c/c4/Stone_Pickaxe_JE2_BE2.png",
|
||||
"Iron Pickaxe": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/d/d1/Iron_Pickaxe_JE3_BE2.png",
|
||||
"Diamond Pickaxe": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/e/e7/Diamond_Pickaxe_JE3_BE3.png",
|
||||
"Wooden Sword": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/d/d5/Wooden_Sword_JE2_BE2.png",
|
||||
"Stone Sword": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/b/b1/Stone_Sword_JE2_BE2.png",
|
||||
"Iron Sword": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/8/8e/Iron_Sword_JE2_BE2.png",
|
||||
"Diamond Sword": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/4/44/Diamond_Sword_JE3_BE3.png",
|
||||
"Leather Tunic": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/b/b7/Leather_Tunic_JE4_BE2.png",
|
||||
"Iron Chestplate": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/3/31/Iron_Chestplate_JE2_BE2.png",
|
||||
"Diamond Chestplate": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/e/e0/Diamond_Chestplate_JE3_BE2.png",
|
||||
"Iron Ingot": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/f/fc/Iron_Ingot_JE3_BE2.png",
|
||||
"Block of Iron": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/7/7e/Block_of_Iron_JE4_BE3.png",
|
||||
"Brewing Stand": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/b/b3/Brewing_Stand_%28empty%29_JE10.png",
|
||||
"Ender Pearl": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/f/f6/Ender_Pearl_JE3_BE2.png",
|
||||
"Bucket": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/f/fc/Bucket_JE2_BE2.png",
|
||||
"Bow": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/a/ab/Bow_%28Pull_2%29_JE1_BE1.png",
|
||||
"Shield": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/c/c6/Shield_JE2_BE1.png",
|
||||
"Red Bed": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/6/6a/Red_Bed_%28N%29.png",
|
||||
"Netherite Scrap": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/3/33/Netherite_Scrap_JE2_BE1.png",
|
||||
"Flint and Steel": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/9/94/Flint_and_Steel_JE4_BE2.png",
|
||||
"Enchanting Table": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/3/31/Enchanting_Table.gif",
|
||||
"Fishing Rod": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/7/7f/Fishing_Rod_JE2_BE2.png",
|
||||
"Campfire": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/9/91/Campfire_JE2_BE2.gif",
|
||||
"Water Bottle": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/7/75/Water_Bottle_JE2_BE2.png",
|
||||
"Spyglass": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/c/c1/Spyglass_JE2_BE1.png",
|
||||
}
|
||||
|
||||
minecraft_location_ids = {
|
||||
"Story": [42073, 42023, 42027, 42039, 42002, 42009, 42010, 42070,
|
||||
42041, 42049, 42004, 42031, 42025, 42029, 42051, 42077],
|
||||
"Nether": [42017, 42044, 42069, 42058, 42034, 42060, 42066, 42076, 42064, 42071, 42021,
|
||||
42062, 42008, 42061, 42033, 42011, 42006, 42019, 42000, 42040, 42001, 42015, 42014],
|
||||
"The End": [42052, 42005, 42012, 42032, 42030, 42042, 42018, 42038, 42046],
|
||||
"Adventure": [42047, 42050, 42096, 42097, 42098, 42059, 42055, 42072, 42003, 42035, 42016, 42020,
|
||||
42048, 42054, 42068, 42043, 42074, 42075, 42024, 42026, 42037, 42045, 42056, 42099, 42100],
|
||||
"Husbandry": [42065, 42067, 42078, 42022, 42007, 42079, 42013, 42028, 42036,
|
||||
42057, 42063, 42053, 42102, 42101, 42092, 42093, 42094, 42095],
|
||||
"Archipelago": [42080, 42081, 42082, 42083, 42084, 42085, 42086, 42087, 42088, 42089, 42090, 42091],
|
||||
}
|
||||
|
||||
display_data = {}
|
||||
|
||||
# Determine display for progressive items
|
||||
progressive_items = {
|
||||
"Progressive Tools": 45013,
|
||||
"Progressive Weapons": 45012,
|
||||
"Progressive Armor": 45014,
|
||||
"Progressive Resource Crafting": 45001
|
||||
}
|
||||
progressive_names = {
|
||||
"Progressive Tools": ["Wooden Pickaxe", "Stone Pickaxe", "Iron Pickaxe", "Diamond Pickaxe"],
|
||||
"Progressive Weapons": ["Wooden Sword", "Stone Sword", "Iron Sword", "Diamond Sword"],
|
||||
"Progressive Armor": ["Leather Tunic", "Iron Chestplate", "Diamond Chestplate"],
|
||||
"Progressive Resource Crafting": ["Iron Ingot", "Iron Ingot", "Block of Iron"]
|
||||
}
|
||||
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]
|
||||
base_name = item_name.split(maxsplit=1)[1].lower().replace(' ', '_')
|
||||
display_data[base_name + "_url"] = icons[display_name]
|
||||
|
||||
# Multi-items
|
||||
multi_items = {
|
||||
"3 Ender Pearls": 45029,
|
||||
"8 Netherite Scrap": 45015
|
||||
}
|
||||
for item_name, item_id in multi_items.items():
|
||||
base_name = item_name.split()[-1].lower()
|
||||
count = inventory[item_id]
|
||||
if count >= 0:
|
||||
display_data[base_name + "_count"] = count
|
||||
|
||||
# Victory condition
|
||||
game_state = multisave.get("client_game_state", {}).get((team, player), 0)
|
||||
display_data['game_finished'] = game_state == 30
|
||||
|
||||
# Turn location IDs into advancement tab counts
|
||||
checked_locations = multisave.get("location_checks", {}).get((team, player), set())
|
||||
lookup_name = lambda id: lookup_any_location_id_to_name[id]
|
||||
location_info = {tab_name: {lookup_name(id): (id in checked_locations) for id in tab_locations}
|
||||
for tab_name, tab_locations in minecraft_location_ids.items()}
|
||||
checks_done = {tab_name: len([id for id in tab_locations if id in checked_locations])
|
||||
for tab_name, tab_locations in minecraft_location_ids.items()}
|
||||
checks_done['Total'] = len(checked_locations)
|
||||
checks_in_area = {tab_name: len(tab_locations) for tab_name, tab_locations in minecraft_location_ids.items()}
|
||||
checks_in_area['Total'] = sum(checks_in_area.values())
|
||||
|
||||
return render_template("minecraftTracker.html",
|
||||
inventory=inventory, icons=icons,
|
||||
acquired_items={lookup_any_item_id_to_name[id] for id in inventory if
|
||||
id in lookup_any_item_id_to_name},
|
||||
player=player, team=team, room=room, player_name=playerName,
|
||||
checks_done=checks_done, checks_in_area=checks_in_area, location_info=location_info,
|
||||
**display_data)
|
||||
|
||||
|
||||
def __renderOoTTracker(multisave: Dict[str, Any], room: Room, locations: Dict[int, Dict[int, Tuple[int, int, int]]],
|
||||
inventory: Counter, team: int, player: int, playerName: str,
|
||||
seed_checks_in_area: Dict[int, Dict[str, int]], checks_done: Dict[str, int], slot_data: Dict) -> str:
|
||||
|
||||
icons = {
|
||||
"Fairy Ocarina": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/9/97/OoT_Fairy_Ocarina_Icon.png",
|
||||
"Ocarina of Time": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/4/4e/OoT_Ocarina_of_Time_Icon.png",
|
||||
"Slingshot": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/3/32/OoT_Fairy_Slingshot_Icon.png",
|
||||
"Boomerang": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/d/d5/OoT_Boomerang_Icon.png",
|
||||
"Bottle": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/f/fc/OoT_Bottle_Icon.png",
|
||||
"Rutos Letter": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/21/OoT_Letter_Icon.png",
|
||||
"Bombs": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/1/11/OoT_Bomb_Icon.png",
|
||||
"Bombchus": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/3/36/OoT_Bombchu_Icon.png",
|
||||
"Lens of Truth": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/0/05/OoT_Lens_of_Truth_Icon.png",
|
||||
"Bow": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/9/9a/OoT_Fairy_Bow_Icon.png",
|
||||
"Hookshot": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/7/77/OoT_Hookshot_Icon.png",
|
||||
"Longshot": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/a/a4/OoT_Longshot_Icon.png",
|
||||
"Megaton Hammer": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/9/93/OoT_Megaton_Hammer_Icon.png",
|
||||
"Fire Arrows": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/1/1e/OoT_Fire_Arrow_Icon.png",
|
||||
"Ice Arrows": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/3/3c/OoT_Ice_Arrow_Icon.png",
|
||||
"Light Arrows": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/7/76/OoT_Light_Arrow_Icon.png",
|
||||
"Dins Fire": r"https://static.wikia.nocookie.net/zelda_gamepedia_en/images/d/da/OoT_Din%27s_Fire_Icon.png",
|
||||
"Farores Wind": r"https://static.wikia.nocookie.net/zelda_gamepedia_en/images/7/7a/OoT_Farore%27s_Wind_Icon.png",
|
||||
"Nayrus Love": r"https://static.wikia.nocookie.net/zelda_gamepedia_en/images/b/be/OoT_Nayru%27s_Love_Icon.png",
|
||||
"Kokiri Sword": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/5/53/OoT_Kokiri_Sword_Icon.png",
|
||||
"Biggoron Sword": r"https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/2e/OoT_Giant%27s_Knife_Icon.png",
|
||||
"Mirror Shield": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/b/b0/OoT_Mirror_Shield_Icon_2.png",
|
||||
"Goron Bracelet": r"https://static.wikia.nocookie.net/zelda_gamepedia_en/images/b/b7/OoT_Goron%27s_Bracelet_Icon.png",
|
||||
"Silver Gauntlets": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/b/b9/OoT_Silver_Gauntlets_Icon.png",
|
||||
"Golden Gauntlets": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/6/6a/OoT_Golden_Gauntlets_Icon.png",
|
||||
"Goron Tunic": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/1/1c/OoT_Goron_Tunic_Icon.png",
|
||||
"Zora Tunic": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/2c/OoT_Zora_Tunic_Icon.png",
|
||||
"Silver Scale": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/4/4e/OoT_Silver_Scale_Icon.png",
|
||||
"Gold Scale": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/9/95/OoT_Golden_Scale_Icon.png",
|
||||
"Iron Boots": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/3/34/OoT_Iron_Boots_Icon.png",
|
||||
"Hover Boots": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/22/OoT_Hover_Boots_Icon.png",
|
||||
"Adults Wallet": r"https://static.wikia.nocookie.net/zelda_gamepedia_en/images/f/f9/OoT_Adult%27s_Wallet_Icon.png",
|
||||
"Giants Wallet": r"https://static.wikia.nocookie.net/zelda_gamepedia_en/images/8/87/OoT_Giant%27s_Wallet_Icon.png",
|
||||
"Small Magic": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/9/9f/OoT3D_Magic_Jar_Icon.png",
|
||||
"Large Magic": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/3/3e/OoT3D_Large_Magic_Jar_Icon.png",
|
||||
"Gerudo Membership Card": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/4/4e/OoT_Gerudo_Token_Icon.png",
|
||||
"Gold Skulltula Token": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/4/47/OoT_Token_Icon.png",
|
||||
"Triforce Piece": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/0/0b/SS_Triforce_Piece_Icon.png",
|
||||
"Triforce": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/6/68/ALttP_Triforce_Title_Sprite.png",
|
||||
"Zeldas Lullaby": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/21/Grey_Note.png",
|
||||
"Eponas Song": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/21/Grey_Note.png",
|
||||
"Sarias Song": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/21/Grey_Note.png",
|
||||
"Suns Song": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/21/Grey_Note.png",
|
||||
"Song of Time": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/21/Grey_Note.png",
|
||||
"Song of Storms": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/21/Grey_Note.png",
|
||||
"Minuet of Forest": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/e/e4/Green_Note.png",
|
||||
"Bolero of Fire": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/f/f0/Red_Note.png",
|
||||
"Serenade of Water": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/0/0f/Blue_Note.png",
|
||||
"Requiem of Spirit": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/a/a4/Orange_Note.png",
|
||||
"Nocturne of Shadow": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/9/97/Purple_Note.png",
|
||||
"Prelude of Light": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/9/90/Yellow_Note.png",
|
||||
"Small Key": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/e/e5/OoT_Small_Key_Icon.png",
|
||||
"Boss Key": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/4/40/OoT_Boss_Key_Icon.png",
|
||||
}
|
||||
|
||||
display_data = {}
|
||||
|
||||
# Determine display for progressive items
|
||||
progressive_items = {
|
||||
"Progressive Hookshot": 66128,
|
||||
"Progressive Strength Upgrade": 66129,
|
||||
"Progressive Wallet": 66133,
|
||||
"Progressive Scale": 66134,
|
||||
"Magic Meter": 66138,
|
||||
"Ocarina": 66139,
|
||||
}
|
||||
|
||||
progressive_names = {
|
||||
"Progressive Hookshot": ["Hookshot", "Hookshot", "Longshot"],
|
||||
"Progressive Strength Upgrade": ["Goron Bracelet", "Goron Bracelet", "Silver Gauntlets", "Golden Gauntlets"],
|
||||
"Progressive Wallet": ["Adults Wallet", "Adults Wallet", "Giants Wallet", "Giants Wallet"],
|
||||
"Progressive Scale": ["Silver Scale", "Silver Scale", "Gold Scale"],
|
||||
"Magic Meter": ["Small Magic", "Small Magic", "Large Magic"],
|
||||
"Ocarina": ["Fairy Ocarina", "Fairy Ocarina", "Ocarina of Time"]
|
||||
}
|
||||
|
||||
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]
|
||||
if item_name.startswith("Progressive"):
|
||||
base_name = item_name.split(maxsplit=1)[1].lower().replace(' ', '_')
|
||||
else:
|
||||
base_name = item_name.lower().replace(' ', '_')
|
||||
display_data[base_name+"_url"] = icons[display_name]
|
||||
|
||||
if base_name == "hookshot":
|
||||
display_data['hookshot_length'] = {0: '', 1: 'H', 2: 'L'}.get(level)
|
||||
if base_name == "wallet":
|
||||
display_data['wallet_size'] = {0: '99', 1: '200', 2: '500', 3: '999'}.get(level)
|
||||
|
||||
# Determine display for bottles. Show letter if it's obtained, determine bottle count
|
||||
bottle_ids = [66015, 66020, 66021, 66140, 66141, 66142, 66143, 66144, 66145, 66146, 66147, 66148]
|
||||
display_data['bottle_count'] = min(sum(map(lambda item_id: inventory[item_id], bottle_ids)), 4)
|
||||
display_data['bottle_url'] = icons['Rutos Letter'] if inventory[66021] > 0 else icons['Bottle']
|
||||
|
||||
# Determine bombchu display
|
||||
display_data['has_bombchus'] = any(map(lambda item_id: inventory[item_id] > 0, [66003, 66106, 66107, 66137]))
|
||||
|
||||
# Multi-items
|
||||
multi_items = {
|
||||
"Gold Skulltula Token": 66091,
|
||||
"Triforce Piece": 66202,
|
||||
}
|
||||
for item_name, item_id in multi_items.items():
|
||||
base_name = item_name.split()[-1].lower()
|
||||
count = inventory[item_id]
|
||||
display_data[base_name+"_count"] = inventory[item_id]
|
||||
|
||||
# Gather dungeon locations
|
||||
area_id_ranges = {
|
||||
"Overworld": (67000, 67280),
|
||||
"Deku Tree": (67281, 67303),
|
||||
"Dodongo's Cavern": (67304, 67334),
|
||||
"Jabu Jabu's Belly": (67335, 67359),
|
||||
"Bottom of the Well": (67360, 67384),
|
||||
"Forest Temple": (67385, 67420),
|
||||
"Fire Temple": (67421, 67457),
|
||||
"Water Temple": (67458, 67484),
|
||||
"Shadow Temple": (67485, 67532),
|
||||
"Spirit Temple": (67533, 67582),
|
||||
"Ice Cavern": (67583, 67596),
|
||||
"Gerudo Training Ground": (67597, 67635),
|
||||
"Thieves' Hideout": (67259, 67263),
|
||||
"Ganon's Castle": (67636, 67673),
|
||||
}
|
||||
|
||||
def lookup_and_trim(id, area):
|
||||
full_name = lookup_any_location_id_to_name[id]
|
||||
if id == 67673:
|
||||
return full_name[13:] # Ganons Tower Boss Key Chest
|
||||
if area not in ["Overworld", "Thieves' Hideout"]:
|
||||
# trim dungeon name. leaves an extra space that doesn't display, or trims fully for DC/Jabu/GC
|
||||
return full_name[len(area):]
|
||||
return full_name
|
||||
|
||||
checked_locations = multisave.get("location_checks", {}).get((team, player), set()).intersection(set(locations[player]))
|
||||
location_info = {area: {lookup_and_trim(id, area): id in checked_locations for id in range(min_id, max_id+1) if id in locations[player]}
|
||||
for area, (min_id, max_id) in area_id_ranges.items()}
|
||||
checks_done = {area: len(list(filter(lambda x: x, location_info[area].values()))) for area in area_id_ranges}
|
||||
checks_in_area = {area: len([id for id in range(min_id, max_id+1) if id in locations[player]])
|
||||
for area, (min_id, max_id) in area_id_ranges.items()}
|
||||
|
||||
# Remove Thieves' Hideout checks from Overworld, since it's in the middle of the range
|
||||
checks_in_area["Overworld"] -= checks_in_area["Thieves' Hideout"]
|
||||
checks_done["Overworld"] -= checks_done["Thieves' Hideout"]
|
||||
for loc in location_info["Thieves' Hideout"]:
|
||||
del location_info["Overworld"][loc]
|
||||
|
||||
checks_done['Total'] = sum(checks_done.values())
|
||||
checks_in_area['Total'] = sum(checks_in_area.values())
|
||||
|
||||
# Give skulltulas on non-tracked locations
|
||||
non_tracked_locations = multisave.get("location_checks", {}).get((team, player), set()).difference(set(locations[player]))
|
||||
for id in non_tracked_locations:
|
||||
if "GS" in lookup_and_trim(id, ''):
|
||||
display_data["token_count"] += 1
|
||||
|
||||
# Gather small and boss key info
|
||||
small_key_counts = {
|
||||
"Forest Temple": inventory[66175],
|
||||
"Fire Temple": inventory[66176],
|
||||
"Water Temple": inventory[66177],
|
||||
"Spirit Temple": inventory[66178],
|
||||
"Shadow Temple": inventory[66179],
|
||||
"Bottom of the Well": inventory[66180],
|
||||
"Gerudo Training Ground": inventory[66181],
|
||||
"Thieves' Hideout": inventory[66182],
|
||||
"Ganon's Castle": inventory[66183],
|
||||
}
|
||||
boss_key_counts = {
|
||||
"Forest Temple": '✔' if inventory[66149] else '✕',
|
||||
"Fire Temple": '✔' if inventory[66150] else '✕',
|
||||
"Water Temple": '✔' if inventory[66151] else '✕',
|
||||
"Spirit Temple": '✔' if inventory[66152] else '✕',
|
||||
"Shadow Temple": '✔' if inventory[66153] else '✕',
|
||||
"Ganon's Castle": '✔' if inventory[66154] else '✕',
|
||||
}
|
||||
|
||||
# Victory condition
|
||||
game_state = multisave.get("client_game_state", {}).get((team, player), 0)
|
||||
display_data['game_finished'] = game_state == 30
|
||||
|
||||
return render_template("ootTracker.html",
|
||||
inventory=inventory, player=player, team=team, room=room, player_name=playerName,
|
||||
icons=icons, acquired_items={lookup_any_item_id_to_name[id] for id in inventory},
|
||||
checks_done=checks_done, checks_in_area=checks_in_area, location_info=location_info,
|
||||
small_key_counts=small_key_counts, boss_key_counts=boss_key_counts,
|
||||
**display_data)
|
||||
|
||||
|
||||
def __renderTimespinnerTracker(multisave: Dict[str, Any], room: Room, locations: Dict[int, Dict[int, Tuple[int, int, int]]],
|
||||
def __renderTimespinnerTracker(multisave: Dict[str, Any], room: Room, locations: set,
|
||||
inventory: Counter, team: int, player: int, playerName: str,
|
||||
seed_checks_in_area: Dict[int, Dict[str, int]], checks_done: Dict[str, int], slot_data: Dict[str, Any]) -> str:
|
||||
|
||||
@@ -745,7 +524,7 @@ def __renderTimespinnerTracker(multisave: Dict[str, Any], room: Room, locations:
|
||||
}
|
||||
|
||||
timespinner_location_ids = {
|
||||
"Present": [
|
||||
"Present": [
|
||||
1337000, 1337001, 1337002, 1337003, 1337004, 1337005, 1337006, 1337007, 1337008, 1337009,
|
||||
1337010, 1337011, 1337012, 1337013, 1337014, 1337015, 1337016, 1337017, 1337018, 1337019,
|
||||
1337020, 1337021, 1337022, 1337023, 1337024, 1337025, 1337026, 1337027, 1337028, 1337029,
|
||||
@@ -766,20 +545,20 @@ def __renderTimespinnerTracker(multisave: Dict[str, Any], room: Room, locations:
|
||||
1337150, 1337151, 1337152, 1337153, 1337154, 1337155,
|
||||
1337171, 1337172, 1337173, 1337174, 1337175],
|
||||
"Ancient Pyramid": [
|
||||
1337236,
|
||||
1337236,
|
||||
1337246, 1337247, 1337248, 1337249]
|
||||
}
|
||||
|
||||
if(slot_data["DownloadableItems"]):
|
||||
timespinner_location_ids["Present"] += [
|
||||
1337156, 1337157, 1337159,
|
||||
1337160, 1337161, 1337162, 1337163, 1337164, 1337165, 1337166, 1337167, 1337168, 1337169,
|
||||
1337160, 1337161, 1337162, 1337163, 1337164, 1337165, 1337166, 1337167, 1337168, 1337169,
|
||||
1337170]
|
||||
if(slot_data["Cantoran"]):
|
||||
timespinner_location_ids["Past"].append(1337176)
|
||||
if(slot_data["LoreChecks"]):
|
||||
timespinner_location_ids["Present"] += [
|
||||
1337177, 1337178, 1337179,
|
||||
1337177, 1337178, 1337179,
|
||||
1337180, 1337181, 1337182, 1337183, 1337184, 1337185, 1337186, 1337187]
|
||||
timespinner_location_ids["Past"] += [
|
||||
1337188, 1337189,
|
||||
@@ -808,13 +587,13 @@ def __renderTimespinnerTracker(multisave: Dict[str, Any], room: Room, locations:
|
||||
acquired_items = {lookup_any_item_id_to_name[id] for id in inventory if id in lookup_any_item_id_to_name}
|
||||
options = {k for k, v in slot_data.items() if v}
|
||||
|
||||
return render_template("timespinnerTracker.html",
|
||||
return render_template("trackers/" + "timespinnerTracker.html",
|
||||
inventory=inventory, icons=icons, acquired_items=acquired_items,
|
||||
player=player, team=team, room=room, player_name=playerName,
|
||||
checks_done=checks_done, checks_in_area=checks_in_area, location_info=location_info,
|
||||
options=options, **display_data)
|
||||
|
||||
def __renderSuperMetroidTracker(multisave: Dict[str, Any], room: Room, locations: Dict[int, Dict[int, Tuple[int, int, int]]],
|
||||
def __renderSuperMetroidTracker(multisave: Dict[str, Any], room: Room, locations: set,
|
||||
inventory: Counter, team: int, player: int, playerName: str,
|
||||
seed_checks_in_area: Dict[int, Dict[str, int]], checks_done: Dict[str, int], slot_data: Dict) -> str:
|
||||
|
||||
@@ -889,6 +668,7 @@ def __renderSuperMetroidTracker(multisave: Dict[str, Any], room: Room, locations
|
||||
|
||||
for item_name, item_id in multi_items.items():
|
||||
base_name = item_name.split()[0].lower()
|
||||
count = inventory[item_id]
|
||||
display_data[base_name+"_count"] = inventory[item_id]
|
||||
|
||||
# Victory condition
|
||||
@@ -906,7 +686,7 @@ def __renderSuperMetroidTracker(multisave: Dict[str, Any], room: Room, locations
|
||||
checks_in_area = {tab_name: len(tab_locations) for tab_name, tab_locations in supermetroid_location_ids.items()}
|
||||
checks_in_area['Total'] = sum(checks_in_area.values())
|
||||
|
||||
return render_template("supermetroidTracker.html",
|
||||
return render_template("trackers/" + "supermetroidTracker.html",
|
||||
inventory=inventory, icons=icons,
|
||||
acquired_items={lookup_any_item_id_to_name[id] for id in inventory if
|
||||
id in lookup_any_item_id_to_name},
|
||||
@@ -914,7 +694,8 @@ def __renderSuperMetroidTracker(multisave: Dict[str, Any], room: Room, locations
|
||||
checks_done=checks_done, checks_in_area=checks_in_area, location_info=location_info,
|
||||
**display_data)
|
||||
|
||||
def __renderGenericTracker(multisave: Dict[str, Any], room: Room, locations: Dict[int, Dict[int, Tuple[int, int, int]]],
|
||||
|
||||
def __renderGenericTracker(multisave: Dict[str, Any], room: Room, locations: set,
|
||||
inventory: Counter, team: int, player: int, playerName: str,
|
||||
seed_checks_in_area: Dict[int, Dict[str, int]], checks_done: Dict[str, int]) -> str:
|
||||
|
||||
@@ -929,11 +710,11 @@ def __renderGenericTracker(multisave: Dict[str, Any], room: Room, locations: Dic
|
||||
for order_index, networkItem in enumerate(ordered_items, start=1):
|
||||
player_received_items[networkItem.item] = order_index
|
||||
|
||||
return render_template("genericTracker.html",
|
||||
return render_template("trackers/" + "genericTracker.html",
|
||||
inventory=inventory,
|
||||
player=player, team=team, room=room, player_name=playerName,
|
||||
checked_locations=checked_locations,
|
||||
not_checked_locations=set(locations[player]) - checked_locations,
|
||||
not_checked_locations=locations - checked_locations,
|
||||
received_items=player_received_items)
|
||||
|
||||
|
||||
@@ -975,9 +756,9 @@ def getTracker(tracker: UUID):
|
||||
continue
|
||||
|
||||
item, recipient, flags = player_locations[location]
|
||||
|
||||
if recipient in names:
|
||||
attribute_item(inventory, team, recipient, item)
|
||||
|
||||
checks_done[team][player][player_location_to_area[player][location]] += 1
|
||||
checks_done[team][player]["Total"] += 1
|
||||
|
||||
@@ -1021,7 +802,7 @@ def getTracker(tracker: UUID):
|
||||
for (team, player), data in multisave.get("video", []):
|
||||
video[(team, player)] = data
|
||||
|
||||
return render_template("tracker.html", inventory=inventory, get_item_name_from_id=lookup_any_item_id_to_name,
|
||||
return render_template("trackers/" + "multiworldTracker.html", inventory=inventory, get_item_name_from_id=lookup_any_item_id_to_name,
|
||||
lookup_id_to_name=Items.lookup_id_to_name, player_names=player_names,
|
||||
tracking_names=tracking_names, tracking_ids=tracking_ids, room=room, icons=alttp_icons,
|
||||
multi_items=multi_items, checks_done=checks_done, ordered_areas=ordered_areas,
|
||||
@@ -1032,9 +813,6 @@ def getTracker(tracker: UUID):
|
||||
|
||||
|
||||
game_specific_trackers: typing.Dict[str, typing.Callable] = {
|
||||
"Minecraft": __renderMinecraftTracker,
|
||||
"Ocarina of Time": __renderOoTTracker,
|
||||
"Timespinner": __renderTimespinnerTracker,
|
||||
"A Link to the Past": __renderAlttpTracker,
|
||||
"Super Metroid": __renderSuperMetroidTracker
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,10 +98,10 @@ def call_stage(world: "MultiWorld", method_name: str, *args: Any) -> None:
|
||||
|
||||
class WebWorld:
|
||||
"""Webhost integration"""
|
||||
|
||||
|
||||
settings_page: Union[bool, str] = True
|
||||
"""display a settings page. Can be a link to a specific page or external tool."""
|
||||
|
||||
|
||||
game_info_languages: List[str] = ['en']
|
||||
"""docs folder will be scanned for game info pages using this list in the format '{language}_{game_name}.md'"""
|
||||
|
||||
@@ -115,6 +115,16 @@ class WebWorld:
|
||||
bug_report_page: Optional[str]
|
||||
"""display a link to a bug report page, most likely a link to a GitHub issue page."""
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from WebHostLib.tracker import PlayerTracker
|
||||
else:
|
||||
PlayerTracker = object
|
||||
|
||||
def modify_tracker(self, tracker: PlayerTracker):
|
||||
"""Can use this to modify tracker data and add icons and regions dictionaries to
|
||||
allow them to render on the game's tracker page."""
|
||||
pass
|
||||
|
||||
|
||||
class World(metaclass=AutoWorldRegister):
|
||||
"""A World object encompasses a game's Items, Locations, Rules and additional data or functionality required.
|
||||
|
||||
@@ -101,6 +101,232 @@ class ALTTPWeb(WebWorld):
|
||||
|
||||
tutorials = [setup_en, setup_de, setup_es, setup_fr, msu, msu_es, msu_fr, plando]
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from WebHostLib.tracker import PlayerTracker
|
||||
else:
|
||||
PlayerTracker = object
|
||||
|
||||
def modify_tracker(self, tracker: PlayerTracker):
|
||||
tracker.template = 'zeldaKeysTracker.html'
|
||||
|
||||
tracker.icons = {
|
||||
"Blue Shield": r"https://www.zeldadungeon.net/wiki/images/8/85/Fighters-Shield.png",
|
||||
"Red Shield": r"https://www.zeldadungeon.net/wiki/images/5/55/Fire-Shield.png",
|
||||
"Mirror Shield": r"https://www.zeldadungeon.net/wiki/images/8/84/Mirror-Shield.png",
|
||||
"Fighter Sword": r"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": r"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": r"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": r"https://oyster.ignimgs.com/mediawiki/apis.ign.com/the-legend-of-zelda-a-link-to-the-past/2/28/SGoldenSword.png?width=1920",
|
||||
"Bow": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/b/bc/ALttP_Bow_%26_Arrows_Sprite.png?version=5f85a70e6366bf473544ef93b274f74c",
|
||||
"Silver Bow": r"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": r"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": r"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": r"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": r"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": r"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": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/c/cc/ALttP_Master_Sword_Sprite.png?version=55869db2a20e157cd3b5c8f556097725",
|
||||
"Pegasus Boots": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/ed/ALttP_Pegasus_Shoes_Sprite.png?version=405f42f97240c9dcd2b71ffc4bebc7f9",
|
||||
"Progressive Glove": r"https://oyster.ignimgs.com/mediawiki/apis.ign.com/the-legend-of-zelda-a-link-to-the-past/c/c1/STitanMitt.png?width=1920",
|
||||
"Flippers": r"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": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/6/63/ALttP_Moon_Pearl_Sprite.png?version=d601542d5abcc3e006ee163254bea77e",
|
||||
"Progressive Bow": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/b/bc/ALttP_Bow_%26_Arrows_Sprite.png?version=cfb7648b3714cccc80e2b17b2adf00ed",
|
||||
"Blue Boomerang": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/c/c3/ALttP_Boomerang_Sprite.png?version=96127d163759395eb510b81a556d500e",
|
||||
"Red Boomerang": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/b/b9/ALttP_Magical_Boomerang_Sprite.png?version=47cddce7a07bc3e4c2c10727b491f400",
|
||||
"Hookshot": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/2/24/Hookshot.png?version=c90bc8e07a52e8090377bd6ef854c18b",
|
||||
"Mushroom": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/3/35/ALttP_Mushroom_Sprite.png?version=1f1acb30d71bd96b60a3491e54bbfe59",
|
||||
"Magic Powder": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/e5/ALttP_Magic_Powder_Sprite.png?version=c24e38effbd4f80496d35830ce8ff4ec",
|
||||
"Fire Rod": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/d6/FireRod.png?version=6eabc9f24d25697e2c4cd43ddc8207c0",
|
||||
"Ice Rod": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/d7/ALttP_Ice_Rod_Sprite.png?version=1f944148223d91cfc6a615c92286c3bc",
|
||||
"Bombos": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/8/8c/ALttP_Bombos_Medallion_Sprite.png?version=f4d6aba47fb69375e090178f0fc33b26",
|
||||
"Ether": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/3/3c/Ether.png?version=34027651a5565fcc5a83189178ab17b5",
|
||||
"Quake": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/5/56/ALttP_Quake_Medallion_Sprite.png?version=efd64d451b1831bd59f7b7d6b61b5879",
|
||||
"Lamp": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/6/63/ALttP_Lantern_Sprite.png?version=e76eaa1ec509c9a5efb2916698d5a4ce",
|
||||
"Hammer": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/d1/ALttP_Hammer_Sprite.png?version=e0adec227193818dcaedf587eba34500",
|
||||
"Shovel": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/c/c4/ALttP_Shovel_Sprite.png?version=e73d1ce0115c2c70eaca15b014bd6f05",
|
||||
"Flute": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/db/Flute.png?version=ec4982b31c56da2c0c010905c5c60390",
|
||||
"Bug Catching Net": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/5/54/Bug-CatchingNet.png?version=4d40e0ee015b687ff75b333b968d8be6",
|
||||
"Book of Mudora": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/2/22/ALttP_Book_of_Mudora_Sprite.png?version=11e4632bba54f6b9bf921df06ac93744",
|
||||
"Bottle": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/ef/ALttP_Magic_Bottle_Sprite.png?version=fd98ab04db775270cbe79fce0235777b",
|
||||
"Cane of Somaria": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/e1/ALttP_Cane_of_Somaria_Sprite.png?version=8cc1900dfd887890badffc903bb87943",
|
||||
"Cane of Byrna": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/b/bc/ALttP_Cane_of_Byrna_Sprite.png?version=758b607c8cbe2cf1900d42a0b3d0fb54",
|
||||
"Cape": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/1/1c/ALttP_Magic_Cape_Sprite.png?version=6b77f0d609aab0c751307fc124736832",
|
||||
"Magic Mirror": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/e5/ALttP_Magic_Mirror_Sprite.png?version=e035dbc9cbe2a3bd44aa6d047762b0cc",
|
||||
"Triforce": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/4/4e/TriforceALttPTitle.png?version=dc398e1293177581c16303e4f9d12a48",
|
||||
"Small Key": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/f/f1/ALttP_Small_Key_Sprite.png?version=4f35d92842f0de39d969181eea03774e",
|
||||
"Big Key": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/3/33/ALttP_Big_Key_Sprite.png?version=136dfa418ba76c8b4e270f466fc12f4d",
|
||||
"Chest": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/7/73/ALttP_Treasure_Chest_Sprite.png?version=5f530ecd98dcb22251e146e8049c0dda",
|
||||
"Light World": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/e7/ALttP_Soldier_Green_Sprite.png?version=d650d417934cd707a47e496489c268a6",
|
||||
"Dark World": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/9/94/ALttP_Moblin_Sprite.png?version=ebf50e33f4657c377d1606bcc0886ddc",
|
||||
"Hyrule Castle": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/d/d3/ALttP_Ball_and_Chain_Trooper_Sprite.png?version=1768a87c06d29cc8e7ddd80b9fa516be",
|
||||
"Agahnims Tower": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/1/1e/ALttP_Agahnim_Sprite.png?version=365956e61b0c2191eae4eddbe591dab5",
|
||||
"Desert Palace": r"https://www.zeldadungeon.net/wiki/images/2/25/Lanmola-ALTTP-Sprite.png",
|
||||
"Eastern Palace": r"https://www.zeldadungeon.net/wiki/images/d/dc/RedArmosKnight.png",
|
||||
"Tower of Hera": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/3/3c/ALttP_Moldorm_Sprite.png?version=c588257bdc2543468e008a6b30f262a7",
|
||||
"Palace of Darkness": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/e/ed/ALttP_Helmasaur_King_Sprite.png?version=ab8a4a1cfd91d4fc43466c56cba30022",
|
||||
"Swamp Palace": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/7/73/ALttP_Arrghus_Sprite.png?version=b098be3122e53f751b74f4a5ef9184b5",
|
||||
"Skull Woods": r"https://alttp-wiki.net/images/6/6a/Mothula.png",
|
||||
"Thieves Town": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/8/86/ALttP_Blind_the_Thief_Sprite.png?version=3833021bfcd112be54e7390679047222",
|
||||
"Ice Palace": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/3/33/ALttP_Kholdstare_Sprite.png?version=e5a1b0e8b2298e550d85f90bf97045c0",
|
||||
"Misery Mire": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/8/85/ALttP_Vitreous_Sprite.png?version=92b2e9cb0aa63f831760f08041d8d8d8",
|
||||
"Turtle Rock": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/9/91/ALttP_Trinexx_Sprite.png?version=0cc867d513952aa03edd155597a0c0be",
|
||||
"Ganons Tower": r"https://gamepedia.cursecdn.com/zelda_gamepedia_en/b/b9/ALttP_Ganon_Sprite.png?version=956f51f054954dfff53c1a9d4f929c74"
|
||||
}
|
||||
|
||||
tracker.regions = {
|
||||
'Light World': [
|
||||
'Lost Woods Hideout', 'Lumberjack Tree', 'Mushroom', 'Master Sword Pedestal', 'Bottle Merchant', 'Flute Spot',
|
||||
'Blind\'s Hideout - Top', 'Blind\'s Hideout - Left', 'Blind\'s Hideout - Right', 'Blind\'s Hideout - Far Left', 'Blind\'s Hideout - Far Right',
|
||||
'Link\'s House', 'Link\'s Uncle', 'Secret Passage',
|
||||
'King Zora', 'Zora\'s Ledge', 'Waterfall Fairy - Left', 'Waterfall Fairy - Right',
|
||||
'King\'s Tomb', 'Graveyard Cave', 'Bonk Rock Cave',
|
||||
'Sunken Treasure', 'Floodgate Chest', 'Hobo', 'Ice Rod Cave', 'Lake Hylia Island',
|
||||
'Kakariko Tavern', 'Chicken House', 'Sick Kid',
|
||||
'Blacksmith', 'Purple Chest', 'Magic Bat',
|
||||
'Aginah\'s Cave', 'Cave 45', 'Checkerboard Cave',
|
||||
'Sahasrahla\'s Hut - Left', 'Sahasrahla\'s Hut - Middle', 'Sahasrahla\'s Hut - Right', 'Sahasrahla',
|
||||
'Kakariko Well - Top', 'Kakariko Well - Left', 'Kakariko Well - Middle', 'Kakariko Well - Right', 'Kakariko Well - Bottom',
|
||||
'Mini Moldorm Cave - Far Left', 'Mini Moldorm Cave - Left', 'Mini Moldorm Cave - Right', 'Mini Moldorm Cave - Far Right', 'Mini Moldorm Cave - Generous Guy',
|
||||
'Library', 'Maze Race', 'Potion Shop', 'Desert Ledge',
|
||||
'Old Man', 'Spectacle Rock',
|
||||
'Paradox Cave Lower - Far Left', 'Paradox Cave Lower - Left', 'Paradox Cave Lower - Right', 'Paradox Cave Lower - Far Right', 'Paradox Cave Lower - Middle',
|
||||
'Paradox Cave Upper - Left', 'Paradox Cave Upper - Right',
|
||||
'Spiral Cave', 'Ether Tablet'
|
||||
],
|
||||
'Dark World': [
|
||||
'Pyramid', 'Catfish', 'Pyramid Fairy - Left', 'Pyramid Fairy - Right',
|
||||
'Stumpy', 'Digging Game',
|
||||
'Bombos Tablet',
|
||||
'Hype Cave - Top', 'Hype Cave - Middle Right', 'Hype Cave - Middle Left', 'Hype Cave - Bottom', 'Hype Cave - Generous Guy',
|
||||
'Peg Cave', 'Brewery', 'C-Shaped House', 'Chest Game',
|
||||
'Bumper Cave Ledge',
|
||||
'Mire Shed - Left', 'Mire Shed - Right',
|
||||
'Superbunny Cave - Top', 'Superbunny Cave - Bottom',
|
||||
'Spike Cave', 'Floating Island', 'Mimic Cave',
|
||||
'Hookshot Cave - Top Right', 'Hookshot Cave - Top Left', 'Hookshot Cave - Bottom Right', 'Hookshot Cave - Bottom Left',
|
||||
|
||||
],
|
||||
'Desert Palace': [
|
||||
'Desert Palace - Big Chest', 'Desert Palace - Torch', 'Desert Palace - Map Chest',
|
||||
'Desert Palace - Compass Chest', 'Desert Palace - Big Key Chest',
|
||||
'Desert Palace - Boss'
|
||||
],
|
||||
'Eastern Palace': [
|
||||
'Eastern Palace - Compass Chest', 'Eastern Palace - Big Chest', 'Eastern Palace - Cannonball Chest',
|
||||
'Eastern Palace - Big Key Chest', 'Eastern Palace - Map Chest', 'Eastern Palace - Boss'
|
||||
],
|
||||
'Hyrule Castle': [
|
||||
'Hyrule Castle - Map Chest', 'Hyrule Castle - Boomerang Chest', 'Hyrule Castle - Zelda\'s Chest',
|
||||
'Sewers - Dark Cross', 'Sewers - Secret Room - Left', 'Sewers - Secret Room - Middle', 'Sewers - Secret Room - Right',
|
||||
'Sanctuary'
|
||||
],
|
||||
'Agahnims Tower': [
|
||||
'Castle Tower - Room 03', 'Castle Tower - Dark Maze'
|
||||
],
|
||||
'Tower of Hera': [
|
||||
'Tower of Hera - Basement Cage', 'Tower of Hera - Map Chest', 'Tower of Hera - Big Key Chest',
|
||||
'Tower of Hera - Compass Chest', 'Tower of Hera - Big Chest', 'Tower of Hera - Boss'
|
||||
],
|
||||
'Swamp Palace': [
|
||||
'Swamp Palace - Entrance', 'Swamp Palace - Map Chest',
|
||||
'Swamp Palace - Big Chest', 'Swamp Palace - Compass Chest',
|
||||
'Swamp Palace - Big Key Chest', 'Swamp Palace - West Chest',
|
||||
'Swamp Palace - Flooded Room - Left', 'Swamp Palace - Flooded Room - Right',
|
||||
'Swamp Palace - Waterfall Room', 'Swamp Palace - Boss'
|
||||
],
|
||||
'Thieves Town': [
|
||||
'Thieves\' Town - Big Key Chest', 'Thieves\' Town - Map Chest', 'Thieves\' Town - Compass Chest', 'Thieves\' Town - Ambush Chest',
|
||||
'Thieves\' Town - Attic', 'Thieves\' Town - Big Chest', 'Thieves\' Town - Blind\'s Cell', 'Thieves\' Town - Boss'
|
||||
],
|
||||
'Skull Woods': [
|
||||
'Skull Woods - Map Chest', 'Skull Woods - Pinball Room',
|
||||
'Skull Woods - Compass Chest', 'Skull Woods - Pot Prison',
|
||||
'Skull Woods - Big Chest',
|
||||
'Skull Woods - Big Key Chest',
|
||||
'Skull Woods - Bridge Room', 'Skull Woods - Boss'
|
||||
],
|
||||
'Ice Palace': [
|
||||
'Ice Palace - Compass Chest', 'Ice Palace - Freezor Chest', 'Ice Palace - Big Chest', 'Ice Palace - Iced T Room',
|
||||
'Ice Palace - Spike Room', 'Ice Palace - Big Key Chest', 'Ice Palace - Map Chest', 'Ice Palace - Boss'
|
||||
],
|
||||
'Misery Mire': [
|
||||
'Misery Mire - Big Chest', 'Misery Mire - Map Chest', 'Misery Mire - Main Lobby', 'Misery Mire - Bridge Chest', 'Misery Mire - Spike Chest',
|
||||
'Misery Mire - Compass Chest', 'Misery Mire - Big Key Chest', 'Misery Mire - Boss'
|
||||
],
|
||||
'Turtle Rock': [
|
||||
'Turtle Rock - Compass Chest', 'Turtle Rock - Roller Room - Left', 'Turtle Rock - Roller Room - Right',
|
||||
'Turtle Rock - Chain Chomps', 'Turtle Rock - Big Key Chest', 'Turtle Rock - Big Chest',
|
||||
'Turtle Rock - Crystaroller Room',
|
||||
'Turtle Rock - Eye Bridge - Bottom Left', 'Turtle Rock - Eye Bridge - Bottom Right', 'Turtle Rock - Eye Bridge - Top Left', 'Turtle Rock - Eye Bridge - Top Right',
|
||||
'Turtle Rock - Boss'
|
||||
],
|
||||
'Palace of Darkness': [
|
||||
'Palace of Darkness - Shooter Room', 'Palace of Darkness - The Arena - Bridge', 'Palace of Darkness - Stalfos Basement',
|
||||
'Palace of Darkness - Big Key Chest',
|
||||
'Palace of Darkness - The Arena - Ledge', 'Palace of Darkness - Map Chest',
|
||||
'Palace of Darkness - Compass Chest', 'Palace of Darkness - Dark Basement - Left', 'Palace of Darkness - Dark Basement - Right',
|
||||
'Palace of Darkness - Dark Maze - Top', 'Palace of Darkness - Dark Maze - Bottom', 'Palace of Darkness - Big Chest',
|
||||
'Palace of Darkness - Harmless Hellway', 'Palace of Darkness - Boss'
|
||||
],
|
||||
'Ganons Tower': [
|
||||
'Ganons Tower - Bob\'s Torch', 'Ganons Tower - Hope Room - Left', 'Ganons Tower - Hope Room - Right',
|
||||
'Ganons Tower - Tile Room',
|
||||
'Ganons Tower - Compass Room - Top Left', 'Ganons Tower - Compass Room - Top Right', 'Ganons Tower - Compass Room - Bottom Left', 'Ganons Tower - Compass Room - Bottom Right',
|
||||
'Ganons Tower - DMs Room - Top Left', 'Ganons Tower - DMs Room - Top Right', 'Ganons Tower - DMs Room - Bottom Left', 'Ganons Tower - DMs Room - Bottom Right',
|
||||
'Ganons Tower - Map Chest', 'Ganons Tower - Firesnake Room',
|
||||
'Ganons Tower - Randomizer Room - Top Left', 'Ganons Tower - Randomizer Room - Top Right', 'Ganons Tower - Randomizer Room - Bottom Left', 'Ganons Tower - Randomizer Room - Bottom Right',
|
||||
'Ganons Tower - Bob\'s Chest',
|
||||
'Ganons Tower - Big Chest', 'Ganons Tower - Big Key Room - Left', 'Ganons Tower - Big Key Room - Right', 'Ganons Tower - Big Key Chest',
|
||||
]
|
||||
}
|
||||
|
||||
tracker.progressive_items = [
|
||||
'Progressive Sword',
|
||||
'Progressive Shield',
|
||||
'Progressive Mail',
|
||||
'Progressive Bow',
|
||||
'Progressive Boomerang',
|
||||
'Hookshot',
|
||||
'Magic Powder',
|
||||
'Mushroom',
|
||||
'Bottle',
|
||||
'Lamp',
|
||||
'Progressive Glove',
|
||||
'Flippers',
|
||||
'Moon Pearl',
|
||||
'Bombos',
|
||||
'Ether',
|
||||
'Quake',
|
||||
'Fire Rod',
|
||||
'Ice Rod',
|
||||
'Hammer',
|
||||
'Book of Mudora',
|
||||
'Shovel',
|
||||
'Flute',
|
||||
'Bug Catching Net',
|
||||
'Cane of Somaria',
|
||||
'Cane of Byrna',
|
||||
'Cape',
|
||||
'Magic Mirror',
|
||||
'Small Key',
|
||||
'Big Key'
|
||||
]
|
||||
|
||||
tracker.progressive_names = {
|
||||
'Progressive Bow': ['Bow', 'Silver Arrows', 'Silver Bow', 'Progressive Bow (Alt)'],
|
||||
'Bottle': ['Bottle (Red Potion)', 'Bottle (Green Potion)', 'Bottle (Blue Potion)', 'Bottle (Fairy)', 'Bottle (Bee)', 'Bottle (Good Bee)'],
|
||||
'Progressive Sword': ['Fighter Sword', 'Master Sword', 'Tempered Sword', 'Golden Sword'],
|
||||
'Progressive Glove': ['Power Glove', 'Titans Mitts'],
|
||||
'Progressive Shield': ['Blue Shield', 'Red Shield', 'Mirror Shield'],
|
||||
'Progressive Boomerang': ['Red Boomerang', 'Blue Boomerang'],
|
||||
'Progressive Mail': ['Green Mail', 'Blue Mail', 'Red Mail'],
|
||||
'Small Key': [f'Small Key ({region})' for region in tracker.regions.keys() if region not in {'Light World', 'Dark World'}],
|
||||
'Big Key': [f'Big Key ({region})' for region in tracker.regions.keys() if region not in {'Light World', 'Dark World'}],
|
||||
}
|
||||
|
||||
tracker.region_keys = {
|
||||
region: [f'Small Key ({region})', f'Big Key ({region})'] for region in tracker.regions.keys() if region not in {'Light World', 'Dark World'}
|
||||
}
|
||||
|
||||
|
||||
class ALTTPWorld(World):
|
||||
"""
|
||||
|
||||
@@ -49,6 +49,79 @@ class MinecraftWebWorld(WebWorld):
|
||||
|
||||
tutorials = [setup, setup_es, setup_sv]
|
||||
|
||||
def modify_tracker(self, tracker):
|
||||
tracker.icons = {
|
||||
"Wooden Pickaxe": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/d/d2/Wooden_Pickaxe_JE3_BE3.png",
|
||||
"Stone Pickaxe": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/c/c4/Stone_Pickaxe_JE2_BE2.png",
|
||||
"Iron Pickaxe": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/d/d1/Iron_Pickaxe_JE3_BE2.png",
|
||||
"Diamond Pickaxe": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/e/e7/Diamond_Pickaxe_JE3_BE3.png",
|
||||
"Wooden Sword": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/d/d5/Wooden_Sword_JE2_BE2.png",
|
||||
"Stone Sword": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/b/b1/Stone_Sword_JE2_BE2.png",
|
||||
"Iron Sword": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/8/8e/Iron_Sword_JE2_BE2.png",
|
||||
"Diamond Sword": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/4/44/Diamond_Sword_JE3_BE3.png",
|
||||
"Leather Tunic": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/b/b7/Leather_Tunic_JE4_BE2.png",
|
||||
"Iron Chestplate": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/3/31/Iron_Chestplate_JE2_BE2.png",
|
||||
"Diamond Chestplate": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/e/e0/Diamond_Chestplate_JE3_BE2.png",
|
||||
"Iron Ingot": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/f/fc/Iron_Ingot_JE3_BE2.png",
|
||||
"Block of Iron": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/7/7e/Block_of_Iron_JE4_BE3.png",
|
||||
"Brewing": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/b/b3/Brewing_Stand_%28empty%29_JE10.png",
|
||||
"Ender Pearls": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/f/f6/Ender_Pearl_JE3_BE2.png",
|
||||
"Bucket": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/f/fc/Bucket_JE2_BE2.png",
|
||||
"Archery": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/a/ab/Bow_%28Pull_2%29_JE1_BE1.png",
|
||||
"Shield": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/c/c6/Shield_JE2_BE1.png",
|
||||
"Bed": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/6/6a/Red_Bed_%28N%29.png",
|
||||
"Netherite Scrap": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/3/33/Netherite_Scrap_JE2_BE1.png",
|
||||
"Flint and Steel": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/9/94/Flint_and_Steel_JE4_BE2.png",
|
||||
"Enchanting": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/3/31/Enchanting_Table.gif",
|
||||
"Fishing Rod": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/7/7f/Fishing_Rod_JE2_BE2.png",
|
||||
"Campfire": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/9/91/Campfire_JE2_BE2.gif",
|
||||
"Bottle": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/7/75/Water_Bottle_JE2_BE2.png",
|
||||
"Spyglass": "https://static.wikia.nocookie.net/minecraft_gamepedia/images/c/c1/Spyglass_JE2_BE1.png",
|
||||
}
|
||||
|
||||
tracker.progressive_items = [
|
||||
"Progressive Tools", "Progressive Weapons", "Progressive Armor", "Progressive Resource Crafting",
|
||||
"Brewing", "Ender Pearls", "Bucket", "Archery", "Shield", "Bed", "Bottle", "Netherite Scrap",
|
||||
"Flint and Steel", "Enchanting", "Fishing Rod", "Campfire", "Spyglass"
|
||||
]
|
||||
|
||||
tracker.progressive_names = {
|
||||
"Progressive Tools": ["Wooden Pickaxe", "Stone Pickaxe", "Iron Pickaxe", "Diamond Pickaxe"],
|
||||
"Progressive Weapons": ["Wooden Sword", "Stone Sword", "Iron Sword", "Diamond Sword"],
|
||||
"Progressive Armor": ["Leather Tunic", "Iron Chestplate", "Diamond Chestplate"],
|
||||
"Progressive Resource Crafting": ["Iron Ingot", "Iron Ingot", "Block of Iron"]
|
||||
}
|
||||
|
||||
tracker.regions = {
|
||||
"Story": ["Minecraft", "Stone Age", "Getting an Upgrade", "Acquire Hardware", "Suit Up",
|
||||
"Not Today, Thank You", "Isn't It Iron Pick", "Diamonds!", "Cover Me With Diamonds", "Enchanter",
|
||||
"Hot Stuff", "Ice Bucket Challenge", "We Need to Go Deeper", "Zombie Doctor", "Eye Spy", "The End?"],
|
||||
|
||||
"Nether": ["Nether", "Return to Sender", "Uneasy Alliance", "Those Were the Days", "War Pigs",
|
||||
"Hidden in the Depths", "Country Lode, Take Me Home", "Cover Me in Debris", "Subspace Bubble",
|
||||
"A Terrible Fortress", "Spooky Scary SKeleton", "This Boat Has Legs", "Hot Tourist Destinations"],
|
||||
|
||||
"The End": ["The End", "Free the End", "The Next Generation", "Remote Getaway",
|
||||
"The City at the End of the Game", "Sky's the Limit", "Great View From Up Here",
|
||||
"The End... Again...", "You Need a Mint"],
|
||||
|
||||
"Adventure": ["Adventure", "Voluntary Exile", "Is It a Bird?", "Is It a Balloon?", "Is It a Plane?",
|
||||
"Hero of the Village", "Monster Hunter", "A Throwaway Joke", "Very Very Frightening",
|
||||
"Take Aim", "Sniper Duel", "Bullseye", "Monsters Hunted", "Postmortal", "What a Deal!",
|
||||
"Hired Help", "Sticky Situation", "Ol' Betsy", "Two Birds, One Arrow",
|
||||
"Who's the Pillager Now?", "Arbalistic", "Sweet Dreams", "Adventuring Time", "Surge Protector",
|
||||
"Light as a Rabbit"],
|
||||
|
||||
"Husbandry": ["Husbandry", "Bee Our Guest", "The Parrots and the Bats", "Two by Two", "Best Friends Forever",
|
||||
"A Complete Catalogue", "Fishy Business", "Tactical Fishing", "Total Beelocation",
|
||||
"A Seedy Place", "A Balanced Diet", "Serious Dedication", "Whatever Floats Your Goat!",
|
||||
"Glow and Behold!", "Wax On", "Wax Off", "The Cutest Predator",
|
||||
"The Healing Power of Friendship"],
|
||||
|
||||
"Archipelago": ["Getting Wood", "Time to Mine!", "Hot Topic", "Bake Bread", "The Lie", "On a Rail",
|
||||
"Time to Strike!", "Cow Tipper", "When Pigs Fly", "Overkill", "Librarian", "Overpowered"]
|
||||
}
|
||||
|
||||
|
||||
class MinecraftWorld(World):
|
||||
"""
|
||||
|
||||
@@ -9,7 +9,7 @@ from .Location import OOTLocation, LocationFactory, location_name_to_id
|
||||
from .Entrance import OOTEntrance
|
||||
from .EntranceShuffle import shuffle_random_entrances, entrance_shuffle_table, EntranceShuffleError
|
||||
from .Items import OOTItem, item_table, oot_data_to_ap_id, oot_is_item_of_type
|
||||
from .ItemPool import generate_itempool, add_dungeon_items, get_junk_item, get_junk_pool
|
||||
from .ItemPool import generate_itempool, add_dungeon_items, get_junk_item, get_junk_pool, normal_bottles
|
||||
from .Regions import OOTRegion, TimeOfDay
|
||||
from .Rules import set_rules, set_shop_rules, set_entrances_based_rules
|
||||
from .RuleParser import Rule_AST_Transformer
|
||||
@@ -87,6 +87,133 @@ class OOTWeb(WebWorld):
|
||||
|
||||
tutorials = [setup, setup_es]
|
||||
|
||||
def modify_tracker(self, tracker):
|
||||
tracker.template = 'zeldaKeysTracker.html'
|
||||
tracker.icons = {
|
||||
"Fairy Ocarina": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/9/97/OoT_Fairy_Ocarina_Icon.png",
|
||||
"Ocarina of Time": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/4/4e/OoT_Ocarina_of_Time_Icon.png",
|
||||
"Slingshot": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/3/32/OoT_Fairy_Slingshot_Icon.png",
|
||||
"Boomerang": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/d/d5/OoT_Boomerang_Icon.png",
|
||||
"Bottle": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/f/fc/OoT_Bottle_Icon.png",
|
||||
"Rutos Letter": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/21/OoT_Letter_Icon.png",
|
||||
"Bombs": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/1/11/OoT_Bomb_Icon.png",
|
||||
"Bombchus": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/3/36/OoT_Bombchu_Icon.png",
|
||||
"Lens of Truth": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/0/05/OoT_Lens_of_Truth_Icon.png",
|
||||
"Bow": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/9/9a/OoT_Fairy_Bow_Icon.png",
|
||||
"Hookshot": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/7/77/OoT_Hookshot_Icon.png",
|
||||
"Longshot": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/a/a4/OoT_Longshot_Icon.png",
|
||||
"Megaton Hammer": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/9/93/OoT_Megaton_Hammer_Icon.png",
|
||||
"Fire Arrows": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/1/1e/OoT_Fire_Arrow_Icon.png",
|
||||
"Ice Arrows": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/3/3c/OoT_Ice_Arrow_Icon.png",
|
||||
"Light Arrows": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/7/76/OoT_Light_Arrow_Icon.png",
|
||||
"Din's Fire": r"https://static.wikia.nocookie.net/zelda_gamepedia_en/images/d/da/OoT_Din%27s_Fire_Icon.png",
|
||||
"Farore's Wind": r"https://static.wikia.nocookie.net/zelda_gamepedia_en/images/7/7a/OoT_Farore%27s_Wind_Icon.png",
|
||||
"Nayru's Love": r"https://static.wikia.nocookie.net/zelda_gamepedia_en/images/b/be/OoT_Nayru%27s_Love_Icon.png",
|
||||
"Kokiri Sword": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/5/53/OoT_Kokiri_Sword_Icon.png",
|
||||
"Biggoron Sword": r"https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/2e/OoT_Giant%27s_Knife_Icon.png",
|
||||
"Mirror Shield": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/b/b0/OoT_Mirror_Shield_Icon_2.png",
|
||||
"Goron Bracelet": r"https://static.wikia.nocookie.net/zelda_gamepedia_en/images/b/b7/OoT_Goron%27s_Bracelet_Icon.png",
|
||||
"Silver Gauntlets": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/b/b9/OoT_Silver_Gauntlets_Icon.png",
|
||||
"Golden Gauntlets": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/6/6a/OoT_Golden_Gauntlets_Icon.png",
|
||||
"Goron Tunic": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/1/1c/OoT_Goron_Tunic_Icon.png",
|
||||
"Zora Tunic": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/2c/OoT_Zora_Tunic_Icon.png",
|
||||
"Silver Scale": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/4/4e/OoT_Silver_Scale_Icon.png",
|
||||
"Gold Scale": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/9/95/OoT_Golden_Scale_Icon.png",
|
||||
"Iron Boots": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/3/34/OoT_Iron_Boots_Icon.png",
|
||||
"Hover Boots": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/22/OoT_Hover_Boots_Icon.png",
|
||||
"Adults Wallet": r"https://static.wikia.nocookie.net/zelda_gamepedia_en/images/f/f9/OoT_Adult%27s_Wallet_Icon.png",
|
||||
"Giants Wallet": r"https://static.wikia.nocookie.net/zelda_gamepedia_en/images/8/87/OoT_Giant%27s_Wallet_Icon.png",
|
||||
"Small Magic": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/9/9f/OoT3D_Magic_Jar_Icon.png",
|
||||
"Large Magic": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/3/3e/OoT3D_Large_Magic_Jar_Icon.png",
|
||||
"Gerudo Membership Card": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/4/4e/OoT_Gerudo_Token_Icon.png",
|
||||
"Gold Skulltula Tokens": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/4/47/OoT_Token_Icon.png",
|
||||
"Triforce Pieces": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/0/0b/SS_Triforce_Piece_Icon.png",
|
||||
"Triforce": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/6/68/ALttP_Triforce_Title_Sprite.png",
|
||||
"Zelda's Lullaby": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/21/Grey_Note.png",
|
||||
"Epona's Song": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/21/Grey_Note.png",
|
||||
"Saria's Song": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/21/Grey_Note.png",
|
||||
"Sun's Song": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/21/Grey_Note.png",
|
||||
"Song of Time": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/21/Grey_Note.png",
|
||||
"Song of Storms": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/2/21/Grey_Note.png",
|
||||
"Minuet of Forest": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/e/e4/Green_Note.png",
|
||||
"Bolero of Fire": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/f/f0/Red_Note.png",
|
||||
"Serenade of Water": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/0/0f/Blue_Note.png",
|
||||
"Requiem of Spirit": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/a/a4/Orange_Note.png",
|
||||
"Nocturne of Shadow": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/9/97/Purple_Note.png",
|
||||
"Prelude of Light": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/9/90/Yellow_Note.png",
|
||||
"Small Key": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/e/e5/OoT_Small_Key_Icon.png",
|
||||
"Big Key": "https://static.wikia.nocookie.net/zelda_gamepedia_en/images/4/40/OoT_Boss_Key_Icon.png",
|
||||
}
|
||||
|
||||
tracker.progressive_items = [
|
||||
"Ocarina", "Bombs", "Bow", "Fire Arrows", "Kokiri Sword", "Biggoron Sword", "Mirror Shield",
|
||||
"Slingshot", "Bombchus", "Progressive Hookshot", "Ice Arrows", "Progressive Strength", "Goron Tunic", "Zora Tunic",
|
||||
"Boomerang", "Lens of Truth", "Megaton Hammer", "Light Arrows", "Progressive Scale", "Iron Boots", "Hover Boots",
|
||||
"Bottles", "Din's Fire", "Farore's Wind", "Nayru's Love", "Progressive Wallet", "Magic Meter", "Gerudo Membership Card",
|
||||
"Zelda's Lullaby", "Epona's Song", "Saria's Song", "Sun's Song", "Song of Time", "Song of Storms", "Gold Skulltula Tokens",
|
||||
"Minuet of Forest", "Bolero of Fire", "Serenade of Water", "Requiem of Spirit", "Nocturne of Shadow", "Prelude of Light", "Triforce Pieces",
|
||||
"Small Key", "Big Key"
|
||||
]
|
||||
|
||||
tracker.progressive_names = {
|
||||
"Progressive Hookshot": ["Hookshot", "Longshot"],
|
||||
"Progressive Strength": ["Goron Bracelet", "Golden Gauntlets"],
|
||||
"Progressive Wallet": ["Adults Wallet", "Giants Wallet"],
|
||||
"Progressive Scale": ["Silver Scale", "Gold Scale"],
|
||||
"Magic Meter": ["Small Magic", "Large Magic"],
|
||||
"Ocarina": ["Fairy Ocarina", "Ocarina of Time"],
|
||||
"Bottles": normal_bottles + ["Rutos Letter"]
|
||||
}
|
||||
|
||||
location_id_to_name = {}
|
||||
for name, id in location_name_to_id.items():
|
||||
location_id_to_name[id] = name
|
||||
tracker.regions = {}
|
||||
for id in location_id_to_name.keys():
|
||||
if id in location_name_to_id.values() and location_id_to_name[id] in tracker.all_locations:
|
||||
if id < 67259:
|
||||
tracker.regions.setdefault("Overworld", []).append(location_id_to_name[id])
|
||||
elif id < 67264:
|
||||
tracker.regions.setdefault("Thieves' Hideout", []).append(location_id_to_name[id])
|
||||
elif id < 67281:
|
||||
tracker.regions.setdefault("Overworld", []).append(location_id_to_name[id])
|
||||
elif id < 67304:
|
||||
tracker.regions.setdefault("Deku Tree", []).append(location_id_to_name[id])
|
||||
elif id < 67335:
|
||||
tracker.regions.setdefault("Dodongo's Cavern", []).append(location_id_to_name[id])
|
||||
elif id < 67360:
|
||||
tracker.regions.setdefault("Jabu Jabu's Belly", []).append(location_id_to_name[id])
|
||||
elif id < 67385:
|
||||
tracker.regions.setdefault("Bottom of the Well", []).append(location_id_to_name[id])
|
||||
elif id < 67421:
|
||||
tracker.regions.setdefault("Forest Temple", []).append(location_id_to_name[id])
|
||||
elif id < 67458:
|
||||
tracker.regions.setdefault("Fire Temple", []).append(location_id_to_name[id])
|
||||
elif id < 67485:
|
||||
tracker.regions.setdefault("Water Temple", []).append(location_id_to_name[id])
|
||||
elif id < 67533:
|
||||
tracker.regions.setdefault("Shadow Temple", []).append(location_id_to_name[id])
|
||||
elif id < 67583:
|
||||
tracker.regions.setdefault("Spirit Temple", []).append(location_id_to_name[id])
|
||||
elif id < 67597:
|
||||
tracker.regions.setdefault("Ice Cavern", []).append(location_id_to_name[id])
|
||||
elif id < 67636:
|
||||
tracker.regions.setdefault("Gerudo Training Ground", []).append(location_id_to_name[id])
|
||||
elif id < 67674:
|
||||
tracker.regions.setdefault("Ganon's Castle", []).append(location_id_to_name[id])
|
||||
|
||||
tracker.region_keys = {
|
||||
'Forest Temple': ['Small Key (Forest Temple)', 'Boss Key (Forest Temple)'],
|
||||
'Fire Temple': ['Small Key (Fire Temple)', 'Boss Key (Forest Temple)'],
|
||||
'Water Temple': ['Small Key (Water Temple)', 'Boss Key (Water Temple)'],
|
||||
'Spirit Temple': ['Small Key (Spirit Temple)', 'Boss Key (Spirit Temple)'],
|
||||
'Shadow Temple': ['Small Key (Shadow Temple)', 'Boss Key (Shadow Temple)'],
|
||||
'Bottom of the Well': ['Small Key (Bottom of the Well)', 'Boss Key (Bottom of the Well)'],
|
||||
'Gerudo Training Ground': ['Small Key (Gerudo Training Ground)', 'Boss Key (Gerudo Training Ground)'],
|
||||
'Thieves Hideout': ['Small Key (Thieves Hideout)', 'Boss Key (Thieves Hideout)'],
|
||||
'Ganons Castle': ['Small Key (Ganons Castle)', 'Boss Key (Ganons Castle)']
|
||||
}
|
||||
|
||||
|
||||
class OOTWorld(World):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user