-
Notifications
You must be signed in to change notification settings - Fork 706
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SoE: use new AP API and naming and make APworld #2701
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
049d0a3
SoE: new file naming
black-sliver dbd2df9
SoE: use options_dataclass
black-sliver 4513e89
SoE: moar typing
black-sliver 72caef3
SoE: no more multiworld.random
black-sliver 15f248f
SoE: replace LogicMixin by SoEPlayerLogic object
black-sliver de8ef4c
SoE: add test that rocket parts always exist
black-sliver ee9fb87
SoE: Even moar typing
black-sliver ee792eb
SoE: can haz apworld now
black-sliver defe144
SoE: pep up test naming
black-sliver 15db6fb
SoE: use self.options for trap chances
black-sliver 43d1f4d
SoE: remove unused import with outdated comment
black-sliver 308093a
SoE: move flag and trap extraction to dataclass + test
black-sliver 7de4d41
SoE: test trap option parsing and item generation
black-sliver File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import typing | ||
from typing import Callable, Set | ||
|
||
from . import pyevermizer | ||
from .options import EnergyCore, OutOfBounds, SequenceBreaks, SoEOptions | ||
|
||
if typing.TYPE_CHECKING: | ||
from BaseClasses import CollectionState | ||
|
||
# TODO: Options may preset certain progress steps (i.e. P_ROCK_SKIP), set in generate_early? | ||
|
||
# TODO: resolve/flatten/expand rules to get rid of recursion below where possible | ||
# Logic.rules are all rules including locations, excluding those with no progress (i.e. locations that only drop items) | ||
rules = [rule for rule in pyevermizer.get_logic() if len(rule.provides) > 0] | ||
# Logic.items are all items and extra items excluding non-progression items and duplicates | ||
item_names: Set[str] = set() | ||
items = [item for item in filter(lambda item: item.progression, pyevermizer.get_items() + pyevermizer.get_extra_items()) | ||
if item.name not in item_names and not item_names.add(item.name)] # type: ignore[func-returns-value] | ||
|
||
|
||
class SoEPlayerLogic: | ||
__slots__ = "player", "out_of_bounds", "sequence_breaks", "has" | ||
player: int | ||
out_of_bounds: bool | ||
sequence_breaks: bool | ||
|
||
has: Callable[..., bool] | ||
""" | ||
Returns True if count of one of evermizer's progress steps is reached based on collected items. i.e. 2 * P_DE | ||
""" | ||
|
||
def __init__(self, player: int, options: "SoEOptions"): | ||
self.player = player | ||
self.out_of_bounds = options.out_of_bounds == OutOfBounds.option_logic | ||
self.sequence_breaks = options.sequence_breaks == SequenceBreaks.option_logic | ||
|
||
if options.energy_core == EnergyCore.option_fragments: | ||
# override logic for energy core fragments | ||
required_fragments = options.required_fragments.value | ||
|
||
def fragmented_has(state: "CollectionState", progress: int, count: int = 1) -> bool: | ||
if progress == pyevermizer.P_ENERGY_CORE: | ||
progress = pyevermizer.P_CORE_FRAGMENT | ||
count = required_fragments | ||
return self._has(state, progress, count) | ||
|
||
self.has = fragmented_has | ||
else: | ||
# default (energy core) logic | ||
self.has = self._has | ||
|
||
def _count(self, state: "CollectionState", progress: int, max_count: int = 0) -> int: | ||
""" | ||
Returns reached count of one of evermizer's progress steps based on collected items. | ||
i.e. returns 0-3 for P_DE based on items providing CHECK_BOSS,DIAMOND_EYE_DROP | ||
""" | ||
n = 0 | ||
for item in items: | ||
for pvd in item.provides: | ||
if pvd[1] == progress: | ||
if state.has(item.name, self.player): | ||
n += state.count(item.name, self.player) * pvd[0] | ||
if n >= max_count > 0: | ||
return n | ||
for rule in rules: | ||
for pvd in rule.provides: | ||
if pvd[1] == progress and pvd[0] > 0: | ||
has = True | ||
for req in rule.requires: | ||
if not self.has(state, req[1], req[0]): | ||
has = False | ||
break | ||
if has: | ||
n += pvd[0] | ||
if n >= max_count > 0: | ||
return n | ||
return n | ||
|
||
def _has(self, state: "CollectionState", progress: int, count: int = 1) -> bool: | ||
"""Default implementation of has""" | ||
if self.out_of_bounds is True and progress == pyevermizer.P_ALLOW_OOB: | ||
return True | ||
if self.sequence_breaks is True and progress == pyevermizer.P_ALLOW_SEQUENCE_BREAKS: | ||
return True | ||
return self._count(state, progress, count) >= count |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't notice before merge,
but wouldn't this be?
flags += option.to_flag()
so you don't have to
getattr
again?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are kind of right, I saw that after
git add
, but it needs a type ignore, or two separate instance() calls, or yet another type abstraction, so I decided to not bother at the moment.Maybe if it isn't obvious why: Flag and Flags use a typing.Protocol for self and the two protocols are incompatible, so currently we'd need to specialize on each rather than use a tuple in isinstance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I didn't notice that those were mixins.
This is how I would do it:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting. That seems like a super easy fix, but I don't understand it (and neither does pycharm 2023.2.3)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm guessing pycharm doesn't understand intersection types?
mypy and pyright see the intersection types:
option: <subclass of EvermizerFlag and Option> | <subclass of EvermizerFlags and Option>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see. the assert creates "typings" that fulfil the individual protocol. Took me a while to see why this works.
And yeah, pycharm seems to think those are Option now, rather than a combined pseudo type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in #2724