1
Fork 0
mirror of https://github.com/RYGhub/royal-mifia.git synced 2024-11-22 13:54:19 +00:00
royal-mifia/main.py

1423 lines
58 KiB
Python
Raw Normal View History

2016-05-26 09:52:01 +00:00
#!/usr/bin/env python3.5
2016-04-25 16:13:16 +00:00
# -*- coding: utf-8 -*-
2017-01-25 17:11:39 +00:00
import datetime
2017-01-31 13:47:56 +00:00
import pickle # Per salvare la partita su file.
2016-12-09 17:43:14 +00:00
import math
2017-07-04 22:40:23 +00:00
import time
2016-12-09 17:43:14 +00:00
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler
2017-07-04 22:40:23 +00:00
from telegram import ParseMode, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.error import Unauthorized, TimedOut
import filemanager
import random
2016-05-25 11:57:15 +00:00
import strings as s
2016-08-10 14:05:30 +00:00
import logging
2016-12-05 18:34:01 +00:00
logging.basicConfig(level=logging.WARNING,
2016-08-10 14:05:30 +00:00
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
2016-04-21 20:14:35 +00:00
token = filemanager.readfile('telegramapi.txt')
updater = Updater(token)
freenames = s.names_list.copy()
2016-05-27 22:13:34 +00:00
2016-04-21 17:52:01 +00:00
# Ruoli possibili per i giocatori
# Base di un ruolo
class Role:
"""Classe base di un ruolo. Da qui si sviluppano tutti gli altri ruoli."""
2016-06-02 15:09:07 +00:00
icon = "-" # Icona del ruolo, da visualizzare di fianco al nome
2017-01-31 13:47:56 +00:00
team = 'None' # Squadra: 'None', 'Good', 'Evil', 'Chaos'; conta per le condizioni di vittoria
2016-06-02 15:09:07 +00:00
name = "UNDEFINED" # Nome del ruolo, viene visualizzato dall'investigatore e durante l'assegnazione
2017-01-31 13:47:56 +00:00
powerdesc = None # Ha un potere? Se sì, queste sono le info su come usarlo in seconda persona.
2016-12-05 18:07:18 +00:00
def __init__(self, player):
self.player = player
2016-05-27 09:46:54 +00:00
def __repr__(self) -> str:
2017-07-04 22:40:23 +00:00
return "<undefined Role>"
def __str__(self) -> str:
return "{} {}".format(self.icon, self.name)
2016-04-21 17:52:01 +00:00
2016-12-05 18:07:18 +00:00
def power(self, bot, game, arg):
2016-05-25 09:52:53 +00:00
"""Il potere del ruolo. Si attiva quando il bot riceve un /power in chat privata."""
2016-04-21 17:52:01 +00:00
pass
2016-05-26 09:30:31 +00:00
def onendday(self, bot, game):
"""Metodo chiamato alla fine di ogni giorno."""
pass
2016-12-05 18:09:07 +00:00
def ondeath(self, bot, game):
"""Metodo chiamato alla morte del giocatore."""
2016-04-21 17:52:01 +00:00
pass
2016-12-11 15:31:44 +00:00
def onstartgame(self, bot, game):
"""Metodo chiamato all'inizio della partita."""
pass
2016-04-21 17:52:01 +00:00
class Royal(Role):
2016-05-25 09:52:53 +00:00
"""Un membro della Royal Games. Il ruolo principale, non ha alcun potere se non quello di votare."""
2016-06-02 15:09:07 +00:00
icon = s.royal_icon
team = 'Good'
name = s.royal_name
2016-12-05 18:07:18 +00:00
def __init__(self, player):
super().__init__(player)
2016-04-21 17:52:01 +00:00
2016-05-27 09:46:54 +00:00
def __repr__(self) -> str:
2017-07-04 22:40:23 +00:00
return "<Role: Royal>"
2016-04-21 17:52:01 +00:00
class Mifioso(Role):
2016-05-25 11:57:15 +00:00
"""Il nemico globale. Può impostare come bersaglio una persona al giorno, per poi ucciderla alla fine."""
2016-06-02 15:09:07 +00:00
icon = s.mifia_icon
team = 'Evil'
name = s.mifia_name
powerdesc = s.mifia_power_description
2016-12-05 18:07:18 +00:00
def __init__(self, player):
super().__init__(player)
2016-05-22 15:13:26 +00:00
self.target = None
2016-05-27 09:46:54 +00:00
def __repr__(self) -> str:
2016-05-26 09:08:50 +00:00
if self.target is None:
2017-07-04 22:40:23 +00:00
return "<Role: Mifioso>"
2016-05-26 09:08:50 +00:00
else:
2017-07-04 22:40:23 +00:00
return "<Role: Mifioso, targeting {target}>".format(target=self.target.tusername)
2016-04-21 17:52:01 +00:00
2016-12-05 18:07:18 +00:00
def power(self, bot, game, arg):
2016-05-25 09:52:53 +00:00
# Imposta una persona come bersaglio da uccidere.
selected = game.findplayerbyusername(arg)
2017-07-05 16:51:52 +00:00
if selected is None:
2016-12-05 18:07:18 +00:00
self.player.message(bot, s.error_username)
2017-07-05 16:51:52 +00:00
return
self.target = selected
self.player.message(bot, s.mifia_target_selected.format(target=self.target.tusername))
2016-04-21 17:52:01 +00:00
2016-05-26 09:30:31 +00:00
def onendday(self, bot, game):
2017-07-05 16:51:52 +00:00
if game.votingmifia:
# Se la partita è in modalità votingmifia l'uccisione della mifia viene gestita dalla classe Game
self.target = None
else:
2016-05-26 13:12:49 +00:00
# Uccidi il bersaglio se non è protetto da un Angelo.
if self.target is not None:
if self.target.protectedby is None:
2016-12-09 16:21:41 +00:00
if game.missingmifia and random.randrange(0, 100) < game.misschance:
# Colpo mancato
game.message(bot, s.mifia_target_missed.format(target=self.target.tusername))
else:
# Uccisione riuscita
self.target.kill(bot, self)
game.message(bot, s.mifia_target_killed.format(target=self.target.tusername,
icon=self.target.role.icon,
role=self.target.role.name))
2016-05-26 13:12:49 +00:00
else:
2017-07-05 16:51:52 +00:00
# Bersaglio protetto da un angelo
2016-05-27 11:42:25 +00:00
game.message(bot, s.mifia_target_protected.format(target=self.target.tusername,
icon=self.target.protectedby.role.icon,
protectedby=self.target.protectedby.tusername))
2016-05-26 13:12:49 +00:00
self.target = None
2016-04-21 17:52:01 +00:00
class Investigatore(Role):
2016-05-25 09:52:53 +00:00
"""L'investigatore può indagare sul vero ruolo di una persona una volta al giorno."""
2016-06-02 15:09:07 +00:00
icon = s.detective_icon
team = 'Good'
name = s.detective_name
powerdesc = s.detective_power_description
refillpoweruses = 1
2016-12-05 18:07:18 +00:00
def __init__(self, player):
super().__init__(player)
self.poweruses = self.refillpoweruses
2016-05-27 09:46:54 +00:00
def __repr__(self) -> str:
2017-07-04 22:40:23 +00:00
return "<Role: Investigatore, {uses} uses left>".format(uses=self.poweruses)
2016-04-21 17:52:01 +00:00
2016-12-05 18:07:18 +00:00
def power(self, bot, game, arg):
2016-05-25 09:52:53 +00:00
# Indaga sul vero ruolo di una persona, se sono ancora disponibili usi del potere.
2017-07-05 16:51:52 +00:00
if self.poweruses <= 0:
# Non hai abbastanza cariche!
2016-12-05 18:07:18 +00:00
self.player.message(bot, s.error_no_uses)
2017-07-05 16:51:52 +00:00
return
target = game.findplayerbyusername(arg)
if target is None:
# Username non valido
self.player.message(bot, s.error_username)
return
# Utilizza il potere su quella persona
self.poweruses -= 1
self.player.message(bot, s.detective_discovery.format(target=target.tusername,
icon=target.role.icon,
role=target.role.name,
left=self.poweruses))
2016-04-21 21:04:53 +00:00
2016-05-26 09:30:31 +00:00
def onendday(self, bot, game):
2016-04-21 21:04:53 +00:00
# Ripristina il potere
self.poweruses = self.refillpoweruses
2016-04-21 21:04:53 +00:00
2017-07-06 15:36:03 +00:00
class Corrotto(Investigatore):
"""Il corrotto è un investigatore che lavora per la Mifia."""
icon = s.corrupt_icon
team = 'Evil'
name = s.corrupt_name
powerdesc = s.detective_power_description
refillpoweruses = 1
def __repr__(self) -> str:
return "<Role: Corrotto, {uses} uses left>".format(uses=self.poweruses)
2016-05-03 11:29:29 +00:00
class Angelo(Role):
2016-05-27 11:42:25 +00:00
"""L'angelo può proteggere una persona al giorno dalla Mifia.
Se ha successo nella protezione, il suo ruolo sarà rivelato a tutti."""
2016-06-02 15:09:07 +00:00
icon = s.angel_icon
2017-01-31 13:47:56 +00:00
team = 'Good'
2016-06-02 15:09:07 +00:00
name = s.angel_name
powerdesc = s.angel_power_description
2016-12-05 18:07:18 +00:00
def __init__(self, player):
super().__init__(player)
2016-05-25 09:52:53 +00:00
self.protecting = None # La persona che questo angelo sta proteggendo
2016-05-27 09:46:54 +00:00
def __repr__(self) -> str:
2016-05-27 22:13:34 +00:00
if self.protecting is None:
2017-07-04 22:40:23 +00:00
return "<Role: Angelo>"
2016-05-26 09:08:50 +00:00
else:
2017-07-04 22:40:23 +00:00
return "<Role: Angelo, protecting {target}>".format(target=self.protecting.tusername)
2016-12-05 18:07:18 +00:00
def power(self, bot, game, arg):
2016-05-25 09:52:53 +00:00
# Imposta qualcuno come protetto
2016-05-03 11:29:29 +00:00
selected = game.findplayerbyusername(arg)
2017-07-05 16:51:52 +00:00
if selected is None:
2016-12-05 18:07:18 +00:00
self.player.message(bot, s.error_username)
2017-07-05 16:51:52 +00:00
return
# Controlla che l'angelo stia provando a proteggere sè stesso
if selected is not self.player:
# Togli la protezione a quello che stavi proteggendo prima
if self.protecting is not None:
self.protecting.protectedby = None
# Aggiungi la protezione al nuovo giocatore selezionato
selected.protectedby = self.player
self.protecting = selected
self.player.message(bot, s.angel_target_selected.format(target=self.protecting.tusername))
else:
self.player.message(bot, s.error_angel_no_selfprotect)
2016-05-26 09:30:31 +00:00
def onendday(self, bot, game):
2016-05-03 11:29:29 +00:00
# Resetta la protezione
if self.protecting is not None:
self.protecting.protectedby = None
2016-05-03 11:29:29 +00:00
self.protecting = None
2016-05-03 19:49:39 +00:00
2016-08-10 15:02:30 +00:00
class Terrorista(Role):
"""Il terrorista è un mifioso che può uccidere in un solo modo: facendosi uccidere dai Royal.
Se riesce, vince la partita e uccide tutti quelli che lo hanno votato."""
icon = s.terrorist_icon
team = "Evil"
name = s.terrorist_name
powerdesc = s.terrorist_power_description
def __repr__(self) -> str:
2017-07-04 22:40:23 +00:00
return "<Role: Terrorista>"
2016-08-10 15:02:30 +00:00
2016-12-05 18:09:07 +00:00
def ondeath(self, bot, game):
2016-08-10 15:02:30 +00:00
# Se è stato ucciso da una votazione, attiva il suo potere
2016-12-05 18:09:07 +00:00
if self.player == game.lastlynch:
2016-08-10 15:02:30 +00:00
game.message(bot, s.terrorist_kaboom)
for selectedplayer in game.players:
2017-01-31 13:47:56 +00:00
# Elimina ogni giocatore che sta votando per sè stesso
2016-12-05 18:16:15 +00:00
if selectedplayer.votingfor == self.player:
2016-08-10 15:02:30 +00:00
game.message(bot, s.terrorist_target_killed.format(target=selectedplayer.tusername,
icon=selectedplayer.role.icon,
role=selectedplayer.role.name))
selectedplayer.kill(bot, game)
2016-12-04 18:32:40 +00:00
class Derek(Role):
"""Derek muore. Quando gli pare."""
icon = s.derek_icon
team = "Good"
name = s.derek_name
powerdesc = s.derek_power_description
2016-12-05 18:07:18 +00:00
def __init__(self, player):
super().__init__(player)
2016-12-04 18:32:40 +00:00
# Per qualche motivo assurdo ho deciso di tenere l'oggetto Player qui
2016-12-12 18:21:06 +00:00
self.deathwish = False
2017-01-29 13:51:11 +00:00
self.chaos = False
2016-12-04 18:32:40 +00:00
def __repr__(self) -> str:
2017-07-04 22:40:23 +00:00
return "<Role: Derek>"
2016-12-04 18:32:40 +00:00
2016-12-05 18:07:18 +00:00
def power(self, bot, game, arg):
2016-12-04 18:32:40 +00:00
# Attiva / disattiva la morte alla fine del round
2017-02-02 13:07:48 +00:00
self.deathwish = not self.deathwish
2016-12-12 18:21:06 +00:00
if self.deathwish:
2016-12-05 18:07:18 +00:00
self.player.message(bot, s.derek_deathwish_unset)
2016-12-04 18:32:40 +00:00
else:
2017-02-02 13:07:48 +00:00
2016-12-05 18:07:18 +00:00
self.player.message(bot, s.derek_deathwish_set)
2016-12-04 18:32:40 +00:00
def onendday(self, bot, game):
2016-12-12 18:21:06 +00:00
if self.deathwish:
game.message(bot, s.derek_deathwish_successful.format(name=self.player.tusername))
self.player.kill(bot, game)
2017-01-29 13:51:11 +00:00
self.chaos = True
2016-12-04 18:32:40 +00:00
class Disastro(Role):
"""L'investigatore sbadato investiga, ma giunge a conclusioni sbagliate..."""
icon = s.detective_icon
team = 'Good'
name = s.detective_name
powerdesc = s.detective_power_description
refillpoweruses = 1
2016-12-05 18:07:18 +00:00
def __init__(self, player):
super().__init__(player)
self.poweruses = self.refillpoweruses
def __repr__(self) -> str:
2017-07-04 22:40:23 +00:00
return "<Role: Investigatore, {uses} uses left>".format(uses=self.poweruses)
2016-12-05 18:07:18 +00:00
def power(self, bot, game, arg):
# Indaga sul vero ruolo di una persona, se sono ancora disponibili usi del potere.
if self.poweruses > 0:
target = game.findplayerbyusername(arg)
if target is not None:
self.poweruses -= 1
randomrole = random.sample(rolepriority, 1)[0]
2016-12-05 18:07:18 +00:00
self.player.message(bot, s.detective_discovery.format(target=target.tusername,
2016-12-05 18:33:00 +00:00
icon=randomrole.icon,
role=randomrole.name,
left=self.poweruses))
else:
2016-12-05 18:07:18 +00:00
self.player.message(bot, s.error_username)
else:
2016-12-05 18:07:18 +00:00
self.player.message(bot, s.error_no_uses)
def onendday(self, bot, game):
# Ripristina il potere
self.poweruses = self.refillpoweruses
2016-12-05 18:09:07 +00:00
def ondeath(self, bot, game):
2016-12-05 18:37:13 +00:00
self.icon = s.disaster_icon
self.name = s.disaster_name
2016-12-11 15:31:44 +00:00
class Mamma(Role):
"""La mamma sente i pettegolezzi in giro per la città e inizia conoscendo un ruolo a caso..."""
icon = s.mom_icon
team = 'Good'
name = s.mom_name
powerdesc = s.mom_power_description
def __repr__(self) -> str:
2017-07-04 22:40:23 +00:00
return "<Role: Mamma>"
2016-12-11 15:31:44 +00:00
def onstartgame(self, bot, game):
2017-02-02 13:07:48 +00:00
# Scegli un bersaglio casuale che non sia il giocatore stesso
possibletargets = game.players.copy()
possibletargets.pop(self.player)
target = random.sample(possibletargets, 1)[0]
self.player.message(bot, s.mom_discovery.format(target=target.tusername,
2016-12-11 16:15:23 +00:00
icon=target.role.icon,
role=target.role.name))
2016-12-11 15:31:44 +00:00
2017-01-28 22:21:52 +00:00
class Stagista(Role):
"""Lo stagista sceglie una persona da cui andare in stage e prende il suo ruolo."""
icon = s.intern_icon
team = 'Good'
name = s.intern_name
powerdesc = s.intern_power_description
def __init__(self, player):
super().__init__(player)
self.master = None
def __repr__(self) -> str:
return "<Role: Stagista>"
def power(self, bot, game, arg):
target = game.findplayerbyusername(arg)
2017-01-28 23:36:58 +00:00
if target is not None and target is not self.player and target.alive:
2017-01-28 22:21:52 +00:00
self.master = target
2017-01-28 23:36:58 +00:00
self.player.message(bot, s.intern_started_internship.format(master=self.master.tusername))
2017-01-28 22:21:52 +00:00
else:
self.player.message(bot, s.error_no_username)
def onendday(self, bot, game):
if self.master is not None:
2017-01-29 13:51:11 +00:00
if isinstance(self.master.role, Derek) and self.master.role.chaos:
2017-01-29 13:22:00 +00:00
game.message(bot, s.intern_chaos_summoned)
self.master.alive = True
2017-01-29 13:42:40 +00:00
game.changerole(bot, self.master, SignoreDelCaos)
game.changerole(bot, self.player, Servitore)
else:
game.message(bot, s.intern_changed_role.format(icon=self.master.role.__class__.icon, role=self.master.role.__class__.name))
game.changerole(bot, self.player, self.master.role.__class__)
2017-01-29 13:22:00 +00:00
class SignoreDelCaos(Role):
"""Il Signore del Caos è un Derek negli ultimi secondi prima della morte.
Può cambiare la vita delle altre persone... Anche se non può decidere in cosa."""
icon = s.chaos_lord_icon
team = 'Chaos'
name = s.chaos_lord_name
powerdesc = s.chaos_lord_power_description
def __init__(self, player):
super().__init__(player)
self.target = None
def __repr__(self) -> str:
return "<Role: Signore del Caos>"
def power(self, bot, game, arg):
selected = game.findplayerbyusername(arg)
if selected is not None and selected is not self.player and selected.alive:
self.target = selected
self.player.message(bot, s.chaos_lord_target_selected.format(target=self.target.tusername))
else:
self.player.message(bot, s.error_no_username)
def onendday(self, bot, game):
if self.target is not None:
2017-01-29 19:18:23 +00:00
if self.target.alive and self.player.alive:
2017-01-29 13:22:00 +00:00
if not isinstance(self.target.role, SignoreDelCaos) or not isinstance(self.target.role, Servitore):
2017-01-29 19:18:23 +00:00
randomrole = random.sample(rolepriority, 1)[0]
2017-01-29 13:22:00 +00:00
game.changerole(bot, self.target, randomrole)
game.message(bot, s.chaos_lord_randomized)
else:
game.message(bot, s.chaos_lord_failed)
class Servitore(Role):
"""Il servitore del Caos è il sottoposto al Signore del Caos.
Se non ci sono Signori del Caos in partita diventa Signore del Caos."""
icon = s.derek_icon
team = 'Chaos'
name = s.chaos_servant_name
powerdesc = s.chaos_servant_power_description
def __repr__(self) -> str:
return "<Role: Servitore del Caos>"
def onendday(self, bot, game):
for chaoslord in game.playersinrole["SignoreDelCaos"]:
if chaoslord.alive:
break
else:
2017-01-29 19:18:23 +00:00
game.changerole(bot, self.player, SignoreDelCaos)
2017-01-29 13:22:00 +00:00
game.message(bot, s.chaos_servant_inherited)
2017-01-28 22:21:52 +00:00
2017-01-25 17:11:39 +00:00
# Ordine in cui vengono eseguiti i onendday dei vari ruoli.
rolepriority = [Mifioso, Investigatore, Corrotto, Disastro, Angelo, Derek, Stagista, Terrorista, Mamma, SignoreDelCaos, Servitore]
2016-08-10 12:55:58 +00:00
2016-04-21 18:20:26 +00:00
class Player:
2016-05-27 11:42:25 +00:00
"""Classe di un giocatore. Contiene tutti i dati riguardanti un giocatore all'interno di una partita, come il ruolo,
e i dati riguardanti telegram, come ID e username."""
2016-12-09 16:52:15 +00:00
def __init__(self, tid, tusername, dummy=False):
2016-05-25 09:52:53 +00:00
self.tid = tid # ID di Telegram
self.tusername = tusername # Username di Telegram
2016-12-05 18:07:18 +00:00
self.role = Role(self) # Di base, ogni giocatore è un ruolo indefinito
2017-02-02 13:07:48 +00:00
self.alive = True # Il giocatore è vivo?
2016-05-22 15:13:26 +00:00
self.votingfor = None # Diventa un player se ha votato
2016-05-25 09:52:53 +00:00
self.votes = 0 # Voti che sta ricevendo questo giocatore. Aggiornato da updatevotes()
2017-02-02 13:07:48 +00:00
self.protectedby = None # Protettore. Oggetto player che protegge questo giocatore dalla mifia. Se è None, la mifia può uccidere questo giocatore
2016-05-26 13:12:49 +00:00
self.mifiavotes = 0 # Voti che sta ricevendo questo giocatore dalla mifia. Aggiornato da updatemifiavotes()
2017-02-02 13:07:48 +00:00
self.dummy = dummy # E' un bot? Usato solo per il debug (/debugjoin)
2016-04-21 18:20:26 +00:00
2016-05-27 09:46:54 +00:00
def __repr__(self) -> str:
2017-07-04 22:40:23 +00:00
return "<Player {username}>".format(username=self.tusername)
def __str__(self) -> str:
return "@{}".format(self.tusername)
2016-05-26 09:30:31 +00:00
def message(self, bot, text):
"""Manda un messaggio privato al giocatore."""
2016-12-09 16:52:15 +00:00
if not self.dummy:
try:
bot.sendMessage(self.tid, text, parse_mode=ParseMode.MARKDOWN)
except Unauthorized:
print("Unauthorized to message {}".format(self))
2016-12-09 16:52:15 +00:00
def kill(self, bot, game):
"""Uccidi il giocatore."""
2016-12-05 18:09:07 +00:00
self.role.ondeath(bot, game)
self.alive = False
2016-05-25 09:52:53 +00:00
2016-05-27 22:13:34 +00:00
2016-04-21 18:20:26 +00:00
class Game:
2016-12-11 15:31:44 +00:00
"""Classe di una partita, contenente parametri riguardanti stato della partita
2016-05-27 11:42:25 +00:00
e informazioni sul gruppo di Telegram."""
2016-12-04 18:54:33 +00:00
def __init__(self, groupid):
2016-05-25 09:52:53 +00:00
self.groupid = groupid # ID del gruppo in cui si sta svolgendo una partita
2016-12-04 18:54:33 +00:00
self.admin = None # ID telegram dell'utente che ha creato la partita con /newgame
2016-05-25 09:52:53 +00:00
self.players = list() # Lista dei giocatori in partita
2016-05-22 15:13:26 +00:00
self.tokill = list() # Giocatori che verranno uccisi all'endday
2016-12-09 17:43:14 +00:00
self.phase = 'Join' # Fase di gioco: 'Join', 'Preset', 'Config', 'Voting'
2016-12-09 16:36:43 +00:00
self.day = 0 # Numero del giorno. 0 se la partita deve ancora iniziare
self.configstep = 0 # Passo attuale di configurazione
2016-08-10 12:55:58 +00:00
self.roleconfig = dict() # Dizionario con le quantità di ruoli da aggiungere
2016-05-26 13:12:49 +00:00
self.votingmifia = False # Seguire le regole originali della mifia che vota?
2016-12-05 18:22:02 +00:00
self.missingmifia = False # La mifia può fallire un'uccisione
2016-12-06 22:00:27 +00:00
self.misschance = 5 # Percentuale di fallimento di un'uccisione
# Liste di ruoli in gioco, per velocizzare gli endday
2016-08-10 12:55:58 +00:00
self.playersinrole = dict()
for currentrole in rolepriority:
self.playersinrole[currentrole.__name__] = list()
# Trova un nome per la partita
if len(freenames) > 0:
2016-05-26 09:49:40 +00:00
random.shuffle(freenames)
2016-05-26 09:08:50 +00:00
self.name = freenames.pop()
else:
2016-05-26 09:08:50 +00:00
self.name = str(groupid)
2016-08-10 15:02:30 +00:00
self.lastlynch = None # Ultima persona uccisa dai Royal, diventa un player
def __del__(self):
2016-05-26 09:08:50 +00:00
# Rimetti il nome che si è liberato in disponibili.
try:
int(self.name)
2016-05-26 09:10:52 +00:00
except ValueError:
2016-05-26 09:08:50 +00:00
freenames.append(self.name)
2016-05-26 09:08:50 +00:00
def __repr__(self):
2016-05-27 11:42:25 +00:00
r = "<Game {name} in group {groupid} with {nplayers} players in phase {phase}>" \
.format(name=self.name, groupid=self.groupid, nplayers=len(self.players), phase=self.phase)
2016-05-26 09:08:50 +00:00
return r
2016-04-21 18:20:26 +00:00
2016-05-26 09:30:31 +00:00
def message(self, bot, text):
2016-05-25 09:52:53 +00:00
"""Manda un messaggio nel gruppo."""
bot.sendMessage(self.groupid, text, parse_mode=ParseMode.MARKDOWN)
2016-04-21 18:20:26 +00:00
2016-05-26 09:30:31 +00:00
def adminmessage(self, bot, text):
2016-05-25 09:52:53 +00:00
"""Manda un messaggio privato al creatore della partita."""
2016-12-04 18:54:33 +00:00
self.admin.message(bot, text)
2016-04-21 18:20:26 +00:00
2016-05-26 09:30:31 +00:00
def mifiamessage(self, bot, text):
2016-05-25 09:52:53 +00:00
"""Manda un messaggio privato a tutti i Mifiosi nella partita."""
2016-04-21 18:20:26 +00:00
# Trova tutti i mifiosi nell'elenco dei giocatori
for player in self.players:
if isinstance(player.role, Mifioso):
player.message(bot, text)
2017-05-08 10:07:19 +00:00
def findplayerbyid(self, tid):
2016-05-25 09:52:53 +00:00
"""Trova il giocatore con un certo id."""
for player in self.players:
if player.tid == tid:
return player
else:
return None
2017-05-08 10:07:19 +00:00
def findplayerbyusername(self, tusername):
2016-05-25 09:52:53 +00:00
"""Trova il giocatore con un certo username."""
for player in self.players:
2017-01-28 23:36:58 +00:00
if player.tusername.lower() == tusername.strip("@").lower():
return player
else:
return None
def assignroles(self, bot):
2016-05-25 09:52:53 +00:00
"""Assegna ruoli casuali a tutti i giocatori."""
2016-04-22 17:55:24 +00:00
random.seed()
playersleft = self.players.copy()
2017-02-02 13:07:48 +00:00
# Assegna i ruoli secondo i numeri all'interno di playersinrole
2016-08-10 12:55:58 +00:00
for currentrole in rolepriority:
for player in random.sample(playersleft, self.roleconfig[currentrole.__name__]):
self.playersinrole[currentrole.__name__].append(player)
2016-12-05 18:33:00 +00:00
player.role = currentrole(player)
2016-08-10 12:55:58 +00:00
playersleft.remove(player)
2016-04-22 17:55:24 +00:00
# Assegna il ruolo di Royal a tutti gli altri
for player in playersleft:
2016-12-05 18:07:18 +00:00
player.role = Royal(self)
2016-04-23 16:26:32 +00:00
# Manda i ruoli assegnati a tutti
for player in self.players:
2016-05-25 11:57:15 +00:00
player.message(bot, s.role_assigned.format(icon=player.role.icon, name=player.role.name))
2016-05-26 09:40:59 +00:00
if player.role.powerdesc is not None:
player.message(bot, player.role.powerdesc.format(gamename=self.name))
2016-06-01 12:21:51 +00:00
# Manda ai mifiosi l'elenco dei loro compagni di squadra
text = s.mifia_team_intro
2016-08-10 12:55:58 +00:00
for player in self.playersinrole['Mifioso']:
2016-06-01 12:21:51 +00:00
text += s.mifia_team_player.format(icon=player.role.icon, name=player.tusername)
for player in self.playersinrole['Corrotto']:
text += s.mifia_team_player.format(icon=player.role.icon, name=player.tusername)
2016-08-10 12:55:58 +00:00
for player in self.playersinrole['Mifioso']:
2016-06-01 12:21:51 +00:00
player.message(bot, text)
for player in self.playersinrole['Corrotto']:
player.message(bot, text)
2016-06-01 12:21:51 +00:00
2016-04-22 19:14:14 +00:00
def updatevotes(self):
2016-05-25 09:52:53 +00:00
"""Aggiorna il conteggio dei voti di tutti i giocatori."""
2016-04-22 19:14:14 +00:00
for player in self.players:
player.votes = 0
for player in self.players:
2016-05-25 14:27:11 +00:00
if player.votingfor is not None and player.alive:
2016-04-23 15:37:43 +00:00
player.votingfor.votes += 1
2016-04-22 19:14:14 +00:00
2016-05-27 08:51:52 +00:00
def updatemifiavotes(self):
2016-05-26 13:12:49 +00:00
"""Aggiorna il conteggio dei voti mifiosi di tutti i giocatori."""
for player in self.players:
player.mifiavotes = 0
2016-08-10 12:55:58 +00:00
for player in self.playersinrole['Mifioso']:
if player.alive:
2016-05-26 13:12:49 +00:00
if player.role.target is not None:
player.role.target.mifiavotes += 1
2016-05-25 14:27:11 +00:00
def mostvotedplayer(self) -> list:
2016-05-25 09:52:53 +00:00
"""Trova il giocatore più votato."""
2016-05-25 14:27:11 +00:00
mostvoted = list()
currenttop = 0
2016-04-22 19:14:14 +00:00
self.updatevotes()
for player in self.players:
2016-05-25 14:27:11 +00:00
if player.votes > currenttop:
2016-05-27 09:51:57 +00:00
mostvoted = list()
mostvoted.append(player)
currenttop = player.votes
2016-05-25 14:27:11 +00:00
elif player.votes == currenttop:
mostvoted.append(player)
2016-05-26 13:12:49 +00:00
if currenttop > 0:
return mostvoted
else:
2016-05-27 08:51:52 +00:00
return list()
2016-05-26 13:12:49 +00:00
def mostvotedmifia(self) -> list:
"""Trova il giocatore più votato dalla mifia."""
mostvoted = list()
currenttop = 0
2016-05-27 08:51:52 +00:00
self.updatemifiavotes()
2016-05-26 13:12:49 +00:00
for player in self.players:
2016-05-27 09:51:57 +00:00
if player.mifiavotes > currenttop:
mostvoted = list()
mostvoted.append(player)
currenttop = player.mifiavotes
2016-05-27 09:51:57 +00:00
elif player.votes == currenttop:
2016-05-26 13:12:49 +00:00
mostvoted.append(player)
if currenttop > 0:
return mostvoted
else:
2016-05-27 08:51:52 +00:00
return list()
2016-05-26 13:12:49 +00:00
2016-04-22 19:14:14 +00:00
def endday(self, bot):
2016-05-25 14:27:11 +00:00
"""Finisci la giornata, uccidi il più votato del giorno ed esegui gli endday di tutti i giocatori."""
2017-01-25 17:11:39 +00:00
# SALVA LA PARTITA, così se crasha si riprende da qui
2017-01-28 23:36:58 +00:00
self.save(bot)
2016-05-25 14:27:11 +00:00
# Conta i voti ed elimina il più votato.
topvotes = self.mostvotedplayer()
if len(topvotes) > 0:
# In caso di pareggio, elimina un giocatore casuale.
random.seed()
random.shuffle(topvotes)
lynched = topvotes.pop()
2016-05-26 09:59:58 +00:00
if lynched.alive:
2016-05-27 11:42:25 +00:00
self.message(bot, s.player_lynched.format(name=lynched.tusername,
icon=lynched.role.icon,
role=lynched.role.name))
2016-08-10 15:02:30 +00:00
self.lastlynch = lynched
lynched.kill(bot, self)
2016-12-09 16:52:15 +00:00
elif self.day > 1:
2016-05-25 14:27:11 +00:00
self.message(bot, s.no_players_lynched)
# Fai gli endday in un certo ordine.
# Si potrebbe fare più velocemente, credo.
2016-05-25 14:27:11 +00:00
# Ma non sto ho voglia di ottimizzare ora.
2017-02-02 13:07:48 +00:00
# Endday dei mifiosi se votingmifia è attivo
2016-05-26 13:12:49 +00:00
if self.votingmifia:
# Trova il più votato dai mifiosi e uccidilo
2016-05-27 09:16:02 +00:00
killlist = self.mostvotedmifia()
2016-05-26 13:12:49 +00:00
if len(killlist) > 0:
# In caso di pareggio, elimina un giocatore casuale.
random.seed()
random.shuffle(killlist)
killed = killlist.pop()
if killed.alive:
2016-05-27 22:40:30 +00:00
if killed.protectedby is None:
2016-12-06 22:00:27 +00:00
if self.missingmifia and random.randrange(0, 100) < self.misschance:
2016-12-05 18:58:46 +00:00
# Colpo mancato
self.message(bot, s.mifia_target_missed.format(target=killed.tusername))
else:
# Uccisione riuscita
killed.kill(bot, self)
self.message(bot, s.mifia_target_killed.format(target=killed.tusername,
icon=killed.role.icon,
role=killed.role.name))
2016-05-27 22:40:30 +00:00
else:
self.message(bot, s.mifia_target_protected.format(target=killed.tusername,
icon=killed.protectedby.role.icon,
protectedby=killed.protectedby.tusername))
2016-08-10 12:55:58 +00:00
# Attiva gli onendday
for currentrole in rolepriority:
for player in self.playersinrole[currentrole.__name__]:
if player.alive:
player.role.onendday(bot, self)
# Cancella tutti i voti
2016-04-23 15:37:43 +00:00
for player in self.players:
player.votingfor = None
2016-08-10 15:42:57 +00:00
# Controlla se qualcuno ha vinto
self.victoryconditions(bot)
2017-02-02 13:07:48 +00:00
# Incrementa il giorno
2016-12-09 16:36:43 +00:00
self.day += 1
2017-02-03 22:29:39 +00:00
# Notifica dell'inizi
self.message(bot, s.new_day.format(day=self.day))
2016-04-23 16:26:32 +00:00
2016-12-09 17:43:14 +00:00
def startpreset(self, bot):
"""Inizio della fase di preset"""
self.phase = 'Preset'
2017-01-28 22:21:52 +00:00
if __debug__:
2017-01-29 13:22:00 +00:00
# Preset di debug
2017-01-28 22:21:52 +00:00
self.roleconfig = {
2017-01-29 13:22:00 +00:00
"Mifioso": 0,
"Investigatore": 0,
2017-07-04 22:40:23 +00:00
"Corrotto": 0,
2017-01-29 13:22:00 +00:00
"Angelo": 0,
"Terrorista": 0,
"Derek": 0,
"Disastro": 0,
"Mamma": 0,
"Stagista": 0,
"SignoreDelCaos": 0,
"Servitore": 0
2017-01-28 22:21:52 +00:00
}
self.votingmifia = True
self.missingmifia = False
self.endconfig(bot)
2017-01-29 13:22:00 +00:00
self.message(bot, "Utilizzando il preset di debug (tutti royal, cambia ruolo con `/debugchangerole nomeutente ruolo`.")
else:
# Crea la tastiera
kbmarkup = InlineKeyboardMarkup([
[
InlineKeyboardButton(s.preset_simple, callback_data="simple"),
InlineKeyboardButton(s.preset_classic, callback_data="classic"),
2017-05-08 10:07:19 +00:00
InlineKeyboardButton(s.preset_advanced, callback_data="advanced")
2017-01-29 13:22:00 +00:00
],
[
InlineKeyboardButton(s.preset_custom, callback_data="custom")
]
])
# Manda la tastiera
bot.sendMessage(self.groupid, s.preset_choose, parse_mode=ParseMode.MARKDOWN, reply_markup=kbmarkup)
def loadpreset(self, bot, preset):
"""Fine della fase di preset: carica il preset selezionato o passa a config"""
if preset == "simple":
2017-02-02 13:07:48 +00:00
# Preset semplice (solo Royal, Mifiosi e Investigatori)
2016-12-09 17:43:14 +00:00
self.roleconfig = {
2017-01-29 13:22:00 +00:00
"Mifioso": math.floor(len(self.players) / 8) + 1, # 1 Mifioso ogni 8 giocatori
"Investigatore": math.floor(len(self.players) / 12) + 1, # 1 Detective ogni 12 giocatori
2017-07-04 22:40:23 +00:00
"Corrotto": 0,
2017-01-29 13:22:00 +00:00
"Angelo": 0,
"Terrorista": 0,
"Derek": 0,
"Disastro": 0,
"Mamma": 0,
"Stagista": 0,
"SignoreDelCaos": 0,
"Servitore": 0
2016-12-09 17:43:14 +00:00
}
self.votingmifia = True
self.missingmifia = False
2017-05-08 10:07:19 +00:00
self.message(bot, s.preset_simple_selected.format(mifioso=self.roleconfig["Mifioso"],
investigatore=self.roleconfig["Investigatore"],
royal=len(self.players) - self.roleconfig["Mifioso"] - self.roleconfig["Investigatore"]))
2016-12-09 17:43:14 +00:00
self.endconfig(bot)
elif preset == "classic":
2017-02-02 13:07:48 +00:00
# Preset classico (solo Royal, Mifiosi, Investigatori, Angeli e Terroristi)
2016-12-09 17:43:14 +00:00
self.roleconfig = {
2017-01-29 13:22:00 +00:00
"Mifioso": math.floor(len(self.players) / 8) + 1, # 1 Mifioso ogni 8 giocatori
"Investigatore": math.floor(len(self.players) / 12) + 1, # 1 Detective ogni 12 giocatori
"Angelo": math.floor(len(self.players) / 10) + 1, # 1 Angelo ogni 10 giocatori
2017-05-08 10:07:19 +00:00
"Terrorista": 1 if random.randrange(0, 100) > 70 else 0, # 30% di avere un terrorista
2017-01-29 13:22:00 +00:00
"Derek": 0,
"Disastro": 0,
"Mamma": 0,
"Stagista": 0,
"SignoreDelCaos": 0,
"Servitore": 0
2016-12-09 17:43:14 +00:00
}
self.votingmifia = True
self.missingmifia = False
2017-05-08 10:07:19 +00:00
self.message(bot, s.preset_classic_selected)
2016-12-09 17:43:14 +00:00
self.endconfig(bot)
2017-05-08 10:07:19 +00:00
elif preset == "advanced":
# Preset avanzato: genera i ruoli in modo da rendere la partita divertente
self.roleconfig = dict()
unassignedplayers = len(self.players)
# Mifioso: tra 1 e 25% dei giocatori
2017-07-04 22:40:23 +00:00
self.roleconfig["Mifioso"] = random.randint(1, math.ceil(unassignedplayers / 4))
2017-05-08 10:07:19 +00:00
unassignedplayers -= self.roleconfig["Mifioso"]
# Investigatore: tra 1 e 19% dei giocatori
2017-07-04 22:40:23 +00:00
self.roleconfig["Investigatore"] = random.randint(1, math.ceil(unassignedplayers / 4))
2017-05-08 10:07:19 +00:00
unassignedplayers -= self.roleconfig["Investigatore"]
# Angelo: tra 1 e 14% dei giocatori
self.roleconfig["Angelo"] = random.randint(1, math.ceil(unassignedplayers / 4))
unassignedplayers -= self.roleconfig["Angelo"]
# Terrorista: ce n'è uno il 30% delle partite e solo se ci sono più di 5 giocatori senza ruoli maggiori
if unassignedplayers >= 6:
self.roleconfig["Terrorista"] = 1 if random.randrange(0, 100) >= 70 else 0
else:
self.roleconfig["Terrorista"] = 0
unassignedplayers -= self.roleconfig["Terrorista"]
# Mamma: tra 0 e il 10% dei giocatori
self.roleconfig["Mamma"] = random.randint(0, math.ceil(unassignedplayers))
unassignedplayers -= self.roleconfig["Mamma"]
# Stagista e Derek: possono essere nella stessa partita solo il 10% delle volte
if random.randint(0, 100) >= 90 and unassignedplayers >= 2:
self.roleconfig["Stagista"] = 1
self.roleconfig["Derek"] = 1
unassignedplayers -= 2
# Altrimenti, viene scelto uno dei due ruoli e ne viene inserito uno (lo stagista ha probabilità più alte perchè più interattivo)
elif unassignedplayers >= 1:
if random.randint(0, 100) >= 30:
self.roleconfig["Stagista"] = 1
self.roleconfig["Derek"] = 0
else:
self.roleconfig["Stagista"] = 0
self.roleconfig["Derek"] = 1
unassignedplayers -= 1
2017-07-04 22:40:23 +00:00
# E se non ce ne fosse nessuno?
else:
self.roleconfig["Stagista"] = 0
self.roleconfig["Derek"] = 0
2017-05-08 10:07:19 +00:00
# Disastro: tra 0 e l'8% dei giocatori
self.roleconfig["Disastro"] = random.randint(0, math.ceil(unassignedplayers) / 4)
unassignedplayers -= self.roleconfig["Disastro"]
# Non ci sono SignoreDelCaos e Servitore per motivi ovvi
self.roleconfig["SignoreDelCaos"] = 0
self.roleconfig["Servitore"] = 0
2017-07-04 22:40:23 +00:00
# Non ho ancora finito il corrotto
self.roleconfig["Corrotto"] = 0
2017-05-08 10:07:19 +00:00
# Altri parametri
2016-12-09 17:43:14 +00:00
self.votingmifia = True
self.missingmifia = True
self.misschance = 5
2017-05-08 10:07:19 +00:00
self.message(bot, s.preset_advanced_selected)
2016-12-09 17:43:14 +00:00
self.endconfig(bot)
elif preset == "custom":
# Preset personalizzabile
self.startconfig(bot)
def startconfig(self, bot):
"""Inizio della fase di config"""
self.phase = 'Config'
self.configstep = 0
self.message(bot, s.config_list[0])
2016-05-27 13:53:06 +00:00
def endconfig(self, bot):
2016-05-27 13:34:23 +00:00
"""Fine della fase di config, inizio assegnazione ruoli"""
# Controlla che ci siano abbastanza giocatori per avviare la partita
requiredplayers = 0
2016-08-10 13:53:55 +00:00
for selectedrole in self.roleconfig:
requiredplayers += self.roleconfig[selectedrole]
# Se non ce ne sono abbastanza, torna alla fase di join
if requiredplayers > len(self.players):
2016-08-10 13:53:55 +00:00
self.message(bot, s.error_not_enough_players)
2016-05-27 13:34:23 +00:00
else:
self.phase = 'Voting'
2016-12-09 16:36:43 +00:00
self.day += 1
self.assignroles(bot)
2016-05-27 13:39:17 +00:00
self.message(bot, s.roles_assigned_successfully)
2016-12-11 15:31:44 +00:00
for player in self.players:
player.role.onstartgame(bot, self)
2016-05-27 13:34:23 +00:00
def revealallroles(self, bot):
text = s.status_header.format(name=self.groupid, admin=self.admin.tid, phase=self.phase)
self.updatevotes()
# Aggiungi l'elenco dei giocatori
for player in self.players:
text += s.status_basic_player.format(icon=player.role.icon,
name=player.tusername)
self.message(bot, text)
2016-04-23 16:26:32 +00:00
def endgame(self):
inprogress.remove(self)
2016-04-22 19:14:14 +00:00
2017-01-28 23:36:58 +00:00
def save(self, bot):
2016-05-29 15:12:23 +00:00
# Crea il file.
2016-06-03 20:04:37 +00:00
try:
file = open(str(self.groupid) + ".p", 'x')
except FileExistsError:
pass
else:
file.close()
2016-05-29 15:12:23 +00:00
# Scrivi sul file.
file = open(str(self.groupid) + ".p", 'wb')
pickle.dump(self, file)
file.close()
2017-01-25 17:11:39 +00:00
# Crea un file uguale ma con un timestamp
2017-01-28 23:36:58 +00:00
# Non sono troppo sicuro che il timestamp si faccia così però funziona
t = datetime.datetime(2000,1,1,1,1).now()
2017-01-25 17:11:39 +00:00
try:
file = open("{group}-{yy}-{mm}-{dd}-{hh}-{mi}.p".format(group=str(self.groupid), yy=t.year, mm=t.month, dd=t.day, hh=t.hour, mi=t.minute), 'x')
except FileExistsError:
pass
else:
file.close()
# Scrivi sul file.
file = open("{group}-{yy}-{mm}-{dd}-{hh}-{mi}.p".format(group=str(self.groupid), yy=t.year, mm=t.month, dd=t.day, hh=t.hour, mi=t.minute), 'wb')
pickle.dump(self, file)
2017-01-28 23:36:58 +00:00
self.message(bot, s.game_saved)
2017-01-25 17:11:39 +00:00
file.close()
2016-05-29 15:12:23 +00:00
2016-08-10 15:42:57 +00:00
def victoryconditions(self, bot):
2017-01-28 22:21:52 +00:00
"""Controlla se qualcuno ha completato le condizioni di vittoria."""
2016-08-10 15:42:57 +00:00
good = 0
evil = 0
2017-01-29 19:18:23 +00:00
alive = 0
2016-08-10 15:42:57 +00:00
for player in self.players:
2017-01-29 19:18:23 +00:00
if player.alive:
if player.role.team == 'Evil':
evil += 1
elif player.role.team == 'Good':
good += 1
alive += 1
2016-08-10 15:42:57 +00:00
# Distruzione atomica!
2017-01-29 19:18:23 +00:00
if alive == 0:
2016-08-10 15:42:57 +00:00
self.message(bot, s.end_game_wiped)
for player in self.players:
player.message(bot, s.end_game_wiped + s.tie)
self.revealallroles(bot)
self.endgame()
# I mifiosi sono più del 50% dei vivi se la mifia è infallibile
# o non ci sono più personaggi buoni se la mifia può mancare i colpi
elif (not self.missingmifia and evil >= (alive-evil)) or good == 0:
2016-08-10 15:42:57 +00:00
self.message(bot, s.end_mifia_outnumber + s.victory_mifia)
for player in self.players:
if player.role.team == 'Good':
player.message(bot, s.end_mifia_outnumber + s.defeat)
elif player.role.team == 'Evil':
player.message(bot, s.end_mifia_outnumber + s.victory)
2017-01-29 19:18:23 +00:00
elif player.role.team == 'Chaos':
player.message(bot, s.end_game_chaos + s.victory)
self.revealallroles(bot)
2016-08-10 15:42:57 +00:00
self.endgame()
# Male distrutto
elif evil == 0:
self.message(bot, s.end_mifia_killed + s.victory_royal)
for player in self.players:
if player.role.team == 'Good':
player.message(bot, s.end_mifia_killed + s.victory)
elif player.role.team == 'Evil':
player.message(bot, s.end_mifia_killed + s.defeat)
2017-01-29 19:18:23 +00:00
elif player.role.team == 'Chaos':
player.message(bot, s.end_game_chaos + s.victory)
self.revealallroles(bot)
2016-08-10 15:42:57 +00:00
self.endgame()
2016-08-10 12:55:58 +00:00
2017-01-29 13:22:00 +00:00
def changerole(self, bot, player, newrole):
2017-01-28 22:21:52 +00:00
"""Cambia il ruolo di un giocatore, aggiornando tutti i valori"""
2017-01-29 13:22:00 +00:00
# Aggiorna le liste dei ruoli
2017-01-28 23:36:58 +00:00
if player.role.__class__ != Royal:
self.playersinrole[player.role.__class__.__name__].remove(player)
2017-01-29 19:18:23 +00:00
if newrole != Royal:
2017-01-29 13:22:00 +00:00
self.playersinrole[newrole.__name__].append(player)
# Cambia il ruolo al giocatore
2017-01-28 22:21:52 +00:00
player.role = newrole(player)
2017-01-29 13:22:00 +00:00
# Manda i messaggi del nuovo ruolo
player.message(bot, s.role_assigned.format(icon=player.role.icon, name=player.role.name))
if player.role.powerdesc is not None:
player.message(bot, player.role.powerdesc.format(gamename=self.name))
# Aggiorna lo stato dei mifiosi
if newrole == Mifioso:
text = s.mifia_team_intro
for player in self.playersinrole['Mifioso']:
text += s.mifia_team_player.format(icon=player.role.icon, name=player.tusername)
for player in self.playersinrole['Mifioso']:
player.message(bot, text)
2017-01-28 22:21:52 +00:00
def joinplayer(self, bot, player):
self.players.append(player)
self.message(bot, s.player_joined.format(name=p.tusername))
# Se è il primo giocatore ad unirsi, diventa admin
if len(self.players) == 0:
self.admin = player
2017-01-28 22:21:52 +00:00
2016-04-21 20:14:35 +00:00
# Partite in corso
inprogress = list()
2016-04-21 18:20:26 +00:00
2016-05-26 09:30:31 +00:00
def findgamebyid(gid) -> Game:
2016-05-25 09:52:53 +00:00
"""Trova una partita con un certo id."""
2016-04-21 21:04:53 +00:00
for game in inprogress:
if game.groupid == gid:
return game
2016-05-26 09:30:31 +00:00
def findgamebyname(name) -> Game:
2016-05-26 09:08:50 +00:00
"""Trova una partita con un certo nome."""
for game in inprogress:
if game.name.lower() == name.lower():
2016-05-26 10:10:07 +00:00
return game
2016-05-27 22:13:34 +00:00
2016-04-21 17:52:01 +00:00
# Comandi a cui risponde il bot
def ping(bot, update):
2016-05-25 09:52:53 +00:00
"""Ping!"""
bot.sendMessage(update.message.chat['id'], s.pong, parse_mode=ParseMode.MARKDOWN)
2016-04-21 20:14:35 +00:00
def newgame(bot, update):
2016-05-25 09:52:53 +00:00
"""Crea una nuova partita."""
2016-04-21 20:14:35 +00:00
if update.message.chat['type'] != 'private':
game = findgamebyid(update.message.chat['id'])
if game is None:
2016-12-04 18:54:33 +00:00
game = Game(update.message.chat['id'])
inprogress.append(game)
game.message(bot, s.new_game.format(groupid=game.groupid, name=game.name))
2016-12-04 18:54:33 +00:00
join(bot, update)
else:
bot.sendMessage(update.message.chat['id'], s.error_game_in_progress, parse_mode=ParseMode.MARKDOWN)
2016-04-21 20:14:35 +00:00
else:
bot.sendMessage(update.message.chat['id'], s.error_chat_type, parse_mode=ParseMode.MARKDOWN)
2016-04-21 21:04:53 +00:00
def join(bot, update):
2016-05-25 09:52:53 +00:00
"""Unisciti a una partita."""
2016-04-21 21:04:53 +00:00
game = findgamebyid(update.message.chat['id'])
# Nessuna partita in corso
if game is None:
bot.sendMessage(update.message.chat['id'], s.error_no_games_found, parse_mode=ParseMode.MARKDOWN)
return
# Fase di join finita
if game.phase != 'Join':
game.message(bot, s.error_join_phase_ended)
return
p = game.findplayerbyid(update.message.from_user['id'])
# Giocatore già in partita
if p is not None:
game.message(bot, s.error_player_already_joined)
return
# Giocatore senza username
if 'username' not in update.message.from_user:
game.message(bot, s.error_no_username)
return
p = Player(update.message.from_user['id'], update.message.from_user['username'])
try:
p.message(bot, s.you_joined.format(game=game.name))
except Unauthorized:
# Bot bloccato dall'utente
game.message(bot, s.error_chat_unavailable)
return
# Aggiungi il giocatore alla partita
game.joinplayer(bot, p)
# Salva
game.save(bot)
def debugjoin(bot, update):
"""Aggiungi un bot alla partita."""
if __debug__:
game = findgamebyid(update.message.chat['id'])
if game is None:
bot.sendMessage(update.message.chat['id'], s.error_no_games_found, parse_mode=ParseMode.MARKDOWN)
return
if game.phase != 'Join':
game.message(bot, s.error_join_phase_ended)
return
arg = update.message.text.split(" ")
p = Player(random.randrange(0, 10000), arg[1], True) # ewwwwww
game.message(bot, s.player_joined.format(name=p.tusername))
game.players.append(p)
def status(bot, update):
2016-05-25 09:52:53 +00:00
"""Visualizza lo stato della partita."""
game = findgamebyid(update.message.chat['id'])
if game is not None:
2016-12-09 16:52:15 +00:00
text = str()
2016-12-04 18:54:33 +00:00
if __debug__:
text += s.debug_mode
2016-12-09 16:52:15 +00:00
text += s.status_header.format(name=game.name, admin=game.admin.tusername, phase=game.phase)
2016-04-23 15:37:43 +00:00
game.updatevotes()
# Aggiungi l'elenco dei giocatori
for player in game.players:
2016-04-23 15:07:09 +00:00
if not player.alive:
2016-05-26 09:52:01 +00:00
text += s.status_dead_player.format(name=player.tusername)
2016-12-09 16:36:43 +00:00
elif game.day > 1:
2016-06-02 15:09:07 +00:00
text += s.status_alive_player.format(icon="\U0001F610",
name=player.tusername,
votes=str(player.votes))
2016-12-09 16:36:43 +00:00
else:
text += s.status_basic_player.format(icon="\U0001F610",
name=player.tusername)
game.message(bot, text)
else:
bot.sendMessage(update.message.chat['id'], s.error_no_games_found, parse_mode=ParseMode.MARKDOWN)
def endjoin(bot, update):
2016-05-25 09:52:53 +00:00
"""Termina la fase di join e inizia quella di votazione."""
game = findgamebyid(update.message.chat['id'])
2016-06-03 20:54:09 +00:00
if game is not None and game.phase == 'Join':
2016-12-04 18:54:33 +00:00
if update.message.from_user['id'] == game.admin.tid:
2016-12-09 17:50:18 +00:00
game.message(bot, s.join_phase_ended)
2016-12-09 17:43:14 +00:00
game.startpreset(bot)
2016-05-26 09:08:50 +00:00
else:
game.message(bot, s.error_not_admin)
else:
bot.sendMessage(update.message.chat['id'], s.error_no_games_found, parse_mode=ParseMode.MARKDOWN)
2016-05-25 11:57:15 +00:00
2016-05-27 22:13:34 +00:00
def config(bot, update):
"""Configura il parametro richiesto."""
game = findgamebyid(update.message.chat['id'])
if game is not None and game.phase is 'Config':
2016-12-04 18:54:33 +00:00
if update.message.from_user['id'] == game.admin.tid:
cmd = update.message.text.split(' ', 1)
2016-05-27 09:46:54 +00:00
if len(cmd) >= 2:
if game.configstep == 0:
try:
game.roleconfig["Mifioso"] = int(cmd[1])
except ValueError:
game.message(bot, s.error_invalid_config)
else:
game.configstep += 1
game.message(bot, s.config_list[game.configstep])
elif game.configstep == 1:
try:
2016-08-10 13:53:55 +00:00
game.roleconfig["Investigatore"] = int(cmd[1])
except ValueError:
game.message(bot, s.error_invalid_config)
else:
game.configstep += 1
game.message(bot, s.config_list[game.configstep])
elif game.configstep == 2:
try:
game.roleconfig["Angelo"] = int(cmd[1])
except ValueError:
game.message(bot, s.error_invalid_config)
2016-05-26 13:12:49 +00:00
else:
game.configstep += 1
game.message(bot, s.config_list[game.configstep])
elif game.configstep == 3:
2016-08-10 15:02:30 +00:00
try:
game.roleconfig["Terrorista"] = int(cmd[1])
except ValueError:
game.message(bot, s.error_invalid_config)
else:
game.configstep += 1
game.message(bot, s.config_list[game.configstep])
elif game.configstep == 4:
2016-12-04 18:54:33 +00:00
try:
game.roleconfig["Derek"] = int(cmd[1])
except ValueError:
game.message(bot, s.error_invalid_config)
else:
game.configstep += 1
game.message(bot, s.config_list[game.configstep])
elif game.configstep == 5:
2016-12-05 17:57:08 +00:00
try:
game.roleconfig["Disastro"] = int(cmd[1])
except ValueError:
game.message(bot, s.error_invalid_config)
else:
game.configstep += 1
game.message(bot, s.config_list[game.configstep])
elif game.configstep == 6:
2016-12-11 16:18:36 +00:00
try:
game.roleconfig["Mamma"] = int(cmd[1])
except ValueError:
game.message(bot, s.error_invalid_config)
else:
game.configstep += 1
game.message(bot, s.config_list[game.configstep])
elif game.configstep == 7:
2017-01-29 13:22:00 +00:00
try:
game.roleconfig["Stagista"] = int(cmd[1])
except ValueError:
game.message(bot, s.error_invalid_config)
else:
game.configstep += 1
game.message(bot, s.config_list[game.configstep])
elif game.configstep == 8:
try:
game.roleconfig["SignoreDelCaos"] = int(cmd[1])
except ValueError:
game.message(bot, s.error_invalid_config)
else:
game.configstep += 1
game.message(bot, s.config_list[game.configstep])
elif game.configstep == 9:
try:
game.roleconfig["SignoreDelCaos"] = int(cmd[1])
except ValueError:
game.message(bot, s.error_invalid_config)
else:
game.configstep += 1
game.message(bot, s.config_list[game.configstep])
elif game.configstep == 10:
2016-05-27 13:16:47 +00:00
if cmd[1].lower() == 'testa':
game.votingmifia = False
2016-12-06 22:00:27 +00:00
game.configstep += 1
game.message(bot, s.config_list[game.configstep])
2016-05-27 13:16:47 +00:00
elif cmd[1].lower() == 'unica':
game.votingmifia = True
2016-12-05 18:58:46 +00:00
game.configstep += 1
2016-12-06 22:00:27 +00:00
game.message(bot, s.config_list[game.configstep])
2016-12-05 18:58:46 +00:00
else:
game.message(bot, s.error_invalid_config)
2017-01-29 13:22:00 +00:00
elif game.configstep == 11:
2016-12-12 18:06:28 +00:00
if cmd[1].lower() == 'perfetti':
2016-12-05 18:58:46 +00:00
game.missingmifia = False
2016-12-06 22:03:14 +00:00
game.endconfig(bot)
2016-12-05 18:58:46 +00:00
elif cmd[1].lower() == 'mancare':
game.missingmifia = True
2016-12-06 22:00:27 +00:00
game.configstep += 1
game.message(bot, s.config_list[game.configstep])
else:
2016-05-27 13:34:23 +00:00
game.message(bot, s.error_invalid_config)
2017-01-29 13:22:00 +00:00
elif game.configstep == 12:
2016-12-06 22:00:27 +00:00
try:
miss = int(cmd[1])
except ValueError:
game.message(bot, s.error_invalid_config)
else:
if miss < 100:
game.misschance = miss
else:
game.misschance = 100
game.endconfig(bot)
else:
game.message(bot, s.config_list[game.configstep])
2016-05-26 11:50:16 +00:00
else:
game.message(bot, s.error_not_admin)
else:
2016-08-10 15:02:30 +00:00
bot.sendMessage(update.message.chat['id'], s.error_no_games_found, parse_mode=ParseMode.MARKDOWN)
def vote(bot, update):
2016-05-25 09:52:53 +00:00
"""Vota per uccidere una persona."""
2016-12-09 16:36:43 +00:00
# Trova la partita
game = findgamebyid(update.message.chat['id'])
2016-12-09 16:36:43 +00:00
if game is None:
bot.sendMessage(update.message.chat['id'], s.error_no_games_found, parse_mode=ParseMode.MARKDOWN)
return
elif game.phase is not 'Voting':
bot.sendMessage(update.message.chat['id'], s.error_no_games_found, parse_mode=ParseMode.MARKDOWN)
2016-12-09 16:36:43 +00:00
return
elif game.day <= 1:
game.message(bot, s.error_no_votes_on_first_day)
return
2017-01-29 17:57:22 +00:00
# Genera la tastiera
table = list()
for player in game.players:
row = list()
row.append(InlineKeyboardButton(s.vote_keyboard_line.format(name=player.tusername), callback_data=player.tusername))
table.append(row)
keyboard = InlineKeyboardMarkup(table)
# Manda la tastiera
bot.sendMessage(game.groupid, s.vote_keyboard, parse_mode=ParseMode.MARKDOWN, reply_markup=keyboard)
2016-04-21 21:04:53 +00:00
2016-04-21 20:14:35 +00:00
2016-04-22 19:14:14 +00:00
def endday(bot, update):
2016-05-25 09:52:53 +00:00
"""Termina la giornata attuale."""
2016-04-22 19:14:14 +00:00
game = findgamebyid(update.message.chat['id'])
2016-12-04 18:54:33 +00:00
if game is not None and game.phase is 'Voting' and update.message.from_user['id'] == game.admin.tid:
2016-04-22 19:14:14 +00:00
game.endday(bot)
2016-04-23 15:07:09 +00:00
def power(bot, update):
2016-05-25 09:52:53 +00:00
"""Attiva il potere del tuo ruolo."""
2016-04-23 15:07:09 +00:00
if update.message.chat['type'] == 'private':
cmd = update.message.text.split(' ', 2)
game = findgamebyname(cmd[1])
# Se non lo trovi con il nome, prova con l'id
if game is None:
2016-12-24 18:15:29 +00:00
try:
game = findgamebyid(int(cmd[1]))
except ValueError:
pass
2016-04-23 15:07:09 +00:00
if game is not None:
2016-05-26 10:12:14 +00:00
player = game.findplayerbyid(int(update.message.from_user['id']))
if player is not None:
2016-05-26 09:08:50 +00:00
if player.alive:
2017-01-25 17:11:39 +00:00
if len(cmd) > 2:
player.role.power(bot, game, cmd[2])
else:
player.message(bot, s.error_missing_parameters)
2016-05-26 09:08:50 +00:00
else:
player.message(bot, s.error_dead)
else:
bot.sendMessage(update.message.chat['id'], s.error_not_in_game, parse_mode=ParseMode.MARKDOWN)
2016-04-23 15:07:09 +00:00
else:
bot.sendMessage(update.message.chat['id'], s.error_no_games_found, parse_mode=ParseMode.MARKDOWN)
2016-04-23 15:07:09 +00:00
else:
bot.sendMessage(update.message.chat['id'], s.error_private_required, parse_mode=ParseMode.MARKDOWN)
2016-04-23 15:07:09 +00:00
2016-05-27 22:13:34 +00:00
def role(bot, update):
2016-05-26 09:08:50 +00:00
"""Visualizza il tuo ruolo."""
game = findgamebyid(update.message.chat['id'])
if game is not None and game.phase is 'Voting':
player = game.findplayerbyid(update.message.from_user['id'])
if player is not None:
2016-05-26 09:08:50 +00:00
if player.alive:
2016-06-01 07:19:37 +00:00
player.message(bot, s.role_assigned.format(icon=player.role.icon, name=player.role.name))
2016-05-26 09:08:50 +00:00
game.message(bot, s.check_private)
else:
game.message(bot, s.error_dead)
else:
bot.sendMessage(update.message.chat['id'], s.error_not_in_game, parse_mode=ParseMode.MARKDOWN)
else:
bot.sendMessage(update.message.chat['id'], s.error_no_games_found, parse_mode=ParseMode.MARKDOWN)
2016-05-26 09:49:40 +00:00
def kill(bot, update):
2016-05-26 09:08:50 +00:00
"""Uccidi un giocatore in partita."""
2016-06-01 11:52:00 +00:00
if __debug__:
game = findgamebyid(update.message.chat['id'])
if game is not None and game.phase is 'Voting':
2016-12-04 18:54:33 +00:00
if update.message.from_user['id'] == game.admin.tid:
2016-06-01 11:52:00 +00:00
target = game.findplayerbyusername(update.message.text.split(' ')[1])
if target is not None:
target.kill(bot, game)
game.message(bot, s.admin_killed.format(name=target.tusername,
icon=target.role.icon,
2016-06-01 11:52:00 +00:00
role=target.role.name))
else:
game.message(bot, s.error_username)
2016-05-26 09:08:50 +00:00
else:
2016-06-01 11:52:00 +00:00
game.message(bot, s.error_not_admin)
2016-05-26 09:08:50 +00:00
else:
2016-06-01 11:52:00 +00:00
bot.sendMessage(update.message.chat['id'], s.error_no_games_found, parse_mode=ParseMode.MARKDOWN)
2016-04-25 17:44:40 +00:00
2016-06-01 11:39:41 +00:00
def delete(bot, update):
"""Elimina una partita in corso."""
if update.message.chat['type'] == 'private':
if update.message.from_user['username'] == "Steffo":
cmd = update.message.text.split(' ', 2)
game = findgamebyname(cmd[1])
# Se non lo trovi con il nome, prova con l'id
if game is None:
game = findgamebyid(int(cmd[1]))
if game is not None:
2016-06-02 15:09:07 +00:00
game.message(bot, s.owner_ended)
2016-06-01 11:39:41 +00:00
game.endgame()
else:
game.message(bot, s.error_no_games_found)
else:
bot.sendMessage(update.message.chat['id'], s.error_not_owner, parse_mode=ParseMode.MARKDOWN)
else:
bot.sendMessage(update.message.chat['id'], s.error_chat_type, parse_mode=ParseMode.MARKDOWN)
2016-05-26 12:55:02 +00:00
def fakerole(bot, update):
"""Manda un finto messaggio di ruolo."""
if update.message.chat['type'] == 'private':
2017-07-04 22:40:23 +00:00
roles = rolepriority.copy()
roles.append(Royal)
for singlerole in roles:
2016-12-05 17:56:34 +00:00
bot.sendMessage(update.message.chat['id'], s.role_assigned.format(icon=singlerole.icon, name=singlerole.name),
parse_mode=ParseMode.MARKDOWN)
2016-05-26 12:55:02 +00:00
else:
bot.sendMessage(update.message.chat['id'], s.error_private_required, parse_mode=ParseMode.MARKDOWN)
2016-05-26 12:55:02 +00:00
2016-05-29 15:12:23 +00:00
def load(bot, update):
"""Carica una partita salvata."""
file = open(str(update.message.chat['id']) + ".p", "rb")
game = pickle.load(file)
inprogress.append(game)
game.message(bot, s.game_loaded)
def save(bot, update):
"""Salva una partita su file."""
game = findgamebyid(update.message.chat['id'])
if game is not None:
2017-01-28 23:36:58 +00:00
game.save(bot)
2016-05-29 15:12:23 +00:00
else:
bot.sendMessage(update.message.chat['id'], s.error_no_games_found, parse_mode=ParseMode.MARKDOWN)
def debug(bot, update):
"""Visualizza tutti i ruoli e gli id."""
if __debug__:
game = findgamebyid(update.message.chat['id'])
if game is not None:
game.revealallroles(bot)
2017-01-28 23:36:58 +00:00
else:
bot.sendMessage(update.message.chat['id'], s.error_no_games_found, parse_mode=ParseMode.MARKDOWN)
def debugchangerole(bot, update):
"""Cambia il ruolo a un giocatore."""
if __debug__:
game = findgamebyid(update.message.chat['id'])
if game is not None:
cmd = update.message.text.split(' ', 2)
2017-01-29 13:22:00 +00:00
game.changerole(bot, game.findplayerbyusername(cmd[1]), globals()[cmd[2]])
else:
bot.sendMessage(update.message.chat['id'], s.error_no_games_found, parse_mode=ParseMode.MARKDOWN)
def debuggameslist(bot, update):
"""Visualizza l'elenco delle partite in corso."""
if __debug__:
bot.sendMessage(update.message.from_user['id'], repr(inprogress), parse_mode=ParseMode.MARKDOWN)
2016-08-10 14:03:11 +00:00
2017-01-29 17:57:22 +00:00
def inlinekeyboard(bot, update):
2016-12-09 17:43:14 +00:00
"""Seleziona un preset dalla tastiera."""
game = findgamebyid(update.callback_query.message.chat['id'])
2017-01-29 17:57:22 +00:00
if game is not None:
if game.phase is 'Preset':
if update.callback_query.from_user['id'] == game.admin.tid:
game.loadpreset(bot, update.callback_query.data)
elif game.phase is 'Voting':
# Trova il giocatore
player = game.findplayerbyid(update.callback_query.from_user['id'])
2017-07-04 22:40:23 +00:00
if player is not None and player.alive:
2017-01-29 17:57:22 +00:00
# Trova il bersaglio
target = game.findplayerbyusername(update.callback_query.data)
player.votingfor = target
game.message(bot, s.vote.format(voting=player.tusername, voted=target.tusername))
bot.answerCallbackQuery(callback_query_id=update.callback_query.id, text=s.vote_fp.format(voted=target.tusername))
2016-12-09 17:43:14 +00:00
2016-06-03 20:04:37 +00:00
updater.dispatcher.add_handler(CommandHandler('ping', ping))
updater.dispatcher.add_handler(CommandHandler('newgame', newgame))
updater.dispatcher.add_handler(CommandHandler('join', join))
updater.dispatcher.add_handler(CommandHandler('debugjoin', debugjoin))
2016-06-03 20:04:37 +00:00
updater.dispatcher.add_handler(CommandHandler('endjoin', endjoin))
updater.dispatcher.add_handler(CommandHandler('vote', vote))
updater.dispatcher.add_handler(CommandHandler('endday', endday))
updater.dispatcher.add_handler(CommandHandler('power', power))
updater.dispatcher.add_handler(CommandHandler('status', status))
updater.dispatcher.add_handler(CommandHandler('role', role))
updater.dispatcher.add_handler(CommandHandler('debug', debug))
updater.dispatcher.add_handler(CommandHandler('debuggameslist', debuggameslist))
updater.dispatcher.add_handler(CommandHandler('kill', kill))
updater.dispatcher.add_handler(CommandHandler('config', config))
updater.dispatcher.add_handler(CommandHandler('fakerole', fakerole))
updater.dispatcher.add_handler(CommandHandler('save', save))
updater.dispatcher.add_handler(CommandHandler('load', load))
updater.dispatcher.add_handler(CommandHandler('delete', delete))
2017-01-28 23:36:58 +00:00
updater.dispatcher.add_handler(CommandHandler('debugchangerole', debugchangerole))
2017-01-29 17:57:22 +00:00
updater.dispatcher.add_handler(CallbackQueryHandler(inlinekeyboard))
2016-04-21 20:14:35 +00:00
updater.start_polling()
2016-05-27 09:34:06 +00:00
print("Bot avviato!")
if __name__ == "__main__":
while True:
2017-07-04 22:40:23 +00:00
try:
updater.idle()
except TimedOut:
time.sleep(10)