Clique: Refactors and Additional Features supported by v1.5 (#1989)

This commit is contained in:
Zach Parks 2023-07-19 17:16:03 -05:00 committed by GitHub
parent 1a29caffcb
commit ca46a64abc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 170 additions and 64 deletions

35
worlds/clique/Items.py Normal file
View File

@ -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}

View File

@ -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}

View File

@ -1,6 +1,6 @@
from typing import Dict
from Options import Option, Toggle
from Options import Choice, Option, Toggle
class HardMode(Toggle):
@ -8,6 +8,27 @@ class HardMode(Toggle):
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)] = {
"hard_mode": HardMode
"color": ButtonColor,
"hard_mode": HardMode,
# DeathLink is always on. Always.
# "death_link": DeathLink,
}

11
worlds/clique/Regions.py Normal file
View File

@ -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(),
}

10
worlds/clique/Rules.py Normal file
View File

@ -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

View File

@ -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.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
class CliqueItem(Item):
game = "Clique"
class CliqueLocation(Location):
game = "Clique"
from .Regions import region_data_table
from .Rules import get_button_rule
class CliqueWebWorld(WebWorld):
@ -27,71 +24,69 @@ class CliqueWebWorld(WebWorld):
class CliqueWorld(World):
"""The greatest game ever designed. Full of exciting gameplay!"""
"""The greatest game of all time."""
game = "Clique"
data_version = 2
data_version = 3
web = CliqueWebWorld()
option_definitions = clique_options
# Yes, I'm like 12 for this.
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,
}
location_name_to_id = location_table
item_name_to_id = item_table
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:
self.multiworld.itempool.append(self.create_item("Feeling of Satisfaction"))
self.multiworld.priority_locations[self.player].value.add("The Big Red Button")
item_pool: List[CliqueItem] = []
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.append(self.create_item("Button Activation"))
self.multiworld.itempool += item_pool
def create_regions(self) -> None:
if self.multiworld.hard_mode[self.player]:
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.", self.location_name_to_id)
]
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
})]
# Create regions.
for region_name in region_data_table.keys():
region = Region(region_name, self.player, self.multiworld)
self.multiworld.regions.append(region)
self.multiworld.get_entrance("The entrance to the button.", self.player) \
.connect(self.multiworld.get_region("The realm of the button.", self.player))
# Create locations.
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:
return self.multiworld.random.choice(self.item_name_to_id)
return "A Cool Filler Item (No Satisfaction Guaranteed)"
def set_rules(self) -> None:
if self.multiworld.hard_mode[self.player]:
set_rule(
self.multiworld.get_location("The Big Red Button", self.player),
lambda state: state.has("Button Activation", self.player))
button_rule = get_button_rule(self.multiworld, self.player)
self.multiworld.get_location("The Big Red Button", self.player).access_rule = button_rule
self.multiworld.get_location("In the Player's Mind", self.player).access_rule = button_rule
self.multiworld.completion_condition[self.player] = lambda state: \
state.has("Feeling of Satisfaction", self.player)
# Do not allow button activations on buttons.
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):
region = Region(name, player, world)
if locations:
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
def fill_slot_data(self):
return {
"color": getattr(self.multiworld, "color")[self.player].current_key
}

View File

@ -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
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?

View File

@ -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 "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!
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.
~~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*~~