Core: cleanup Item classes (#849)

This commit is contained in:
black-sliver 2022-08-06 00:49:54 +02:00 committed by GitHub
parent dd6e212519
commit f6da81ac70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 75 additions and 75 deletions

View File

@ -1144,31 +1144,21 @@ class ItemClassification(IntFlag):
class Item:
location: Optional[Location] = None
code: Optional[int] = None # an item with ID None is called an Event, and does not get written to multidata
name: str
game: str = "Generic"
type: str = None
__slots__ = ("name", "classification", "code", "player", "location")
name: str
classification: ItemClassification
# need to find a decent place for these to live and to allow other games to register texts if they want.
pedestal_credit_text: str = "and the Unknown Item"
sickkid_credit_text: Optional[str] = None
magicshop_credit_text: Optional[str] = None
zora_credit_text: Optional[str] = None
fluteboy_credit_text: Optional[str] = None
# hopefully temporary attributes to satisfy legacy LttP code, proper implementation in subclass ALttPItem
smallkey: bool = False
bigkey: bool = False
map: bool = False
compass: bool = False
code: Optional[int]
"""an item with code None is called an Event, and does not get written to multidata"""
player: int
location: Optional[Location]
def __init__(self, name: str, classification: ItemClassification, code: Optional[int], player: int):
self.name = name
self.classification = classification
self.player = player
self.code = code
self.location = None
@property
def hint_text(self) -> str:

View File

@ -51,6 +51,11 @@ class ItemData(typing.NamedTuple):
flute_boy_credit: typing.Optional[str]
hint_text: typing.Optional[str]
def as_init_dict(self) -> typing.Dict[str, typing.Any]:
return {key: getattr(self, key) for key in
('classification', 'type', 'item_code', 'pedestal_hint', 'hint_text')}
# Format: Name: (Advancement, Type, ItemCode, Pedestal Hint Text, Pedestal Credit Text, Sick Kid Credit Text, Zora Credit Text, Witch Credit Text, Flute Boy Credit Text, Hint Text)
item_table = {'Bow': ItemData(IC.progression, None, 0x0B, 'You have\nchosen the\narcher class.', 'the stick and twine', 'arrow-slinging kid', 'arrow sling for sale', 'witch and robin hood', 'archer boy shoots again', 'the Bow'),
'Progressive Bow': ItemData(IC.progression, None, 0x64, 'You have\nchosen the\narcher class.', 'the stick and twine', 'arrow-slinging kid', 'arrow sling for sale', 'witch and robin hood', 'archer boy shoots again', 'a Bow'),
@ -218,7 +223,7 @@ item_table = {'Bow': ItemData(IC.progression, None, 0x0B, 'You have\nchosen the\
'Open Floodgate': ItemData(IC.progression, 'Event', None, None, None, None, None, None, None, None),
}
as_dict_item_table = {name: data._asdict() for name, data in item_table.items()}
item_init_table = {name: data.as_init_dict() for name, data in item_table.items()}
progression_mapping = {
"Golden Sword": ("Progressive Sword", 4),

View File

@ -2091,7 +2091,9 @@ def write_string_to_rom(rom, target, string):
def write_strings(rom, world, player):
from . import ALTTPWorld
local_random = world.slot_seeds[player]
w: ALTTPWorld = world.worlds[player]
tt = TextTable()
tt.removeUnwantedText()
@ -2420,7 +2422,8 @@ def write_strings(rom, world, player):
pedestal_text = 'Some Hot Air' if pedestalitem is None else hint_text(pedestalitem,
True) if pedestalitem.pedestal_hint_text is not None else 'Unknown Item'
tt['mastersword_pedestal_translated'] = pedestal_text
pedestal_credit_text = 'and the Hot Air' if pedestalitem is None else pedestalitem.pedestal_credit_text if pedestalitem.pedestal_credit_text is not None else 'and the Unknown Item'
pedestal_credit_text = 'and the Hot Air' if pedestalitem is None else \
w.pedestal_credit_texts.get(pedestalitem.code, 'and the Unknown Item')
etheritem = world.get_location('Ether Tablet', player).item
ether_text = 'Some Hot Air' if etheritem is None else hint_text(etheritem,
@ -2448,20 +2451,24 @@ def write_strings(rom, world, player):
credits = Credits()
sickkiditem = world.get_location('Sick Kid', player).item
sickkiditem_text = local_random.choice(
SickKid_texts) if sickkiditem is None or sickkiditem.sickkid_credit_text is None else sickkiditem.sickkid_credit_text
sickkiditem_text = local_random.choice(SickKid_texts) \
if sickkiditem is None or sickkiditem.code not in w.sickkid_credit_texts \
else w.sickkid_credit_texts[sickkiditem.code]
zoraitem = world.get_location('King Zora', player).item
zoraitem_text = local_random.choice(
Zora_texts) if zoraitem is None or zoraitem.zora_credit_text is None else zoraitem.zora_credit_text
zoraitem_text = local_random.choice(Zora_texts) \
if zoraitem is None or zoraitem.code not in w.zora_credit_texts \
else w.zora_credit_texts[zoraitem.code]
magicshopitem = world.get_location('Potion Shop', player).item
magicshopitem_text = local_random.choice(
MagicShop_texts) if magicshopitem is None or magicshopitem.magicshop_credit_text is None else magicshopitem.magicshop_credit_text
magicshopitem_text = local_random.choice(MagicShop_texts) \
if magicshopitem is None or magicshopitem.code not in w.magicshop_credit_texts \
else w.magicshop_credit_texts[magicshopitem.code]
fluteboyitem = world.get_location('Flute Spot', player).item
fluteboyitem_text = local_random.choice(
FluteBoy_texts) if fluteboyitem is None or fluteboyitem.fluteboy_credit_text is None else fluteboyitem.fluteboy_credit_text
fluteboyitem_text = local_random.choice(FluteBoy_texts) \
if fluteboyitem is None or fluteboyitem.code not in w.fluteboy_credit_texts \
else w.fluteboy_credit_texts[fluteboyitem.code]
credits.update_credits_line('castle', 0, local_random.choice(KingsReturn_texts))
credits.update_credits_line('sanctuary', 0, local_random.choice(Sanctuary_texts))

View File

@ -18,19 +18,16 @@ class ALttPLocation(Location):
class ALttPItem(Item):
game: str = "A Link to the Past"
type: Optional[str]
_pedestal_hint_text: Optional[str]
_hint_text: Optional[str]
dungeon = None
def __init__(self, name, player, classification=ItemClassification.filler, type=None, item_code=None, pedestal_hint=None,
pedestal_credit=None, sick_kid_credit=None, zora_credit=None, witch_credit=None,
flute_boy_credit=None, hint_text=None):
def __init__(self, name, player, classification=ItemClassification.filler, type=None, item_code=None,
pedestal_hint=None, hint_text=None):
super(ALttPItem, self).__init__(name, classification, item_code, player)
self.type = type
self._pedestal_hint_text = pedestal_hint
self.pedestal_credit_text = pedestal_credit
self.sickkid_credit_text = sick_kid_credit
self.zora_credit_text = zora_credit
self.magicshop_credit_text = witch_credit
self.fluteboy_credit_text = flute_boy_credit
self._hint_text = hint_text
@property

View File

@ -8,7 +8,7 @@ from BaseClasses import Item, CollectionState, Tutorial
from .SubClasses import ALttPItem
from ..AutoWorld import World, WebWorld, LogicMixin
from .Options import alttp_options, smallkey_shuffle
from .Items import as_dict_item_table, item_name_groups, item_table, GetBeemizerItem
from .Items import item_init_table, item_name_groups, item_table, GetBeemizerItem
from .Regions import lookup_name_to_id, create_regions, mark_light_world_regions
from .Rules import set_rules
from .ItemPool import generate_itempool, difficulties
@ -124,6 +124,17 @@ class ALTTPWorld(World):
required_client_version = (0, 3, 2)
web = ALTTPWeb()
pedestal_credit_texts: typing.Dict[int, str] = \
{data.item_code: data.pedestal_credit for data in item_table.values() if data.pedestal_credit}
sickkid_credit_texts: typing.Dict[int, str] = \
{data.item_code: data.sick_kid_credit for data in item_table.values() if data.sick_kid_credit}
zora_credit_texts: typing.Dict[int, str] = \
{data.item_code: data.zora_credit for data in item_table.values() if data.zora_credit}
magicshop_credit_texts: typing.Dict[int, str] = \
{data.item_code: data.witch_credit for data in item_table.values() if data.witch_credit}
fluteboy_credit_texts: typing.Dict[int, str] = \
{data.item_code: data.flute_boy_credit for data in item_table.values() if data.flute_boy_credit}
set_rules = set_rules
create_items = generate_itempool
@ -400,7 +411,7 @@ class ALTTPWorld(World):
multidata["connect_names"][new_name] = multidata["connect_names"][self.world.player_name[self.player]]
def create_item(self, name: str) -> Item:
return ALttPItem(name, self.player, **as_dict_item_table[name])
return ALttPItem(name, self.player, **item_init_table[name])
@classmethod
def stage_fill_hook(cls, world, progitempool, nonexcludeditempool, localrestitempool, nonlocalrestitempool,

View File

@ -47,13 +47,12 @@ class ArchipIDLEWorld(World):
item_pool = []
for i in range(100):
item = Item(
item = ArchipIDLEItem(
item_table_copy[i],
ItemClassification.progression if i < 20 else ItemClassification.filler,
self.item_name_to_id[item_table_copy[i]],
self.player
)
item.game = 'ArchipIDLE'
item_pool.append(item)
self.world.itempool += item_pool
@ -93,6 +92,10 @@ def create_region(world: MultiWorld, player: int, name: str, locations=None, exi
return region
class ArchipIDLEItem(Item):
game = "ArchipIDLE"
class ArchipIDLELocation(Location):
game: str = "ArchipIDLE"

View File

@ -632,8 +632,9 @@ class HKLocation(Location):
class HKItem(Item):
game = "Hollow Knight"
type: str
def __init__(self, name, advancement, code, type, player: int = None):
def __init__(self, name, advancement, code, type: str, player: int = None):
if name == "Mimic_Grub":
classification = ItemClassification.trap
elif type in ("Grub", "DreamWarrior", "Root", "Egg"):

View File

@ -6,14 +6,9 @@
import typing
from BaseClasses import Item, ItemClassification
from worlds.alttp import ALTTPWorld
# pedestal_credit_text: str = "and the Unknown Item"
# sickkid_credit_text: Optional[str] = None
# magicshop_credit_text: Optional[str] = None
# zora_credit_text: Optional[str] = None
# fluteboy_credit_text: Optional[str] = None
class MeritousLttPText(typing.NamedTuple):
pedestal: typing.Optional[str]
sickkid: typing.Optional[str]
@ -143,6 +138,7 @@ LttPCreditsText = {
class MeritousItem(Item):
game: str = "Meritous"
type: str
def __init__(self, name, advancement, code, player):
super(MeritousItem, self).__init__(name,
@ -171,14 +167,6 @@ class MeritousItem(Item):
self.type = "Artifact"
self.classification = ItemClassification.useful
if name in LttPCreditsText:
lttp = LttPCreditsText[name]
self.pedestal_credit_text = f"and the {lttp.pedestal}"
self.sickkid_credit_text = lttp.sickkid
self.magicshop_credit_text = lttp.magicshop
self.zora_credit_text = lttp.zora
self.fluteboy_credit_text = lttp.fluteboy
offset = 593_000
@ -217,3 +205,10 @@ item_groups = {
"Important Artifacts": ["Shield Boost", "Circuit Booster", "Metabolism", "Dodge Enhancer"],
"Crystals": ["Crystals x500", "Crystals x1000", "Crystals x2000"]
}
ALTTPWorld.pedestal_credit_texts.update({item_table[name]: f"and the {texts.pedestal}"
for name, texts in LttPCreditsText.items()})
ALTTPWorld.sickkid_credit_texts.update({item_table[name]: texts.sickkid for name, texts in LttPCreditsText.items()})
ALTTPWorld.magicshop_credit_texts.update({item_table[name]: texts.magicshop for name, texts in LttPCreditsText.items()})
ALTTPWorld.zora_credit_texts.update({item_table[name]: texts.zora for name, texts in LttPCreditsText.items()})
ALTTPWorld.fluteboy_credit_texts.update({item_table[name]: texts.fluteboy for name, texts in LttPCreditsText.items()})

View File

@ -24,6 +24,7 @@ def ap_id_to_oot_data(ap_id):
class OOTItem(Item):
game: str = "Ocarina of Time"
type: str
def __init__(self, name, player, data, event, force_not_advancement):
(type, advancement, index, special) = data
@ -38,7 +39,6 @@ class OOTItem(Item):
classification = ItemClassification.progression
else:
classification = ItemClassification.filler
adv = bool(advancement) and not force_not_advancement
super(OOTItem, self).__init__(name, classification, oot_data_to_ap_id(data, event), player)
self.type = type
self.index = index
@ -47,24 +47,11 @@ class OOTItem(Item):
self.price = special.get('price', None) if special else None
self.internal = False
# The playthrough calculation calls a function that uses "sweep_for_events(key_only=True)"
# This checks if the item it's looking for is a small key, using the small key property.
# Because of overlapping item fields, this means that OoT small keys are technically counted, unless we do this.
# This causes them to be double-collected during playthrough and generation.
@property
def smallkey(self) -> bool:
return False
@property
def bigkey(self) -> bool:
return False
@property
def dungeonitem(self) -> bool:
return self.type in ['SmallKey', 'HideoutSmallKey', 'BossKey', 'GanonBossKey', 'Map', 'Compass']
# Progressive: True -> Advancement
# False -> Priority
# None -> Normal

View File

@ -2,6 +2,7 @@ import typing
from BaseClasses import Item, ItemClassification
from .Names import ItemName
from worlds.alttp import ALTTPWorld
class ItemData(typing.NamedTuple):
@ -18,9 +19,6 @@ class SA2BItem(Item):
def __init__(self, name, classification: ItemClassification, code: int = None, player: int = None):
super(SA2BItem, self).__init__(name, classification, code, player)
if self.name == ItemName.sonic_light_shoes or self.name == ItemName.shadow_air_shoes:
self.pedestal_credit_text = "and the Soap Shoes"
# Separate tables for each type of item.
emblems_table = {
@ -94,3 +92,6 @@ item_table = {
}
lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in item_table.items() if data.code}
ALTTPWorld.pedestal_credit_texts[item_table[ItemName.sonic_light_shoes].code] = "and the Soap Shoes"
ALTTPWorld.pedestal_credit_texts[item_table[ItemName.shadow_air_shoes].code] = "and the Soap Shoes"

View File

@ -5,7 +5,7 @@ import copy
import os
import threading
import base64
from typing import Set, List, TextIO
from typing import Set, TextIO
from worlds.sm.variaRandomizer.graph.graph_utils import GraphUtils
@ -735,7 +735,8 @@ class SMLocation(Location):
class SMItem(Item):
game = "Super Metroid"
type: str
def __init__(self, name, classification, type, code, player: int = None):
def __init__(self, name, classification, type: str, code, player: int):
super(SMItem, self).__init__(name, classification, code, player)
self.type = type

View File

@ -573,8 +573,10 @@ class SMZ3Location(Location):
class SMZ3Item(Item):
game = "SMZ3"
type: ItemType
item: Item
def __init__(self, name, classification, type, code, player: int = None, item=None):
def __init__(self, name, classification, type: ItemType, code, player: int, item: Item):
super(SMZ3Item, self).__init__(name, classification, code, player)
self.type = type
self.item = item
super(SMZ3Item, self).__init__(name, classification, code, player)