-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsettings.js
151 lines (140 loc) · 5.7 KB
/
settings.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import { getDefaultGameplaySettings } from "./default-settings.js";
let settings = {"GameplaySettings": {}};
/**
* Sets the current settings to the provided settings, filling in default values as needed.
* Does not clear or modify unrecognized settings in the provided object; this way users can
* upload and modify their settings.json without losing CosmeticSettings or other new settings.
*
* @returns Warning to show, if any, upon upload. A list of strings where each element will
* display as one line of warning.
*/
export function setSettings(newSettings) {
settings = newSettings;
const gpSettings = settings["GameplaySettings"];
// If EnabledTricks is not defined, explicitly set it to the default.
// Otherwise, modifying tricks list will clear the default-enabled tricks.
// Same for ShortenCutsceneSettings.
const defaultGpSettings = getDefaultGameplaySettings();
if (!gpSettings["EnabledTricks"]) {
gpSettings["EnabledTricks"] = getDefaultGameplaySettings()["EnabledTricks"];
}
if (!gpSettings["ShortenCutsceneSettings"]) {
gpSettings["ShortenCutsceneSettings"] = defaultGpSettings["ShortenCutsceneSettings"];
} else {
const scSettings = gpSettings["ShortenCutsceneSettings"];
// Note that "" is not a valid value for cutscene lists; to specify no cutscenes, it must be "None".
if (!scSettings["General"]) {
scSettings["General"] = defaultGpSettings["ShortenCutsceneSettings"]["General"];
}
if (!scSettings["BossIntros"]) {
scSettings["BossIntros"] = defaultGpSettings["ShortenCutsceneSettings"]["BossIntros"];
}
}
const customItems = "CustomItemListString";
const customStarting = "CustomStartingItemListString";
const customJunk = "CustomJunkLocationsString";
if (!gpSettings[customItems] && !gpSettings[customStarting] && !gpSettings[customJunk]) {
return [];
}
const warnings = ["Warning: This page cannot yet interpret custom item strings."];
if (gpSettings[customItems]) {
warnings.push("Categories to randomize must be configured manually using the below form.");
// Remove custom item string from settings.
// This is just cleanup for clarity; adding ItemCategoriesRandomized, LocationCategoriesRandomized, or
// ClassicCategoriesRandomized causes custom item string to be ignored.
// TODO Would it be better to keep the custom item string until user modifies checks to randomize?
// Enables use case where user wants to change other settings but keep the same checks randomized.
delete gpSettings[customItems];
}
if (gpSettings[customStarting] || gpSettings[customJunk]) {
warnings.push("Starting items and junk locations will be preserved as configured in the uploaded settings.");
}
return warnings;
}
/** Returns current active settings */
export function getSettings() {
return settings;
}
/** Update current settings from a form element change */
export function update(changedFormElement) {
switch (changedFormElement.tagName) {
case "INPUT":
if (changedFormElement.type !== "checkbox") {
console.warn(`Warning: Unhandled input type ${changedFormElement.type}`);
break;
}
updateCheckbox(changedFormElement);
break;
case "SELECT":
updateDropdown(changedFormElement);
break;
default:
console.warn(`Warning: Unhandled update element ${changedFormElement.tagName}`);
}
}
function updateCheckbox(checkbox) {
const gpSettings = settings["GameplaySettings"];
let listName;
switch(checkbox.className) {
// Top level checkbox
case "gpCheckbox":
gpSettings[checkbox.name] = checkbox.checked;
break;
// Item randomization checkboxes
case "item_cat":
listName = "ItemCategoriesRandomized";
case "location_cat":
listName = listName || "LocationCategoriesRandomized";
case "classic_cat":
listName = listName || "ClassicCategoriesRandomized";
case "tricks":
listName = listName || "EnabledTricks";
const checklist = getOrCreateList(gpSettings, listName);
updateChecklist(checkbox.name, checkbox.checked, checklist);
break;
case "cutscene_general":
listName = "General";
case "cutscene_bossintros":
listName = listName || "BossIntros";
// Cutscene setting lists have to work a little differently because the shortened cutscene
// setting has a string format like "BossIntros": "Odolwa, Goht, Gyorg, Majora"
const shortenCutsceneSettings = getOrCreateObj(gpSettings, "ShortenCutsceneSettings");
const cutsceneListStr = shortenCutsceneSettings[listName];
const cutsceneList = cutsceneListStr === "None" ? [] : cutsceneListStr.split(", ");
updateChecklist(checkbox.name, checkbox.checked, cutsceneList);
shortenCutsceneSettings[listName] = cutsceneList.length ? cutsceneList.join(", ") : "None";
break;
default:
console.warn(`Warning: Unhandled checkbox class ${checkbox.className}`);
}
}
function getOrCreateList(obj, listName) {
const list = obj[listName] || [];
obj[listName] = list;
return list;
}
function getOrCreateObj(parentObj, objName) {
const obj = parentObj[objName] || {};
parentObj[objName] = obj;
return obj;
}
function updateChecklist(checkboxName, isChecked, list) {
if (isChecked) {
if (list.indexOf(checkboxName) === -1) {
list.push(checkboxName);
}
} else {
const settingIndex = list.indexOf(checkboxName);
if (settingIndex !== -1) {
list.splice(settingIndex, 1);
}
}
}
function updateDropdown(dropdown) {
if (dropdown.name === "RequiredBossRemains") {
// TODO: Probably a cleaner way to do this.
settings["GameplaySettings"][dropdown.name] = parseInt(dropdown.value);
} else {
settings["GameplaySettings"][dropdown.name] = dropdown.value;
}
}