ea881cf520
* Changes for possible bug * New sanic mode wip * More changes for fast mode, WIP * Fast mode is playable (code is ugly tho) * Fixed skip error * Fixed fast mode error * Bug fixing * Possible fix for the /leave bug before the game starts * Update README to include Codacy badge * Fixing error prone code * Removing code smells * Removing more code smells * How long can this go on? (More smells according to Codacy) * Compile locale fixed for Linux. Small es_ES fix. * Major refactoring * Wild mode finished. Changed emojis for text in log. * Removing test prints, back to emojis * Code cleaning and fix for player time in fast mode * Changing help to not override builtin function * Decreased bot.py's complexity * Default gamemode is now Fast. Added a bot configuration file * back to random * Moved logger to shared_vars * Added MIN_FAST_TURN_TIME to config and fixed 'skipped 4 times' message * Pull review changes * More review changes * Removing codacy badge linked to my account for pull request * Fixed first special card issue, logger back to how it was (with just one logging init) * Renamed gameplay config file to gameplay_config.py.
171 lines
4.6 KiB
Python
171 lines
4.6 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
#
|
|
# Telegram bot to play UNO in group chats
|
|
# Copyright (c) 2016 Jannes Höke <uno@jhoeke.de>
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU Affero General Public License as
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
# License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
import gettext
|
|
from functools import wraps
|
|
|
|
from locales import available_locales
|
|
from pony.orm import db_session
|
|
from user_setting import UserSetting
|
|
from shared_vars import gm
|
|
|
|
GETTEXT_DOMAIN = 'unobot'
|
|
GETTEXT_DIR = 'locales'
|
|
|
|
|
|
class _Underscore(object):
|
|
"""Class to emulate flufl.i18n behaviour, but with plural support"""
|
|
def __init__(self):
|
|
self.translators = {
|
|
locale: gettext.GNUTranslations(
|
|
open(gettext.find(
|
|
GETTEXT_DOMAIN, GETTEXT_DIR, languages=[locale]
|
|
), 'rb')
|
|
)
|
|
for locale
|
|
in available_locales.keys()
|
|
if locale != 'en_US' # No translation file for en_US
|
|
}
|
|
self.locale_stack = list()
|
|
|
|
def push(self, locale):
|
|
self.locale_stack.append(locale)
|
|
|
|
def pop(self):
|
|
if self.locale_stack:
|
|
return self.locale_stack.pop()
|
|
else:
|
|
return None
|
|
|
|
@property
|
|
def code(self):
|
|
if self.locale_stack:
|
|
return self.locale_stack[-1]
|
|
else:
|
|
return None
|
|
|
|
def __call__(self, singular, plural=None, n=1, locale=None):
|
|
if not locale:
|
|
locale = self.locale_stack[-1]
|
|
|
|
if locale not in self.translators.keys():
|
|
if n is 1:
|
|
return singular
|
|
else:
|
|
return plural
|
|
|
|
translator = self.translators[locale]
|
|
|
|
if plural is None:
|
|
return translator.gettext(singular)
|
|
else:
|
|
return translator.ngettext(singular, plural, n)
|
|
|
|
_ = _Underscore()
|
|
|
|
|
|
def __(singular, plural=None, n=1, multi=False):
|
|
"""Translates text into all locales on the stack"""
|
|
translations = list()
|
|
|
|
if not multi and len(set(_.locale_stack)) >= 1:
|
|
translations.append(_(singular, plural, n, 'en_US'))
|
|
|
|
else:
|
|
for locale in _.locale_stack:
|
|
translation = _(singular, plural, n, locale)
|
|
|
|
if translation not in translations:
|
|
translations.append(translation)
|
|
|
|
return '\n'.join(translations)
|
|
|
|
|
|
def user_locale(func):
|
|
@wraps(func)
|
|
@db_session
|
|
def wrapped(bot, update, *pargs, **kwargs):
|
|
user = _user_chat_from_update(update)[0]
|
|
|
|
with db_session:
|
|
us = UserSetting.get(id=user.id)
|
|
|
|
if us and us.lang != 'en':
|
|
_.push(us.lang)
|
|
else:
|
|
_.push('en_US')
|
|
|
|
result = func(bot, update, *pargs, **kwargs)
|
|
_.pop()
|
|
return result
|
|
return wrapped
|
|
|
|
|
|
def game_locales(func):
|
|
@wraps(func)
|
|
@db_session
|
|
def wrapped(bot, update, *pargs, **kwargs):
|
|
user, chat = _user_chat_from_update(update)
|
|
player = gm.player_for_user_in_chat(user, chat)
|
|
locales = list()
|
|
|
|
if player:
|
|
for player in player.game.players:
|
|
us = UserSetting.get(id=player.user.id)
|
|
|
|
if us and us.lang != 'en':
|
|
loc = us.lang
|
|
else:
|
|
loc = 'en_US'
|
|
|
|
if loc in locales:
|
|
continue
|
|
|
|
_.push(loc)
|
|
locales.append(loc)
|
|
|
|
result = func(bot, update, *pargs, **kwargs)
|
|
|
|
while _.code:
|
|
_.pop()
|
|
|
|
return result
|
|
return wrapped
|
|
|
|
|
|
def _user_chat_from_update(update):
|
|
|
|
try:
|
|
user = update.message.from_user
|
|
chat = update.message.chat
|
|
except (NameError, AttributeError):
|
|
try:
|
|
user = update.inline_query.from_user
|
|
chat = gm.userid_current[user.id].game.chat
|
|
except KeyError:
|
|
chat = None
|
|
except (NameError, AttributeError):
|
|
try:
|
|
user = update.chosen_inline_result.from_user
|
|
chat = gm.userid_current[user.id].game.chat
|
|
except (NameError, AttributeError, KeyError):
|
|
chat = None
|
|
|
|
return user, chat
|