SoE: update to v042 and balancing changes (#1125)
* SoE: rebalancing and cleanup * ModuleUpdate: make url detection more generic * SoE: change item rules to depend on target player difficulty * SoE: Update to pyevermizer 0.41.0 * adds footknight * adds location difficulty * SoE: minor optimization in item rule if .. in is faster with sets * SoE: drop support of patch format v3 * SoE: fix some typing and warnings * SoE: cleanup imports
This commit is contained in:
parent
40c3ef35c7
commit
04b6c31076
|
@ -39,18 +39,25 @@ def update(yes=False, force=False):
|
|||
path = os.path.join(os.path.dirname(__file__), req_file)
|
||||
with open(path) as requirementsfile:
|
||||
for line in requirementsfile:
|
||||
if line.startswith('https://'):
|
||||
# extract name and version from url
|
||||
wheel = line.split('/')[-1]
|
||||
name, version, _ = wheel.split('-', 2)
|
||||
line = f'{name}=={version}'
|
||||
elif line.startswith('git+https://'):
|
||||
# extract name and version
|
||||
end = line.split('/')[-1]
|
||||
name_hash, egg = end.split("#", 1)
|
||||
name, _ = name_hash.split("@", 1)
|
||||
version = egg.split('==')[-1]
|
||||
line = f'{name}=={version}'
|
||||
if line.startswith(("https://", "git+https://")):
|
||||
# extract name and version for url
|
||||
rest = line.split('/')[-1]
|
||||
line = ""
|
||||
if "#egg=" in rest:
|
||||
# from egg info
|
||||
rest, egg = rest.split("#egg=", 1)
|
||||
egg = egg.split(";", 1)[0]
|
||||
if any(compare in egg for compare in ("==", ">=", ">", "<", "<=", "!=")):
|
||||
line = egg
|
||||
else:
|
||||
egg = ""
|
||||
if "@" in rest and not line:
|
||||
raise ValueError("Can't deduce version from requirement")
|
||||
elif not line:
|
||||
# from filename
|
||||
rest = rest.replace(".zip", "-").replace(".tar.gz", "-")
|
||||
name, version, _ = rest.split("-", 2)
|
||||
line = f'{egg or name}=={version}'
|
||||
requirements = pkg_resources.parse_requirements(line)
|
||||
for requirement in requirements:
|
||||
requirement = str(requirement)
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
from BaseClasses import MultiWorld
|
||||
from ..AutoWorld import LogicMixin
|
||||
from .Options import EnergyCore
|
||||
from typing import Set
|
||||
# TODO: Options may preset certain progress steps (i.e. P_ROCK_SKIP), set in generate_early?
|
||||
from typing import Protocol, Set
|
||||
|
||||
from BaseClasses import MultiWorld
|
||||
from worlds.AutoWorld import LogicMixin
|
||||
from . import pyevermizer
|
||||
from .Options import EnergyCore
|
||||
|
||||
# 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)
|
||||
|
@ -15,9 +16,16 @@ items = [item for item in filter(lambda item: item.progression, pyevermizer.get_
|
|||
if item.name not in item_names and not item_names.add(item.name)]
|
||||
|
||||
|
||||
class LogicProtocol(Protocol):
|
||||
def has(self, name: str, player: int) -> bool: ...
|
||||
def item_count(self, name: str, player: int) -> int: ...
|
||||
def soe_has(self, progress: int, world: MultiWorld, player: int, count: int) -> bool: ...
|
||||
def _soe_count(self, progress: int, world: MultiWorld, player: int, max_count: int) -> int: ...
|
||||
|
||||
|
||||
# when this module is loaded, this mixin will extend BaseClasses.CollectionState
|
||||
class SecretOfEvermoreLogic(LogicMixin):
|
||||
def _soe_count(self, progress: int, world: MultiWorld, player: int, max_count: int = 0) -> int:
|
||||
def _soe_count(self: LogicProtocol, progress: int, world: MultiWorld, player: 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
|
||||
|
@ -44,7 +52,7 @@ class SecretOfEvermoreLogic(LogicMixin):
|
|||
return n
|
||||
return n
|
||||
|
||||
def soe_has(self, progress: int, world: MultiWorld, player: int, count: int = 1) -> bool:
|
||||
def soe_has(self: LogicProtocol, progress: int, world: MultiWorld, player: int, count: int = 1) -> bool:
|
||||
"""
|
||||
Returns True if count of one of evermizer's progress steps is reached based on collected items. i.e. 2 * P_DE
|
||||
"""
|
||||
|
|
|
@ -1,18 +1,33 @@
|
|||
import typing
|
||||
from Options import Option, Range, Choice, Toggle, DefaultOnToggle, AssembleOptions, DeathLink, ProgressionBalancing
|
||||
|
||||
from Options import Range, Choice, Toggle, DefaultOnToggle, AssembleOptions, DeathLink, ProgressionBalancing
|
||||
|
||||
|
||||
# typing boilerplate
|
||||
class FlagsProtocol(typing.Protocol):
|
||||
value: int
|
||||
default: int
|
||||
flags: typing.List[str]
|
||||
|
||||
|
||||
class FlagProtocol(typing.Protocol):
|
||||
value: int
|
||||
default: int
|
||||
flag: str
|
||||
|
||||
|
||||
# meta options
|
||||
class EvermizerFlags:
|
||||
flags: typing.List[str]
|
||||
|
||||
def to_flag(self) -> str:
|
||||
def to_flag(self: FlagsProtocol) -> str:
|
||||
return self.flags[self.value]
|
||||
|
||||
|
||||
class EvermizerFlag:
|
||||
flag: str
|
||||
|
||||
def to_flag(self) -> str:
|
||||
def to_flag(self: FlagProtocol) -> str:
|
||||
return self.flag if self.value != self.default else ''
|
||||
|
||||
|
||||
|
@ -23,6 +38,7 @@ class OffOnFullChoice(Choice):
|
|||
alias_chaos = 2
|
||||
|
||||
|
||||
# actual options
|
||||
class Difficulty(EvermizerFlags, Choice):
|
||||
"""Changes relative spell cost and stuff"""
|
||||
display_name = "Difficulty"
|
||||
|
@ -168,6 +184,7 @@ class TrapCount(Range):
|
|||
default = 0
|
||||
|
||||
|
||||
# more meta options
|
||||
class ItemChanceMeta(AssembleOptions):
|
||||
def __new__(mcs, name, bases, attrs):
|
||||
if 'item_name' in attrs:
|
||||
|
@ -183,6 +200,7 @@ class TrapChance(Range, metaclass=ItemChanceMeta):
|
|||
default = 20
|
||||
|
||||
|
||||
# more actual options
|
||||
class TrapChanceQuake(TrapChance):
|
||||
"""Sets the chance/ratio of quake traps"""
|
||||
item_name = "Quake Trap"
|
||||
|
@ -210,11 +228,12 @@ class TrapChanceOHKO(TrapChance):
|
|||
|
||||
class SoEProgressionBalancing(ProgressionBalancing):
|
||||
default = 30
|
||||
__doc__ = ProgressionBalancing.__doc__.replace(f"default {ProgressionBalancing.default}", f"default {default}")
|
||||
__doc__ = ProgressionBalancing.__doc__.replace(f"default {ProgressionBalancing.default}", f"default {default}") \
|
||||
if ProgressionBalancing.__doc__ else None
|
||||
special_range_names = {**ProgressionBalancing.special_range_names, "normal": default}
|
||||
|
||||
|
||||
soe_options: typing.Dict[str, type(Option)] = {
|
||||
soe_options: typing.Dict[str, AssembleOptions] = {
|
||||
"difficulty": Difficulty,
|
||||
"energy_core": EnergyCore,
|
||||
"required_fragments": RequiredFragments,
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import bsdiff4
|
||||
import yaml
|
||||
import os
|
||||
from typing import Optional
|
||||
|
||||
import Utils
|
||||
from worlds.Files import APDeltaPatch
|
||||
import os
|
||||
|
||||
|
||||
USHASH = '6e9c94511d04fac6e0a1e582c170be3a'
|
||||
|
@ -24,6 +23,8 @@ def get_base_rom_path(file_name: Optional[str] = None) -> str:
|
|||
options = Utils.get_options()
|
||||
if not file_name:
|
||||
file_name = options["soe_options"]["rom_file"]
|
||||
if not file_name:
|
||||
raise ValueError("Missing soe_options -> rom_file from host.yaml")
|
||||
if not os.path.exists(file_name):
|
||||
file_name = Utils.user_path(file_name)
|
||||
return file_name
|
||||
|
@ -37,30 +38,6 @@ def read_rom(stream, strip_header=True) -> bytes:
|
|||
return data
|
||||
|
||||
|
||||
def generate_yaml(patch: bytes, metadata: Optional[dict] = None) -> bytes:
|
||||
"""Generate old (<4) apbp format yaml"""
|
||||
patch = yaml.dump({"meta": metadata,
|
||||
"patch": patch,
|
||||
"game": "Secret of Evermore",
|
||||
# minimum version of patch system expected for patching to be successful
|
||||
"compatible_version": 1,
|
||||
"version": 2,
|
||||
"base_checksum": USHASH})
|
||||
return patch.encode(encoding="utf-8-sig")
|
||||
|
||||
|
||||
def generate_patch(vanilla_file, randomized_file, metadata: Optional[dict] = None) -> bytes:
|
||||
"""Generate old (<4) apbp format patch data. Run through lzma to get a complete apbp file."""
|
||||
with open(vanilla_file, "rb") as f:
|
||||
vanilla = read_rom(f)
|
||||
with open(randomized_file, "rb") as f:
|
||||
randomized = read_rom(f)
|
||||
if metadata is None:
|
||||
metadata = {}
|
||||
patch = bsdiff4.diff(vanilla, randomized)
|
||||
return generate_yaml(patch, metadata)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
print('Please use ../../Patch.py', file=sys.stderr)
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
from ..AutoWorld import World, WebWorld
|
||||
from ..generic.Rules import set_rule
|
||||
from BaseClasses import Region, Location, Entrance, Item, RegionType, Tutorial, ItemClassification
|
||||
from Utils import output_path
|
||||
import typing
|
||||
import itertools
|
||||
import os
|
||||
import os.path
|
||||
import threading
|
||||
import itertools
|
||||
import typing
|
||||
from worlds.AutoWorld import WebWorld, World
|
||||
from worlds.generic.Rules import add_item_rule, set_rule
|
||||
from BaseClasses import Entrance, Item, ItemClassification, Location, LocationProgressType, Region, RegionType, Tutorial
|
||||
from Utils import output_path
|
||||
|
||||
try:
|
||||
import pyevermizer # from package
|
||||
|
@ -16,7 +16,7 @@ except ImportError:
|
|||
from . import pyevermizer # as part of the source tree
|
||||
|
||||
from . import Logic # load logic mixin
|
||||
from .Options import soe_options, EnergyCore, RequiredFragments, AvailableFragments
|
||||
from .Options import soe_options, Difficulty, EnergyCore, RequiredFragments, AvailableFragments
|
||||
from .Patch import SoEDeltaPatch, get_base_rom_path
|
||||
|
||||
"""
|
||||
|
@ -154,9 +154,9 @@ class SoEWorld(World):
|
|||
option_definitions = soe_options
|
||||
topology_present = False
|
||||
remote_items = False
|
||||
data_version = 3
|
||||
data_version = 4
|
||||
web = SoEWebWorld()
|
||||
required_client_version = (0, 3, 3)
|
||||
required_client_version = (0, 3, 5)
|
||||
|
||||
item_name_to_id, item_id_to_raw = _get_item_mapping()
|
||||
location_name_to_id, location_id_to_raw = _get_location_mapping()
|
||||
|
@ -188,7 +188,7 @@ class SoEWorld(World):
|
|||
return SoEItem(event, ItemClassification.progression, None, self.player)
|
||||
|
||||
def create_item(self, item: typing.Union[pyevermizer.Item, str]) -> Item:
|
||||
if type(item) is str:
|
||||
if isinstance(item, str):
|
||||
item = self.item_id_to_raw[self.item_name_to_id[item]]
|
||||
if item.type == pyevermizer.CHECK_TRAP:
|
||||
classification = ItemClassification.trap
|
||||
|
@ -208,14 +208,68 @@ class SoEWorld(World):
|
|||
raise FileNotFoundError(rom_file)
|
||||
|
||||
def create_regions(self):
|
||||
# exclude 'hidden' on easy
|
||||
max_difficulty = 1 if self.world.difficulty[self.player] == Difficulty.option_easy else 256
|
||||
|
||||
# TODO: generate *some* regions from locations' requirements?
|
||||
r = Region('Menu', RegionType.Generic, 'Menu', self.player, self.world)
|
||||
r.exits = [Entrance(self.player, 'New Game', r)]
|
||||
self.world.regions += [r]
|
||||
|
||||
# group locations into spheres (1, 2, 3+ at index 0, 1, 2)
|
||||
spheres: typing.Dict[int, typing.Dict[int, typing.List[SoELocation]]] = {}
|
||||
for loc in _locations:
|
||||
spheres.setdefault(min(2, len(loc.requires)), {}).setdefault(loc.type, []).append(
|
||||
SoELocation(self.player, loc.name, self.location_name_to_id[loc.name], r,
|
||||
loc.difficulty > max_difficulty))
|
||||
|
||||
# location balancing data
|
||||
trash_fills: typing.Dict[int, typing.Dict[int, typing.Tuple[int, int, int, int]]] = {
|
||||
0: {pyevermizer.CHECK_GOURD: (20, 40, 40, 40)}, # remove up to 40 gourds from sphere 1
|
||||
1: {pyevermizer.CHECK_GOURD: (70, 90, 90, 90)}, # remove up to 90 gourds from sphere 2
|
||||
}
|
||||
|
||||
# mark some as excluded based on numbers above
|
||||
for trash_sphere, fills in trash_fills.items():
|
||||
for typ, counts in fills.items():
|
||||
count = counts[self.world.difficulty[self.player].value]
|
||||
for location in self.world.random.sample(spheres[trash_sphere][typ], count):
|
||||
location.progress_type = LocationProgressType.EXCLUDED
|
||||
# TODO: do we need to set an item rule?
|
||||
|
||||
def sphere1_blocked_items_rule(item):
|
||||
if isinstance(item, SoEItem):
|
||||
# disable certain items in sphere 1
|
||||
if item.name in {"Gauge", "Wheel"}:
|
||||
return False
|
||||
# and some more for non-easy, non-mystery
|
||||
if self.world.difficulty[item.player] not in (Difficulty.option_easy, Difficulty.option_mystery):
|
||||
if item.name in {"Laser Lance", "Atom Smasher", "Diamond Eye"}:
|
||||
return False
|
||||
return True
|
||||
|
||||
for locations in spheres[0].values():
|
||||
for location in locations:
|
||||
add_item_rule(location, sphere1_blocked_items_rule)
|
||||
|
||||
# make some logically late(r) bosses priority locations to increase complexity
|
||||
if self.world.difficulty[self.player] == Difficulty.option_mystery:
|
||||
late_count = self.world.random.randint(0, 2)
|
||||
else:
|
||||
late_count = self.world.difficulty[self.player].value
|
||||
late_bosses = ("Tiny", "Aquagoth", "Megataur", "Rimsala",
|
||||
"Mungola", "Lightning Storm", "Magmar", "Volcano Viper")
|
||||
late_locations = self.world.random.sample(late_bosses, late_count)
|
||||
|
||||
# add locations to the world
|
||||
r = Region('Ingame', RegionType.Generic, 'Ingame', self.player, self.world)
|
||||
r.locations = [SoELocation(self.player, loc.name, self.location_name_to_id[loc.name], r)
|
||||
for loc in _locations]
|
||||
for sphere in spheres.values():
|
||||
for locations in sphere.values():
|
||||
for location in locations:
|
||||
r.locations.append(location)
|
||||
if location.name in late_locations:
|
||||
location.progress_type = LocationProgressType.PRIORITY
|
||||
|
||||
r.locations.append(SoELocation(self.player, 'Done', None, r))
|
||||
self.world.regions += [r]
|
||||
|
||||
|
@ -269,6 +323,7 @@ class SoEWorld(World):
|
|||
if v < c:
|
||||
return self.create_item(trap_names[t])
|
||||
v -= c
|
||||
assert False, "Bug in create_trap"
|
||||
|
||||
for _ in range(trap_count):
|
||||
if len(ingredients) < 1:
|
||||
|
@ -289,7 +344,7 @@ class SoEWorld(World):
|
|||
location = self.world.get_location(loc.name, self.player)
|
||||
set_rule(location, self.make_rule(loc.requires))
|
||||
|
||||
def make_rule(self, requires: typing.List[typing.Tuple[int]]) -> typing.Callable[[typing.Any], bool]:
|
||||
def make_rule(self, requires: typing.List[typing.Tuple[int, int]]) -> typing.Callable[[typing.Any], bool]:
|
||||
def rule(state) -> bool:
|
||||
for count, progress in requires:
|
||||
if not state.soe_has(progress, self.world, self.player, count):
|
||||
|
@ -321,8 +376,8 @@ class SoEWorld(World):
|
|||
while len(self.connect_name.encode('utf-8')) > 32:
|
||||
self.connect_name = self.connect_name[:-1]
|
||||
self.connect_name_available_event.set()
|
||||
placement_file = None
|
||||
out_file = None
|
||||
placement_file = ""
|
||||
out_file = ""
|
||||
try:
|
||||
money = self.world.money_modifier[self.player].value
|
||||
exp = self.world.exp_modifier[self.player].value
|
||||
|
@ -346,14 +401,15 @@ class SoEWorld(World):
|
|||
with open(placement_file, "wb") as f: # generate placement file
|
||||
for location in filter(lambda l: l.player == self.player, self.world.get_locations()):
|
||||
item = location.item
|
||||
if item.code is None:
|
||||
assert item is not None, "Can't handle unfilled location"
|
||||
if item.code is None or location.address is None:
|
||||
continue # skip events
|
||||
loc = self.location_id_to_raw[location.address]
|
||||
if item.player != self.player:
|
||||
line = f'{loc.type},{loc.index}:{pyevermizer.CHECK_NONE},{item.code},{item.player}\n'
|
||||
else:
|
||||
item = self.item_id_to_raw[item.code]
|
||||
line = f'{loc.type},{loc.index}:{item.type},{item.index}\n'
|
||||
soe_item = self.item_id_to_raw[item.code]
|
||||
line = f'{loc.type},{loc.index}:{soe_item.type},{soe_item.index}\n'
|
||||
f.write(line.encode('utf-8'))
|
||||
|
||||
if not os.path.exists(rom_file):
|
||||
|
@ -364,14 +420,14 @@ class SoEWorld(World):
|
|||
patch = SoEDeltaPatch(patch_file, player=self.player,
|
||||
player_name=player_name, patched_path=out_file)
|
||||
patch.write()
|
||||
except:
|
||||
except Exception:
|
||||
raise
|
||||
finally:
|
||||
try:
|
||||
os.unlink(placement_file)
|
||||
os.unlink(out_file)
|
||||
os.unlink(out_file[:-4] + '_SPOILER.log')
|
||||
except:
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
def modify_multidata(self, multidata: dict):
|
||||
|
@ -388,11 +444,15 @@ class SoEWorld(World):
|
|||
|
||||
class SoEItem(Item):
|
||||
game: str = "Secret of Evermore"
|
||||
__slots__ = () # disable __dict__
|
||||
|
||||
|
||||
class SoELocation(Location):
|
||||
game: str = "Secret of Evermore"
|
||||
__slots__ = () # disables __dict__ once Location has __slots__
|
||||
|
||||
def __init__(self, player: int, name: str, address: typing.Optional[int], parent):
|
||||
def __init__(self, player: int, name: str, address: typing.Optional[int], parent: Region, exclude: bool = False):
|
||||
super().__init__(player, name, address, parent)
|
||||
# unconditional assignments favor a split dict, saving memory
|
||||
self.progress_type = LocationProgressType.EXCLUDED if exclude else LocationProgressType.DEFAULT
|
||||
self.event = not address
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp38-cp38-win_amd64.whl#egg=pyevermizer; sys_platform == 'win32' and platform_machine == 'AMD64' and python_version == '3.8'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp39-cp39-win_amd64.whl#egg=pyevermizer; sys_platform == 'win32' and platform_machine == 'AMD64' and python_version == '3.9'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp310-cp310-win_amd64.whl#egg=pyevermizer; sys_platform == 'win32' and platform_machine == 'AMD64' and python_version == '3.10'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl#egg=pyevermizer; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version == '3.8'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl#egg=pyevermizer; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version == '3.9'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl#egg=pyevermizer; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version == '3.10'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#egg=pyevermizer; sys_platform == 'linux' and platform_machine == 'aarch64' and python_version == '3.8'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#egg=pyevermizer; sys_platform == 'linux' and platform_machine == 'aarch64' and python_version == '3.9'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#egg=pyevermizer; sys_platform == 'linux' and platform_machine == 'aarch64' and python_version == '3.10'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp38-cp38-macosx_10_9_x86_64.whl#egg=pyevermizer; sys_platform == 'darwin' and python_version == '3.8'
|
||||
#https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp39-cp39-macosx_10_9_x86_64.whl#egg=pyevermizer; sys_platform == 'darwin' and python_version == '3.9'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp39-cp39-macosx_10_9_universal2.whl#egg=pyevermizer; sys_platform == 'darwin' and python_version == '3.9'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp310-cp310-macosx_10_9_universal2.whl#egg=pyevermizer; sys_platform == 'darwin' and python_version == '3.10'
|
||||
#https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3.tar.gz#egg=pyevermizer; python_version == '3.11'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.42.0/pyevermizer-0.42.0-cp38-cp38-win_amd64.whl#egg=pyevermizer==0.42.0; sys_platform == 'win32' and platform_machine == 'AMD64' and python_version == '3.8'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.42.0/pyevermizer-0.42.0-cp39-cp39-win_amd64.whl#egg=pyevermizer==0.42.0; sys_platform == 'win32' and platform_machine == 'AMD64' and python_version == '3.9'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.42.0/pyevermizer-0.42.0-cp310-cp310-win_amd64.whl#egg=pyevermizer==0.42.0; sys_platform == 'win32' and platform_machine == 'AMD64' and python_version == '3.10'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.42.0/pyevermizer-0.42.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl#egg=pyevermizer==0.42.0; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version == '3.8'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.42.0/pyevermizer-0.42.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl#egg=pyevermizer==0.42.0; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version == '3.9'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.42.0/pyevermizer-0.42.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl#egg=pyevermizer==0.42.0; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version == '3.10'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.42.0/pyevermizer-0.42.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#egg=pyevermizer==0.42.0; sys_platform == 'linux' and platform_machine == 'aarch64' and python_version == '3.8'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.42.0/pyevermizer-0.42.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#egg=pyevermizer==0.42.0; sys_platform == 'linux' and platform_machine == 'aarch64' and python_version == '3.9'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.42.0/pyevermizer-0.42.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#egg=pyevermizer==0.42.0; sys_platform == 'linux' and platform_machine == 'aarch64' and python_version == '3.10'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.42.0/pyevermizer-0.42.0-cp38-cp38-macosx_10_9_x86_64.whl#egg=pyevermizer==0.42.0; sys_platform == 'darwin' and python_version == '3.8'
|
||||
#https://github.com/black-sliver/pyevermizer/releases/download/v0.42.0/pyevermizer-0.42.0-cp39-cp39-macosx_10_9_x86_64.whl#egg=pyevermizer==0.42.0; sys_platform == 'darwin' and python_version == '3.9'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.42.0/pyevermizer-0.42.0-cp39-cp39-macosx_10_9_universal2.whl#egg=pyevermizer==0.42.0; sys_platform == 'darwin' and python_version == '3.9'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.42.0/pyevermizer-0.42.0-cp310-cp310-macosx_10_9_universal2.whl#egg=pyevermizer==0.42.0; sys_platform == 'darwin' and python_version == '3.10'
|
||||
https://github.com/black-sliver/pyevermizer/releases/download/v0.42.0/pyevermizer-0.42.0.tar.gz#egg=pyevermizer==0.42.0; python_version < '3.8' or python_version > '3.10' or (sys_platform != 'win32' and sys_platform != 'linux' and sys_platform != 'darwin') or (platform_machine != 'AMD64' and platform_machine != 'x86_64' and platform_machine != 'aarch64' and platform_machine != 'universal2' and platform_machine != 'arm64')
|
||||
|
|
Loading…
Reference in New Issue