Clique: Refactors and Additional Features supported by v1.5 (#1989)
This commit is contained in:
		
							parent
							
								
									1a29caffcb
								
							
						
					
					
						commit
						ca46a64abc
					
				|  | @ -0,0 +1,35 @@ | ||||||
|  | from typing import Callable, Dict, NamedTuple, Optional | ||||||
|  | 
 | ||||||
|  | from BaseClasses import Item, ItemClassification, MultiWorld | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class CliqueItem(Item): | ||||||
|  |     game = "Clique" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class CliqueItemData(NamedTuple): | ||||||
|  |     code: Optional[int] = None | ||||||
|  |     type: ItemClassification = ItemClassification.filler | ||||||
|  |     can_create: Callable[[MultiWorld, int], bool] = lambda multiworld, player: True | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | item_data_table: Dict[str, CliqueItemData] = { | ||||||
|  |     "Feeling of Satisfaction": CliqueItemData( | ||||||
|  |         code=69696969, | ||||||
|  |         type=ItemClassification.progression, | ||||||
|  |     ), | ||||||
|  |     "Button Activation": CliqueItemData( | ||||||
|  |         code=69696968, | ||||||
|  |         type=ItemClassification.progression, | ||||||
|  |         can_create=lambda multiworld, player: bool(getattr(multiworld, "hard_mode")[player]), | ||||||
|  |     ), | ||||||
|  |     "A Cool Filler Item (No Satisfaction Guaranteed)": CliqueItemData( | ||||||
|  |         code=69696967, | ||||||
|  |         can_create=lambda multiworld, player: False  # Only created from `get_filler_item_name`. | ||||||
|  |     ), | ||||||
|  |     "The Urge to Push": CliqueItemData( | ||||||
|  |         type=ItemClassification.progression, | ||||||
|  |     ), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | item_table = {name: data.code for name, data in item_data_table.items() if data.code is not None} | ||||||
|  | @ -0,0 +1,34 @@ | ||||||
|  | from typing import Callable, Dict, NamedTuple, Optional | ||||||
|  | 
 | ||||||
|  | from BaseClasses import Location, MultiWorld | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class CliqueLocation(Location): | ||||||
|  |     game = "Clique" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class CliqueLocationData(NamedTuple): | ||||||
|  |     region: str | ||||||
|  |     address: Optional[int] = None | ||||||
|  |     can_create: Callable[[MultiWorld, int], bool] = lambda multiworld, player: True | ||||||
|  |     locked_item: Optional[str] = None | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | location_data_table: Dict[str, CliqueLocationData] = { | ||||||
|  |     "The Big Red Button": CliqueLocationData( | ||||||
|  |         region="The Button Realm", | ||||||
|  |         address=69696969, | ||||||
|  |     ), | ||||||
|  |     "The Item on the Desk": CliqueLocationData( | ||||||
|  |         region="The Button Realm", | ||||||
|  |         address=69696968, | ||||||
|  |         can_create=lambda multiworld, player: bool(getattr(multiworld, "hard_mode")[player]), | ||||||
|  |     ), | ||||||
|  |     "In the Player's Mind": CliqueLocationData( | ||||||
|  |         region="The Button Realm", | ||||||
|  |         locked_item="The Urge to Push", | ||||||
|  |     ), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | location_table = {name: data.address for name, data in location_data_table.items() if data.address is not None} | ||||||
|  | locked_locations = {name: data for name, data in location_data_table.items() if data.locked_item} | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| from typing import Dict | from typing import Dict | ||||||
| 
 | 
 | ||||||
| from Options import Option, Toggle | from Options import Choice, Option, Toggle | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class HardMode(Toggle): | class HardMode(Toggle): | ||||||
|  | @ -8,6 +8,27 @@ class HardMode(Toggle): | ||||||
|     display_name = "Hard Mode" |     display_name = "Hard Mode" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class ButtonColor(Choice): | ||||||
|  |     """Customize your button! Now available in 12 unique colors.""" | ||||||
|  |     display_name = "Button Color" | ||||||
|  |     option_red = 0 | ||||||
|  |     option_orange = 1 | ||||||
|  |     option_yellow = 2 | ||||||
|  |     option_green = 3 | ||||||
|  |     option_cyan = 4 | ||||||
|  |     option_blue = 5 | ||||||
|  |     option_magenta = 6 | ||||||
|  |     option_purple = 7 | ||||||
|  |     option_pink = 8 | ||||||
|  |     option_brown = 9 | ||||||
|  |     option_white = 10 | ||||||
|  |     option_black = 11 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| clique_options: Dict[str, type(Option)] = { | clique_options: Dict[str, type(Option)] = { | ||||||
|     "hard_mode": HardMode |     "color": ButtonColor, | ||||||
|  |     "hard_mode": HardMode, | ||||||
|  | 
 | ||||||
|  |     # DeathLink is always on. Always. | ||||||
|  |     # "death_link": DeathLink, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,11 @@ | ||||||
|  | from typing import Dict, List, NamedTuple | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class CliqueRegionData(NamedTuple): | ||||||
|  |     connecting_regions: List[str] = [] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | region_data_table: Dict[str, CliqueRegionData] = { | ||||||
|  |     "Menu": CliqueRegionData(["The Button Realm"]), | ||||||
|  |     "The Button Realm": CliqueRegionData(), | ||||||
|  | } | ||||||
|  | @ -0,0 +1,10 @@ | ||||||
|  | from typing import Callable | ||||||
|  | 
 | ||||||
|  | from BaseClasses import CollectionState, MultiWorld | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_button_rule(multiworld: MultiWorld, player: int) -> Callable[[CollectionState], bool]: | ||||||
|  |     if getattr(multiworld, "hard_mode")[player]: | ||||||
|  |         return lambda state: state.has("Button Activation", player) | ||||||
|  | 
 | ||||||
|  |     return lambda state: True | ||||||
|  | @ -1,15 +1,12 @@ | ||||||
| from BaseClasses import Entrance, Item, ItemClassification, Location, MultiWorld, Region, Tutorial | from typing import List | ||||||
|  | 
 | ||||||
|  | from BaseClasses import Region, Tutorial | ||||||
| from worlds.AutoWorld import WebWorld, World | from worlds.AutoWorld import WebWorld, World | ||||||
| from worlds.generic.Rules import set_rule | from .Items import CliqueItem, item_data_table, item_table | ||||||
|  | from .Locations import CliqueLocation, location_data_table, location_table, locked_locations | ||||||
| from .Options import clique_options | from .Options import clique_options | ||||||
| 
 | from .Regions import region_data_table | ||||||
| 
 | from .Rules import get_button_rule | ||||||
| class CliqueItem(Item): |  | ||||||
|     game = "Clique" |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class CliqueLocation(Location): |  | ||||||
|     game = "Clique" |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class CliqueWebWorld(WebWorld): | class CliqueWebWorld(WebWorld): | ||||||
|  | @ -27,71 +24,69 @@ class CliqueWebWorld(WebWorld): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class CliqueWorld(World): | class CliqueWorld(World): | ||||||
|     """The greatest game ever designed. Full of exciting gameplay!""" |     """The greatest game of all time.""" | ||||||
| 
 | 
 | ||||||
|     game = "Clique" |     game = "Clique" | ||||||
|     data_version = 2 |     data_version = 3 | ||||||
|     web = CliqueWebWorld() |     web = CliqueWebWorld() | ||||||
|     option_definitions = clique_options |     option_definitions = clique_options | ||||||
| 
 |     location_name_to_id = location_table | ||||||
|     # Yes, I'm like 12 for this. |     item_name_to_id = item_table | ||||||
|     location_name_to_id = { |  | ||||||
|         "The Big Red Button":   69696969, |  | ||||||
|         "The Item on the Desk": 69696968, |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     item_name_to_id = { |  | ||||||
|         "Feeling of Satisfaction": 69696969, |  | ||||||
|         "Button Activation":       69696968, |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     def create_item(self, name: str) -> CliqueItem: |     def create_item(self, name: str) -> CliqueItem: | ||||||
|         return CliqueItem(name, ItemClassification.progression, self.item_name_to_id[name], self.player) |         return CliqueItem(name, item_data_table[name].type, item_data_table[name].code, self.player) | ||||||
| 
 | 
 | ||||||
|     def create_items(self) -> None: |     def create_items(self) -> None: | ||||||
|         self.multiworld.itempool.append(self.create_item("Feeling of Satisfaction")) |         item_pool: List[CliqueItem] = [] | ||||||
|         self.multiworld.priority_locations[self.player].value.add("The Big Red Button") |         for name, item in item_data_table.items(): | ||||||
|  |             if item.code and item.can_create(self.multiworld, self.player): | ||||||
|  |                 item_pool.append(self.create_item(name)) | ||||||
| 
 | 
 | ||||||
|         if self.multiworld.hard_mode[self.player]: |         self.multiworld.itempool += item_pool | ||||||
|             self.multiworld.itempool.append(self.create_item("Button Activation")) |  | ||||||
| 
 | 
 | ||||||
|     def create_regions(self) -> None: |     def create_regions(self) -> None: | ||||||
|         if self.multiworld.hard_mode[self.player]: |         # Create regions. | ||||||
|             self.multiworld.regions += [ |         for region_name in region_data_table.keys(): | ||||||
|                 create_region(self.multiworld, self.player, "Menu", None, ["The entrance to the button."]), |             region = Region(region_name, self.player, self.multiworld) | ||||||
|                 create_region(self.multiworld, self.player, "The realm of the button.", self.location_name_to_id) |             self.multiworld.regions.append(region) | ||||||
|             ] |  | ||||||
|         else: |  | ||||||
|             self.multiworld.regions += [ |  | ||||||
|                 create_region(self.multiworld, self.player, "Menu", None, ["The entrance to the button."]), |  | ||||||
|                 create_region(self.multiworld, self.player, "The realm of the button.", { |  | ||||||
|                     "The Big Red Button": 69696969 |  | ||||||
|                 })] |  | ||||||
| 
 | 
 | ||||||
|         self.multiworld.get_entrance("The entrance to the button.", self.player) \ |         # Create locations. | ||||||
|             .connect(self.multiworld.get_region("The realm of the button.", self.player)) |         for region_name, region_data in region_data_table.items(): | ||||||
|  |             region = self.multiworld.get_region(region_name, self.player) | ||||||
|  |             region.add_locations({ | ||||||
|  |                 location_name: location_data.address for location_name, location_data in location_data_table.items() | ||||||
|  |                 if location_data.region == region_name and location_data.can_create(self.multiworld, self.player) | ||||||
|  |             }, CliqueLocation) | ||||||
|  |             region.add_exits(region_data_table[region_name].connecting_regions) | ||||||
|  | 
 | ||||||
|  |         # Place locked locations. | ||||||
|  |         for location_name, location_data in locked_locations.items(): | ||||||
|  |             # Ignore locations we never created. | ||||||
|  |             if not location_data.can_create(self.multiworld, self.player): | ||||||
|  |                 continue | ||||||
|  | 
 | ||||||
|  |             locked_item = self.create_item(location_data_table[location_name].locked_item) | ||||||
|  |             self.multiworld.get_location(location_name, self.player).place_locked_item(locked_item) | ||||||
|  | 
 | ||||||
|  |         # Set priority location for the Big Red Button! | ||||||
|  |         self.multiworld.priority_locations[self.player].value.add("The Big Red Button") | ||||||
| 
 | 
 | ||||||
|     def get_filler_item_name(self) -> str: |     def get_filler_item_name(self) -> str: | ||||||
|         return self.multiworld.random.choice(self.item_name_to_id) |         return "A Cool Filler Item (No Satisfaction Guaranteed)" | ||||||
| 
 | 
 | ||||||
|     def set_rules(self) -> None: |     def set_rules(self) -> None: | ||||||
|         if self.multiworld.hard_mode[self.player]: |         button_rule = get_button_rule(self.multiworld, self.player) | ||||||
|             set_rule( |         self.multiworld.get_location("The Big Red Button", self.player).access_rule = button_rule | ||||||
|                 self.multiworld.get_location("The Big Red Button", self.player), |         self.multiworld.get_location("In the Player's Mind", self.player).access_rule = button_rule | ||||||
|                 lambda state: state.has("Button Activation", self.player)) |  | ||||||
| 
 | 
 | ||||||
|         self.multiworld.completion_condition[self.player] = lambda state: \ |         # Do not allow button activations on buttons. | ||||||
|             state.has("Feeling of Satisfaction", self.player) |         self.multiworld.get_location("The Big Red Button", self.player).item_rule =\ | ||||||
|  |             lambda item: item.name != "Button Activation" | ||||||
| 
 | 
 | ||||||
|  |         # Completion condition. | ||||||
|  |         self.multiworld.completion_condition[self.player] = lambda state: state.has("The Urge to Push", self.player) | ||||||
| 
 | 
 | ||||||
| def create_region(world: MultiWorld, player: int, name: str, locations=None, exits=None): |     def fill_slot_data(self): | ||||||
|     region = Region(name, player, world) |         return { | ||||||
|     if locations: |             "color": getattr(self.multiworld, "color")[self.player].current_key | ||||||
|         for location_name in locations.keys(): |         } | ||||||
|             region.locations.append(CliqueLocation(player, location_name, locations[location_name], region)) |  | ||||||
| 
 |  | ||||||
|     if exits: |  | ||||||
|         for _exit in exits: |  | ||||||
|             region.exits.append(Entrance(player, _exit, region)) |  | ||||||
| 
 |  | ||||||
|     return region |  | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ Clique is a joke game developed for Archipelago in March 2023 to showcase how ea | ||||||
| Archipelago. The objective of the game is to press the big red button. If a player is playing on `hard_mode`, they must | Archipelago. The objective of the game is to press the big red button. If a player is playing on `hard_mode`, they must | ||||||
| wait for someone else in the multiworld to "activate" their button before they can press it. | wait for someone else in the multiworld to "activate" their button before they can press it. | ||||||
| 
 | 
 | ||||||
| Clique can be played on any HTML5-capable browser. | Clique can be played on most modern HTML5-capable browsers. | ||||||
| 
 | 
 | ||||||
| ## Where is the settings page? | ## Where is the settings page? | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -6,7 +6,7 @@ slot name, and a room password if one is required. Then click "Connect". | ||||||
| If you're playing on "easy mode", just click the button and receive "Satisfaction". | If you're playing on "easy mode", just click the button and receive "Satisfaction". | ||||||
| 
 | 
 | ||||||
| If you're playing on "hard mode", you may need to wait for activation before you can complete your objective. Luckily,  | If you're playing on "hard mode", you may need to wait for activation before you can complete your objective. Luckily,  | ||||||
| Clique runs in all the major browsers that support HTML5, so you can load Clique on your phone and be productive while  | Clique runs in most major browsers that support HTML5, so you can load Clique on your phone and be productive while  | ||||||
| you wait! | you wait! | ||||||
| 
 | 
 | ||||||
| If you need some ideas for what to do while waiting for button activation, give the following a try: | If you need some ideas for what to do while waiting for button activation, give the following a try: | ||||||
|  | @ -19,4 +19,4 @@ If you need some ideas for what to do while waiting for button activation, give | ||||||
| - Do your school work. | - Do your school work. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ~~If you run into any issues with this game, definitely do not contact Phar#4444 on discord. *wink* *wink*~~ | ~~If you run into any issues with this game, definitely do not contact **thephar** on discord. *wink* *wink*~~ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue