forked from nortti/tea_cah
Add a concept of deck namespaces
This commit is contained in:
parent
8fedaf40d1
commit
4357ea6510
18
botcmd.py
18
botcmd.py
|
@ -145,8 +145,8 @@ def usage(command):
|
|||
('limit',) : HelpEntry('!limit [<number> [<type>]]', 'Show or adjust the win limit. Type can be "r" for rounds and "p" for points.', False),
|
||||
('help',) : HelpEntry('!help [command [subcommand]]', 'Show a synopsis and description for the specified command.', False),
|
||||
|
||||
('deck', 'add') : HelpEntry('!deck add <code> | random', 'Add the deck with the specified cardcast code (or pick one randomly).', False),
|
||||
('deck', 'remove') : HelpEntry('!deck remove <code>', 'Remove the deck with the specified cardcast code.', False),
|
||||
('deck', 'add') : HelpEntry('!deck add <namespace> <code> | random', 'Add the deck with the specified namespace and code (or pick one randomly).', False),
|
||||
('deck', 'remove') : HelpEntry('!deck remove <namespace> <code>', 'Remove the deck with the namespace and code.', False),
|
||||
('deck', 'list') : HelpEntry('!deck list', 'List selected decks.', False),
|
||||
('bot', 'add') : HelpEntry('!bot add <type> [<name>]', 'Add a bot of the specified type and name. If the name is omitted, name the bot after its type.', False),
|
||||
('bot', 'remove') : HelpEntry('!bot remove <name>', 'Remove the specified bot.', False),
|
||||
|
@ -247,19 +247,19 @@ def parse_command(message, nick, irc):
|
|||
|
||||
subc = message[1]
|
||||
if subc == 'add':
|
||||
args = arg(1, 2)
|
||||
args = arg(2, 2)
|
||||
if args is not None:
|
||||
code, = args
|
||||
namespace, code, = args
|
||||
if code == 'random':
|
||||
send_event((events.deck_add_random,))
|
||||
send_event((events.deck_add_random, namespace))
|
||||
else:
|
||||
send_event((events.deck_add, code))
|
||||
send_event((events.deck_add, namespace, code))
|
||||
|
||||
elif subc == 'remove':
|
||||
args = arg(1, 2)
|
||||
args = arg(2, 2)
|
||||
if args is not None:
|
||||
code, = args
|
||||
send_event((events.deck_remove, code))
|
||||
namespace, code, = args
|
||||
send_event((events.deck_remove, namespace, code))
|
||||
|
||||
elif subc == 'list':
|
||||
if arg(0, 2) is not None:
|
||||
|
|
157
gameloop.py
157
gameloop.py
|
@ -16,12 +16,21 @@ class events(enum.Enum):
|
|||
class limit_types(enum.Enum):
|
||||
points, rounds = range(2)
|
||||
|
||||
Deck = namedtuple('Deck', ['code', 'name', 'author', 'call_count', 'response_count', 'calls', 'responses'])
|
||||
# fqcode = fully qualified code = (namespace, code)
|
||||
Deck = namedtuple('Deck', ['fqcode', 'name', 'author', 'call_count', 'response_count', 'calls', 'responses'])
|
||||
|
||||
Limit = namedtuple('Limit', ['type', 'number'])
|
||||
|
||||
Card = namedtuple('Card', ['deck', 'text'])
|
||||
|
||||
Namespace = namedtuple('Namespace', ['url', 'supports_random'])
|
||||
|
||||
deck_namespaces = {
|
||||
'cardcast': Namespace(None, True), # Use the library's default URL
|
||||
'bslsk05': Namespace('https://dl.puckipedia.com/', False)
|
||||
}
|
||||
|
||||
|
||||
class IRCFormattingState:
|
||||
def __init__(self):
|
||||
# 99 is the "client default colour"
|
||||
|
@ -130,15 +139,11 @@ def game(send, notice, voice, devoice, get_event):
|
|||
|
||||
send(', '.join(sorted(players) + sorted(i.nick for i in bots.values())))
|
||||
|
||||
def add_deck(code):
|
||||
def add_deck(namespace, code):
|
||||
nonlocal decks
|
||||
assert code not in decks
|
||||
assert (namespace, code) not in decks
|
||||
|
||||
# Colondeck and offtopiadeck deck live elsewhere
|
||||
if code in ('colondeck', 'offtopiadeck'):
|
||||
base_url = 'https://dl.puckipedia.com/'
|
||||
else:
|
||||
base_url = None
|
||||
base_url = deck_namespaces[namespace].url
|
||||
|
||||
# First get info for the deck we're adding
|
||||
info = cardcast_api.info(code, base_url = base_url)
|
||||
|
@ -192,8 +197,8 @@ def game(send, notice, voice, devoice, get_event):
|
|||
responses[i] = responses[i][:159] + '…'
|
||||
|
||||
# Add a new deck to list of decks
|
||||
decks[code] = Deck(
|
||||
code = code,
|
||||
decks[(namespace, code)] = Deck(
|
||||
fqcode = (namespace, code),
|
||||
name = name,
|
||||
author = author,
|
||||
call_count = call_count,
|
||||
|
@ -202,33 +207,32 @@ def game(send, notice, voice, devoice, get_event):
|
|||
responses = responses
|
||||
)
|
||||
|
||||
def get_random_deck_code():
|
||||
nonlocal cardcast_deck_count
|
||||
def get_random_deck_code(namespace):
|
||||
nonlocal remote_deck_count
|
||||
|
||||
# Provide the count on subsequent calls
|
||||
# First time around cardcast_deck_count will be None, so it
|
||||
# gets requested from Cardcast, like if we didn't pass the
|
||||
# `count` parameter
|
||||
# This will update cardcast_deck_count for each call
|
||||
# unnecessarily, but I think it simplifies the code and is not
|
||||
# too bad
|
||||
code, cardcast_deck_count = cardcast_api.random_code(count = cardcast_deck_count)
|
||||
base_url = deck_namespaces[namespace].url
|
||||
# Keep track of how many cards there are on the remote, so that we don't
|
||||
# need to keep rerequesting that
|
||||
if namespace not in remote_deck_count:
|
||||
code, remote_deck_count[namespace] = cardcast_api.random_code(base_url = base_url)
|
||||
else:
|
||||
code, remote_deck_count[namespace] = cardcast_api.random_code(count = remote_deck_count[namespace], base_url = base_url)
|
||||
|
||||
return code
|
||||
|
||||
def remove_deck(code):
|
||||
def remove_deck(namespace, code):
|
||||
nonlocal decks, round_call_card
|
||||
|
||||
# Purge all the cards from the deck from the game
|
||||
for player_bot in players_bots():
|
||||
for index, card in enumerate(player_bot.hand):
|
||||
if card is not None and card.deck.code == code:
|
||||
if card is not None and card.deck.fqcode == (namespace, code):
|
||||
player_bot.hand[index] = None
|
||||
|
||||
if round_call_card is not None and round_call_card.deck.code == code:
|
||||
if round_call_card is not None and round_call_card.deck.fqcode == (namespace, code):
|
||||
round_call_card = None
|
||||
|
||||
del decks[code]
|
||||
del decks[(namespace, code)]
|
||||
|
||||
def list_decks():
|
||||
nonlocal decks
|
||||
|
@ -246,33 +250,45 @@ def game(send, notice, voice, devoice, get_event):
|
|||
responses_left = len(deck.responses)
|
||||
responses = str(response_count) if response_count == responses_left else '%i/%i' % (responses_left, response_count)
|
||||
|
||||
send('%s (%s, by %s, %s black, %s white)' % (
|
||||
namespace, code = deck.fqcode
|
||||
|
||||
send('%s (%s %s, by %s, %s black, %s white)' % (
|
||||
deck.name,
|
||||
deck.code,
|
||||
namespace,
|
||||
code,
|
||||
deck.author,
|
||||
calls,
|
||||
responses
|
||||
))
|
||||
|
||||
def deck_add_handler(code):
|
||||
def deck_add_handler(namespace, code):
|
||||
nonlocal decks
|
||||
|
||||
if code not in decks:
|
||||
errwrapper('Failure adding deck: %s (%%s)' % code, add_deck, code)
|
||||
if namespace in deck_namespaces:
|
||||
if (namespace, code) not in decks:
|
||||
errwrapper('Failure adding deck: %s %s (%%s)' % (namespace, code), add_deck, namespace, code)
|
||||
else:
|
||||
send('Deck already added')
|
||||
else:
|
||||
send('Deck already added')
|
||||
send('Unknown deck namespace %s. Try one of: %s' % (namespace, ', '.join(deck_namespaces.keys())))
|
||||
|
||||
def deck_add_random_handler():
|
||||
def deck_add_random_handler(namespace):
|
||||
nonlocal decks
|
||||
|
||||
# Let's hope this never bites us in the butt
|
||||
while True:
|
||||
code = errwrapper('Failure getting random code for a deck. (%s)', get_random_deck_code)
|
||||
if code is Error: return
|
||||
if code not in decks: break
|
||||
send('That was weird, got %s randomly but it was already added' % code)
|
||||
errwrapper('Failure adding deck: %s (%%s)' % code, add_deck, code)
|
||||
send('Added deck %s (%s)' % (decks[code].name, code))
|
||||
if namespace in deck_namespaces:
|
||||
if deck_namespaces[namespace].supports_random:
|
||||
# Let's hope this never bites us in the butt
|
||||
while True:
|
||||
code = errwrapper('Failure getting random code for a deck. (%s)', get_random_deck_code, namespace)
|
||||
if code is Error: return
|
||||
if (namespace, code) not in decks: break
|
||||
send('That was weird, got %s randomly but it was already added' % code)
|
||||
errwrapper('Failure adding deck: %s %s (%%s)' % (namespace, code), add_deck, namespace, code)
|
||||
send('Added deck %s (%s %s)' % (decks[(namespace, code)].name, namespace, code))
|
||||
else:
|
||||
send('Namespace %s does\'t support adding a random deck. Try one of: %s' % (namespace, ', '.join(namespace for namespace in deck_namespaces.keys() if deck_namespaces[namespace].supports_random)))
|
||||
else:
|
||||
send('Unknown deck namespace %s. Try one of: %s' % (namespace, ', '.join(deck_namespaces.keys())))
|
||||
|
||||
def get_hand_origins(player):
|
||||
hand_origins = []
|
||||
|
@ -281,7 +297,7 @@ def game(send, notice, voice, devoice, get_event):
|
|||
if card is None:
|
||||
hand_origins.append('<empty>')
|
||||
else:
|
||||
hand_origins.append(card.deck.code)
|
||||
hand_origins.append('%s %s' % card.deck.fqcode)
|
||||
|
||||
return ', '.join('%i: %s' % (index, i) for index, i in enumerate(hand_origins))
|
||||
|
||||
|
@ -348,18 +364,19 @@ def game(send, notice, voice, devoice, get_event):
|
|||
send('%s has been removed from the game' % kickee)
|
||||
|
||||
elif event == events.deck_add:
|
||||
code, = args
|
||||
deck_add_handler(code)
|
||||
namespace, code = args
|
||||
deck_add_handler(namespace, code)
|
||||
|
||||
elif event == events.deck_add_random:
|
||||
deck_add_random_handler()
|
||||
namespace, = args
|
||||
deck_add_random_handler(namespace)
|
||||
|
||||
elif event == events.deck_remove:
|
||||
code, = args
|
||||
if code in decks:
|
||||
errwrapper('Failure removing deck %s (%%s)' % code, remove_deck, code)
|
||||
namespace, code = args
|
||||
if (namespace, code) in decks:
|
||||
errwrapper('Failure removing deck %s (%%s)' % code, remove_deck, namespace, code)
|
||||
else:
|
||||
send('No such deck %s' % code)
|
||||
send('No such deck %s %s' % (namespace, code))
|
||||
|
||||
elif event == events.deck_list:
|
||||
list_decks()
|
||||
|
@ -412,27 +429,26 @@ def game(send, notice, voice, devoice, get_event):
|
|||
|
||||
def start_game(rest):
|
||||
if len(rest) == 0 or rest[0] == 'default':
|
||||
send('Adding the default CAH deck (A5DCM)')
|
||||
send('Adding the default CAH deck (cardcast A5DCM)')
|
||||
|
||||
deck_add_handler('A5DCM')
|
||||
deck_add_handler('cardcast', 'A5DCM')
|
||||
|
||||
elif rest[0] == 'offtopia-random':
|
||||
send('Adding the default CAH deck (A5DCM), offtopia injoke deck (offtopiadeck), :Deck (colondeck) and three random decks')
|
||||
send('Adding the default CAH deck (cardcast A5DCM), offtopia injoke deck (bslsk05 offtopiadeck), :Deck (bslsk05 colondeck) and three random cardcast decks')
|
||||
|
||||
deck_add_handler('A5DCM')
|
||||
deck_add_handler('offtopiadeck')
|
||||
deck_add_handler('colondeck')
|
||||
deck_add_handler('cardcast', 'A5DCM')
|
||||
deck_add_handler('bslsk05', 'offtopiadeck')
|
||||
deck_add_handler('bslsk05', 'colondeck')
|
||||
|
||||
deck_add_random_handler()
|
||||
deck_add_random_handler()
|
||||
deck_add_random_handler()
|
||||
for _ in range(3):
|
||||
deck_add_random_handler('cardcast')
|
||||
|
||||
elif rest[0] == 'offtopia':
|
||||
send('Adding the default CAH deck (A5DCM), offtopia injoke deck (offtopiadeck), and :Deck (colondeck)')
|
||||
send('Adding the default CAH deck (cardcast A5DCM), offtopia injoke deck (bslsk05 offtopiadeck), and :Deck (bslsk05 colondeck)')
|
||||
|
||||
deck_add_handler('A5DCM')
|
||||
deck_add_handler('offtopiadeck')
|
||||
deck_add_handler('colondeck')
|
||||
deck_add_handler('cardcast', 'A5DCM')
|
||||
deck_add_handler('bslsk05', 'offtopiadeck')
|
||||
deck_add_handler('bslsk05', 'colondeck')
|
||||
|
||||
elif rest[0] != 'empty':
|
||||
send('Unknown preset %s' % rest[0])
|
||||
|
@ -1067,10 +1083,10 @@ def game(send, notice, voice, devoice, get_event):
|
|||
nick, = args
|
||||
|
||||
if nick not in players:
|
||||
notice(nick, 'call: %s' % round_call_card.deck.code)
|
||||
notice(nick, 'call: %s %s ' % round_call_card.deck.fqcode)
|
||||
|
||||
else:
|
||||
notice(nick, 'call: %s, %s' % (round_call_card.deck.code, get_hand_origins(players[nick])))
|
||||
notice(nick, 'call: %s %s, %s' % (*round_call_card.deck.fqcode, get_hand_origins(players[nick])))
|
||||
|
||||
elif event == events.redeal:
|
||||
nick, = args
|
||||
|
@ -1204,15 +1220,15 @@ def game(send, notice, voice, devoice, get_event):
|
|||
nick, = args
|
||||
|
||||
if nick not in players:
|
||||
notice(nick, 'call: %s' % round_call_card.deck.code)
|
||||
notice(nick, 'call: %s %s' % round_call_card.deck.fqcode)
|
||||
|
||||
else:
|
||||
answers_origins = []
|
||||
for index, player_bot in enumerate(choosers):
|
||||
answer_origins = [i.deck.code for i in card_choices[player_bot]]
|
||||
answer_origins = ['%s %s' % i.deck.fqcode for i in card_choices[player_bot]]
|
||||
answers_origins.append('%i: %s' % (index, ', '.join(answer_origins)))
|
||||
|
||||
notice(nick, 'call: %s; %s' % (round_call_card.deck.code, '; '.join(answers_origins)))
|
||||
notice(nick, 'call: %s %s; %s' % (*round_call_card.deck.fqcode, '; '.join(answers_origins)))
|
||||
|
||||
elif event == events.redeal:
|
||||
nick, = args
|
||||
|
@ -1314,7 +1330,7 @@ def game(send, notice, voice, devoice, get_event):
|
|||
czar = None
|
||||
card_choices = None
|
||||
|
||||
cardcast_deck_count = None
|
||||
remote_deck_count = {}
|
||||
|
||||
state = no_game
|
||||
while state != quit:
|
||||
|
@ -1366,13 +1382,16 @@ if __name__ == '__main__':
|
|||
kickee = input('kickee> ')
|
||||
return (events.kick, kicker, kickee)
|
||||
elif t == 'deck add':
|
||||
namespace = input('namespace> ')
|
||||
code = input('code> ')
|
||||
return (events.deck_add, code)
|
||||
return (events.deck_add, namespace, code)
|
||||
elif t == 'deck add random':
|
||||
return (events.deck_add_random,)
|
||||
namespace = input('namespace> ')
|
||||
return (events.deck_add_random, namespace)
|
||||
elif t == 'deck remove':
|
||||
namespace = input('namespace> ')
|
||||
code = input('code> ')
|
||||
return (events.deck_remove, code)
|
||||
return (events.deck_remove, namespace, code)
|
||||
elif t == 'deck list':
|
||||
return (events.deck_list,)
|
||||
elif t == 'bot add rando':
|
||||
|
|
Loading…
Reference in New Issue