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