Skip to content

Commit 5d067ec

Browse files
authored
Merge pull request #54 from ManualForArchipelago/adding-Option.json
Adding options.json
2 parents 4d8e449 + 85ec7db commit 5d067ec

File tree

9 files changed

+606
-63
lines changed

9 files changed

+606
-63
lines changed

schemas/Manual.options.schema.json

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"$id": "https://raw.githubusercontent.com/ManualForArchipelago/Manual/main/schemas/Manual.options.schema.json",
4+
"description": "Schema for Manual's options.json",
5+
"type": "object",
6+
"properties": {
7+
"$schema": {
8+
"description": "The schema to verify this document against.",
9+
"type":"string"
10+
11+
},
12+
"core": {
13+
"description": "Dictionary of the Modifications of Core Options of Manual",
14+
"type": "object",
15+
"patternProperties": {
16+
"^_.*$": {
17+
"description": "A commented out Option Modification",
18+
"$ref": "#/definitions/OptionCore"
19+
},
20+
"^.*$": {
21+
"description": "A Modification of a Core Option of Manual",
22+
"$ref": "#/definitions/OptionCore"
23+
}
24+
}
25+
},
26+
"user": {
27+
"description": "Dictionary of options for this apworld",
28+
"type": "object",
29+
"patternProperties": {
30+
"^_.*$": {
31+
"description": "A commented out Option",
32+
"allOf": [{"$ref": "#/definitions/OptionBase"}],
33+
"properties": {
34+
"type": {"$ref": "#/definitions/Type"}
35+
}
36+
},
37+
"^.*$": {
38+
"description": "An Option for your World, the possible properties depend on the type of option you set in \"type\"\nToggle: \"default\"* \n Let the player choose between yes or no \nChoice: \"values\"*, \"aliases\", \"default\" and \"allow_custom_value\" \n Let the player pick from a list of values \nRange: \"range_start\", \"range_end\", \"default\" and an \"values\"\nAllow the player to specify a number between 'start' and 'end'",
39+
"$ref": "#/definitions/OptionUser"
40+
}
41+
}
42+
},
43+
"_comment": {"$ref": "#/definitions/comment"}
44+
},
45+
"definitions": {
46+
"OptionBase": {
47+
"$comment": "The basic properties of an Option that are safe to modify",
48+
"type": "object",
49+
"properties": {
50+
"display_name": {
51+
"description": "(Optional) The name shown in the spoiler logs and on the website options pages",
52+
"type": "string"
53+
},
54+
"description": {
55+
"description": "(Optional) A long description of what this option is for, as shown in the yaml template or on hover of the (?) on the website options pages",
56+
"type": ["array", "string"],
57+
"items": {"type": "string"}
58+
},
59+
"rich_text_doc": {
60+
"description": "(Optional) Enables support for HTML generated from the standard Python reStructuredText format for your description. \nfor more info: https://github.com/ArchipelagoMW/Archipelago/blob/main/docs/options%20api.md#option-documentation",
61+
"type": "boolean",
62+
"default": false
63+
},
64+
"group": {
65+
"description": "(Optional) The name of the group this option is a part of on the website options pages",
66+
"type": "string",
67+
"default": "Game Options",
68+
"examples": ["Item & Location Options", "Example Options", "Option Group Name"]
69+
},
70+
"hidden": {
71+
"description": "(Optional) Should this option be Hidden everywhere? Use Visibility instead for a more precise control",
72+
"type": "boolean",
73+
"default": false
74+
},
75+
"visibility": {
76+
"description": "(Optional) (Advanced) Specify where this option can be seen. \nIt can be represented by the value names, an array of those, \nthe binary string representation of that choice (\"0b1111\") or the integer value of the binary \nEvery example values other than 'none' and 'all' gives the same results aka 14 aka 0b1110 aka that array \nMore info at https://github.com/ArchipelagoMW/Archipelago/blob/main/docs/options%20api.md#option-visibility",
77+
"type":["string","array","integer"],
78+
"items": {"type": "string", "enum": [ "template", "simple_ui", "complex_ui", "spoiler"]},
79+
"default": "all",
80+
"examples": ["none", "0b1110", ["spoiler", "simple_ui", "complex_ui"], 14 ],
81+
"if": {"type":"string", "pattern": "0b[01]..."},
82+
"else": {"if": {"type": "string"}, "then": {"enum": ["all", "none", "template", "simple_ui", "complex_ui", "spoiler"]} }
83+
},
84+
"_comment": {"$ref": "#/definitions/comment"}
85+
}
86+
},
87+
"OptionUser": {
88+
"type": "object",
89+
"$comment": "The version with all the type logic aka normal options",
90+
"allOf": [{"$ref": "#/definitions/OptionBase"}],
91+
"properties": {
92+
"type": {"$ref": "#/definitions/Type"}
93+
},
94+
"required": ["type"],
95+
"if": {"properties": { "type": {"const": "Toggle"}}},
96+
"then": {
97+
"properties": {
98+
"default": { "$ref": "#/definitions/DefaultToggle"}
99+
},
100+
"required": ["default", "type"]
101+
},
102+
"else": {
103+
"if": {"properties": { "type": {"const": "Choice"}}},
104+
"then": {
105+
"properties": {
106+
"values": {"$ref": "#/definitions/ChoiceValue"},
107+
"aliases": {"$ref": "#/definitions/ChoiceAlias"},
108+
"default": {"$ref": "#/definitions/DefaultInt"},
109+
"allow_custom_value": { "$ref": "#/definitions/ChoiceAllowCustomValue"}
110+
},
111+
"required": ["values", "type"]
112+
},
113+
"else": {
114+
"if": {"properties": { "type": {"const": "Range"}}},
115+
"then": {
116+
"properties": {
117+
"range_start": {"$ref": "#/definitions/RangeStart"},
118+
"range_end": {"$ref": "#/definitions/RangeEnd"},
119+
"default": {"$ref": "#/definitions/DefaultInt"},
120+
"values":{"$ref": "#/definitions/SpecialRangeNames"}
121+
}
122+
}
123+
}
124+
}
125+
},
126+
"OptionCore":{
127+
"type": "object",
128+
"allOf": [{"$ref": "#/definitions/OptionBase"}],
129+
"properties": {
130+
"default": {"$ref": "#/definitions/DefaultCore"},
131+
"aliases": {"$ref": "#/definitions/ChoiceAlias"},
132+
"values":{"$ref": "#/definitions/SpecialRangeNames_core"}
133+
}
134+
},
135+
136+
"Type": {
137+
"description": "The type of this options. \nHover your mouse on any uncommented option's name to get a list of valid types for Manual options and a short description for each",
138+
"type": "string",
139+
"enum": ["Toggle", "Choice", "Range"]
140+
},
141+
"ChoiceValue": {
142+
"description": "A dictionary of possible values in the format {\"name\":0, \"other name\":2} \nUnless the default is changed, there need to be a defined value of 0.",
143+
"type":"object",
144+
"patternProperties": {
145+
"^.*$": {
146+
"description": "An int value this option can have",
147+
"type": "integer"
148+
}
149+
}
150+
151+
},
152+
"ChoiceAlias": {
153+
"description": "(Optional) A dictionary of aliases in the format {\"name\":0, \"other name\":2} or {\"name\":\"name of another value/alias\"}",
154+
"type": "object",
155+
"patternProperties": {
156+
"^.*$": {
157+
"description": "An alias for one of this option's value",
158+
"type": ["integer", "string"]
159+
}
160+
}
161+
},
162+
"ChoiceAllowCustomValue": {
163+
"description": "(Optional) Allow the user to set their own custom string Value",
164+
"type": "boolean",
165+
"default": false
166+
},
167+
"RangeStart": {
168+
"type": "integer",
169+
"description": "(Optional) The lowest Value for this range",
170+
"default": 0
171+
},
172+
"RangeEnd": {
173+
"type":"integer",
174+
"description": "(Optional) The Highest Value for this range",
175+
"default": 1
176+
},
177+
"SpecialRangeNames_base": {
178+
"type":"object",
179+
"patternProperties": {
180+
"^.*$": {
181+
"description": "A named numerical value",
182+
"type": "integer"
183+
}
184+
},
185+
"default": {},
186+
"examples": [{"test": 1}]
187+
},
188+
"SpecialRangeNames": {
189+
"description": "(Optional) A Special Dictionary in the format {\"name\":0, \"other name\":2} of named values for this range \nAll names need to be lowercase",
190+
"allOf": [{"$ref": "#/definitions/SpecialRangeNames_base"}]
191+
},
192+
"SpecialRangeNames_core": {
193+
"description": "(Optional) A Special Dictionary in the format {\"name\":0, \"other name\":2} of named values for this range \nAll names need to be lowercase \nForbidden for Options of type Choice",
194+
"allOf": [{"$ref": "#/definitions/SpecialRangeNames_base"}]
195+
},
196+
"DefaultInt": {
197+
"description": "(Optional) The default integer value of this option",
198+
"type": "integer",
199+
"default": 0
200+
},
201+
"DefaultToggle": {
202+
"description": "The default value of this Toggle",
203+
"type": "boolean",
204+
"default": false
205+
},
206+
"DefaultCore": {
207+
"description": "The default value of this option, its type depend on the type of the option you are overriding",
208+
"type": ["integer", "boolean"]
209+
},
210+
"comment": {
211+
"description": "(Optional) Does nothing, Its mainly here for Dev notes for future devs to understand your logic",
212+
"type": ["string", "array"],
213+
"items": {
214+
"description": "A line of comment",
215+
"type":"string"
216+
}
217+
}
218+
}
219+
}

schemas/Manual.schema.catalog.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,13 @@
3636
"description": "meta.json schema file for APWorlds created with Manual",
3737
"fileMatch": [ "**/manual*/data/meta.json" ],
3838
"url": "https://raw.githubusercontent.com/ManualForArchipelago/Manual/main/schemas/Manual.meta.schema.json"
39+
},
40+
{
41+
"name": "Manual options.json",
42+
"description": "options.json schema file for APWorlds created with Manual",
43+
"fileMatch": [ "**/manual*/data/options.json" ],
44+
"url": "https://raw.githubusercontent.com/ManualForArchipelago/Manual/main/schemas/Manual.options.schema.json"
3945
}
4046
],
41-
"version": 20240429.01
47+
"version": 20240721.01
4248
}

src/Data.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
after_load_game_file, \
88
after_load_item_file, after_load_location_file, \
99
after_load_region_file, after_load_category_file, \
10-
after_load_meta_file
10+
after_load_option_file, after_load_meta_file
1111

1212
# blatantly copied from the minecraft ap world because why not
1313
def load_data_file(*args) -> dict:
@@ -19,7 +19,6 @@ def convert_to_list(data, property_name: str) -> list:
1919
data = data.get(property_name, [])
2020
return data
2121

22-
2322
class ManualFile:
2423
filename: str
2524
data_type: dict|list
@@ -42,6 +41,7 @@ def load(self):
4241
location_table = convert_to_list(ManualFile('locations.json', list).load(), 'data') #list
4342
region_table = ManualFile('regions.json', dict).load() #dict
4443
category_table = ManualFile('categories.json', dict).load() #dict
44+
option_table = ManualFile('options.json', dict).load() #dict
4545
meta_table = ManualFile('meta.json', dict).load() #dict
4646

4747
# Removal of schemas in root of tables
@@ -54,6 +54,7 @@ def load(self):
5454
location_table = after_load_location_file(location_table)
5555
region_table = after_load_region_file(region_table)
5656
category_table = after_load_category_file(category_table)
57+
option_table = after_load_option_file(option_table)
5758
meta_table = after_load_meta_file(meta_table)
5859

5960
# seed all of the tables for validation

src/Helpers.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,9 @@ def get_items_with_value(world: World, multiworld: MultiWorld, value: str, playe
155155
and i.name in world.item_name_groups.get(f'has_{value}_value', [])}
156156
world.item_values[player][value] = item_with_values
157157
return world.item_values[player].get(value)
158+
159+
def convert_to_long_string(input: str | list[str]) -> str:
160+
"""Verify that the input is a str. If it's a list[str] then it combine them into a str in a way that works with yaml template/website options descriptions"""
161+
if not isinstance(input, str):
162+
return str.join("\n ", input)
163+
return input

src/Meta.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from BaseClasses import Tutorial
33
from worlds.AutoWorld import World, WebWorld
44
from .Data import meta_table
5+
from .Helpers import convert_to_long_string
56

67
##############
78
# Meta Classes
@@ -20,26 +21,22 @@ class ManualWeb(WebWorld):
2021
# Convert meta.json data to properties
2122
######################################
2223
def set_world_description(base_doc: str) -> str:
23-
if meta_table.get("docs", {}).get("apworld_description", None) is None:
24-
return base_doc
24+
if meta_table.get("docs", {}).get("apworld_description"):
25+
return convert_to_long_string(meta_table["docs"]["apworld_description"])
2526

26-
if isinstance(meta_table["docs"]["apworld_description"], str):
27-
base_doc = meta_table["docs"]["apworld_description"]
28-
else:
29-
fullstring = ""
30-
for line in meta_table["docs"]["apworld_description"]:
31-
fullstring += "\n" + line
32-
base_doc = fullstring
3327
return base_doc
3428

29+
3530
def set_world_webworld(web: WebWorld) -> WebWorld:
31+
from .Options import make_options_group
3632
if meta_table.get("docs", {}).get("web", {}):
3733
Web_Config = meta_table["docs"]["web"]
3834

3935
web.theme = Web_Config.get("theme", web.theme)
4036
web.game_info_languages = Web_Config.get("game_info_languages", web.game_info_languages)
4137
web.options_presets = Web_Config.get("options_presets", web.options_presets)
4238
web.options_page = Web_Config.get("options_page", web.options_page)
39+
web.option_groups = make_options_group()
4340
if hasattr(web, 'bug_report_page'):
4441
web.bug_report_page = Web_Config.get("bug_report_page", web.bug_report_page)
4542
else:

0 commit comments

Comments
 (0)