Skip to content

Commit d18bd89

Browse files
authored
Move to AutoGameRegister and add Rabbit & Steel (ArchipelagoMW#4)
* first pass * move to a metaclass approach * another concept for rabbits goals * ffxvi and pizza tower
1 parent a856644 commit d18bd89

21 files changed

+338
-176
lines changed

worlds/keymasters_keep/game.py

+23-3
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,44 @@
1+
from __future__ import annotations
2+
13
import abc
24

35
from random import Random
4-
from typing import Any, List, Optional, Tuple
6+
from typing import Any, List, Optional, Tuple, Dict, Type
57

68
from .enums import KeymastersKeepGamePlatforms
79

810
from .game_objective_template import GameObjectiveTemplate
911

1012

11-
class Game:
13+
class AutoGameRegister(type):
14+
games: Dict[str, Type[Game]] = {}
15+
metagames: Dict[str, Type[Game]] = {}
16+
17+
def __new__(mcs, name: str, bases: Tuple[type, ...], dct: Dict[str, Any]) -> AutoGameRegister:
18+
new_class = super().__new__(mcs, name, bases, dct)
19+
if name != "Game":
20+
game_name = dct["name"]
21+
if "is_metagame" in dct and dct["is_metagame"]:
22+
mcs.metagames[game_name] = new_class
23+
else:
24+
mcs.games[game_name] = new_class
25+
26+
return new_class
27+
28+
29+
class Game(metaclass=AutoGameRegister):
1230
name: str # Official name of the game. Use a resource like IGDB to get the correct name
31+
options_cls: Optional[Type] = None # Archipelago options type
1332
platform: KeymastersKeepGamePlatforms # Platform that the game integration was developed with and tested on
1433

1534
# Other available platforms the game integration might work with
1635
platforms_other: Optional[List[KeymastersKeepGamePlatforms]] = None
1736

1837
is_adult_only_or_unrated: bool = True # ESRB AO / PEGI 18 / USK 18 / Unrated? Used for filtering
38+
is_metagame: bool = False # Whether the game should be considered a metagame for grouping purposes
1939

2040
random: Random # Random instance
21-
archipelago_options: Any # Archipelago options dataclass
41+
archipelago_options: Any # Archipelago options dataclass for access
2242

2343
def __init__(self, random: Random = None, archipelago_options: Any = None) -> None:
2444
self.random = random or Random()

worlds/keymasters_keep/game_objective_generator.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
from random import Random
22
from typing import Any, List, Tuple, Type
33

4-
from .game import Game
5-
from .games import games, metagames
4+
from .game import Game, AutoGameRegister
5+
6+
from .games import *
7+
# * imports aren't great, but we need to ensure every game is imported at least once for registration
68

79

810
GameObjectiveGeneratorData = List[Tuple[Type[Game], List[str], List[str]]]
@@ -87,10 +89,10 @@ def _filter_games(
8789

8890
game_name: str
8991
for game_name in allowable_games:
90-
if game_name not in games and game_name not in metagames:
92+
if game_name not in AutoGameRegister.games and game_name not in AutoGameRegister.metagames:
9193
continue
9294

93-
game: Type[Game] = games.get(game_name, metagames.get(game_name))
95+
game: Type[Game] = AutoGameRegister.games.get(game_name, AutoGameRegister.metagames.get(game_name))
9496
game_instance: Game = game(archipelago_options=self.archipelago_options)
9597

9698
if not include_adult_only_or_unrated_games and game.is_adult_only_or_unrated:
+13-66
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,28 @@
1-
from typing import Dict, Type
1+
import pkgutil
2+
from typing import List, Type
23

34
from dataclasses import dataclass
45

5-
from ..game import Game
6+
from ..game import AutoGameRegister
67

7-
# Game Imports
8-
from .a_dance_of_fire_and_ice_game import ADanceOfFireAndIceGame, ADanceOfFireAndIceArchipelagoOptions
9-
from .anger_foot_game import AngerFootGame, AngerFootArchipelagoOptions
10-
from .final_fantasy_xvi_game import FinalFantasyXVIGame, FinalFantasyXVIArchipelagoOptions
11-
from .halls_of_torment_game import HallsOfTormentGame, HallsOfTormentArchipelagoOptions
12-
from .neon_white_game import NeonWhiteGame, NeonWhiteArchipelagoOptions
13-
from .pinball_fx3_game import PinballFX3Game, PinballFX3ArchipelagoOptions
14-
from .pizza_tower_game import PizzaTowerGame, PizzaTowerArchipelagoOptions
8+
from pkgutil import iter_modules
9+
from importlib import import_module
1510

16-
from .placid_plastic_duck_simulator_game import (
17-
PlacidPlasticDuckSimulatorGame, PlacidPlasticDuckSimulatorArchipelagoOptions
18-
)
11+
for game in iter_modules(__path__):
12+
import_module(f".{game.name}", __package__)
1913

20-
from .star_wars_battlefront_ii_classic_game import (
21-
StarWarsBattlefrontIIClassicGame, StarWarsBattlefrontIIClassicArchipelagoOptions
22-
)
2314

24-
from .street_fighter_6_game import StreetFighter6Game, StreetFighter6ArchipelagoOptions
25-
from .trackmania_game import TrackmaniaGame, TrackmaniaArchipelagoOptions
26-
from .trombone_champ_game import TromboneChampGame, TromboneChampArchipelagoOptions
27-
from .ultrakill_game import UltrakillGame, UltrakillArchipelagoOptions
15+
option_classes: List[Type] = []
2816

29-
# Metagame Imports
30-
from .archipelago_multiworld_randomizer_game import (
31-
ArchipelagoMultiworldRandomizerGame, ArchipelagoMultiworldRandomizerArchipelagoOptions
32-
)
33-
34-
from .game_backlog_game import GameBacklogGame, GameBacklogArchipelagoOptions
35-
from .retro_achievements_game import RetroAchievementsGame, RetroAchievementsArchipelagoOptions
36-
37-
38-
games: Dict[str, Type[Game]] = {
39-
ADanceOfFireAndIceGame.game_name_with_platforms(): ADanceOfFireAndIceGame,
40-
AngerFootGame.game_name_with_platforms(): AngerFootGame,
41-
FinalFantasyXVIGame.game_name_with_platforms(): FinalFantasyXVIGame,
42-
HallsOfTormentGame.game_name_with_platforms(): HallsOfTormentGame,
43-
NeonWhiteGame.game_name_with_platforms(): NeonWhiteGame,
44-
PinballFX3Game.game_name_with_platforms(): PinballFX3Game,
45-
PizzaTowerGame.game_name_with_platforms(): PizzaTowerGame,
46-
PlacidPlasticDuckSimulatorGame.game_name_with_platforms(): PlacidPlasticDuckSimulatorGame,
47-
StarWarsBattlefrontIIClassicGame.game_name_with_platforms(): StarWarsBattlefrontIIClassicGame,
48-
StreetFighter6Game.game_name_with_platforms(): StreetFighter6Game,
49-
TrackmaniaGame.game_name_with_platforms(): TrackmaniaGame,
50-
TromboneChampGame.game_name_with_platforms(): TromboneChampGame,
51-
UltrakillGame.game_name_with_platforms(): UltrakillGame,
52-
}
53-
54-
metagames: Dict[str, Type[Game]] = {
55-
ArchipelagoMultiworldRandomizerGame.game_name_with_platforms(): ArchipelagoMultiworldRandomizerGame,
56-
GameBacklogGame.game_name_with_platforms(): GameBacklogGame,
57-
RetroAchievementsGame.game_name_with_platforms(): RetroAchievementsGame,
58-
}
17+
for name, game in [*sorted(AutoGameRegister.games.items(), reverse=True),
18+
*sorted(AutoGameRegister.metagames.items(), reverse=True)]:
19+
if game.options_cls:
20+
option_classes.append(game.options_cls)
5921

6022

6123
@dataclass
6224
class GameArchipelagoOptions(
6325
# Add in reverse alphabetical order
64-
UltrakillArchipelagoOptions,
65-
TromboneChampArchipelagoOptions,
66-
TrackmaniaArchipelagoOptions,
67-
StreetFighter6ArchipelagoOptions,
68-
StarWarsBattlefrontIIClassicArchipelagoOptions,
69-
RetroAchievementsArchipelagoOptions,
70-
PlacidPlasticDuckSimulatorArchipelagoOptions,
71-
PizzaTowerArchipelagoOptions,
72-
PinballFX3ArchipelagoOptions,
73-
NeonWhiteArchipelagoOptions,
74-
HallsOfTormentArchipelagoOptions,
75-
GameBacklogArchipelagoOptions,
76-
FinalFantasyXVIArchipelagoOptions,
77-
ArchipelagoMultiworldRandomizerArchipelagoOptions,
78-
AngerFootArchipelagoOptions,
79-
ADanceOfFireAndIceArchipelagoOptions,
26+
*option_classes
8027
):
8128
pass

worlds/keymasters_keep/games/a_dance_of_fire_and_ice_game.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
import functools
24
from typing import List, Set
35

@@ -11,10 +13,17 @@
1113
from ..enums import KeymastersKeepGamePlatforms
1214

1315

16+
@dataclass
17+
class ADanceOfFireAndIceArchipelagoOptions:
18+
a_dance_of_fire_and_ice_dlc_owned: ADanceOfFireAndIceDLCOwned
19+
a_dance_of_fire_and_ice_custom_tracks: ADanceOfFireAndIceCustomTracks
20+
21+
1422
class ADanceOfFireAndIceGame(Game):
1523
# Initial Proposal by @im_not_original on Discord
1624

1725
name = "A Dance of Fire and Ice"
26+
options_cls = ADanceOfFireAndIceArchipelagoOptions
1827
platform = KeymastersKeepGamePlatforms.PC
1928

2029
platforms_other = [
@@ -234,9 +243,3 @@ class ADanceOfFireAndIceCustomTracks(OptionSet):
234243

235244
display_name = "A Dance of Fire and Ice Custom Tracks"
236245
default = list()
237-
238-
239-
@dataclass
240-
class ADanceOfFireAndIceArchipelagoOptions:
241-
a_dance_of_fire_and_ice_dlc_owned: ADanceOfFireAndIceDLCOwned
242-
a_dance_of_fire_and_ice_custom_tracks: ADanceOfFireAndIceCustomTracks

worlds/keymasters_keep/games/anger_foot_game.py

+1-6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
class AngerFootGame(Game):
1212
name = "Anger Foot"
13+
options_cls = None
1314
platform = KeymastersKeepGamePlatforms.PC
1415

1516
platforms_other = None
@@ -169,9 +170,3 @@ def bosses() -> List[str]:
169170
"The CEO",
170171
"Pizza Pig",
171172
]
172-
173-
174-
# Archipelago Options
175-
@dataclass
176-
class AngerFootArchipelagoOptions:
177-
pass

worlds/keymasters_keep/games/archipelago_multiworld_randomizer_game.py

+20-16
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
from typing import List
24

35
from dataclasses import dataclass
@@ -10,13 +12,31 @@
1012
from ..enums import KeymastersKeepGamePlatforms
1113

1214

15+
@dataclass
16+
class ArchipelagoMultiworldRandomizerArchipelagoOptions:
17+
archipelago_multiworld_randomizer_supported_game_selection: ArchipelagoMultiworldRandomizerSupportedGameSelection
18+
19+
archipelago_multiworld_randomizer_unsupported_game_selection: (
20+
ArchipelagoMultiworldRandomizerUnsupportedGameSelection
21+
)
22+
23+
archipelago_multiworld_randomizer_adult_only_or_unrated_game_selection: (
24+
ArchipelagoMultiworldRandomizerAdultOnlyOrUnratedGameSelection
25+
)
26+
27+
archipelago_multiworld_randomizer_custom_game_selection: ArchipelagoMultiworldRandomizerCustomGameSelection
28+
archipelago_multiworld_randomizer_allow_apbingo_objectives: ArchipelagoMultiworldRandomizerAllowAPBingoObjectives
29+
30+
1331
class ArchipelagoMultiworldRandomizerGame(Game):
1432
name = "Archipelago Multiworld Randomizer"
1533
platform = KeymastersKeepGamePlatforms.META
34+
options_cls = ArchipelagoMultiworldRandomizerArchipelagoOptions
1635

1736
platforms_other = None
1837

1938
is_adult_only_or_unrated = False
39+
is_metagame = True
2040

2141
def optional_game_constraint_templates(self) -> List[GameObjectiveTemplate]:
2242
return [
@@ -421,19 +441,3 @@ class ArchipelagoMultiworldRandomizerAllowAPBingoObjectives(Toggle):
421441
"""
422442

423443
display_name = "Allow APBingo Objectives"
424-
425-
426-
@dataclass
427-
class ArchipelagoMultiworldRandomizerArchipelagoOptions:
428-
archipelago_multiworld_randomizer_supported_game_selection: ArchipelagoMultiworldRandomizerSupportedGameSelection
429-
430-
archipelago_multiworld_randomizer_unsupported_game_selection: (
431-
ArchipelagoMultiworldRandomizerUnsupportedGameSelection
432-
)
433-
434-
archipelago_multiworld_randomizer_adult_only_or_unrated_game_selection: (
435-
ArchipelagoMultiworldRandomizerAdultOnlyOrUnratedGameSelection
436-
)
437-
438-
archipelago_multiworld_randomizer_custom_game_selection: ArchipelagoMultiworldRandomizerCustomGameSelection
439-
archipelago_multiworld_randomizer_allow_apbingo_objectives: ArchipelagoMultiworldRandomizerAllowAPBingoObjectives

worlds/keymasters_keep/games/final_fantasy_xvi_game.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
import functools
24
from typing import List
35

@@ -11,6 +13,11 @@
1113
from ..enums import KeymastersKeepGamePlatforms
1214

1315

16+
@dataclass
17+
class FinalFantasyXVIArchipelagoOptions:
18+
final_fantasy_xvi_dlc_owned: FinalFantasyXVIDLCOwned
19+
20+
1421
class FinalFantasyXVIGame(Game):
1522
# Initial Proposal by @delcake on Discord
1623

@@ -221,8 +228,3 @@ class FinalFantasyXVIDLCOwned(OptionSet):
221228
]
222229

223230
default = valid_keys
224-
225-
226-
@dataclass
227-
class FinalFantasyXVIArchipelagoOptions:
228-
final_fantasy_xvi_dlc_owned: FinalFantasyXVIDLCOwned

worlds/keymasters_keep/games/game_backlog_game.py

+10-6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
from typing import List
24

35
from dataclasses import dataclass
@@ -10,13 +12,21 @@
1012
from ..enums import KeymastersKeepGamePlatforms
1113

1214

15+
@dataclass
16+
class GameBacklogArchipelagoOptions:
17+
game_backlog_game_selection: GameBacklogGameSelection
18+
game_backlog_actions: GameBacklogActions
19+
20+
1321
class GameBacklogGame(Game):
1422
name = "Game Backlog"
23+
options_cls = GameBacklogArchipelagoOptions
1524
platform = KeymastersKeepGamePlatforms.META
1625

1726
platforms_other = None
1827

1928
is_adult_only_or_unrated = False
29+
is_metagame = True
2030

2131
def optional_game_constraint_templates(self) -> List[GameObjectiveTemplate]:
2232
return list()
@@ -66,9 +76,3 @@ class GameBacklogActions(OptionSet):
6676
]
6777

6878
default = valid_keys
69-
70-
71-
@dataclass
72-
class GameBacklogArchipelagoOptions:
73-
game_backlog_game_selection: GameBacklogGameSelection
74-
game_backlog_actions: GameBacklogActions

worlds/keymasters_keep/games/halls_of_torment_game.py

+1-6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
class HallsOfTormentGame(Game):
1212
name = "Halls of Torment"
13+
options_cls = None
1314
platform = KeymastersKeepGamePlatforms.PC
1415

1516
platforms_other = [
@@ -328,9 +329,3 @@ def traits() -> List[str]:
328329
@staticmethod
329330
def agony_range() -> range:
330331
return range(1, 13)
331-
332-
333-
# Archipelago Options
334-
@dataclass
335-
class HallsOfTormentArchipelagoOptions:
336-
pass

worlds/keymasters_keep/games/neon_white_game.py

+1-6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class NeonWhiteGame(Game):
1313
# Initial Proposal by @pitchouli on Discord
1414

1515
name = "Neon White"
16+
options_cls = None
1617
platform = KeymastersKeepGamePlatforms.PC
1718

1819
platforms_other = [
@@ -263,9 +264,3 @@ def rushes() -> List[str]:
263264
"Red",
264265
"Purple",
265266
]
266-
267-
268-
# Archipelago Options
269-
@dataclass
270-
class NeonWhiteArchipelagoOptions:
271-
pass

0 commit comments

Comments
 (0)