Skip to content

Commit

Permalink
Merge branch 'main' into generate_main_ermain_split
Browse files Browse the repository at this point in the history
  • Loading branch information
Berserker66 authored Jun 16, 2024
2 parents 7dd9764 + 2a11d61 commit 25e8764
Show file tree
Hide file tree
Showing 20 changed files with 310 additions and 134 deletions.
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ jobs:
run: |
Invoke-WebRequest -Uri https://github.com/Ijwu/Enemizer/releases/download/${Env:ENEMIZER_VERSION}/win-x64.zip -OutFile enemizer.zip
Expand-Archive -Path enemizer.zip -DestinationPath EnemizerCLI -Force
choco install innosetup --version=6.2.2 --allow-downgrade
- name: Build
run: |
python -m pip install --upgrade pip
Expand Down
75 changes: 60 additions & 15 deletions Options.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ def __new__(mcs, name, bases, attrs):
attrs["name_lookup"].update({option_id: name for name, option_id in new_options.items()})
options.update(new_options)
# apply aliases, without name_lookup
aliases = {name[6:].lower(): option_id for name, option_id in attrs.items() if
name.startswith("alias_")}
aliases = attrs["aliases"] = {name[6:].lower(): option_id for name, option_id in attrs.items() if
name.startswith("alias_")}

assert (
name in {"Option", "VerifyKeys"} or # base abstract classes don't need default
Expand Down Expand Up @@ -126,10 +126,28 @@ class Option(typing.Generic[T], metaclass=AssembleOptions):
# can be weighted between selections
supports_weighting = True

rich_text_doc: typing.Optional[bool] = None
"""Whether the WebHost should render the Option's docstring as rich text.
If this is True, the Option's docstring is interpreted as reStructuredText_,
the standard Python markup format. In the WebHost, it's rendered to HTML so
that lists, emphasis, and other rich text features are displayed properly.
If this is False, the docstring is instead interpreted as plain text, and
displayed as-is on the WebHost with whitespace preserved.
If this is None, it inherits the value of `World.rich_text_options_doc`. For
backwards compatibility, this defaults to False, but worlds are encouraged to
set it to True and use reStructuredText for their Option documentation.
.. _reStructuredText: https://docutils.sourceforge.io/rst.html
"""

# filled by AssembleOptions:
name_lookup: typing.ClassVar[typing.Dict[T, str]] # type: ignore
# https://github.com/python/typing/discussions/1460 the reason for this type: ignore
options: typing.ClassVar[typing.Dict[str, int]]
aliases: typing.ClassVar[typing.Dict[str, int]]

def __repr__(self) -> str:
return f"{self.__class__.__name__}({self.current_option_name})"
Expand Down Expand Up @@ -735,6 +753,12 @@ def __init__(self, value: int) -> None:
elif value > self.range_end and value not in self.special_range_names.values():
raise Exception(f"{value} is higher than maximum {self.range_end} for option {self.__class__.__name__} " +
f"and is also not one of the supported named special values: {self.special_range_names}")

# See docstring
for key in self.special_range_names:
if key != key.lower():
raise Exception(f"{self.__class__.__name__} has an invalid special_range_names key: {key}. "
f"NamedRange keys must use only lowercase letters, and ideally should be snake_case.")
self.value = value

@classmethod
Expand Down Expand Up @@ -1121,10 +1145,13 @@ def __len__(self) -> int:

class Accessibility(Choice):
"""Set rules for reachability of your items/locations.
Locations: ensure everything can be reached and acquired.
Items: ensure all logically relevant items can be acquired.
Minimal: ensure what is needed to reach your goal can be acquired."""
- **Locations:** ensure everything can be reached and acquired.
- **Items:** ensure all logically relevant items can be acquired.
- **Minimal:** ensure what is needed to reach your goal can be acquired.
"""
display_name = "Accessibility"
rich_text_doc = True
option_locations = 0
option_items = 1
option_minimal = 2
Expand All @@ -1133,14 +1160,15 @@ class Accessibility(Choice):


class ProgressionBalancing(NamedRange):
"""
A system that can move progression earlier, to try and prevent the player from getting stuck and bored early.
"""A system that can move progression earlier, to try and prevent the player from getting stuck and bored early.
A lower setting means more getting stuck. A higher setting means less getting stuck.
"""
default = 50
range_start = 0
range_end = 99
display_name = "Progression Balancing"
rich_text_doc = True
special_range_names = {
"disabled": 0,
"normal": 50,
Expand Down Expand Up @@ -1205,29 +1233,36 @@ def as_dict(self, *option_names: str, casing: str = "snake") -> typing.Dict[str,
class LocalItems(ItemSet):
"""Forces these items to be in their native world."""
display_name = "Local Items"
rich_text_doc = True


class NonLocalItems(ItemSet):
"""Forces these items to be outside their native world."""
display_name = "Non-local Items"
rich_text_doc = True


class StartInventory(ItemDict):
"""Start with these items."""
verify_item_name = True
display_name = "Start Inventory"
rich_text_doc = True


class StartInventoryPool(StartInventory):
"""Start with these items and don't place them in the world.
The game decides what the replacement items will be."""
The game decides what the replacement items will be.
"""
verify_item_name = True
display_name = "Start Inventory from Pool"
rich_text_doc = True


class StartHints(ItemSet):
"""Start with these item's locations prefilled into the !hint command."""
"""Start with these item's locations prefilled into the ``!hint`` command."""
display_name = "Start Hints"
rich_text_doc = True


class LocationSet(OptionSet):
Expand All @@ -1236,28 +1271,33 @@ class LocationSet(OptionSet):


class StartLocationHints(LocationSet):
"""Start with these locations and their item prefilled into the !hint command"""
"""Start with these locations and their item prefilled into the ``!hint`` command."""
display_name = "Start Location Hints"
rich_text_doc = True


class ExcludeLocations(LocationSet):
"""Prevent these locations from having an important item"""
"""Prevent these locations from having an important item."""
display_name = "Excluded Locations"
rich_text_doc = True


class PriorityLocations(LocationSet):
"""Prevent these locations from having an unimportant item"""
"""Prevent these locations from having an unimportant item."""
display_name = "Priority Locations"
rich_text_doc = True


class DeathLink(Toggle):
"""When you die, everyone dies. Of course the reverse is true too."""
display_name = "Death Link"
rich_text_doc = True


class ItemLinks(OptionList):
"""Share part of your item pool with other players."""
display_name = "Item Links"
rich_text_doc = True
default = []
schema = Schema([
{
Expand Down Expand Up @@ -1324,6 +1364,7 @@ def verify(self, world: typing.Type[World], player_name: str, plando_options: "P

class Removed(FreeText):
"""This Option has been Removed."""
rich_text_doc = True
default = ""
visibility = Visibility.none

Expand Down Expand Up @@ -1426,14 +1467,18 @@ def dictify_range(option: Range):

return data, notes

def yaml_dump_scalar(scalar) -> str:
# yaml dump may add end of document marker and newlines.
return yaml.dump(scalar).replace("...\n", "").strip()

for game_name, world in AutoWorldRegister.world_types.items():
if not world.hidden or generate_hidden:
grouped_options = get_option_groups(world)
option_groups = get_option_groups(world)
with open(local_path("data", "options.yaml")) as f:
file_data = f.read()
res = Template(file_data).render(
option_groups=grouped_options,
__version__=__version__, game=game_name, yaml_dump=yaml.dump,
option_groups=option_groups,
__version__=__version__, game=game_name, yaml_dump=yaml_dump_scalar,
dictify_range=dictify_range,
)

Expand Down
17 changes: 17 additions & 0 deletions WebHostLib/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import os
from textwrap import dedent
from typing import Dict, Union
from docutils.core import publish_parts

import yaml
from flask import redirect, render_template, request, Response
Expand Down Expand Up @@ -66,6 +67,22 @@ def filter_dedent(text: str) -> str:
return dedent(text).strip("\n ")


@app.template_filter("rst_to_html")
def filter_rst_to_html(text: str) -> str:
"""Converts reStructuredText (such as a Python docstring) to HTML."""
if text.startswith(" ") or text.startswith("\t"):
text = dedent(text)
elif "\n" in text:
lines = text.splitlines()
text = lines[0] + "\n" + dedent("\n".join(lines[1:]))

return publish_parts(text, writer_name='html', settings=None, settings_overrides={
'raw_enable': False,
'file_insertion_enabled': False,
'output_encoding': 'unicode'
})['body']


@app.template_test("ordered")
def test_ordered(obj):
return isinstance(obj, collections.abc.Sequence)
Expand Down
54 changes: 34 additions & 20 deletions WebHostLib/static/styles/tooltip.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ give it one of the following classes: tooltip-left, tooltip-right, tooltip-top,
*/

/* Base styles for the element that has a tooltip */
[data-tooltip], .tooltip {
[data-tooltip], .tooltip-container {
position: relative;
}

/* Base styles for the entire tooltip */
[data-tooltip]:before, [data-tooltip]:after, .tooltip:before, .tooltip:after {
[data-tooltip]:before, [data-tooltip]:after, .tooltip-container:before, .tooltip {
position: absolute;
visibility: hidden;
opacity: 0;
Expand All @@ -39,22 +39,23 @@ give it one of the following classes: tooltip-left, tooltip-right, tooltip-top,
pointer-events: none;
}

[data-tooltip]:hover:before, [data-tooltip]:hover:after, .tooltip:hover:before, .tooltip:hover:after{
[data-tooltip]:hover:before, [data-tooltip]:hover:after, .tooltip-container:hover:before,
.tooltip-container:hover .tooltip {
visibility: visible;
opacity: 1;
word-break: break-word;
}

/** Directional arrow styles */
.tooltip:before, [data-tooltip]:before {
[data-tooltip]:before, .tooltip-container:before {
z-index: 10000;
border: 6px solid transparent;
background: transparent;
content: "";
}

/** Content styles */
.tooltip:after, [data-tooltip]:after {
[data-tooltip]:after, .tooltip {
width: 260px;
z-index: 10000;
padding: 8px;
Expand All @@ -63,44 +64,46 @@ give it one of the following classes: tooltip-left, tooltip-right, tooltip-top,
background-color: hsla(0, 0%, 20%, 0.9);
color: #fff;
content: attr(data-tooltip);
white-space: pre-wrap;
font-size: 14px;
line-height: 1.2;
}

[data-tooltip]:before, [data-tooltip]:after{
[data-tooltip]:after {
white-space: pre-wrap;
}

[data-tooltip]:before, [data-tooltip]:after, .tooltip-container:before, .tooltip {
visibility: hidden;
opacity: 0;
pointer-events: none;
}

[data-tooltip]:before, [data-tooltip]:after, .tooltip:before, .tooltip:after,
.tooltip-top:before, .tooltip-top:after {
[data-tooltip]:before, [data-tooltip]:after, .tooltip-container:before, .tooltip {
bottom: 100%;
left: 50%;
}

[data-tooltip]:before, .tooltip:before, .tooltip-top:before {
[data-tooltip]:before, .tooltip-container:before {
margin-left: -6px;
margin-bottom: -12px;
border-top-color: #000;
border-top-color: hsla(0, 0%, 20%, 0.9);
}

/** Horizontally align tooltips on the top and bottom */
[data-tooltip]:after, .tooltip:after, .tooltip-top:after {
[data-tooltip]:after, .tooltip {
margin-left: -80px;
}

[data-tooltip]:hover:before, [data-tooltip]:hover:after, .tooltip:hover:before, .tooltip:hover:after,
.tooltip-top:hover:before, .tooltip-top:hover:after {
[data-tooltip]:hover:before, [data-tooltip]:hover:after, .tooltip-container:hover:before,
.tooltip-container:hover .tooltip {
-webkit-transform: translateY(-12px);
-moz-transform: translateY(-12px);
transform: translateY(-12px);
}

/** Tooltips on the left */
.tooltip-left:before, .tooltip-left:after {
.tooltip-left:before, [data-tooltip].tooltip-left:after, .tooltip-left .tooltip {
right: 100%;
bottom: 50%;
left: auto;
Expand All @@ -115,14 +118,14 @@ give it one of the following classes: tooltip-left, tooltip-right, tooltip-top,
border-left-color: hsla(0, 0%, 20%, 0.9);
}

.tooltip-left:hover:before, .tooltip-left:hover:after {
.tooltip-left:hover:before, [data-tooltip].tooltip-left:hover:after, .tooltip-left:hover .tooltip {
-webkit-transform: translateX(-12px);
-moz-transform: translateX(-12px);
transform: translateX(-12px);
}

/** Tooltips on the bottom */
.tooltip-bottom:before, .tooltip-bottom:after {
.tooltip-bottom:before, [data-tooltip].tooltip-bottom:after, .tooltip-bottom .tooltip {
top: 100%;
bottom: auto;
left: 50%;
Expand All @@ -136,14 +139,15 @@ give it one of the following classes: tooltip-left, tooltip-right, tooltip-top,
border-bottom-color: hsla(0, 0%, 20%, 0.9);
}

.tooltip-bottom:hover:before, .tooltip-bottom:hover:after {
.tooltip-bottom:hover:before, [data-tooltip].tooltip-bottom:hover:after,
.tooltip-bottom:hover .tooltip {
-webkit-transform: translateY(12px);
-moz-transform: translateY(12px);
transform: translateY(12px);
}

/** Tooltips on the right */
.tooltip-right:before, .tooltip-right:after {
.tooltip-right:before, [data-tooltip].tooltip-right:after, .tooltip-right .tooltip {
bottom: 50%;
left: 100%;
}
Expand All @@ -156,7 +160,8 @@ give it one of the following classes: tooltip-left, tooltip-right, tooltip-top,
border-right-color: hsla(0, 0%, 20%, 0.9);
}

.tooltip-right:hover:before, .tooltip-right:hover:after {
.tooltip-right:hover:before, [data-tooltip].tooltip-right:hover:after,
.tooltip-right:hover .tooltip {
-webkit-transform: translateX(12px);
-moz-transform: translateX(12px);
transform: translateX(12px);
Expand All @@ -168,7 +173,16 @@ give it one of the following classes: tooltip-left, tooltip-right, tooltip-top,
}

/** Center content vertically for tooltips ont he left and right */
.tooltip-left:after, .tooltip-right:after {
[data-tooltip].tooltip-left:after, [data-tooltip].tooltip-right:after,
.tooltip-left .tooltip, .tooltip-right .tooltip {
margin-left: 0;
margin-bottom: -16px;
}

.tooltip ul, .tooltip ol {
padding-left: 1rem;
}

.tooltip :last-child {
margin-bottom: 0;
}
Loading

0 comments on commit 25e8764

Please sign in to comment.