mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
shopsanity
This commit is contained in:
@@ -5,7 +5,7 @@ from enum import Enum, unique
|
||||
import logging
|
||||
import json
|
||||
from collections import OrderedDict, Counter, deque
|
||||
from typing import Union, Optional
|
||||
from typing import Union, Optional, List
|
||||
import secrets
|
||||
import random
|
||||
|
||||
@@ -521,6 +521,10 @@ class CollectionState(object):
|
||||
return any(shop.region.player == player and shop.has_unlimited(item) and shop.region.can_reach(self) for
|
||||
shop in self.world.shops)
|
||||
|
||||
def can_buy(self, item: str, player: int) -> bool:
|
||||
return any(shop.region.player == player and shop.has(item) and shop.region.can_reach(self) for
|
||||
shop in self.world.shops)
|
||||
|
||||
def item_count(self, item, player: int) -> int:
|
||||
return self.prog_items[item, player]
|
||||
|
||||
@@ -598,7 +602,7 @@ class CollectionState(object):
|
||||
def can_shoot_arrows(self, player: int) -> bool:
|
||||
if self.world.retro[player]:
|
||||
# TODO: Progressive and Non-Progressive silvers work differently (progressive is not usable until the shop arrow is bought)
|
||||
return (self.has('Bow', player) or self.has('Silver Bow', player)) and self.can_buy_unlimited('Single Arrow', player)
|
||||
return (self.has('Bow', player) or self.has('Silver Bow', player)) and self.can_buy('Single Arrow', player)
|
||||
return self.has('Bow', player) or self.has('Silver Bow', player)
|
||||
|
||||
def can_get_good_bee(self, player: int) -> bool:
|
||||
@@ -1054,11 +1058,12 @@ class ShopType(Enum):
|
||||
|
||||
class Shop(object):
|
||||
slots = 3
|
||||
def __init__(self, region, room_id, type, shopkeeper_config, custom, locked):
|
||||
|
||||
def __init__(self, region, room_id, type, shopkeeper_config, custom, locked: bool):
|
||||
self.region = region
|
||||
self.room_id = room_id
|
||||
self.type = type
|
||||
self.inventory = [None, None, None]
|
||||
self.inventory: List[Union[None, dict]] = [None, None, None]
|
||||
self.shopkeeper_config = shopkeeper_config
|
||||
self.custom = custom
|
||||
self.locked = locked
|
||||
@@ -1085,20 +1090,31 @@ class Shop(object):
|
||||
config |= 0x10 # Alt. VRAM
|
||||
return [0x00]+int16_as_bytes(self.room_id)+[door_id, 0x00, config, self.shopkeeper_config, 0x00]
|
||||
|
||||
def has_unlimited(self, item):
|
||||
def has_unlimited(self, item: str) -> bool:
|
||||
for inv in self.inventory:
|
||||
if inv is None:
|
||||
continue
|
||||
if inv['item'] == item:
|
||||
return True
|
||||
if inv['max'] != 0 and inv['replacement'] is not None and inv['replacement'] == item:
|
||||
return True
|
||||
elif inv['item'] is not None and inv['item'] == item:
|
||||
return False
|
||||
|
||||
def has(self, item: str) -> bool:
|
||||
for inv in self.inventory:
|
||||
if inv is None:
|
||||
continue
|
||||
if inv['item'] == item:
|
||||
return True
|
||||
if inv['max'] != 0 and inv['replacement'] == item:
|
||||
return True
|
||||
return False
|
||||
|
||||
def clear_inventory(self):
|
||||
self.inventory = [None, None, None]
|
||||
|
||||
def add_inventory(self, slot, item, price, max=0, replacement=None, replacement_price=0, create_location=False):
|
||||
def add_inventory(self, slot: int, item: str, price: int, max: int = 0,
|
||||
replacement: Optional[str] = None, replacement_price: int = 0, create_location: bool = False):
|
||||
self.inventory[slot] = {
|
||||
'item': item,
|
||||
'price': price,
|
||||
@@ -1108,6 +1124,18 @@ class Shop(object):
|
||||
'create_location': create_location
|
||||
}
|
||||
|
||||
def push_inventory(self, slot: int, item: str, price: int, max: int = 1):
|
||||
if not self.inventory[slot]:
|
||||
raise ValueError("Inventory can't be pushed back if it doesn't exist")
|
||||
|
||||
self.inventory[slot] = {
|
||||
'item': item,
|
||||
'price': price,
|
||||
'max': max,
|
||||
'replacement': self.inventory[slot]["item"],
|
||||
'replacement_price': self.inventory[slot]["price"],
|
||||
'create_location': self.inventory[slot]["create_location"]
|
||||
}
|
||||
|
||||
class Spoiler(object):
|
||||
world: World
|
||||
@@ -1243,6 +1271,7 @@ class Spoiler(object):
|
||||
'progression_balancing': self.world.progression_balancing,
|
||||
'triforce_pieces_available': self.world.triforce_pieces_available,
|
||||
'triforce_pieces_required': self.world.triforce_pieces_required,
|
||||
'shop_shuffle': self.world.shop_shuffle
|
||||
}
|
||||
|
||||
def to_json(self):
|
||||
@@ -1290,15 +1319,15 @@ class Spoiler(object):
|
||||
outfile.write('Progression Balanced: %s\n' % (
|
||||
'Yes' if self.metadata['progression_balancing'][player] else 'No'))
|
||||
outfile.write('Mode: %s\n' % self.metadata['mode'][player])
|
||||
outfile.write(
|
||||
'Retro: %s\n' % ('Yes' if self.metadata['retro'][player] else 'No'))
|
||||
outfile.write('Retro: %s\n' %
|
||||
('Yes' if self.metadata['retro'][player] else 'No'))
|
||||
outfile.write('Swords: %s\n' % self.metadata['weapons'][player])
|
||||
outfile.write('Goal: %s\n' % self.metadata['goal'][player])
|
||||
if "triforce" in self.metadata["goal"][player]: # triforce hunt
|
||||
outfile.write(
|
||||
"Pieces available for Triforce: %s\n" % self.metadata['triforce_pieces_available'][player])
|
||||
outfile.write(
|
||||
"Pieces required for Triforce: %s\n" % self.metadata["triforce_pieces_required"][player])
|
||||
outfile.write("Pieces available for Triforce: %s\n" %
|
||||
self.metadata['triforce_pieces_available'][player])
|
||||
outfile.write("Pieces required for Triforce: %s\n" %
|
||||
self.metadata["triforce_pieces_required"][player])
|
||||
outfile.write('Difficulty: %s\n' % self.metadata['item_pool'][player])
|
||||
outfile.write('Item Functionality: %s\n' % self.metadata['item_functionality'][player])
|
||||
outfile.write('Item Progression: %s\n' % self.metadata['progressive'][player])
|
||||
@@ -1308,14 +1337,20 @@ class Spoiler(object):
|
||||
outfile.write('Pyramid hole pre-opened: %s\n' % (
|
||||
'Yes' if self.metadata['open_pyramid'][player] else 'No'))
|
||||
outfile.write('Accessibility: %s\n' % self.metadata['accessibility'][player])
|
||||
outfile.write(
|
||||
'Map shuffle: %s\n' % ('Yes' if self.metadata['mapshuffle'][player] else 'No'))
|
||||
outfile.write('Compass shuffle: %s\n' % (
|
||||
'Yes' if self.metadata['compassshuffle'][player] else 'No'))
|
||||
outfile.write('Map shuffle: %s\n' %
|
||||
('Yes' if self.metadata['mapshuffle'][player] else 'No'))
|
||||
outfile.write('Compass shuffle: %s\n' %
|
||||
('Yes' if self.metadata['compassshuffle'][player] else 'No'))
|
||||
outfile.write(
|
||||
'Small Key shuffle: %s\n' % (bool_to_text(self.metadata['keyshuffle'][player])))
|
||||
outfile.write('Big Key shuffle: %s\n' % (
|
||||
'Yes' if self.metadata['bigkeyshuffle'][player] else 'No'))
|
||||
outfile.write('Shop inventory shuffle: %s\n' %
|
||||
bool_to_text("i" in self.metadata["shop_shuffle"][player]))
|
||||
outfile.write('Shop price shuffle: %s\n' %
|
||||
bool_to_text("p" in self.metadata["shop_shuffle"][player]))
|
||||
outfile.write('Shop upgrade shuffle: %s\n' %
|
||||
bool_to_text("u" in self.metadata["shop_shuffle"][player]))
|
||||
outfile.write('Boss shuffle: %s\n' % self.metadata['boss_shuffle'][player])
|
||||
outfile.write(
|
||||
'Enemy shuffle: %s\n' % bool_to_text(self.metadata['enemy_shuffle'][player]))
|
||||
@@ -1331,7 +1366,11 @@ class Spoiler(object):
|
||||
'Pot shuffle %s\n' % ('Yes' if self.metadata['shufflepots'][player] else 'No'))
|
||||
if self.entrances:
|
||||
outfile.write('\n\nEntrances:\n\n')
|
||||
outfile.write('\n'.join(['%s%s %s %s' % (f'{self.world.get_player_names(entry["player"])}: ' if self.world.players > 1 else '', entry['entrance'], '<=>' if entry['direction'] == 'both' else '<=' if entry['direction'] == 'exit' else '=>', entry['exit']) for entry in self.entrances.values()]))
|
||||
outfile.write('\n'.join(['%s%s %s %s' % (f'{self.world.get_player_names(entry["player"])}: '
|
||||
if self.world.players > 1 else '', entry['entrance'],
|
||||
'<=>' if entry['direction'] == 'both' else
|
||||
'<=' if entry['direction'] == 'exit' else '=>',
|
||||
entry['exit']) for entry in self.entrances.values()]))
|
||||
outfile.write('\n\nMedallions:\n')
|
||||
for dungeon, medallion in self.medallions.items():
|
||||
outfile.write(f'\n{dungeon}: {medallion}')
|
||||
|
Reference in New Issue
Block a user