@@ -22,8 +22,8 @@ allows using WebSockets.
22
22
23
23
## Coding style
24
24
25
- AP follows all the PEPs. When in doubt use an IDE with coding style
26
- linter, for example PyCharm Community Edition.
25
+ AP follows [ style.md ] ( https://github.com/ArchipelagoMW/Archipelago/blob/main/docs/ style.md ) .
26
+ When in doubt use an IDE with coding style linter, for example PyCharm Community Edition.
27
27
28
28
29
29
## Docstrings
@@ -44,7 +44,7 @@ class MyGameWorld(World):
44
44
## Definitions
45
45
46
46
This section will cover various classes and objects you can use for your world.
47
- While some of the attributes and methods are mentioned here not all of them are,
47
+ While some of the attributes and methods are mentioned here, not all of them are,
48
48
but you can find them in ` BaseClasses.py ` .
49
49
50
50
### World Class
@@ -56,11 +56,12 @@ game.
56
56
### WebWorld Class
57
57
58
58
A ` WebWorld ` class contains specific attributes and methods that can be modified
59
- for your world specifically on the webhost.
59
+ for your world specifically on the webhost:
60
60
61
- ` settings_page ` which can be changed to a link instead of an AP generated settings page.
61
+ ` settings_page ` , which can be changed to a link instead of an AP generated settings page.
62
62
63
63
` theme ` to be used for your game specific AP pages. Available themes:
64
+
64
65
| dirt | grass (default) | grassFlowers | ice | jungle | ocean | partyTime | stone |
65
66
| ---| ---| ---| ---| ---| ---| ---| ---|
66
67
| <img src =" img/theme_dirt.JPG " width =" 100 " > | <img src =" img/theme_grass.JPG " width =" 100 " > | <img src =" img/theme_grassFlowers.JPG " width =" 100 " > | <img src =" img/theme_ice.JPG " width =" 100 " > | <img src =" img/theme_jungle.JPG " width =" 100 " > | <img src =" img/theme_ocean.JPG " width =" 100 " > | <img src =" img/theme_partyTime.JPG " width =" 100 " > | <img src =" img/theme_stone.JPG " width =" 100 " > |
@@ -75,26 +76,27 @@ prefixed with the same string as defined here. Default already has 'en'.
75
76
### MultiWorld Object
76
77
77
78
The ` MultiWorld ` object references the whole multiworld (all items and locations
78
- for all players) and is accessible through ` self.world ` inside a ` World ` object.
79
+ for all players) and is accessible through ` self.multiworld ` inside a ` World ` object.
79
80
80
81
### Player
81
82
82
83
The player is just an integer in AP and is accessible through ` self.player `
83
- inside a World object.
84
+ inside a ` World ` object.
84
85
85
86
### Player Options
86
87
87
88
Players provide customized settings for their World in the form of yamls.
88
- Those are accessible through ` self.world .<option_name>[self.player] ` . A dict
89
+ Those are accessible through ` self.multiworld .<option_name>[self.player] ` . A dict
89
90
of valid options has to be provided in ` self.option_definitions ` . Options are automatically
90
91
added to the ` World ` object for easy access.
91
92
92
- ### World Options
93
+ ### World Settings
93
94
94
- Any AP installation can provide settings for a world, for example a ROM file, accessible through ` self.settings.option `
95
- or ` cls.settings.option ` (new API) or ` Utils.get_options()["<world>_options"]["<option>"] ` (deprecated).
95
+ Any AP installation can provide settings for a world, for example a ROM file, accessible through
96
+ ` self.settings.<setting_name> ` or ` cls.settings.<setting_name> ` (new API)
97
+ or ` Utils.get_options()["<world>_options"]["<setting_name>"] ` (deprecated).
96
98
97
- Users can set those in their ` host.yaml ` file. Some options may automatically open a file browser if a file is missing.
99
+ Users can set those in their ` host.yaml ` file. Some settings may automatically open a file browser if a file is missing.
98
100
99
101
Refer to [ settings api.md] ( https://github.com/ArchipelagoMW/Archipelago/blob/main/docs/settings%20api.md )
100
102
for details.
@@ -135,10 +137,10 @@ same ID. Name must not be numeric (has to contain at least 1 letter or symbol).
135
137
Special items with ID ` None ` can mark events (read below).
136
138
137
139
Other classifications include
138
- * filler: a regular item or trash item
139
- * useful: generally quite useful, but not required for anything logical
140
- * trap: negative impact on the player
141
- * skip_balancing: add to progression to skip balancing; e.g. currency or tokens
140
+ * ` filler ` : a regular item or trash item
141
+ * ` useful ` : generally quite useful, but not required for anything logical
142
+ * ` trap ` : negative impact on the player
143
+ * ` skip_balancing ` : add to ` progression ` to skip balancing; e.g. currency or tokens
142
144
143
145
### Events
144
146
@@ -162,10 +164,10 @@ or more event locations based on player options.
162
164
163
165
Regions are logical groups of locations that share some common access rules. If
164
166
location logic is written from scratch, using regions greatly simplifies the
165
- definition and allow to somewhat easily implement things like entrance
167
+ definition and allows to somewhat easily implement things like entrance
166
168
randomizer in logic.
167
169
168
- Regions have a list called ` exits ` which are ` Entrance ` objects representing
170
+ Regions have a list called ` exits ` , which are ` Entrance ` objects representing
169
171
transitions to other regions.
170
172
171
173
There has to be one special region "Menu" from which the logic unfolds. AP
@@ -182,7 +184,7 @@ They can be static (regular logic) or be defined/connected during generation
182
184
### Access Rules
183
185
184
186
An access rule is a function that returns ` True ` or ` False ` for a ` Location ` or
185
- ` Entrance ` based on the the current ` state ` (items that can be collected).
187
+ ` Entrance ` based on the current ` state ` (items that can be collected).
186
188
187
189
### Item Rules
188
190
@@ -199,14 +201,14 @@ the `/worlds` directory. The starting point for the package is `__init__.py`.
199
201
Conventionally, your world class is placed in that file.
200
202
201
203
World classes must inherit from the ` World ` class in ` /worlds/AutoWorld.py ` ,
202
- which can be imported as ` worlds.AutoWorld. World ` from your package.
204
+ which can be imported as ` from worlds.AutoWorld import World` from your package.
203
205
204
206
AP will pick up your world automatically due to the ` AutoWorld ` implementation.
205
207
206
208
### Requirements
207
209
208
210
If your world needs specific python packages, they can be listed in
209
- ` world/[ world_name] /requirements.txt` . ModuleUpdate.py will automatically
211
+ ` worlds/< world_name> /requirements.txt` . ModuleUpdate.py will automatically
210
212
pick up and install them.
211
213
212
214
See [ pip documentation] ( https://pip.pypa.io/en/stable/cli/pip_install/#requirements-file-format ) .
@@ -217,7 +219,7 @@ AP will only import the `__init__.py`. Depending on code size it makes sense to
217
219
use multiple files and use relative imports to access them.
218
220
219
221
e.g. ` from .Options import mygame_options ` from your ` __init__.py ` will load
220
- ` world/[ world_name] /Options.py` and make its ` mygame_options ` accesible .
222
+ ` worlds/< world_name> /Options.py` and make its ` mygame_options ` accessible .
221
223
222
224
When imported names pile up it may be easier to use ` from . import Options `
223
225
and access the variable as ` Options.mygame_options ` .
@@ -228,12 +230,12 @@ function, see [apworld specification.md](apworld%20specification.md).
228
230
229
231
### Your Item Type
230
232
231
- Each world uses its own subclass of ` BaseClasses.Item ` . The constuctor can be
233
+ Each world uses its own subclass of ` BaseClasses.Item ` . The constructor can be
232
234
overridden to attach additional data to it, e.g. "price in shop".
233
235
Since the constructor is only ever called from your code, you can add whatever
234
236
arguments you like to the constructor.
235
237
236
- In its simplest form we only set the game name and use the default constuctor
238
+ In its simplest form we only set the game name and use the default constructor
237
239
``` python
238
240
from BaseClasses import Item
239
241
@@ -268,7 +270,7 @@ Each option has its own class, inherits from a base option type, has a docstring
268
270
to describe it and a ` display_name ` property for display on the website and in
269
271
spoiler logs.
270
272
271
- The actual name as used in the yaml is defined in a ` dict [str, Option ]` , that is
273
+ The actual name as used in the yaml is defined in a ` Dict [str, AssembleOptions ]` , that is
272
274
assigned to the world under ` self.option_definitions ` .
273
275
274
276
Common option types are ` Toggle ` , ` DefaultOnToggle ` , ` Choice ` , ` Range ` .
@@ -329,10 +331,10 @@ class FixXYZGlitch(Toggle):
329
331
display_name = " Fix XYZ Glitch"
330
332
331
333
# By convention we call the options dict variable `<world>_options`.
332
- mygame_options: typing.Dict[str , type (Option) ] = {
334
+ mygame_options: typing.Dict[str , AssembleOptions ] = {
333
335
" difficulty" : Difficulty,
334
336
" final_boss_hp" : FinalBossHP,
335
- " fix_xyz_glitch" : FixXYZGlitch
337
+ " fix_xyz_glitch" : FixXYZGlitch,
336
338
}
337
339
```
338
340
``` python
@@ -359,7 +361,6 @@ from .Items import mygame_items # data used below to add items to the World
359
361
from .Locations import mygame_locations # same as above
360
362
from worlds.AutoWorld import World
361
363
from BaseClasses import Region, Location, Entrance, Item, RegionType, ItemClassification
362
- from Utils import get_options, output_path
363
364
364
365
365
366
class MyGameItem (Item ): # or from Items import MyGameItem
@@ -385,7 +386,7 @@ class MyGameWorld(World):
385
386
topology_present = True # show path to required location checks in spoiler
386
387
387
388
# ID of first item and location, could be hard-coded but code may be easier
388
- # to read with this as a propery .
389
+ # to read with this as a property .
389
390
base_id = 1234
390
391
# Instead of dynamic numbering, IDs could be part of data.
391
392
@@ -400,7 +401,7 @@ class MyGameWorld(World):
400
401
# Items can be grouped using their names to allow easy checking if any item
401
402
# from that group has been collected. Group names can also be used for !hint
402
403
item_name_groups = {
403
- " weapons" : {" sword" , " lance" }
404
+ " weapons" : {" sword" , " lance" },
404
405
}
405
406
```
406
407
@@ -414,7 +415,7 @@ The world has to provide the following things for generation
414
415
* locations placed inside those regions
415
416
* a ` def create_item(self, item: str) -> MyGameItem ` to create any item on demand
416
417
* applying ` self.multiworld.push_precollected ` for start inventory
417
- * ` required_client_version: Tuple( int, int, int) `
418
+ * ` required_client_version: Tuple[ int, int, int] `
418
419
Optional client version as tuple of 3 ints to make sure the client is compatible to
419
420
this world (e.g. implements all required features) when connecting.
420
421
@@ -587,7 +588,7 @@ def set_rules(self) -> None:
587
588
# require one item from an item group
588
589
add_rule(self .multiworld.get_location(" Chest3" , self .player),
589
590
lambda state : state.has_group(" weapons" , self .player))
590
- # state also has .item_count() for items, .has_any() and.has_all() for sets
591
+ # state also has .item_count() for items, .has_any() and .has_all() for sets
591
592
# and .count_group() for groups
592
593
# set_rule is likely to be a bit faster than add_rule
593
594
@@ -625,7 +626,7 @@ public members with `mygame_`.
625
626
More advanced uses could be to add additional variables to the state object,
626
627
override ` World.collect(self, state, item) ` and ` remove(self, state, item) `
627
628
to update the state object, and check those added variables in added methods.
628
- Please do this with caution and only when neccessary .
629
+ Please do this with caution and only when necessary .
629
630
630
631
#### Sample
631
632
@@ -637,7 +638,7 @@ from worlds.AutoWorld import LogicMixin
637
638
class MyGameLogic (LogicMixin ):
638
639
def mygame_has_key (self , player : int ):
639
640
# Arguments above are free to choose
640
- # MultiWorld can be accessed through self.world , explicitly passing in
641
+ # MultiWorld can be accessed through self.multiworld , explicitly passing in
641
642
# MyGameWorld instance for easy options access is also a valid approach
642
643
return self .has(" key" , player) # or whatever
643
644
```
@@ -650,8 +651,8 @@ import .Logic # apply the mixin by importing its file
650
651
class MyGameWorld (World ):
651
652
# ...
652
653
def set_rules (self ):
653
- set_rule(self .world .get_location(" A Door" , self .player),
654
- lamda state: state.mygame_has_key(self .player))
654
+ set_rule(self .multiworld .get_location(" A Door" , self .player),
655
+ lambda state : state.mygame_has_key(self .player))
655
656
```
656
657
657
658
### Generate Output
@@ -679,14 +680,14 @@ def generate_output(self, output_directory: str):
679
680
# store option name "easy", "normal" or "hard" for difficuly
680
681
" difficulty" : self .multiworld.difficulty[self .player].current_key,
681
682
# store option value True or False for fixing a glitch
682
- " fix_xyz_glitch" : self .multiworld.fix_xyz_glitch[self .player].value
683
+ " fix_xyz_glitch" : self .multiworld.fix_xyz_glitch[self .player].value,
683
684
}
684
685
# point to a ROM specified by the installation
685
686
src = self .settings.rom_file
686
687
# or point to worlds/mygame/data/mod_template
687
688
src = os.path.join(os.path.dirname(__file__ ), " data" , " mod_template" )
688
689
# generate output path
689
- mod_name = f " AP- { self .multiworld.seed_name } -P { self .player} - { self .multiworld.player_name[ self .player] } "
690
+ mod_name = self .multiworld.get_out_file_name_base( self .player)
690
691
out_file = os.path.join(output_directory, mod_name + " .zip" )
691
692
# generate the file
692
693
generate_mod(src, out_file, data)
@@ -735,14 +736,14 @@ from . import MyGameTestBase
735
736
736
737
737
738
class TestChestAccess (MyGameTestBase ):
738
- def testSwordChests (self ):
739
+ def test_sword_chests (self ):
739
740
""" Test locations that require a sword"""
740
741
locations = [" Chest1" , " Chest2" ]
741
742
items = [[" Sword" ]]
742
743
# this will test that each location can't be accessed without the "Sword", but can be accessed once obtained.
743
744
self .assertAccessDependency(locations, items)
744
-
745
- def testAnyWeaponChests (self ):
745
+
746
+ def test_any_weapon_chests (self ):
746
747
""" Test locations that require any weapon"""
747
748
locations = [f " Chest { i} " for i in range (3 , 6 )]
748
749
items = [[" Sword" ], [" Axe" ], [" Spear" ]]
0 commit comments