Files
dockipelago/worlds/apquest/options.py
NewSoupVi e0cbf77dae APQuest: Implement New Game (#5393)
* APQuest

* Add confetti cannon

* ID change on enemy drop

* nevermind

* Write the apworld

* Actually implement hard mode

* split everything into multiple files

* Push out webworld into a file

* Comment

* Enemy health graphics

* more ruff rules

* graphics :)

* heal player when receiving health upgrade

* the dumbest client of all time

* Fix typo

* You can kinda play it now! Now we just need to render the game... :)))

* fix kvui imports again

* It's playable. Kind of

* oops

* Sounds and stuff

* exceptions for audio

* player sprite stuff

* Not attack without sword

* Make sure it plays correctly

* Collect behavior

* ruff

* don't need to clear checked_locations, but do need to still clear finished_game

* Connect calls disconnect, so this is not necessary

* more seemless reconnection

* Ok now I think it's correct

* Bgm

* Bgm

* minor adjustment

* More refactoring of graphics and sound

* add graphics

* Item column

* Fix enemies not regaining their health

* oops

* oops

* oops

* 6 health final boss on hard mode

* boss_6.png

* Display APQuest items correctly

* auto switch tabs

* some mypy stuff

* Intro song

* Confetti Cannon

* a bit more confetti work

* launcher component

* Graphics change

* graphics and cleanup

* fix apworld

* comment out horse and cat for now

* add docs

* copypasta

* ruff made my comment look unhinged

* Move that comment

* Fix typing and don't import kvui in nogui

* lmao that already exists I don't need to do it myself

* Must've just copied this from somewhere

* order change

* Add unit tests

* Notes about the client

* oops

* another intro song case

* Write WebWorld and setup guides

* Yes description provided

* thing

* how to play

* Music and Volume

* Add cat and horse player sprites

* updates

* Add hammer and breakable wall

* TODO

* replace wav with ogg

* Codeowners and readme

* finish unit tests

* lint

* Todid

* Update worlds/apquest/client/ap_quest_client.py

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Update worlds/apquest/client/custom_views.py

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Filler pattern

* __future__ annotations

* twebhost

* Allow wasd and arrow keys

* correct wording

* oops

* just say the website

* append instead of +=

* qwint is onto my favoritism

* kitty alias

* Add a comment about preplaced items for assertAccessDependency

* Use classvar_matrix instead of MultiworldTestBase

* actually remove multiworld stuff from those tests

* missed one more

* Refactor a bit more

* Fix getting of the user path

* Actually explain components

* Meh

* Be a bit clearer about what's what

* oops

* More comments in the regions.py file

* Nevermind

* clarify regions further

* I use too many brackets

* Ok I'm done fr

* simplify wording

* missing .

* Add precollected example

* add note about precollected advancements

* missing s

* APQuest sound rework

* Volume slider

* I forgot I made this

* a

* fix volume of jingles

* Add math trap to game (only works in play_in_console mode so far)

* Math trap in apworld and client side

* Fix background during math trap

* fix leading 0

* Sound and further ui improvements for Math Trap

* fix music bug

* rename apquest subfolder to game

* Move comment to where it belongs

* Clear up language around components (hopefully)

* Clear up what CommonClient is

* Reword some more

* Mention Archipelago (the program) explicitly

* Update worlds/apquest/docs/en_APQuest.md

Co-authored-by: Ixrec <ericrhitchcock@gmail.com>

* Explain a bit more why you would use classvar matrix

* reword the assert raises stuff

* the volume slider thing is no longer true

* german game page

* Be more clear about why we're overriding Item and Location

* default item classification

* logically considered -> relevant to logic ()

* Update worlds/apquest/items.py

Co-authored-by: Ixrec <ericrhitchcock@gmail.com>

* a word on the ambiguity of the word 'filler'

* more rewording

* amount -> number

* stress the necessity of appending to the multiworld itempool

* Update worlds/apquest/locations.py

Co-authored-by: Ixrec <ericrhitchcock@gmail.com>

* get_location_names_with_ids

* slight rewording of the new helper method

* add some words about creating known location+item pairs

* Add some more words to worlds/apqeust/options.py

* more words in options.py

* 120 chars (thanks Ixrec >:((( LOL)

* Less confusing wording about rules, hopefully?

* victory -> completion

* remove the immediate creation of the hammer rule on the option region entrance

* access rule performance

* Make all imports module-level in world.py

* formatting

* get rid of noqa RUF012 (and also disable the rule in my local ruff.toml

* move comment for docstring closer to docstring in another place

* advancement????

* Missing function type annotations

* pass mypy again (I don't love this one but all the alternatives are equally bad)

* subclass instead of override

* I forgor to remove these

* Get rid of classvar_matrix and instead talk about some other stuff

* protect people a bit from the assertAccessDependency nonsense

* reword a bit more

* word

* More accessdependency text

* More accessdependency text

* More accessdependency text

* More accessdependency text

* oops

* this is supposed to be absolute

* Add some links to docs

* that's called game now

* Add an archipelago.json and explain what it means

* new line who dis

* reorganize a bit

* ignore instead of skip

* Update archipelago.json

* She new on my line till I

* Update archipelago.json

* add controls tab

* new ruff rule? idk

* WHOOPS

* Pack graphics into fewer files

* annoying ruff format thing

* Cleanup + mypy

* relative import

* Update worlds/apquest/client/custom_views.py

Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>

* Update generate_math_problem.py

* Update worlds/apquest/game/player.py

Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>

---------

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>
Co-authored-by: Ixrec <ericrhitchcock@gmail.com>
Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
2025-11-25 00:38:06 +01:00

153 lines
4.9 KiB
Python

from dataclasses import dataclass
from Options import Choice, OptionGroup, PerGameCommonOptions, Range, Toggle
# In this file, we define the options the player can pick.
# The most common types of options are Toggle, Range and Choice.
# Options will be in the game's template yaml.
# They will be represented by checkboxes, sliders etc. on the game's options page on the website.
# (Note: Options can also be made invisible from either of these places by overriding Option.visibility.
# APQuest doesn't have an example of this, but this can be used for secret / hidden / advanced options.)
# For further reading on options, you can also read the Options API Document:
# https://github.com/ArchipelagoMW/Archipelago/blob/main/docs/options%20api.md
# The first type of Option we'll discuss is the Toggle.
# A toggle is an option that can either be on or off. This will be represented by a checkbox on the website.
# The default for a toggle is "off".
# If you want a toggle to be on by default, you can use the "DefaultOnToggle" class instead of the "Toggle" class.
class HardMode(Toggle):
"""
In hard mode, the basic enemy and the final boss will have more health.
The Health Upgrades become progression, as they are now required to beat the final boss.
"""
# The docstring of an option is used as the description on the website and in the template yaml.
# You'll also want to set a display name, which will determine what the option is called on the website.
display_name = "Hard Mode"
class Hammer(Toggle):
"""
Adds another item to the itempool: The Hammer.
The top middle chest will now be locked behind a breakable wall, requiring the Hammer.
"""
display_name = "Hammer"
class ExtraStartingChest(Toggle):
"""
Adds an extra chest in the bottom left, making room for an extra Confetti Cannon.
"""
display_name = "Extra Starting Chest"
class TrapChance(Range):
"""
Percentage chance that any given Confetti Cannon will be replaced by a Math Trap.
"""
display_name = "Trap Chance"
range_start = 0
range_end = 100
default = 0
class StartWithOneConfettiCannon(Toggle):
"""
Start with a confetti cannon already in your inventory.
Why? Because you deserve it. You get to celebrate yourself without doing any work first.
"""
display_name = "Start With One Confetti Cannon"
# A Range is a numeric option with a min and max value. This will be represented by a slider on the website.
class ConfettiExplosiveness(Range):
"""
How much confetti each use of a confetti cannon will fire.
"""
display_name = "Confetti Explosiveness"
range_start = 0
range_end = 10
# Range options must define an explicit default value.
default = 3
# A Choice is an option with multiple discrete choices. This will be represented by a dropdown on the website.
class PlayerSprite(Choice):
"""
The sprite that the player will have.
"""
display_name = "Player Sprite"
option_human = 0
option_duck = 1
option_horse = 2
option_cat = 3
# Choice options must define an explicit default value.
default = option_human
# For choices, you can also define aliases.
# For example, we could make it so "player_sprite: kitty" resolves to "player_sprite: cat" like this:
alias_kitty = option_cat
# We must now define a dataclass inheriting from PerGameCommonOptions that we put all our options in.
# This is in the format "option_name_in_snake_case: OptionClassName".
@dataclass
class APQuestOptions(PerGameCommonOptions):
hard_mode: HardMode
hammer: Hammer
extra_starting_chest: ExtraStartingChest
start_with_one_confetti_cannon: StartWithOneConfettiCannon
trap_chance: TrapChance
confetti_explosiveness: ConfettiExplosiveness
player_sprite: PlayerSprite
# If we want to group our options by similar type, we can do so as well. This looks nice on the website.
option_groups = [
OptionGroup(
"Gameplay Options",
[HardMode, Hammer, ExtraStartingChest, StartWithOneConfettiCannon, TrapChance],
),
OptionGroup(
"Aesthetic Options",
[ConfettiExplosiveness, PlayerSprite],
),
]
# Finally, we can define some option presets if we want the player to be able to quickly choose a specific "mode".
option_presets = {
"boring": {
"hard_mode": False,
"hammer": False,
"extra_starting_chest": False,
"start_with_one_confetti_cannon": False,
"trap_chance": 0,
"confetti_explosiveness": ConfettiExplosiveness.range_start,
"player_sprite": PlayerSprite.option_human,
},
"the true way to play": {
"hard_mode": True,
"hammer": True,
"extra_starting_chest": True,
"start_with_one_confetti_cannon": True,
"trap_chance": 50,
"confetti_explosiveness": ConfettiExplosiveness.range_end,
"player_sprite": PlayerSprite.option_duck,
},
}