mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-30 04:53:20 -07:00
a
This commit is contained in:
@@ -139,13 +139,7 @@ def create():
|
||||
weighted_options["games"][game_name] = {}
|
||||
weighted_options["games"][game_name]["gameSettings"] = game_options
|
||||
weighted_options["games"][game_name]["gameItems"] = tuple(world.item_names)
|
||||
weighted_options["games"][game_name]["gameItemGroups"] = [
|
||||
group for group in world.item_name_groups.keys() if group != "Everything"
|
||||
]
|
||||
weighted_options["games"][game_name]["gameLocations"] = tuple(world.location_names)
|
||||
weighted_options["games"][game_name]["gameLocationGroups"] = [
|
||||
group for group in world.location_name_groups.keys() if group != "Everywhere"
|
||||
]
|
||||
|
||||
with open(os.path.join(target_folder, 'weighted-options.json'), "w") as f:
|
||||
json.dump(weighted_options, f, indent=2, separators=(',', ': '))
|
||||
|
||||
@@ -2,62 +2,13 @@
|
||||
|
||||
## What is a randomizer?
|
||||
|
||||
A randomizer is a modification of a game which reorganizes the items required to progress through that game. A
|
||||
normal play-through might require you to use item A to unlock item B, then C, and so forth. In a randomized
|
||||
A randomizer is a modification of a video game which reorganizes the items required to progress through the game. A
|
||||
normal play-through of a game might require you to use item A to unlock item B, then C, and so forth. In a randomized
|
||||
game, you might first find item C, then A, then B.
|
||||
|
||||
This transforms the game from a linear experience into a puzzle, presenting players with a new challenge each time they
|
||||
play. Putting items in non-standard locations can require the player to think about the game world and the items they
|
||||
encounter in new and interesting ways.
|
||||
|
||||
## What is a multiworld?
|
||||
|
||||
While a randomizer shuffles a game, a multiworld randomizer shuffles that game for multiple players. For example, in a
|
||||
two player multiworld, players A and B each get their own randomized version of a game, called a world. In each
|
||||
player's game, they may find items which belong to the other player. If player A finds an item which belongs to
|
||||
player B, the item will be sent to player B's world over the internet. This creates a cooperative experience, requiring
|
||||
players to rely upon each other to complete their game.
|
||||
|
||||
## What does multi-game mean?
|
||||
|
||||
While a multiworld game traditionally requires all players to be playing the same game, a multi-game multiworld allows
|
||||
players to randomize any of the supported games, and send items between them. This allows players of different
|
||||
games to interact with one another in a single multiplayer environment. Archipelago supports multi-game multiworld.
|
||||
Here is a list of our [Supported Games](https://archipelago.gg/games).
|
||||
|
||||
## Can I generate a single-player game with Archipelago?
|
||||
|
||||
Yes. All of our supported games can be generated as single-player experiences both on the website and by installing
|
||||
the Archipelago generator software. The fastest way to do this is on the website. Find the Supported Game you wish to
|
||||
play, open the Settings Page, pick your settings, and click Generate Game.
|
||||
|
||||
## How do I get started?
|
||||
|
||||
We have a [Getting Started](https://archipelago.gg/tutorial/Archipelago/setup/en) guide that will help you get the
|
||||
software set up. You can use that guide to learn how to generate multiworlds. There are also basic instructions for
|
||||
including multiple games, and hosting multiworlds on the website for ease and convenience.
|
||||
|
||||
If you are ready to start randomizing games, or want to start playing your favorite randomizer with others, please join
|
||||
our discord server at the [Archipelago Discord](https://discord.gg/8Z65BR2). There are always people ready to answer
|
||||
any questions you might have.
|
||||
|
||||
## What are some common terms I should know?
|
||||
|
||||
As randomizers and multiworld randomizers have been around for a while now, there are quite a few common terms used
|
||||
by the communities surrounding them. A list of Archipelago jargon and terms commonly used by the community can be
|
||||
found in the [Glossary](/glossary/en).
|
||||
|
||||
## Does everyone need to be connected at the same time?
|
||||
|
||||
There are two different play-styles that are common for Archipelago multiworld sessions. These sessions can either
|
||||
be considered synchronous (or "sync"), where everyone connects and plays at the same time, or asynchronous (or "async"),
|
||||
where players connect and play at their own pace. The setup for both is identical. The difference in play-style is how
|
||||
you and your friends choose to organize and play your multiworld. Most groups decide on the format before creating
|
||||
their multiworld.
|
||||
|
||||
If a player must leave early, they can use Archipelago's release system. When a player releases their game, all items
|
||||
in that game belonging to other players are sent out automatically. This allows other players to continue to play
|
||||
uninterrupted. Here is a list of all of our [Server Commands](https://archipelago.gg/tutorial/Archipelago/commands/en).
|
||||
This transforms games from a linear experience into a puzzle, presenting players with a new challenge each time they
|
||||
play a randomized game. Putting items in non-standard locations can require the player to think about the game world and
|
||||
the items they encounter in new and interesting ways.
|
||||
|
||||
## What happens if an item is placed somewhere it is impossible to get?
|
||||
|
||||
@@ -66,15 +17,53 @@ is to ensure items necessary to complete the game will be accessible to the play
|
||||
rules allowing certain items to be placed in normally unreachable locations, provided the player has indicated they are
|
||||
comfortable exploiting certain glitches in the game.
|
||||
|
||||
## What is a multi-world?
|
||||
|
||||
While a randomizer shuffles a game, a multi-world randomizer shuffles that game for multiple players. For example, in a
|
||||
two player multi-world, players A and B each get their own randomized version of a game, called a world. In each player's
|
||||
game, they may find items which belong to the other player. If player A finds an item which belongs to player B, the
|
||||
item will be sent to player B's world over the internet.
|
||||
|
||||
This creates a cooperative experience during multi-world games, requiring players to rely upon each other to complete
|
||||
their game.
|
||||
|
||||
## What happens if a person has to leave early?
|
||||
|
||||
If a player must leave early, they can use Archipelago's release system. When a player releases their game, all the
|
||||
items in that game which belong to other players are sent out automatically, so other players can continue to play.
|
||||
|
||||
## What does multi-game mean?
|
||||
|
||||
While a multi-world game traditionally requires all players to be playing the same game, a multi-game multi-world allows
|
||||
players to randomize any of a number of supported games, and send items between them. This allows players of different
|
||||
games to interact with one another in a single multiplayer environment.
|
||||
|
||||
## Can I generate a single-player game with Archipelago?
|
||||
|
||||
Yes. All our supported games can be generated as single-player experiences, and so long as you download the software,
|
||||
the website is not required to generate them.
|
||||
|
||||
## How do I get started?
|
||||
|
||||
If you are ready to start randomizing games, or want to start playing your favorite randomizer with others, please join
|
||||
our discord server at the [Archipelago Discord](https://discord.gg/8Z65BR2). There are always people ready to answer
|
||||
any questions you might have.
|
||||
|
||||
## What are some common terms I should know?
|
||||
|
||||
As randomizers and multiworld randomizers have been around for a while now there are quite a lot of common terms
|
||||
and jargon that is used in conjunction by the communities surrounding them. For a lot of the terms that are more common
|
||||
to Archipelago and its specific systems please see the [Glossary](/glossary/en).
|
||||
|
||||
## I want to add a game to the Archipelago randomizer. How do I do that?
|
||||
|
||||
The best way to get started is to take a look at our code on GitHub:
|
||||
[Archipelago GitHub Page](https://github.com/ArchipelagoMW/Archipelago).
|
||||
The best way to get started is to take a look at our code on GitHub
|
||||
at [Archipelago GitHub Page](https://github.com/ArchipelagoMW/Archipelago).
|
||||
|
||||
There, you will find examples of games in the `worlds` folder:
|
||||
[/worlds Folder in Archipelago Code](https://github.com/ArchipelagoMW/Archipelago/tree/main/worlds).
|
||||
There you will find examples of games in the worlds folder
|
||||
at [/worlds Folder in Archipelago Code](https://github.com/ArchipelagoMW/Archipelago/tree/main/worlds).
|
||||
|
||||
You may also find developer documentation in the `docs` folder:
|
||||
[/docs Folder in Archipelago Code](https://github.com/ArchipelagoMW/Archipelago/tree/main/docs).
|
||||
You may also find developer documentation in the docs folder
|
||||
at [/docs Folder in Archipelago Code](https://github.com/ArchipelagoMW/Archipelago/tree/main/docs).
|
||||
|
||||
If you have more questions, feel free to ask in the **#archipelago-dev** channel on our Discord.
|
||||
|
||||
@@ -43,7 +43,7 @@ const resetSettings = () => {
|
||||
};
|
||||
|
||||
const fetchSettingData = () => new Promise((resolve, reject) => {
|
||||
fetch(new Request(`${window.location.origin}/static/generated/weighted-options.json`)).then((response) => {
|
||||
fetch(new Request(`${window.location.origin}/static/generated/weighted-settings.json`)).then((response) => {
|
||||
try{ response.json().then((jsonObj) => resolve(jsonObj)); }
|
||||
catch(error){ reject(error); }
|
||||
});
|
||||
@@ -428,13 +428,13 @@ class GameSettings {
|
||||
const weightedSettingsDiv = this.#buildWeightedSettingsDiv();
|
||||
gameDiv.appendChild(weightedSettingsDiv);
|
||||
|
||||
const itemPoolDiv = this.#buildItemPoolDiv();
|
||||
const itemPoolDiv = this.#buildItemsDiv();
|
||||
gameDiv.appendChild(itemPoolDiv);
|
||||
|
||||
const hintsDiv = this.#buildHintsDiv();
|
||||
gameDiv.appendChild(hintsDiv);
|
||||
|
||||
const locationsDiv = this.#buildPriorityExclusionDiv();
|
||||
const locationsDiv = this.#buildLocationsDiv();
|
||||
gameDiv.appendChild(locationsDiv);
|
||||
|
||||
collapseButton.addEventListener('click', () => {
|
||||
@@ -734,17 +734,107 @@ class GameSettings {
|
||||
break;
|
||||
|
||||
case 'items-list':
|
||||
const itemsList = this.#buildItemsDiv(settingName);
|
||||
const itemsList = document.createElement('div');
|
||||
itemsList.classList.add('simple-list');
|
||||
|
||||
Object.values(this.data.gameItems).forEach((item) => {
|
||||
const itemRow = document.createElement('div');
|
||||
itemRow.classList.add('list-row');
|
||||
|
||||
const itemLabel = document.createElement('label');
|
||||
itemLabel.setAttribute('for', `${this.name}-${settingName}-${item}`)
|
||||
|
||||
const itemCheckbox = document.createElement('input');
|
||||
itemCheckbox.setAttribute('id', `${this.name}-${settingName}-${item}`);
|
||||
itemCheckbox.setAttribute('type', 'checkbox');
|
||||
itemCheckbox.setAttribute('data-game', this.name);
|
||||
itemCheckbox.setAttribute('data-setting', settingName);
|
||||
itemCheckbox.setAttribute('data-option', item.toString());
|
||||
itemCheckbox.addEventListener('change', (evt) => this.#updateListSetting(evt));
|
||||
if (this.current[settingName].includes(item)) {
|
||||
itemCheckbox.setAttribute('checked', '1');
|
||||
}
|
||||
|
||||
const itemName = document.createElement('span');
|
||||
itemName.innerText = item.toString();
|
||||
|
||||
itemLabel.appendChild(itemCheckbox);
|
||||
itemLabel.appendChild(itemName);
|
||||
|
||||
itemRow.appendChild(itemLabel);
|
||||
itemsList.appendChild((itemRow));
|
||||
});
|
||||
|
||||
settingWrapper.appendChild(itemsList);
|
||||
break;
|
||||
|
||||
case 'locations-list':
|
||||
const locationsList = this.#buildLocationsDiv(settingName);
|
||||
const locationsList = document.createElement('div');
|
||||
locationsList.classList.add('simple-list');
|
||||
|
||||
Object.values(this.data.gameLocations).forEach((location) => {
|
||||
const locationRow = document.createElement('div');
|
||||
locationRow.classList.add('list-row');
|
||||
|
||||
const locationLabel = document.createElement('label');
|
||||
locationLabel.setAttribute('for', `${this.name}-${settingName}-${location}`)
|
||||
|
||||
const locationCheckbox = document.createElement('input');
|
||||
locationCheckbox.setAttribute('id', `${this.name}-${settingName}-${location}`);
|
||||
locationCheckbox.setAttribute('type', 'checkbox');
|
||||
locationCheckbox.setAttribute('data-game', this.name);
|
||||
locationCheckbox.setAttribute('data-setting', settingName);
|
||||
locationCheckbox.setAttribute('data-option', location.toString());
|
||||
locationCheckbox.addEventListener('change', (evt) => this.#updateListSetting(evt));
|
||||
if (this.current[settingName].includes(location)) {
|
||||
locationCheckbox.setAttribute('checked', '1');
|
||||
}
|
||||
|
||||
const locationName = document.createElement('span');
|
||||
locationName.innerText = location.toString();
|
||||
|
||||
locationLabel.appendChild(locationCheckbox);
|
||||
locationLabel.appendChild(locationName);
|
||||
|
||||
locationRow.appendChild(locationLabel);
|
||||
locationsList.appendChild((locationRow));
|
||||
});
|
||||
|
||||
settingWrapper.appendChild(locationsList);
|
||||
break;
|
||||
|
||||
case 'custom-list':
|
||||
const customList = this.#buildListDiv(settingName, this.data.gameSettings[settingName].options);
|
||||
const customList = document.createElement('div');
|
||||
customList.classList.add('simple-list');
|
||||
|
||||
Object.values(this.data.gameSettings[settingName].options).forEach((listItem) => {
|
||||
const customListRow = document.createElement('div');
|
||||
customListRow.classList.add('list-row');
|
||||
|
||||
const customItemLabel = document.createElement('label');
|
||||
customItemLabel.setAttribute('for', `${this.name}-${settingName}-${listItem}`)
|
||||
|
||||
const customItemCheckbox = document.createElement('input');
|
||||
customItemCheckbox.setAttribute('id', `${this.name}-${settingName}-${listItem}`);
|
||||
customItemCheckbox.setAttribute('type', 'checkbox');
|
||||
customItemCheckbox.setAttribute('data-game', this.name);
|
||||
customItemCheckbox.setAttribute('data-setting', settingName);
|
||||
customItemCheckbox.setAttribute('data-option', listItem.toString());
|
||||
customItemCheckbox.addEventListener('change', (evt) => this.#updateListSetting(evt));
|
||||
if (this.current[settingName].includes(listItem)) {
|
||||
customItemCheckbox.setAttribute('checked', '1');
|
||||
}
|
||||
|
||||
const customItemName = document.createElement('span');
|
||||
customItemName.innerText = listItem.toString();
|
||||
|
||||
customItemLabel.appendChild(customItemCheckbox);
|
||||
customItemLabel.appendChild(customItemName);
|
||||
|
||||
customListRow.appendChild(customItemLabel);
|
||||
customList.appendChild((customListRow));
|
||||
});
|
||||
|
||||
settingWrapper.appendChild(customList);
|
||||
break;
|
||||
|
||||
@@ -759,7 +849,7 @@ class GameSettings {
|
||||
return settingsWrapper;
|
||||
}
|
||||
|
||||
#buildItemPoolDiv() {
|
||||
#buildItemsDiv() {
|
||||
const itemsDiv = document.createElement('div');
|
||||
itemsDiv.classList.add('items-div');
|
||||
|
||||
@@ -968,7 +1058,35 @@ class GameSettings {
|
||||
itemHintsWrapper.classList.add('hints-wrapper');
|
||||
itemHintsWrapper.innerText = 'Starting Item Hints';
|
||||
|
||||
const itemHintsDiv = this.#buildItemsDiv('start_hints');
|
||||
const itemHintsDiv = document.createElement('div');
|
||||
itemHintsDiv.classList.add('simple-list');
|
||||
this.data.gameItems.forEach((item) => {
|
||||
const itemRow = document.createElement('div');
|
||||
itemRow.classList.add('list-row');
|
||||
|
||||
const itemLabel = document.createElement('label');
|
||||
itemLabel.setAttribute('for', `${this.name}-start_hints-${item}`);
|
||||
|
||||
const itemCheckbox = document.createElement('input');
|
||||
itemCheckbox.setAttribute('type', 'checkbox');
|
||||
itemCheckbox.setAttribute('id', `${this.name}-start_hints-${item}`);
|
||||
itemCheckbox.setAttribute('data-game', this.name);
|
||||
itemCheckbox.setAttribute('data-setting', 'start_hints');
|
||||
itemCheckbox.setAttribute('data-option', item);
|
||||
if (this.current.start_hints.includes(item)) {
|
||||
itemCheckbox.setAttribute('checked', 'true');
|
||||
}
|
||||
itemCheckbox.addEventListener('change', (evt) => this.#updateListSetting(evt));
|
||||
itemLabel.appendChild(itemCheckbox);
|
||||
|
||||
const itemName = document.createElement('span');
|
||||
itemName.innerText = item;
|
||||
itemLabel.appendChild(itemName);
|
||||
|
||||
itemRow.appendChild(itemLabel);
|
||||
itemHintsDiv.appendChild(itemRow);
|
||||
});
|
||||
|
||||
itemHintsWrapper.appendChild(itemHintsDiv);
|
||||
itemHintsContainer.appendChild(itemHintsWrapper);
|
||||
|
||||
@@ -977,7 +1095,35 @@ class GameSettings {
|
||||
locationHintsWrapper.classList.add('hints-wrapper');
|
||||
locationHintsWrapper.innerText = 'Starting Location Hints';
|
||||
|
||||
const locationHintsDiv = this.#buildLocationsDiv('start_location_hints');
|
||||
const locationHintsDiv = document.createElement('div');
|
||||
locationHintsDiv.classList.add('simple-list');
|
||||
this.data.gameLocations.forEach((location) => {
|
||||
const locationRow = document.createElement('div');
|
||||
locationRow.classList.add('list-row');
|
||||
|
||||
const locationLabel = document.createElement('label');
|
||||
locationLabel.setAttribute('for', `${this.name}-start_location_hints-${location}`);
|
||||
|
||||
const locationCheckbox = document.createElement('input');
|
||||
locationCheckbox.setAttribute('type', 'checkbox');
|
||||
locationCheckbox.setAttribute('id', `${this.name}-start_location_hints-${location}`);
|
||||
locationCheckbox.setAttribute('data-game', this.name);
|
||||
locationCheckbox.setAttribute('data-setting', 'start_location_hints');
|
||||
locationCheckbox.setAttribute('data-option', location);
|
||||
if (this.current.start_location_hints.includes(location)) {
|
||||
locationCheckbox.setAttribute('checked', '1');
|
||||
}
|
||||
locationCheckbox.addEventListener('change', (evt) => this.#updateListSetting(evt));
|
||||
locationLabel.appendChild(locationCheckbox);
|
||||
|
||||
const locationName = document.createElement('span');
|
||||
locationName.innerText = location;
|
||||
locationLabel.appendChild(locationName);
|
||||
|
||||
locationRow.appendChild(locationLabel);
|
||||
locationHintsDiv.appendChild(locationRow);
|
||||
});
|
||||
|
||||
locationHintsWrapper.appendChild(locationHintsDiv);
|
||||
itemHintsContainer.appendChild(locationHintsWrapper);
|
||||
|
||||
@@ -985,7 +1131,7 @@ class GameSettings {
|
||||
return hintsDiv;
|
||||
}
|
||||
|
||||
#buildPriorityExclusionDiv() {
|
||||
#buildLocationsDiv() {
|
||||
const locationsDiv = document.createElement('div');
|
||||
locationsDiv.classList.add('locations-div');
|
||||
const locationsHeader = document.createElement('h3');
|
||||
@@ -1005,7 +1151,35 @@ class GameSettings {
|
||||
priorityLocationsWrapper.classList.add('locations-wrapper');
|
||||
priorityLocationsWrapper.innerText = 'Priority Locations';
|
||||
|
||||
const priorityLocationsDiv = this.#buildLocationsDiv('priority_locations');
|
||||
const priorityLocationsDiv = document.createElement('div');
|
||||
priorityLocationsDiv.classList.add('simple-list');
|
||||
this.data.gameLocations.forEach((location) => {
|
||||
const locationRow = document.createElement('div');
|
||||
locationRow.classList.add('list-row');
|
||||
|
||||
const locationLabel = document.createElement('label');
|
||||
locationLabel.setAttribute('for', `${this.name}-priority_locations-${location}`);
|
||||
|
||||
const locationCheckbox = document.createElement('input');
|
||||
locationCheckbox.setAttribute('type', 'checkbox');
|
||||
locationCheckbox.setAttribute('id', `${this.name}-priority_locations-${location}`);
|
||||
locationCheckbox.setAttribute('data-game', this.name);
|
||||
locationCheckbox.setAttribute('data-setting', 'priority_locations');
|
||||
locationCheckbox.setAttribute('data-option', location);
|
||||
if (this.current.priority_locations.includes(location)) {
|
||||
locationCheckbox.setAttribute('checked', '1');
|
||||
}
|
||||
locationCheckbox.addEventListener('change', (evt) => this.#updateListSetting(evt));
|
||||
locationLabel.appendChild(locationCheckbox);
|
||||
|
||||
const locationName = document.createElement('span');
|
||||
locationName.innerText = location;
|
||||
locationLabel.appendChild(locationName);
|
||||
|
||||
locationRow.appendChild(locationLabel);
|
||||
priorityLocationsDiv.appendChild(locationRow);
|
||||
});
|
||||
|
||||
priorityLocationsWrapper.appendChild(priorityLocationsDiv);
|
||||
locationsContainer.appendChild(priorityLocationsWrapper);
|
||||
|
||||
@@ -1014,7 +1188,35 @@ class GameSettings {
|
||||
excludeLocationsWrapper.classList.add('locations-wrapper');
|
||||
excludeLocationsWrapper.innerText = 'Exclude Locations';
|
||||
|
||||
const excludeLocationsDiv = this.#buildLocationsDiv('exclude_locations');
|
||||
const excludeLocationsDiv = document.createElement('div');
|
||||
excludeLocationsDiv.classList.add('simple-list');
|
||||
this.data.gameLocations.forEach((location) => {
|
||||
const locationRow = document.createElement('div');
|
||||
locationRow.classList.add('list-row');
|
||||
|
||||
const locationLabel = document.createElement('label');
|
||||
locationLabel.setAttribute('for', `${this.name}-exclude_locations-${location}`);
|
||||
|
||||
const locationCheckbox = document.createElement('input');
|
||||
locationCheckbox.setAttribute('type', 'checkbox');
|
||||
locationCheckbox.setAttribute('id', `${this.name}-exclude_locations-${location}`);
|
||||
locationCheckbox.setAttribute('data-game', this.name);
|
||||
locationCheckbox.setAttribute('data-setting', 'exclude_locations');
|
||||
locationCheckbox.setAttribute('data-option', location);
|
||||
if (this.current.exclude_locations.includes(location)) {
|
||||
locationCheckbox.setAttribute('checked', '1');
|
||||
}
|
||||
locationCheckbox.addEventListener('change', (evt) => this.#updateListSetting(evt));
|
||||
locationLabel.appendChild(locationCheckbox);
|
||||
|
||||
const locationName = document.createElement('span');
|
||||
locationName.innerText = location;
|
||||
locationLabel.appendChild(locationName);
|
||||
|
||||
locationRow.appendChild(locationLabel);
|
||||
excludeLocationsDiv.appendChild(locationRow);
|
||||
});
|
||||
|
||||
excludeLocationsWrapper.appendChild(excludeLocationsDiv);
|
||||
locationsContainer.appendChild(excludeLocationsWrapper);
|
||||
|
||||
@@ -1022,71 +1224,6 @@ class GameSettings {
|
||||
return locationsDiv;
|
||||
}
|
||||
|
||||
// Builds a div for a setting whose value is a list of locations.
|
||||
#buildLocationsDiv(setting) {
|
||||
return this.#buildListDiv(setting, this.data.gameLocations, this.data.gameLocationGroups);
|
||||
}
|
||||
|
||||
// Builds a div for a setting whose value is a list of items.
|
||||
#buildItemsDiv(setting) {
|
||||
return this.#buildListDiv(setting, this.data.gameItems, this.data.gameItemGroups);
|
||||
}
|
||||
|
||||
// Builds a div for a setting named `setting` with a list value that can
|
||||
// contain `items`.
|
||||
//
|
||||
// The `groups` option can be a list of additional options for this list
|
||||
// (usually `item_name_groups` or `location_name_groups`) that are displayed
|
||||
// in a special section at the top of the list.
|
||||
#buildListDiv(setting, items, groups = []) {
|
||||
const div = document.createElement('div');
|
||||
div.classList.add('simple-list');
|
||||
|
||||
groups.forEach((group) => {
|
||||
const row = this.#addListRow(setting, group);
|
||||
div.appendChild(row);
|
||||
});
|
||||
|
||||
if (groups.length > 0) {
|
||||
div.appendChild(document.createElement('hr'));
|
||||
}
|
||||
|
||||
items.forEach((item) => {
|
||||
const row = this.#addListRow(setting, item);
|
||||
div.appendChild(row);
|
||||
});
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
// Builds and returns a row for a list of checkboxes.
|
||||
#addListRow(setting, item) {
|
||||
const row = document.createElement('div');
|
||||
row.classList.add('list-row');
|
||||
|
||||
const label = document.createElement('label');
|
||||
label.setAttribute('for', `${this.name}-${setting}-${item}`);
|
||||
|
||||
const checkbox = document.createElement('input');
|
||||
checkbox.setAttribute('type', 'checkbox');
|
||||
checkbox.setAttribute('id', `${this.name}-${setting}-${item}`);
|
||||
checkbox.setAttribute('data-game', this.name);
|
||||
checkbox.setAttribute('data-setting', setting);
|
||||
checkbox.setAttribute('data-option', item);
|
||||
if (this.current[setting].includes(item)) {
|
||||
checkbox.setAttribute('checked', '1');
|
||||
}
|
||||
checkbox.addEventListener('change', (evt) => this.#updateListSetting(evt));
|
||||
label.appendChild(checkbox);
|
||||
|
||||
const name = document.createElement('span');
|
||||
name.innerText = item;
|
||||
label.appendChild(name);
|
||||
|
||||
row.appendChild(label);
|
||||
return row;
|
||||
}
|
||||
|
||||
#updateRangeSetting(evt) {
|
||||
const setting = evt.target.getAttribute('data-setting');
|
||||
const option = evt.target.getAttribute('data-option');
|
||||
|
||||
@@ -292,12 +292,6 @@ html{
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
#weighted-settings .simple-list hr{
|
||||
width: calc(100% - 2px);
|
||||
margin: 2px auto;
|
||||
border-bottom: 1px solid rgb(255 255 255 / 0.6);
|
||||
}
|
||||
|
||||
#weighted-settings .invisible{
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
{%- endif -%}
|
||||
{% endif %}
|
||||
{%- endfor -%}
|
||||
<td class="center-column">{{ "{0:.2f}".format(percent_total_checks_done[team][player]) }}</td>
|
||||
<td class="center-column">{{ percent_total_checks_done[team][player] }}</td>
|
||||
{%- if activity_timers[(team, player)] -%}
|
||||
<td class="center-column">{{ activity_timers[(team, player)].total_seconds() }}</td>
|
||||
{%- else -%}
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<td class="center-column" data-sort="{{ checks["Total"] }}">
|
||||
{{ checks["Total"] }}/{{ locations[player] | length }}
|
||||
</td>
|
||||
<td class="center-column">{{ "{0:.2f}".format(percent_total_checks_done[team][player]) }}</td>
|
||||
<td class="center-column">{{ percent_total_checks_done[team][player] }}</td>
|
||||
{%- if activity_timers[team, player] -%}
|
||||
<td class="center-column">{{ activity_timers[team, player].total_seconds() }}</td>
|
||||
{%- else -%}
|
||||
@@ -72,13 +72,7 @@
|
||||
<td>All Games</td>
|
||||
<td>{{ completed_worlds }}/{{ players|length }} Complete</td>
|
||||
<td class="center-column">{{ players.values()|sum(attribute='Total') }}/{{ total_locations[team] }}</td>
|
||||
<td class="center-column">
|
||||
{% if total_locations[team] == 0 %}
|
||||
100
|
||||
{% else %}
|
||||
{{ "{0:.2f}".format(players.values()|sum(attribute='Total') / total_locations[team] * 100) }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="center-column">{{ (players.values()|sum(attribute='Total') / total_locations[team] * 100) | int }}</td>
|
||||
<td class="center-column last-activity"></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
|
||||
@@ -1532,11 +1532,9 @@ def _get_multiworld_tracker_data(tracker: UUID) -> typing.Optional[typing.Dict[s
|
||||
continue
|
||||
player_locations = locations[player]
|
||||
checks_done[team][player]["Total"] = len(locations_checked)
|
||||
percent_total_checks_done[team][player] = (
|
||||
checks_done[team][player]["Total"] / len(player_locations) * 100
|
||||
if player_locations
|
||||
else 100
|
||||
)
|
||||
percent_total_checks_done[team][player] = int(checks_done[team][player]["Total"] /
|
||||
len(player_locations) * 100) \
|
||||
if player_locations else 100
|
||||
|
||||
activity_timers = {}
|
||||
now = datetime.datetime.utcnow()
|
||||
@@ -1692,13 +1690,10 @@ def get_LttP_multiworld_tracker(tracker: UUID):
|
||||
for recipient in recipients:
|
||||
attribute_item(team, recipient, item)
|
||||
checks_done[team][player][player_location_to_area[player][location]] += 1
|
||||
checks_done[team][player]["Total"] = len(locations_checked)
|
||||
|
||||
percent_total_checks_done[team][player] = (
|
||||
checks_done[team][player]["Total"] / len(player_locations) * 100
|
||||
if player_locations
|
||||
else 100
|
||||
)
|
||||
checks_done[team][player]["Total"] += 1
|
||||
percent_total_checks_done[team][player] = int(
|
||||
checks_done[team][player]["Total"] / len(player_locations) * 100) if \
|
||||
player_locations else 100
|
||||
|
||||
for (team, player), game_state in multisave.get("client_game_state", {}).items():
|
||||
if player in groups:
|
||||
|
||||
Reference in New Issue
Block a user