| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  | window.addEventListener('load', () => { | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |   fetchSettingData().then((data) => { | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  |     let settingHash = localStorage.getItem('weighted-settings-hash'); | 
					
						
							|  |  |  |     if (!settingHash) { | 
					
						
							|  |  |  |       // If no hash data has been set before, set it now
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |       settingHash = md5(JSON.stringify(data)); | 
					
						
							| 
									
										
										
										
											2022-04-04 19:38:42 -04:00
										 |  |  |       localStorage.setItem('weighted-settings-hash', settingHash); | 
					
						
							|  |  |  |       localStorage.removeItem('weighted-settings'); | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     if (settingHash !== md5(JSON.stringify(data))) { | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  |       const userMessage = document.getElementById('user-message'); | 
					
						
							|  |  |  |       userMessage.innerText = "Your settings are out of date! Click here to update them! Be aware this will reset " + | 
					
						
							|  |  |  |         "them all to default."; | 
					
						
							| 
									
										
										
										
											2022-01-30 16:53:53 -05:00
										 |  |  |       userMessage.classList.add('visible'); | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  |       userMessage.addEventListener('click', resetSettings); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Page setup
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     const settings = new WeightedSettings(data); | 
					
						
							|  |  |  |     settings.buildUI(); | 
					
						
							|  |  |  |     settings.updateVisibleGames(); | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  |     adjustHeaderWidth(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Event listeners
 | 
					
						
							| 
									
										
										
										
											2023-10-23 19:20:08 -05:00
										 |  |  |     document.getElementById('export-options').addEventListener('click', () => settings.export()); | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     document.getElementById('generate-race').addEventListener('click', () => settings.generateGame(true)); | 
					
						
							|  |  |  |     document.getElementById('generate-game').addEventListener('click', () => settings.generateGame()); | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Name input field
 | 
					
						
							|  |  |  |     const nameInput = document.getElementById('player-name'); | 
					
						
							| 
									
										
										
										
											2022-01-01 16:59:58 -05:00
										 |  |  |     nameInput.setAttribute('data-type', 'data'); | 
					
						
							|  |  |  |     nameInput.setAttribute('data-setting', 'name'); | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     nameInput.addEventListener('keyup', (evt) => settings.updateBaseSetting(evt)); | 
					
						
							|  |  |  |     nameInput.value = settings.current.name; | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  |   }); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const resetSettings = () => { | 
					
						
							|  |  |  |   localStorage.removeItem('weighted-settings'); | 
					
						
							|  |  |  |   localStorage.removeItem('weighted-settings-hash') | 
					
						
							|  |  |  |   window.location.reload(); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const fetchSettingData = () => new Promise((resolve, reject) => { | 
					
						
							| 
									
										
										
										
											2023-10-31 14:22:02 -07:00
										 |  |  |   fetch(new Request(`${window.location.origin}/static/generated/weighted-options.json`)).then((response) => { | 
					
						
							| 
									
										
										
										
											2022-01-30 16:50:04 -05:00
										 |  |  |     try{ response.json().then((jsonObj) => resolve(jsonObj)); } | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  |     catch(error){ reject(error); } | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  | /// The weighted settings across all games.
 | 
					
						
							|  |  |  | class WeightedSettings { | 
					
						
							|  |  |  |   // The data from the server describing the types of settings available for
 | 
					
						
							|  |  |  |   // each game, as a JSON-safe blob.
 | 
					
						
							|  |  |  |   data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // The settings chosen by the user as they'd appear in the YAML file, stored
 | 
					
						
							|  |  |  |   // to and retrieved from local storage.
 | 
					
						
							|  |  |  |   current; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // A record mapping game names to the associated GameSettings.
 | 
					
						
							|  |  |  |   games; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   constructor(data) { | 
					
						
							|  |  |  |     this.data = data; | 
					
						
							|  |  |  |     this.current = JSON.parse(localStorage.getItem('weighted-settings')); | 
					
						
							|  |  |  |     this.games = Object.keys(this.data.games).map((game) => new GameSettings(this, game)); | 
					
						
							|  |  |  |     if (this.current) { return; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this.current = {}; | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Transfer base options directly
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     for (let baseOption of Object.keys(this.data.baseOptions)){ | 
					
						
							|  |  |  |       this.current[baseOption] = this.data.baseOptions[baseOption]; | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Set options per game
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     for (let game of Object.keys(this.data.games)) { | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  |       // Initialize game object
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |       this.current[game] = {}; | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-01 16:59:58 -05:00
										 |  |  |       // Transfer game settings
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |       for (let gameSetting of Object.keys(this.data.games[game].gameSettings)){ | 
					
						
							|  |  |  |         this.current[game][gameSetting] = {}; | 
					
						
							| 
									
										
										
										
											2022-01-01 16:59:58 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |         const setting = this.data.games[game].gameSettings[gameSetting]; | 
					
						
							| 
									
										
										
										
											2022-01-01 16:59:58 -05:00
										 |  |  |         switch(setting.type){ | 
					
						
							|  |  |  |           case 'select': | 
					
						
							|  |  |  |             setting.options.forEach((option) => { | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |               this.current[game][gameSetting][option.value] = | 
					
						
							| 
									
										
										
										
											2022-01-01 16:59:58 -05:00
										 |  |  |                 (setting.hasOwnProperty('defaultValue') && setting.defaultValue === option.value) ? 25 : 0; | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           case 'range': | 
					
						
							| 
									
										
										
										
											2023-11-25 00:10:52 +01:00
										 |  |  |           case 'named_range': | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |             this.current[game][gameSetting]['random'] = 0; | 
					
						
							|  |  |  |             this.current[game][gameSetting]['random-low'] = 0; | 
					
						
							| 
									
										
										
										
											2023-11-25 00:10:52 +01:00
										 |  |  |             this.current[game][gameSetting]['random-middle'] = 0; | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |             this.current[game][gameSetting]['random-high'] = 0; | 
					
						
							| 
									
										
										
										
											2022-10-20 21:10:38 -04:00
										 |  |  |             if (setting.hasOwnProperty('defaultValue')) { | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |               this.current[game][gameSetting][setting.defaultValue] = 25; | 
					
						
							| 
									
										
										
										
											2022-10-20 21:10:38 -04:00
										 |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |               this.current[game][gameSetting][setting.min] = 25; | 
					
						
							| 
									
										
										
										
											2022-10-20 21:10:38 -04:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-01-01 16:59:58 -05:00
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2022-01-11 18:06:22 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |           case 'items-list': | 
					
						
							|  |  |  |           case 'locations-list': | 
					
						
							|  |  |  |           case 'custom-list': | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |             this.current[game][gameSetting] = setting.defaultValue; | 
					
						
							| 
									
										
										
										
											2022-01-11 18:06:22 -05:00
										 |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-01 16:59:58 -05:00
										 |  |  |           default: | 
					
						
							|  |  |  |             console.error(`Unknown setting type for ${game} setting ${gameSetting}: ${setting.type}`); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |       this.current[game].start_inventory = {}; | 
					
						
							|  |  |  |       this.current[game].exclude_locations = []; | 
					
						
							|  |  |  |       this.current[game].priority_locations = []; | 
					
						
							|  |  |  |       this.current[game].local_items = []; | 
					
						
							|  |  |  |       this.current[game].non_local_items = []; | 
					
						
							|  |  |  |       this.current[game].start_hints = []; | 
					
						
							|  |  |  |       this.current[game].start_location_hints = []; | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     this.save(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Saves the current settings to local storage.
 | 
					
						
							|  |  |  |   save() { | 
					
						
							|  |  |  |     localStorage.setItem('weighted-settings', JSON.stringify(this.current)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   buildUI() { | 
					
						
							|  |  |  |     // Build the game-choice div
 | 
					
						
							|  |  |  |     this.#buildGameChoice(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const gamesWrapper = document.getElementById('games-wrapper'); | 
					
						
							|  |  |  |     this.games.forEach((game) => { | 
					
						
							|  |  |  |       gamesWrapper.appendChild(game.buildUI()); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   #buildGameChoice() { | 
					
						
							|  |  |  |     const gameChoiceDiv = document.getElementById('game-choice'); | 
					
						
							|  |  |  |     const h2 = document.createElement('h2'); | 
					
						
							|  |  |  |     h2.innerText = 'Game Select'; | 
					
						
							|  |  |  |     gameChoiceDiv.appendChild(h2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const gameSelectDescription = document.createElement('p'); | 
					
						
							|  |  |  |     gameSelectDescription.classList.add('setting-description'); | 
					
						
							|  |  |  |     gameSelectDescription.innerText = 'Choose which games you might be required to play.'; | 
					
						
							|  |  |  |     gameChoiceDiv.appendChild(gameSelectDescription); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const hintText = document.createElement('p'); | 
					
						
							|  |  |  |     hintText.classList.add('hint-text'); | 
					
						
							|  |  |  |     hintText.innerText = 'If a game\'s value is greater than zero, you can click it\'s name to jump ' + | 
					
						
							|  |  |  |       'to that section.' | 
					
						
							|  |  |  |     gameChoiceDiv.appendChild(hintText); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Build the game choice table
 | 
					
						
							|  |  |  |     const table = document.createElement('table'); | 
					
						
							|  |  |  |     const tbody = document.createElement('tbody'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Object.keys(this.data.games).forEach((game) => { | 
					
						
							|  |  |  |       const tr = document.createElement('tr'); | 
					
						
							|  |  |  |       const tdLeft = document.createElement('td'); | 
					
						
							|  |  |  |       tdLeft.classList.add('td-left'); | 
					
						
							|  |  |  |       const span = document.createElement('span'); | 
					
						
							|  |  |  |       span.innerText = game; | 
					
						
							|  |  |  |       span.setAttribute('id', `${game}-game-option`) | 
					
						
							|  |  |  |       tdLeft.appendChild(span); | 
					
						
							|  |  |  |       tr.appendChild(tdLeft); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const tdMiddle = document.createElement('td'); | 
					
						
							|  |  |  |       tdMiddle.classList.add('td-middle'); | 
					
						
							|  |  |  |       const range = document.createElement('input'); | 
					
						
							|  |  |  |       range.setAttribute('type', 'range'); | 
					
						
							|  |  |  |       range.setAttribute('min', 0); | 
					
						
							|  |  |  |       range.setAttribute('max', 50); | 
					
						
							|  |  |  |       range.setAttribute('data-type', 'weight'); | 
					
						
							|  |  |  |       range.setAttribute('data-setting', 'game'); | 
					
						
							|  |  |  |       range.setAttribute('data-option', game); | 
					
						
							|  |  |  |       range.value = this.current.game[game]; | 
					
						
							|  |  |  |       range.addEventListener('change', (evt) => { | 
					
						
							|  |  |  |         this.updateBaseSetting(evt); | 
					
						
							|  |  |  |         this.updateVisibleGames(); // Show or hide games based on the new settings
 | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       tdMiddle.appendChild(range); | 
					
						
							|  |  |  |       tr.appendChild(tdMiddle); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const tdRight = document.createElement('td'); | 
					
						
							|  |  |  |       tdRight.setAttribute('id', `game-${game}`) | 
					
						
							|  |  |  |       tdRight.classList.add('td-right'); | 
					
						
							|  |  |  |       tdRight.innerText = range.value; | 
					
						
							|  |  |  |       tr.appendChild(tdRight); | 
					
						
							|  |  |  |       tbody.appendChild(tr); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     table.appendChild(tbody); | 
					
						
							|  |  |  |     gameChoiceDiv.appendChild(table); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Verifies that `this.settings` meets all the requirements for world
 | 
					
						
							|  |  |  |   // generation, normalizes it for serialization, and returns the result.
 | 
					
						
							|  |  |  |   #validateSettings() { | 
					
						
							|  |  |  |     const settings = structuredClone(this.current); | 
					
						
							|  |  |  |     const userMessage = document.getElementById('user-message'); | 
					
						
							|  |  |  |     let errorMessage = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // User must choose a name for their file
 | 
					
						
							| 
									
										
										
										
											2023-11-24 16:50:32 -05:00
										 |  |  |     if ( | 
					
						
							|  |  |  |       !settings.name || | 
					
						
							|  |  |  |       settings.name.toString().trim().length === 0 || | 
					
						
							|  |  |  |       settings.name.toString().toLowerCase().trim() === 'player' | 
					
						
							|  |  |  |     ) { | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |       userMessage.innerText = 'You forgot to set your player name at the top of the page!'; | 
					
						
							|  |  |  |       userMessage.classList.add('visible'); | 
					
						
							|  |  |  |       userMessage.scrollIntoView({ | 
					
						
							|  |  |  |         behavior: 'smooth', | 
					
						
							|  |  |  |         block: 'start', | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Clean up the settings output
 | 
					
						
							|  |  |  |     Object.keys(settings.game).forEach((game) => { | 
					
						
							|  |  |  |       // Remove any disabled games
 | 
					
						
							|  |  |  |       if (settings.game[game] === 0) { | 
					
						
							|  |  |  |         delete settings.game[game]; | 
					
						
							|  |  |  |         delete settings[game]; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       Object.keys(settings[game]).forEach((setting) => { | 
					
						
							|  |  |  |         // Remove any disabled options
 | 
					
						
							|  |  |  |         Object.keys(settings[game][setting]).forEach((option) => { | 
					
						
							|  |  |  |           if (settings[game][setting][option] === 0) { | 
					
						
							|  |  |  |             delete settings[game][setting][option]; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ( | 
					
						
							|  |  |  |           Object.keys(settings[game][setting]).length === 0 && | 
					
						
							|  |  |  |           !Array.isArray(settings[game][setting]) && | 
					
						
							|  |  |  |           setting !== 'start_inventory' | 
					
						
							|  |  |  |         ) { | 
					
						
							|  |  |  |           errorMessage = `${game} // ${setting} has no values above zero!`; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Remove weights from options with only one possibility
 | 
					
						
							|  |  |  |         if ( | 
					
						
							|  |  |  |           Object.keys(settings[game][setting]).length === 1 && | 
					
						
							|  |  |  |           !Array.isArray(settings[game][setting]) && | 
					
						
							|  |  |  |           setting !== 'start_inventory' | 
					
						
							|  |  |  |         ) { | 
					
						
							|  |  |  |           settings[game][setting] = Object.keys(settings[game][setting])[0]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Remove empty arrays
 | 
					
						
							|  |  |  |         else if ( | 
					
						
							| 
									
										
										
										
											2023-11-24 16:50:32 -05:00
										 |  |  |           ['exclude_locations', 'priority_locations', 'local_items', | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |           'non_local_items', 'start_hints', 'start_location_hints'].includes(setting) && | 
					
						
							|  |  |  |           settings[game][setting].length === 0 | 
					
						
							|  |  |  |         ) { | 
					
						
							|  |  |  |           delete settings[game][setting]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Remove empty start inventory
 | 
					
						
							|  |  |  |         else if ( | 
					
						
							|  |  |  |           setting === 'start_inventory' && | 
					
						
							|  |  |  |           Object.keys(settings[game]['start_inventory']).length === 0 | 
					
						
							|  |  |  |         ) { | 
					
						
							|  |  |  |           delete settings[game]['start_inventory']; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (Object.keys(settings.game).length === 0) { | 
					
						
							|  |  |  |       errorMessage = 'You have not chosen a game to play!'; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Remove weights if there is only one game
 | 
					
						
							|  |  |  |     else if (Object.keys(settings.game).length === 1) { | 
					
						
							|  |  |  |       settings.game = Object.keys(settings.game)[0]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // If an error occurred, alert the user and do not export the file
 | 
					
						
							|  |  |  |     if (errorMessage) { | 
					
						
							|  |  |  |       userMessage.innerText = errorMessage; | 
					
						
							|  |  |  |       userMessage.classList.add('visible'); | 
					
						
							|  |  |  |       userMessage.scrollIntoView({ | 
					
						
							|  |  |  |         behavior: 'smooth', | 
					
						
							|  |  |  |         block: 'start', | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // If no error occurred, hide the user message if it is visible
 | 
					
						
							|  |  |  |     userMessage.classList.remove('visible'); | 
					
						
							|  |  |  |     return settings; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   updateVisibleGames() { | 
					
						
							|  |  |  |     Object.entries(this.current.game).forEach(([game, weight]) => { | 
					
						
							|  |  |  |       const gameDiv = document.getElementById(`${game}-div`); | 
					
						
							|  |  |  |       const gameOption = document.getElementById(`${game}-game-option`); | 
					
						
							|  |  |  |       if (parseInt(weight, 10) > 0) { | 
					
						
							|  |  |  |         gameDiv.classList.remove('invisible'); | 
					
						
							|  |  |  |         gameOption.classList.add('jump-link'); | 
					
						
							|  |  |  |         gameOption.addEventListener('click', () => { | 
					
						
							|  |  |  |           const gameDiv = document.getElementById(`${game}-div`); | 
					
						
							|  |  |  |           if (gameDiv.classList.contains('invisible')) { return; } | 
					
						
							|  |  |  |           gameDiv.scrollIntoView({ | 
					
						
							|  |  |  |             behavior: 'smooth', | 
					
						
							|  |  |  |             block: 'start', | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         gameDiv.classList.add('invisible'); | 
					
						
							|  |  |  |         gameOption.classList.remove('jump-link'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   updateBaseSetting(event) { | 
					
						
							|  |  |  |     const setting = event.target.getAttribute('data-setting'); | 
					
						
							|  |  |  |     const option = event.target.getAttribute('data-option'); | 
					
						
							|  |  |  |     const type = event.target.getAttribute('data-type'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch(type){ | 
					
						
							|  |  |  |       case 'weight': | 
					
						
							|  |  |  |         this.current[setting][option] = isNaN(event.target.value) ? event.target.value : parseInt(event.target.value, 10); | 
					
						
							|  |  |  |         document.getElementById(`${setting}-${option}`).innerText = event.target.value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case 'data': | 
					
						
							|  |  |  |         this.current[setting] = isNaN(event.target.value) ? event.target.value : parseInt(event.target.value, 10); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this.save(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   export() { | 
					
						
							|  |  |  |     const settings = this.#validateSettings(); | 
					
						
							|  |  |  |     if (!settings) { return; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const yamlText = jsyaml.safeDump(settings, { noCompatMode: true }).replaceAll(/'(\d+)':/g, (x, y) => `${y}:`); | 
					
						
							|  |  |  |     download(`${document.getElementById('player-name').value}.yaml`, yamlText); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   generateGame(raceMode = false) { | 
					
						
							|  |  |  |     const settings = this.#validateSettings(); | 
					
						
							|  |  |  |     if (!settings) { return; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     axios.post('/api/generate', { | 
					
						
							|  |  |  |       weights: { player: JSON.stringify(settings) }, | 
					
						
							|  |  |  |       presetData: { player: JSON.stringify(settings) }, | 
					
						
							|  |  |  |       playerCount: 1, | 
					
						
							|  |  |  |       spoiler: 3, | 
					
						
							|  |  |  |       race: raceMode ? '1' : '0', | 
					
						
							|  |  |  |     }).then((response) => { | 
					
						
							|  |  |  |       window.location.href = response.data.url; | 
					
						
							|  |  |  |     }).catch((error) => { | 
					
						
							|  |  |  |       const userMessage = document.getElementById('user-message'); | 
					
						
							|  |  |  |       userMessage.innerText = 'Something went wrong and your game could not be generated.'; | 
					
						
							|  |  |  |       if (error.response.data.text) { | 
					
						
							|  |  |  |         userMessage.innerText += ' ' + error.response.data.text; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       userMessage.classList.add('visible'); | 
					
						
							|  |  |  |       userMessage.scrollIntoView({ | 
					
						
							|  |  |  |         behavior: 'smooth', | 
					
						
							|  |  |  |         block: 'start', | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       console.error(error); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Settings for an individual game.
 | 
					
						
							|  |  |  | class GameSettings { | 
					
						
							|  |  |  |   // The WeightedSettings that contains this game's settings. Used to save
 | 
					
						
							|  |  |  |   // settings after editing.
 | 
					
						
							|  |  |  |   #allSettings; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // The name of this game.
 | 
					
						
							|  |  |  |   name; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // The data from the server describing the types of settings available for
 | 
					
						
							|  |  |  |   // this game, as a JSON-safe blob.
 | 
					
						
							|  |  |  |   get data() { | 
					
						
							|  |  |  |     return this.#allSettings.data.games[this.name]; | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |   // The settings chosen by the user as they'd appear in the YAML file, stored
 | 
					
						
							|  |  |  |   // to and retrieved from local storage.
 | 
					
						
							|  |  |  |   get current() { | 
					
						
							|  |  |  |     return this.#allSettings.current[this.name]; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-01-01 16:59:58 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |   constructor(allSettings, name) { | 
					
						
							|  |  |  |     this.#allSettings = allSettings; | 
					
						
							|  |  |  |     this.name = name; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Builds and returns the settings UI for this game.
 | 
					
						
							|  |  |  |   buildUI() { | 
					
						
							| 
									
										
										
										
											2022-01-01 16:59:58 -05:00
										 |  |  |     // Create game div, invisible by default
 | 
					
						
							|  |  |  |     const gameDiv = document.createElement('div'); | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     gameDiv.setAttribute('id', `${this.name}-div`); | 
					
						
							| 
									
										
										
										
											2022-01-01 16:59:58 -05:00
										 |  |  |     gameDiv.classList.add('game-div'); | 
					
						
							|  |  |  |     gameDiv.classList.add('invisible'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const gameHeader = document.createElement('h2'); | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     gameHeader.innerText = this.name; | 
					
						
							| 
									
										
										
										
											2022-01-01 16:59:58 -05:00
										 |  |  |     gameDiv.appendChild(gameHeader); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-02 18:55:38 -05:00
										 |  |  |     const collapseButton = document.createElement('a'); | 
					
						
							|  |  |  |     collapseButton.innerText = '(Collapse)'; | 
					
						
							|  |  |  |     gameDiv.appendChild(collapseButton); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const expandButton = document.createElement('a'); | 
					
						
							|  |  |  |     expandButton.innerText = '(Expand)'; | 
					
						
							|  |  |  |     expandButton.classList.add('invisible'); | 
					
						
							|  |  |  |     gameDiv.appendChild(expandButton); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     // Sort items and locations alphabetically.
 | 
					
						
							|  |  |  |     this.data.gameItems.sort(); | 
					
						
							|  |  |  |     this.data.gameLocations.sort(); | 
					
						
							| 
									
										
										
										
											2023-03-29 17:37:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     const weightedSettingsDiv = this.#buildWeightedSettingsDiv(); | 
					
						
							| 
									
										
										
										
											2022-01-08 16:59:39 -05:00
										 |  |  |     gameDiv.appendChild(weightedSettingsDiv); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-31 14:25:07 -07:00
										 |  |  |     const itemPoolDiv = this.#buildItemPoolDiv(); | 
					
						
							| 
									
										
										
										
											2023-03-29 17:37:39 -04:00
										 |  |  |     gameDiv.appendChild(itemPoolDiv); | 
					
						
							| 
									
										
										
										
											2022-01-10 23:20:15 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     const hintsDiv = this.#buildHintsDiv(); | 
					
						
							| 
									
										
										
										
											2022-01-10 23:20:15 -05:00
										 |  |  |     gameDiv.appendChild(hintsDiv); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-31 14:25:07 -07:00
										 |  |  |     const locationsDiv = this.#buildPriorityExclusionDiv(); | 
					
						
							| 
									
										
										
										
											2023-03-29 17:37:39 -04:00
										 |  |  |     gameDiv.appendChild(locationsDiv); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-02 18:55:38 -05:00
										 |  |  |     collapseButton.addEventListener('click', () => { | 
					
						
							|  |  |  |       collapseButton.classList.add('invisible'); | 
					
						
							| 
									
										
										
										
											2022-01-08 16:59:39 -05:00
										 |  |  |       weightedSettingsDiv.classList.add('invisible'); | 
					
						
							| 
									
										
										
										
											2023-03-29 17:37:39 -04:00
										 |  |  |       itemPoolDiv.classList.add('invisible'); | 
					
						
							| 
									
										
										
										
											2022-01-10 23:20:15 -05:00
										 |  |  |       hintsDiv.classList.add('invisible'); | 
					
						
							| 
									
										
										
										
											2023-09-20 14:53:00 -06:00
										 |  |  |       locationsDiv.classList.add('invisible'); | 
					
						
							| 
									
										
										
										
											2022-01-02 18:55:38 -05:00
										 |  |  |       expandButton.classList.remove('invisible'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expandButton.addEventListener('click', () => { | 
					
						
							|  |  |  |       collapseButton.classList.remove('invisible'); | 
					
						
							| 
									
										
										
										
											2022-01-08 16:59:39 -05:00
										 |  |  |       weightedSettingsDiv.classList.remove('invisible'); | 
					
						
							| 
									
										
										
										
											2023-03-29 17:37:39 -04:00
										 |  |  |       itemPoolDiv.classList.remove('invisible'); | 
					
						
							| 
									
										
										
										
											2022-01-10 23:20:15 -05:00
										 |  |  |       hintsDiv.classList.remove('invisible'); | 
					
						
							| 
									
										
										
										
											2023-09-20 14:53:00 -06:00
										 |  |  |       locationsDiv.classList.remove('invisible'); | 
					
						
							| 
									
										
										
										
											2022-01-02 18:55:38 -05:00
										 |  |  |       expandButton.classList.add('invisible'); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     return gameDiv; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |   #buildWeightedSettingsDiv() { | 
					
						
							|  |  |  |     const settingsWrapper = document.createElement('div'); | 
					
						
							|  |  |  |     settingsWrapper.classList.add('settings-wrapper'); | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     Object.keys(this.data.gameSettings).forEach((settingName) => { | 
					
						
							|  |  |  |       const setting = this.data.gameSettings[settingName]; | 
					
						
							|  |  |  |       const settingWrapper = document.createElement('div'); | 
					
						
							|  |  |  |       settingWrapper.classList.add('setting-wrapper'); | 
					
						
							| 
									
										
										
										
											2022-01-01 16:59:58 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |       const settingNameHeader = document.createElement('h4'); | 
					
						
							|  |  |  |       settingNameHeader.innerText = setting.displayName; | 
					
						
							|  |  |  |       settingWrapper.appendChild(settingNameHeader); | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |       const settingDescription = document.createElement('p'); | 
					
						
							|  |  |  |       settingDescription.classList.add('setting-description'); | 
					
						
							|  |  |  |       settingDescription.innerText = setting.description.replace(/(\n)/g, ' '); | 
					
						
							|  |  |  |       settingWrapper.appendChild(settingDescription); | 
					
						
							| 
									
										
										
										
											2022-01-02 18:31:15 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |       switch(setting.type){ | 
					
						
							|  |  |  |         case 'select': | 
					
						
							|  |  |  |           const optionTable = document.createElement('table'); | 
					
						
							|  |  |  |           const tbody = document.createElement('tbody'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           // Add a weight range for each option
 | 
					
						
							|  |  |  |           setting.options.forEach((option) => { | 
					
						
							| 
									
										
										
										
											2022-01-02 18:31:15 -05:00
										 |  |  |             const tr = document.createElement('tr'); | 
					
						
							| 
									
										
										
										
											2023-03-27 11:55:13 -04:00
										 |  |  |             const tdLeft = document.createElement('td'); | 
					
						
							|  |  |  |             tdLeft.classList.add('td-left'); | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |             tdLeft.innerText = option.name; | 
					
						
							| 
									
										
										
										
											2023-03-27 11:55:13 -04:00
										 |  |  |             tr.appendChild(tdLeft); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const tdMiddle = document.createElement('td'); | 
					
						
							|  |  |  |             tdMiddle.classList.add('td-middle'); | 
					
						
							|  |  |  |             const range = document.createElement('input'); | 
					
						
							|  |  |  |             range.setAttribute('type', 'range'); | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |             range.setAttribute('data-game', this.name); | 
					
						
							| 
									
										
										
										
											2023-03-27 11:55:13 -04:00
										 |  |  |             range.setAttribute('data-setting', settingName); | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |             range.setAttribute('data-option', option.value); | 
					
						
							|  |  |  |             range.setAttribute('data-type', setting.type); | 
					
						
							| 
									
										
										
										
											2023-03-27 11:55:13 -04:00
										 |  |  |             range.setAttribute('min', 0); | 
					
						
							|  |  |  |             range.setAttribute('max', 50); | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |             range.addEventListener('change', (evt) => this.#updateRangeSetting(evt)); | 
					
						
							|  |  |  |             range.value = this.current[settingName][option.value]; | 
					
						
							| 
									
										
										
										
											2023-03-27 11:55:13 -04:00
										 |  |  |             tdMiddle.appendChild(range); | 
					
						
							|  |  |  |             tr.appendChild(tdMiddle); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const tdRight = document.createElement('td'); | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |             tdRight.setAttribute('id', `${this.name}-${settingName}-${option.value}`); | 
					
						
							| 
									
										
										
										
											2023-03-27 11:55:13 -04:00
										 |  |  |             tdRight.classList.add('td-right'); | 
					
						
							|  |  |  |             tdRight.innerText = range.value; | 
					
						
							|  |  |  |             tr.appendChild(tdRight); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |             tbody.appendChild(tr); | 
					
						
							| 
									
										
										
										
											2022-01-08 16:59:39 -05:00
										 |  |  |           }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |           optionTable.appendChild(tbody); | 
					
						
							|  |  |  |           settingWrapper.appendChild(optionTable); | 
					
						
							|  |  |  |           break; | 
					
						
							| 
									
										
										
										
											2022-01-08 16:59:39 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |         case 'range': | 
					
						
							| 
									
										
										
										
											2023-11-25 00:10:52 +01:00
										 |  |  |         case 'named_range': | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |           const rangeTable = document.createElement('table'); | 
					
						
							|  |  |  |           const rangeTbody = document.createElement('tbody'); | 
					
						
							| 
									
										
										
										
											2022-01-08 16:59:39 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-25 00:10:52 +01:00
										 |  |  |           const hintText = document.createElement('p'); | 
					
						
							|  |  |  |           hintText.classList.add('hint-text'); | 
					
						
							|  |  |  |           hintText.innerHTML = 'This is a range option. You may enter a valid numerical value in the text box ' + | 
					
						
							|  |  |  |             `below, then press the "Add" button to add a weight for it.<br /><br />Accepted values:<br />` + | 
					
						
							|  |  |  |             `Normal range: ${setting.min} - ${setting.max}`; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           const acceptedValuesOutsideRange = []; | 
					
						
							|  |  |  |           if (setting.hasOwnProperty('value_names')) { | 
					
						
							|  |  |  |             Object.keys(setting.value_names).forEach((specialName) => { | 
					
						
							|  |  |  |               if ( | 
					
						
							|  |  |  |                 (setting.value_names[specialName] < setting.min) || | 
					
						
							|  |  |  |                 (setting.value_names[specialName] > setting.max) | 
					
						
							|  |  |  |               ) { | 
					
						
							|  |  |  |                 hintText.innerHTML += `<br />${specialName}: ${setting.value_names[specialName]}`; | 
					
						
							|  |  |  |                 acceptedValuesOutsideRange.push(setting.value_names[specialName]); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             }); | 
					
						
							| 
									
										
										
										
											2022-01-08 16:59:39 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-25 00:10:52 +01:00
										 |  |  |             hintText.innerHTML += '<br /><br />Certain values have special meaning:'; | 
					
						
							|  |  |  |             Object.keys(setting.value_names).forEach((specialName) => { | 
					
						
							|  |  |  |               hintText.innerHTML += `<br />${specialName}: ${setting.value_names[specialName]}`; | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           settingWrapper.appendChild(hintText); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           const addOptionDiv = document.createElement('div'); | 
					
						
							|  |  |  |           addOptionDiv.classList.add('add-option-div'); | 
					
						
							|  |  |  |           const optionInput = document.createElement('input'); | 
					
						
							|  |  |  |           optionInput.setAttribute('id', `${this.name}-${settingName}-option`); | 
					
						
							|  |  |  |           let placeholderText = `${setting.min} - ${setting.max}`; | 
					
						
							|  |  |  |           acceptedValuesOutsideRange.forEach((aVal) => placeholderText += `, ${aVal}`); | 
					
						
							|  |  |  |           optionInput.setAttribute('placeholder', placeholderText); | 
					
						
							|  |  |  |           addOptionDiv.appendChild(optionInput); | 
					
						
							|  |  |  |           const addOptionButton = document.createElement('button'); | 
					
						
							|  |  |  |           addOptionButton.innerText = 'Add'; | 
					
						
							|  |  |  |           addOptionDiv.appendChild(addOptionButton); | 
					
						
							|  |  |  |           settingWrapper.appendChild(addOptionDiv); | 
					
						
							|  |  |  |           optionInput.addEventListener('keydown', (evt) => { | 
					
						
							|  |  |  |             if (evt.key === 'Enter') { addOptionButton.dispatchEvent(new Event('click')); } | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           addOptionButton.addEventListener('click', () => { | 
					
						
							|  |  |  |             const optionInput = document.getElementById(`${this.name}-${settingName}-option`); | 
					
						
							|  |  |  |             let option = optionInput.value; | 
					
						
							|  |  |  |             if (!option || !option.trim()) { return; } | 
					
						
							|  |  |  |             option = parseInt(option, 10); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             let optionAcceptable = false; | 
					
						
							| 
									
										
										
										
											2023-11-29 22:57:40 -05:00
										 |  |  |             if ((option >= setting.min) && (option <= setting.max)) { | 
					
						
							| 
									
										
										
										
											2023-11-25 00:10:52 +01:00
										 |  |  |               optionAcceptable = true; | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-11-25 00:10:52 +01:00
										 |  |  |             if (setting.hasOwnProperty('value_names') && Object.values(setting.value_names).includes(option)){ | 
					
						
							|  |  |  |               optionAcceptable = true; | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-11-25 00:10:52 +01:00
										 |  |  |             if (!optionAcceptable) { return; } | 
					
						
							| 
									
										
										
										
											2022-10-20 21:10:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-25 00:10:52 +01:00
										 |  |  |             optionInput.value = ''; | 
					
						
							|  |  |  |             if (document.getElementById(`${this.name}-${settingName}-${option}-range`)) { return; } | 
					
						
							| 
									
										
										
										
											2022-01-08 16:59:39 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-25 00:10:52 +01:00
										 |  |  |             const tr = document.createElement('tr'); | 
					
						
							|  |  |  |             const tdLeft = document.createElement('td'); | 
					
						
							|  |  |  |             tdLeft.classList.add('td-left'); | 
					
						
							|  |  |  |             tdLeft.innerText = option; | 
					
						
							|  |  |  |             if ( | 
					
						
							|  |  |  |               setting.hasOwnProperty('value_names') && | 
					
						
							|  |  |  |               Object.values(setting.value_names).includes(parseInt(option, 10)) | 
					
						
							|  |  |  |             ) { | 
					
						
							|  |  |  |               const optionName = Object.keys(setting.value_names).find( | 
					
						
							|  |  |  |                 (key) => setting.value_names[key] === parseInt(option, 10) | 
					
						
							|  |  |  |               ); | 
					
						
							|  |  |  |               tdLeft.innerText += ` [${optionName}]`; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             tr.appendChild(tdLeft); | 
					
						
							| 
									
										
										
										
											2022-10-20 21:10:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-25 00:10:52 +01:00
										 |  |  |             const tdMiddle = document.createElement('td'); | 
					
						
							|  |  |  |             tdMiddle.classList.add('td-middle'); | 
					
						
							|  |  |  |             const range = document.createElement('input'); | 
					
						
							|  |  |  |             range.setAttribute('type', 'range'); | 
					
						
							|  |  |  |             range.setAttribute('id', `${this.name}-${settingName}-${option}-range`); | 
					
						
							|  |  |  |             range.setAttribute('data-game', this.name); | 
					
						
							|  |  |  |             range.setAttribute('data-setting', settingName); | 
					
						
							|  |  |  |             range.setAttribute('data-option', option); | 
					
						
							|  |  |  |             range.setAttribute('min', 0); | 
					
						
							|  |  |  |             range.setAttribute('max', 50); | 
					
						
							|  |  |  |             range.addEventListener('change', (evt) => this.#updateRangeSetting(evt)); | 
					
						
							|  |  |  |             range.value = this.current[settingName][parseInt(option, 10)]; | 
					
						
							|  |  |  |             tdMiddle.appendChild(range); | 
					
						
							|  |  |  |             tr.appendChild(tdMiddle); | 
					
						
							| 
									
										
										
										
											2022-01-03 19:56:54 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-25 00:10:52 +01:00
										 |  |  |             const tdRight = document.createElement('td'); | 
					
						
							|  |  |  |             tdRight.setAttribute('id', `${this.name}-${settingName}-${option}`) | 
					
						
							|  |  |  |             tdRight.classList.add('td-right'); | 
					
						
							|  |  |  |             tdRight.innerText = range.value; | 
					
						
							|  |  |  |             tr.appendChild(tdRight); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const tdDelete = document.createElement('td'); | 
					
						
							|  |  |  |             tdDelete.classList.add('td-delete'); | 
					
						
							|  |  |  |             const deleteButton = document.createElement('span'); | 
					
						
							|  |  |  |             deleteButton.classList.add('range-option-delete'); | 
					
						
							|  |  |  |             deleteButton.innerText = '❌'; | 
					
						
							|  |  |  |             deleteButton.addEventListener('click', () => { | 
					
						
							|  |  |  |               range.value = 0; | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |               range.dispatchEvent(new Event('change')); | 
					
						
							| 
									
										
										
										
											2023-11-25 00:10:52 +01:00
										 |  |  |               rangeTbody.removeChild(tr); | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |             }); | 
					
						
							| 
									
										
										
										
											2023-11-25 00:10:52 +01:00
										 |  |  |             tdDelete.appendChild(deleteButton); | 
					
						
							|  |  |  |             tr.appendChild(tdDelete); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             rangeTbody.appendChild(tr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Save new option to settings
 | 
					
						
							|  |  |  |             range.dispatchEvent(new Event('change')); | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           Object.keys(this.current[settingName]).forEach((option) => { | 
					
						
							|  |  |  |             // These options are statically generated below, and should always appear even if they are deleted
 | 
					
						
							|  |  |  |             // from localStorage
 | 
					
						
							|  |  |  |             if (['random', 'random-low', 'random-middle', 'random-high'].includes(option)) { return; } | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-25 00:10:52 +01:00
										 |  |  |             const tr = document.createElement('tr'); | 
					
						
							|  |  |  |             const tdLeft = document.createElement('td'); | 
					
						
							|  |  |  |             tdLeft.classList.add('td-left'); | 
					
						
							|  |  |  |             tdLeft.innerText = option; | 
					
						
							|  |  |  |             if ( | 
					
						
							|  |  |  |               setting.hasOwnProperty('value_names') && | 
					
						
							|  |  |  |               Object.values(setting.value_names).includes(parseInt(option, 10)) | 
					
						
							|  |  |  |             ) { | 
					
						
							|  |  |  |               const optionName = Object.keys(setting.value_names).find( | 
					
						
							|  |  |  |                 (key) => setting.value_names[key] === parseInt(option, 10) | 
					
						
							|  |  |  |               ); | 
					
						
							|  |  |  |               tdLeft.innerText += ` [${optionName}]`; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             tr.appendChild(tdLeft); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const tdMiddle = document.createElement('td'); | 
					
						
							|  |  |  |             tdMiddle.classList.add('td-middle'); | 
					
						
							|  |  |  |             const range = document.createElement('input'); | 
					
						
							|  |  |  |             range.setAttribute('type', 'range'); | 
					
						
							|  |  |  |             range.setAttribute('id', `${this.name}-${settingName}-${option}-range`); | 
					
						
							|  |  |  |             range.setAttribute('data-game', this.name); | 
					
						
							|  |  |  |             range.setAttribute('data-setting', settingName); | 
					
						
							|  |  |  |             range.setAttribute('data-option', option); | 
					
						
							|  |  |  |             range.setAttribute('min', 0); | 
					
						
							|  |  |  |             range.setAttribute('max', 50); | 
					
						
							|  |  |  |             range.addEventListener('change', (evt) => this.#updateRangeSetting(evt)); | 
					
						
							|  |  |  |             range.value = this.current[settingName][parseInt(option, 10)]; | 
					
						
							|  |  |  |             tdMiddle.appendChild(range); | 
					
						
							|  |  |  |             tr.appendChild(tdMiddle); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const tdRight = document.createElement('td'); | 
					
						
							|  |  |  |             tdRight.setAttribute('id', `${this.name}-${settingName}-${option}`) | 
					
						
							|  |  |  |             tdRight.classList.add('td-right'); | 
					
						
							|  |  |  |             tdRight.innerText = range.value; | 
					
						
							|  |  |  |             tr.appendChild(tdRight); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const tdDelete = document.createElement('td'); | 
					
						
							|  |  |  |             tdDelete.classList.add('td-delete'); | 
					
						
							|  |  |  |             const deleteButton = document.createElement('span'); | 
					
						
							|  |  |  |             deleteButton.classList.add('range-option-delete'); | 
					
						
							|  |  |  |             deleteButton.innerText = '❌'; | 
					
						
							|  |  |  |             deleteButton.addEventListener('click', () => { | 
					
						
							|  |  |  |               range.value = 0; | 
					
						
							|  |  |  |               const changeEvent = new Event('change'); | 
					
						
							|  |  |  |               changeEvent.action = 'rangeDelete'; | 
					
						
							|  |  |  |               range.dispatchEvent(changeEvent); | 
					
						
							|  |  |  |               rangeTbody.removeChild(tr); | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |             }); | 
					
						
							| 
									
										
										
										
											2023-11-25 00:10:52 +01:00
										 |  |  |             tdDelete.appendChild(deleteButton); | 
					
						
							|  |  |  |             tr.appendChild(tdDelete); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             rangeTbody.appendChild(tr); | 
					
						
							|  |  |  |           }); | 
					
						
							| 
									
										
										
										
											2023-03-29 17:37:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-25 00:10:52 +01:00
										 |  |  |           ['random', 'random-low', 'random-middle', 'random-high'].forEach((option) => { | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |             const tr = document.createElement('tr'); | 
					
						
							|  |  |  |               const tdLeft = document.createElement('td'); | 
					
						
							|  |  |  |               tdLeft.classList.add('td-left'); | 
					
						
							|  |  |  |               switch(option){ | 
					
						
							|  |  |  |                 case 'random': | 
					
						
							|  |  |  |                   tdLeft.innerText = 'Random'; | 
					
						
							|  |  |  |                   break; | 
					
						
							|  |  |  |                 case 'random-low': | 
					
						
							|  |  |  |                   tdLeft.innerText = "Random (Low)"; | 
					
						
							|  |  |  |                   break; | 
					
						
							| 
									
										
										
										
											2023-11-25 00:10:52 +01:00
										 |  |  |                 case 'random-middle': | 
					
						
							|  |  |  |                   tdLeft.innerText = 'Random (Middle)'; | 
					
						
							|  |  |  |                   break; | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |                 case 'random-high': | 
					
						
							|  |  |  |                   tdLeft.innerText = "Random (High)"; | 
					
						
							|  |  |  |                   break; | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |               tr.appendChild(tdLeft); | 
					
						
							| 
									
										
										
										
											2023-03-29 17:37:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |               const tdMiddle = document.createElement('td'); | 
					
						
							|  |  |  |               tdMiddle.classList.add('td-middle'); | 
					
						
							|  |  |  |               const range = document.createElement('input'); | 
					
						
							|  |  |  |               range.setAttribute('type', 'range'); | 
					
						
							|  |  |  |               range.setAttribute('id', `${this.name}-${settingName}-${option}-range`); | 
					
						
							|  |  |  |               range.setAttribute('data-game', this.name); | 
					
						
							|  |  |  |               range.setAttribute('data-setting', settingName); | 
					
						
							|  |  |  |               range.setAttribute('data-option', option); | 
					
						
							|  |  |  |               range.setAttribute('min', 0); | 
					
						
							|  |  |  |               range.setAttribute('max', 50); | 
					
						
							|  |  |  |               range.addEventListener('change', (evt) => this.#updateRangeSetting(evt)); | 
					
						
							|  |  |  |               range.value = this.current[settingName][option]; | 
					
						
							|  |  |  |               tdMiddle.appendChild(range); | 
					
						
							|  |  |  |               tr.appendChild(tdMiddle); | 
					
						
							| 
									
										
										
										
											2023-03-29 17:37:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |               const tdRight = document.createElement('td'); | 
					
						
							|  |  |  |               tdRight.setAttribute('id', `${this.name}-${settingName}-${option}`) | 
					
						
							|  |  |  |               tdRight.classList.add('td-right'); | 
					
						
							|  |  |  |               tdRight.innerText = range.value; | 
					
						
							|  |  |  |               tr.appendChild(tdRight); | 
					
						
							|  |  |  |               rangeTbody.appendChild(tr); | 
					
						
							|  |  |  |           }); | 
					
						
							| 
									
										
										
										
											2023-03-29 17:37:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |           rangeTable.appendChild(rangeTbody); | 
					
						
							|  |  |  |           settingWrapper.appendChild(rangeTable); | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case 'items-list': | 
					
						
							| 
									
										
										
										
											2023-10-31 14:25:07 -07:00
										 |  |  |           const itemsList = this.#buildItemsDiv(settingName); | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |           settingWrapper.appendChild(itemsList); | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case 'locations-list': | 
					
						
							| 
									
										
										
										
											2023-10-31 14:25:07 -07:00
										 |  |  |           const locationsList = this.#buildLocationsDiv(settingName); | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |           settingWrapper.appendChild(locationsList); | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case 'custom-list': | 
					
						
							| 
									
										
										
										
											2023-10-31 14:25:07 -07:00
										 |  |  |           const customList = this.#buildListDiv(settingName, this.data.gameSettings[settingName].options); | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |           settingWrapper.appendChild(customList); | 
					
						
							|  |  |  |           break; | 
					
						
							| 
									
										
										
										
											2022-01-08 16:59:39 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |         default: | 
					
						
							|  |  |  |           console.error(`Unknown setting type for ${this.name} setting ${settingName}: ${setting.type}`); | 
					
						
							|  |  |  |           return; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-01-08 16:59:39 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |       settingsWrapper.appendChild(settingWrapper); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     return settingsWrapper; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-01-01 16:59:58 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-31 14:25:07 -07:00
										 |  |  |   #buildItemPoolDiv() { | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     const itemsDiv = document.createElement('div'); | 
					
						
							|  |  |  |     itemsDiv.classList.add('items-div'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const itemsDivHeader = document.createElement('h3'); | 
					
						
							|  |  |  |     itemsDivHeader.innerText = 'Item Pool'; | 
					
						
							|  |  |  |     itemsDiv.appendChild(itemsDivHeader); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const itemsDescription = document.createElement('p'); | 
					
						
							|  |  |  |     itemsDescription.classList.add('setting-description'); | 
					
						
							|  |  |  |     itemsDescription.innerText = 'Choose if you would like to start with items, or control if they are placed in ' + | 
					
						
							|  |  |  |       'your seed or someone else\'s.'; | 
					
						
							|  |  |  |     itemsDiv.appendChild(itemsDescription); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const itemsHint = document.createElement('p'); | 
					
						
							|  |  |  |     itemsHint.classList.add('hint-text'); | 
					
						
							|  |  |  |     itemsHint.innerText = 'Drag and drop items from one box to another.'; | 
					
						
							|  |  |  |     itemsDiv.appendChild(itemsHint); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const itemsWrapper = document.createElement('div'); | 
					
						
							|  |  |  |     itemsWrapper.classList.add('items-wrapper'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const itemDragoverHandler = (evt) => evt.preventDefault(); | 
					
						
							|  |  |  |     const itemDropHandler = (evt) => this.#itemDropHandler(evt); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Create container divs for each category
 | 
					
						
							|  |  |  |     const availableItemsWrapper = document.createElement('div'); | 
					
						
							|  |  |  |     availableItemsWrapper.classList.add('item-set-wrapper'); | 
					
						
							|  |  |  |     availableItemsWrapper.innerText = 'Available Items'; | 
					
						
							|  |  |  |     const availableItems = document.createElement('div'); | 
					
						
							|  |  |  |     availableItems.classList.add('item-container'); | 
					
						
							|  |  |  |     availableItems.setAttribute('id', `${this.name}-available_items`); | 
					
						
							|  |  |  |     availableItems.addEventListener('dragover', itemDragoverHandler); | 
					
						
							|  |  |  |     availableItems.addEventListener('drop', itemDropHandler); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const startInventoryWrapper = document.createElement('div'); | 
					
						
							|  |  |  |     startInventoryWrapper.classList.add('item-set-wrapper'); | 
					
						
							|  |  |  |     startInventoryWrapper.innerText = 'Start Inventory'; | 
					
						
							|  |  |  |     const startInventory = document.createElement('div'); | 
					
						
							|  |  |  |     startInventory.classList.add('item-container'); | 
					
						
							|  |  |  |     startInventory.setAttribute('id', `${this.name}-start_inventory`); | 
					
						
							|  |  |  |     startInventory.setAttribute('data-setting', 'start_inventory'); | 
					
						
							|  |  |  |     startInventory.addEventListener('dragover', itemDragoverHandler); | 
					
						
							|  |  |  |     startInventory.addEventListener('drop', itemDropHandler); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const localItemsWrapper = document.createElement('div'); | 
					
						
							|  |  |  |     localItemsWrapper.classList.add('item-set-wrapper'); | 
					
						
							|  |  |  |     localItemsWrapper.innerText = 'Local Items'; | 
					
						
							|  |  |  |     const localItems = document.createElement('div'); | 
					
						
							|  |  |  |     localItems.classList.add('item-container'); | 
					
						
							|  |  |  |     localItems.setAttribute('id', `${this.name}-local_items`); | 
					
						
							|  |  |  |     localItems.setAttribute('data-setting', 'local_items') | 
					
						
							|  |  |  |     localItems.addEventListener('dragover', itemDragoverHandler); | 
					
						
							|  |  |  |     localItems.addEventListener('drop', itemDropHandler); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const nonLocalItemsWrapper = document.createElement('div'); | 
					
						
							|  |  |  |     nonLocalItemsWrapper.classList.add('item-set-wrapper'); | 
					
						
							|  |  |  |     nonLocalItemsWrapper.innerText = 'Non-Local Items'; | 
					
						
							|  |  |  |     const nonLocalItems = document.createElement('div'); | 
					
						
							|  |  |  |     nonLocalItems.classList.add('item-container'); | 
					
						
							|  |  |  |     nonLocalItems.setAttribute('id', `${this.name}-non_local_items`); | 
					
						
							|  |  |  |     nonLocalItems.setAttribute('data-setting', 'non_local_items'); | 
					
						
							|  |  |  |     nonLocalItems.addEventListener('dragover', itemDragoverHandler); | 
					
						
							|  |  |  |     nonLocalItems.addEventListener('drop', itemDropHandler); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Populate the divs
 | 
					
						
							|  |  |  |     this.data.gameItems.forEach((item) => { | 
					
						
							|  |  |  |       if (Object.keys(this.current.start_inventory).includes(item)){ | 
					
						
							|  |  |  |         const itemDiv = this.#buildItemQtyDiv(item); | 
					
						
							|  |  |  |         itemDiv.setAttribute('data-setting', 'start_inventory'); | 
					
						
							|  |  |  |         startInventory.appendChild(itemDiv); | 
					
						
							|  |  |  |       } else if (this.current.local_items.includes(item)) { | 
					
						
							|  |  |  |         const itemDiv = this.#buildItemDiv(item); | 
					
						
							|  |  |  |         itemDiv.setAttribute('data-setting', 'local_items'); | 
					
						
							|  |  |  |         localItems.appendChild(itemDiv); | 
					
						
							|  |  |  |       } else if (this.current.non_local_items.includes(item)) { | 
					
						
							|  |  |  |         const itemDiv = this.#buildItemDiv(item); | 
					
						
							|  |  |  |         itemDiv.setAttribute('data-setting', 'non_local_items'); | 
					
						
							|  |  |  |         nonLocalItems.appendChild(itemDiv); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         const itemDiv = this.#buildItemDiv(item); | 
					
						
							|  |  |  |         availableItems.appendChild(itemDiv); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2022-01-08 19:59:35 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     availableItemsWrapper.appendChild(availableItems); | 
					
						
							|  |  |  |     startInventoryWrapper.appendChild(startInventory); | 
					
						
							|  |  |  |     localItemsWrapper.appendChild(localItems); | 
					
						
							|  |  |  |     nonLocalItemsWrapper.appendChild(nonLocalItems); | 
					
						
							|  |  |  |     itemsWrapper.appendChild(availableItemsWrapper); | 
					
						
							|  |  |  |     itemsWrapper.appendChild(startInventoryWrapper); | 
					
						
							|  |  |  |     itemsWrapper.appendChild(localItemsWrapper); | 
					
						
							|  |  |  |     itemsWrapper.appendChild(nonLocalItemsWrapper); | 
					
						
							|  |  |  |     itemsDiv.appendChild(itemsWrapper); | 
					
						
							|  |  |  |     return itemsDiv; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-01-11 04:20:33 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |   #buildItemDiv(item) { | 
					
						
							|  |  |  |     const itemDiv = document.createElement('div'); | 
					
						
							|  |  |  |     itemDiv.classList.add('item-div'); | 
					
						
							|  |  |  |     itemDiv.setAttribute('id', `${this.name}-${item}`); | 
					
						
							|  |  |  |     itemDiv.setAttribute('data-game', this.name); | 
					
						
							|  |  |  |     itemDiv.setAttribute('data-item', item); | 
					
						
							|  |  |  |     itemDiv.setAttribute('draggable', 'true'); | 
					
						
							|  |  |  |     itemDiv.innerText = item; | 
					
						
							|  |  |  |     itemDiv.addEventListener('dragstart', (evt) => { | 
					
						
							|  |  |  |       evt.dataTransfer.setData('text/plain', itemDiv.getAttribute('id')); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return itemDiv; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-01-11 04:20:33 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |   #buildItemQtyDiv(item) { | 
					
						
							|  |  |  |     const itemQtyDiv = document.createElement('div'); | 
					
						
							|  |  |  |     itemQtyDiv.classList.add('item-qty-div'); | 
					
						
							|  |  |  |     itemQtyDiv.setAttribute('id', `${this.name}-${item}`); | 
					
						
							|  |  |  |     itemQtyDiv.setAttribute('data-game', this.name); | 
					
						
							|  |  |  |     itemQtyDiv.setAttribute('data-item', item); | 
					
						
							|  |  |  |     itemQtyDiv.setAttribute('draggable', 'true'); | 
					
						
							|  |  |  |     itemQtyDiv.innerText = item; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const inputWrapper = document.createElement('div'); | 
					
						
							|  |  |  |     inputWrapper.classList.add('item-qty-input-wrapper') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const itemQty = document.createElement('input'); | 
					
						
							|  |  |  |     itemQty.setAttribute('value', this.current.start_inventory.hasOwnProperty(item) ? | 
					
						
							|  |  |  |       this.current.start_inventory[item] : '1'); | 
					
						
							|  |  |  |     itemQty.setAttribute('data-game', this.name); | 
					
						
							|  |  |  |     itemQty.setAttribute('data-setting', 'start_inventory'); | 
					
						
							|  |  |  |     itemQty.setAttribute('data-option', item); | 
					
						
							|  |  |  |     itemQty.setAttribute('maxlength', '3'); | 
					
						
							|  |  |  |     itemQty.addEventListener('keyup', (evt) => { | 
					
						
							|  |  |  |       evt.target.value = isNaN(parseInt(evt.target.value)) ? 0 : parseInt(evt.target.value); | 
					
						
							|  |  |  |       this.#updateItemSetting(evt); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     inputWrapper.appendChild(itemQty); | 
					
						
							|  |  |  |     itemQtyDiv.appendChild(inputWrapper); | 
					
						
							| 
									
										
										
										
											2022-01-08 19:59:35 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     itemQtyDiv.addEventListener('dragstart', (evt) => { | 
					
						
							|  |  |  |       evt.dataTransfer.setData('text/plain', itemQtyDiv.getAttribute('id')); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return itemQtyDiv; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-01-08 19:59:35 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |   #itemDropHandler(evt) { | 
					
						
							|  |  |  |     evt.preventDefault(); | 
					
						
							|  |  |  |     const sourceId = evt.dataTransfer.getData('text/plain'); | 
					
						
							|  |  |  |     const sourceDiv = document.getElementById(sourceId); | 
					
						
							| 
									
										
										
										
											2022-01-08 19:59:35 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     const item = sourceDiv.getAttribute('data-item'); | 
					
						
							| 
									
										
										
										
											2022-01-08 19:59:35 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     const oldSetting = sourceDiv.hasAttribute('data-setting') ? sourceDiv.getAttribute('data-setting') : null; | 
					
						
							|  |  |  |     const newSetting = evt.target.hasAttribute('data-setting') ? evt.target.getAttribute('data-setting') : null; | 
					
						
							| 
									
										
										
										
											2022-01-11 04:20:33 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     const itemDiv = newSetting === 'start_inventory' ? this.#buildItemQtyDiv(item) : this.#buildItemDiv(item); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (oldSetting) { | 
					
						
							|  |  |  |       if (oldSetting === 'start_inventory') { | 
					
						
							|  |  |  |         if (this.current[oldSetting].hasOwnProperty(item)) { | 
					
						
							|  |  |  |           delete this.current[oldSetting][item]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         if (this.current[oldSetting].includes(item)) { | 
					
						
							|  |  |  |           this.current[oldSetting].splice(this.current[oldSetting].indexOf(item), 1); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-01-11 04:20:33 -05:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-01-08 19:59:35 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     if (newSetting) { | 
					
						
							|  |  |  |       itemDiv.setAttribute('data-setting', newSetting); | 
					
						
							|  |  |  |       document.getElementById(`${this.name}-${newSetting}`).appendChild(itemDiv); | 
					
						
							|  |  |  |       if (newSetting === 'start_inventory') { | 
					
						
							|  |  |  |         this.current[newSetting][item] = 1; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         if (!this.current[newSetting].includes(item)){ | 
					
						
							|  |  |  |           this.current[newSetting].push(item); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-01-11 04:20:33 -05:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     } else { | 
					
						
							|  |  |  |       // No setting was assigned, this item has been removed from the settings
 | 
					
						
							|  |  |  |       document.getElementById(`${this.name}-available_items`).appendChild(itemDiv); | 
					
						
							| 
									
										
										
										
											2022-01-08 19:59:35 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     // Remove the source drag object
 | 
					
						
							|  |  |  |     sourceDiv.parentElement.removeChild(sourceDiv); | 
					
						
							| 
									
										
										
										
											2022-01-08 19:59:35 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     // Save the updated settings
 | 
					
						
							|  |  |  |     this.save(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-01-08 19:59:35 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |   #buildHintsDiv() { | 
					
						
							|  |  |  |     const hintsDiv = document.createElement('div'); | 
					
						
							|  |  |  |     hintsDiv.classList.add('hints-div'); | 
					
						
							|  |  |  |     const hintsHeader = document.createElement('h3'); | 
					
						
							|  |  |  |     hintsHeader.innerText = 'Item & Location Hints'; | 
					
						
							|  |  |  |     hintsDiv.appendChild(hintsHeader); | 
					
						
							|  |  |  |     const hintsDescription = document.createElement('p'); | 
					
						
							|  |  |  |     hintsDescription.classList.add('setting-description'); | 
					
						
							|  |  |  |     hintsDescription.innerText = 'Choose any items or locations to begin the game with the knowledge of where those ' + | 
					
						
							|  |  |  |       ' items are, or what those locations contain.'; | 
					
						
							|  |  |  |     hintsDiv.appendChild(hintsDescription); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const itemHintsContainer = document.createElement('div'); | 
					
						
							|  |  |  |     itemHintsContainer.classList.add('hints-container'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Item Hints
 | 
					
						
							|  |  |  |     const itemHintsWrapper = document.createElement('div'); | 
					
						
							|  |  |  |     itemHintsWrapper.classList.add('hints-wrapper'); | 
					
						
							|  |  |  |     itemHintsWrapper.innerText = 'Starting Item Hints'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-31 14:25:07 -07:00
										 |  |  |     const itemHintsDiv = this.#buildItemsDiv('start_hints'); | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     itemHintsWrapper.appendChild(itemHintsDiv); | 
					
						
							|  |  |  |     itemHintsContainer.appendChild(itemHintsWrapper); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Starting Location Hints
 | 
					
						
							|  |  |  |     const locationHintsWrapper = document.createElement('div'); | 
					
						
							|  |  |  |     locationHintsWrapper.classList.add('hints-wrapper'); | 
					
						
							|  |  |  |     locationHintsWrapper.innerText = 'Starting Location Hints'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-31 14:25:07 -07:00
										 |  |  |     const locationHintsDiv = this.#buildLocationsDiv('start_location_hints'); | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     locationHintsWrapper.appendChild(locationHintsDiv); | 
					
						
							|  |  |  |     itemHintsContainer.appendChild(locationHintsWrapper); | 
					
						
							| 
									
										
										
										
											2022-01-11 01:26:12 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     hintsDiv.appendChild(itemHintsContainer); | 
					
						
							|  |  |  |     return hintsDiv; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-03-29 17:37:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-31 14:25:07 -07:00
										 |  |  |   #buildPriorityExclusionDiv() { | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     const locationsDiv = document.createElement('div'); | 
					
						
							|  |  |  |     locationsDiv.classList.add('locations-div'); | 
					
						
							|  |  |  |     const locationsHeader = document.createElement('h3'); | 
					
						
							|  |  |  |     locationsHeader.innerText = 'Priority & Exclusion Locations'; | 
					
						
							|  |  |  |     locationsDiv.appendChild(locationsHeader); | 
					
						
							|  |  |  |     const locationsDescription = document.createElement('p'); | 
					
						
							|  |  |  |     locationsDescription.classList.add('setting-description'); | 
					
						
							|  |  |  |     locationsDescription.innerText = 'Priority locations guarantee a progression item will be placed there while ' + | 
					
						
							|  |  |  |       'excluded locations will not contain progression or useful items.'; | 
					
						
							|  |  |  |     locationsDiv.appendChild(locationsDescription); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const locationsContainer = document.createElement('div'); | 
					
						
							|  |  |  |     locationsContainer.classList.add('locations-container'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Priority Locations
 | 
					
						
							|  |  |  |     const priorityLocationsWrapper = document.createElement('div'); | 
					
						
							|  |  |  |     priorityLocationsWrapper.classList.add('locations-wrapper'); | 
					
						
							|  |  |  |     priorityLocationsWrapper.innerText = 'Priority Locations'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-31 14:25:07 -07:00
										 |  |  |     const priorityLocationsDiv = this.#buildLocationsDiv('priority_locations'); | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     priorityLocationsWrapper.appendChild(priorityLocationsDiv); | 
					
						
							|  |  |  |     locationsContainer.appendChild(priorityLocationsWrapper); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Exclude Locations
 | 
					
						
							|  |  |  |     const excludeLocationsWrapper = document.createElement('div'); | 
					
						
							|  |  |  |     excludeLocationsWrapper.classList.add('locations-wrapper'); | 
					
						
							|  |  |  |     excludeLocationsWrapper.innerText = 'Exclude Locations'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-31 14:25:07 -07:00
										 |  |  |     const excludeLocationsDiv = this.#buildLocationsDiv('exclude_locations'); | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     excludeLocationsWrapper.appendChild(excludeLocationsDiv); | 
					
						
							|  |  |  |     locationsContainer.appendChild(excludeLocationsWrapper); | 
					
						
							| 
									
										
										
										
											2022-01-10 23:20:15 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     locationsDiv.appendChild(locationsContainer); | 
					
						
							|  |  |  |     return locationsDiv; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-01-11 01:26:12 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-31 14:25:07 -07:00
										 |  |  |   // Builds a div for a setting whose value is a list of locations.
 | 
					
						
							|  |  |  |   #buildLocationsDiv(setting) { | 
					
						
							| 
									
										
										
										
											2023-11-10 22:06:54 -08:00
										 |  |  |     return this.#buildListDiv(setting, this.data.gameLocations, { | 
					
						
							|  |  |  |       groups: this.data.gameLocationGroups, | 
					
						
							|  |  |  |       descriptions: this.data.gameLocationDescriptions, | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2023-10-31 14:25:07 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Builds a div for a setting whose value is a list of items.
 | 
					
						
							|  |  |  |   #buildItemsDiv(setting) { | 
					
						
							| 
									
										
										
										
											2023-11-10 22:06:54 -08:00
										 |  |  |     return this.#buildListDiv(setting, this.data.gameItems, { | 
					
						
							|  |  |  |       groups: this.data.gameItemGroups, | 
					
						
							|  |  |  |       descriptions: this.data.gameItemDescriptions | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2023-10-31 14:25:07 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // 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.
 | 
					
						
							| 
									
										
										
										
											2023-11-10 22:06:54 -08:00
										 |  |  |   //
 | 
					
						
							|  |  |  |   // The `descriptions` option can be a map from item names or group names to
 | 
					
						
							|  |  |  |   // descriptions for the user's benefit.
 | 
					
						
							|  |  |  |   #buildListDiv(setting, items, {groups = [], descriptions = {}} = {}) { | 
					
						
							| 
									
										
										
										
											2023-10-31 14:25:07 -07:00
										 |  |  |     const div = document.createElement('div'); | 
					
						
							|  |  |  |     div.classList.add('simple-list'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     groups.forEach((group) => { | 
					
						
							| 
									
										
										
										
											2023-11-10 22:06:54 -08:00
										 |  |  |       const row = this.#addListRow(setting, group, descriptions[group]); | 
					
						
							| 
									
										
										
										
											2023-10-31 14:25:07 -07:00
										 |  |  |       div.appendChild(row); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (groups.length > 0) { | 
					
						
							|  |  |  |       div.appendChild(document.createElement('hr')); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     items.forEach((item) => { | 
					
						
							| 
									
										
										
										
											2023-11-10 22:06:54 -08:00
										 |  |  |       const row = this.#addListRow(setting, item, descriptions[item]); | 
					
						
							| 
									
										
										
										
											2023-10-31 14:25:07 -07:00
										 |  |  |       div.appendChild(row); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return div; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Builds and returns a row for a list of checkboxes.
 | 
					
						
							| 
									
										
										
										
											2023-11-10 22:06:54 -08:00
										 |  |  |   //
 | 
					
						
							|  |  |  |   // If `help` is passed, it's displayed as a help tooltip for this list item.
 | 
					
						
							|  |  |  |   #addListRow(setting, item, help = undefined) { | 
					
						
							| 
									
										
										
										
											2023-10-31 14:25:07 -07:00
										 |  |  |     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; | 
					
						
							| 
									
										
										
										
											2023-11-10 22:06:54 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (help) { | 
					
						
							|  |  |  |       const helpSpan = document.createElement('span'); | 
					
						
							|  |  |  |       helpSpan.classList.add('interactive'); | 
					
						
							|  |  |  |       helpSpan.setAttribute('data-tooltip', help); | 
					
						
							|  |  |  |       helpSpan.innerText = '(?)'; | 
					
						
							|  |  |  |       name.innerText += ' '; | 
					
						
							|  |  |  |       name.appendChild(helpSpan); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Put the first 7 tooltips below their rows. CSS tooltips in scrolling
 | 
					
						
							|  |  |  |       // containers can't be visible outside those containers, so this helps
 | 
					
						
							|  |  |  |       // ensure they won't be pushed out the top.
 | 
					
						
							|  |  |  |       if (helpSpan.parentNode.childNodes.length < 7) { | 
					
						
							|  |  |  |         helpSpan.classList.add('tooltip-bottom'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-31 14:25:07 -07:00
										 |  |  |     label.appendChild(name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     row.appendChild(label); | 
					
						
							|  |  |  |     return row; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |   #updateRangeSetting(evt) { | 
					
						
							|  |  |  |     const setting = evt.target.getAttribute('data-setting'); | 
					
						
							|  |  |  |     const option = evt.target.getAttribute('data-option'); | 
					
						
							|  |  |  |     document.getElementById(`${this.name}-${setting}-${option}`).innerText = evt.target.value; | 
					
						
							|  |  |  |     if (evt.action && evt.action === 'rangeDelete') { | 
					
						
							|  |  |  |       delete this.current[setting][option]; | 
					
						
							| 
									
										
										
										
											2022-01-02 16:31:49 -05:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |       this.current[setting][option] = parseInt(evt.target.value, 10); | 
					
						
							| 
									
										
										
										
											2022-01-02 16:31:49 -05:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     this.save(); | 
					
						
							| 
									
										
										
										
											2022-01-01 16:59:58 -05:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |   #updateListSetting(evt) { | 
					
						
							|  |  |  |     const setting = evt.target.getAttribute('data-setting'); | 
					
						
							|  |  |  |     const option = evt.target.getAttribute('data-option'); | 
					
						
							| 
									
										
										
										
											2023-03-29 17:37:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     if (evt.target.checked) { | 
					
						
							|  |  |  |       // If the option is to be enabled and it is already enabled, do nothing
 | 
					
						
							|  |  |  |       if (this.current[setting].includes(option)) { return; } | 
					
						
							| 
									
										
										
										
											2023-03-29 17:37:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |       this.current[setting].push(option); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       // If the option is to be disabled and it is already disabled, do nothing
 | 
					
						
							|  |  |  |       if (!this.current[setting].includes(option)) { return; } | 
					
						
							| 
									
										
										
										
											2022-01-02 18:45:45 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |       this.current[setting].splice(this.current[setting].indexOf(option), 1); | 
					
						
							| 
									
										
										
										
											2022-01-02 18:45:45 -05:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |     this.save(); | 
					
						
							| 
									
										
										
										
											2022-01-11 02:26:11 -05:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |   #updateItemSetting(evt) { | 
					
						
							|  |  |  |     const setting = evt.target.getAttribute('data-setting'); | 
					
						
							|  |  |  |     const option = evt.target.getAttribute('data-option'); | 
					
						
							|  |  |  |     if (setting === 'start_inventory') { | 
					
						
							|  |  |  |       this.current[setting][option] = evt.target.value.trim() ? parseInt(evt.target.value) : 0; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       this.current[setting][option] = isNaN(evt.target.value) ? | 
					
						
							|  |  |  |         evt.target.value : parseInt(evt.target.value, 10); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this.save(); | 
					
						
							| 
									
										
										
										
											2023-09-11 21:17:11 +00:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  |   // Saves the current settings to local storage.
 | 
					
						
							|  |  |  |   save() { | 
					
						
							|  |  |  |     this.#allSettings.save(); | 
					
						
							| 
									
										
										
										
											2022-01-11 01:56:14 -05:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-10-18 15:26:52 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-12-31 14:42:04 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** Create an anchor and trigger a download of a text file. */ | 
					
						
							|  |  |  | const download = (filename, text) => { | 
					
						
							|  |  |  |   const downloadLink = document.createElement('a'); | 
					
						
							|  |  |  |   downloadLink.setAttribute('href','data:text/yaml;charset=utf-8,'+ encodeURIComponent(text)) | 
					
						
							|  |  |  |   downloadLink.setAttribute('download', filename); | 
					
						
							|  |  |  |   downloadLink.style.display = 'none'; | 
					
						
							|  |  |  |   document.body.appendChild(downloadLink); | 
					
						
							|  |  |  |   downloadLink.click(); | 
					
						
							|  |  |  |   document.body.removeChild(downloadLink); | 
					
						
							|  |  |  | }; |