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