2016-04-25 16:13:16 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
# -*- coding: utf-8 -*-
|
2016-04-21 16:57:23 +00:00
|
|
|
from telegram.ext import Updater
|
|
|
|
import filemanager
|
|
|
|
|
2016-04-21 20:14:35 +00:00
|
|
|
import logging
|
|
|
|
logger = logging.getLogger()
|
2016-04-23 15:07:09 +00:00
|
|
|
logger.setLevel(logging.DEBUG)
|
2016-04-21 20:14:35 +00:00
|
|
|
|
2016-04-21 16:57:23 +00:00
|
|
|
token = filemanager.readfile('telegramapi.txt')
|
|
|
|
updater = Updater(token)
|
|
|
|
|
|
|
|
|
2016-04-21 17:52:01 +00:00
|
|
|
# Ruoli possibili per i giocatori
|
|
|
|
# Base di un ruolo
|
|
|
|
class Role:
|
2016-04-22 17:21:50 +00:00
|
|
|
icon = "-"
|
2016-04-21 18:20:26 +00:00
|
|
|
team = 'None' # Squadra: 'None', 'Good', 'Evil'
|
2016-04-22 19:14:14 +00:00
|
|
|
name = "UNDEFINED"
|
2016-04-21 17:52:01 +00:00
|
|
|
haspower = False
|
|
|
|
poweruses = 0
|
|
|
|
|
2016-04-23 15:07:09 +00:00
|
|
|
def power(self, bot, game, player, arg):
|
2016-04-21 17:52:01 +00:00
|
|
|
pass
|
|
|
|
|
2016-04-23 15:07:09 +00:00
|
|
|
def onendday(self, bot, game):
|
2016-04-21 17:52:01 +00:00
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class Royal(Role):
|
|
|
|
icon = "\U0001F610"
|
2016-04-21 18:20:26 +00:00
|
|
|
team = 'Good'
|
2016-04-22 19:14:14 +00:00
|
|
|
name = "Royal"
|
2016-04-21 17:52:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Mifioso(Role):
|
|
|
|
icon = "\U0001F47F"
|
2016-04-21 18:20:26 +00:00
|
|
|
team = 'Evil'
|
2016-04-21 17:52:01 +00:00
|
|
|
target = None
|
2016-04-22 19:14:14 +00:00
|
|
|
name = "Mifioso"
|
2016-04-21 17:52:01 +00:00
|
|
|
|
2016-04-23 15:07:09 +00:00
|
|
|
def power(self, bot, game, player, arg):
|
2016-04-21 17:52:01 +00:00
|
|
|
# Imposta qualcuno come bersaglio
|
2016-04-23 15:07:09 +00:00
|
|
|
self.target = game.findplayerbyusername(arg)
|
|
|
|
player.message(bot, "Hai selezionato come bersaglio {0}.".format(self.target.tusername))
|
2016-04-21 17:52:01 +00:00
|
|
|
|
2016-04-23 15:07:09 +00:00
|
|
|
def onendday(self, bot, game):
|
2016-04-21 17:52:01 +00:00
|
|
|
# Uccidi il bersaglio
|
2016-04-23 15:07:09 +00:00
|
|
|
if self.target is not None:
|
|
|
|
self.target.kill()
|
|
|
|
game.message(bot, "{0} è stato ucciso dalla Mifia.\n"
|
|
|
|
"Era un {1} {2}."
|
|
|
|
.format(self.target.tusername, self.target.role.icon, self.target.role.name))
|
2016-04-21 17:52:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Investigatore(Role):
|
|
|
|
icon = "\U0001F575"
|
2016-04-21 18:20:26 +00:00
|
|
|
team = 'Good'
|
2016-04-21 17:52:01 +00:00
|
|
|
poweruses = 1
|
2016-04-22 19:14:14 +00:00
|
|
|
name = "Investigatore"
|
2016-04-21 17:52:01 +00:00
|
|
|
|
2016-04-23 15:07:09 +00:00
|
|
|
def power(self, bot, game, player, arg):
|
2016-04-23 15:12:52 +00:00
|
|
|
if self.poweruses > 0:
|
|
|
|
target = game.findplayerbyusername(arg)
|
|
|
|
if target is not None:
|
|
|
|
self.poweruses -= 1
|
|
|
|
player.message(bot, "{0} è un {1} {2}.\n"
|
|
|
|
"Puoi usare il tuo potere ancora {3} volte oggi."
|
|
|
|
.format(target.tusername, target.role.icon, target.role.name, self.poweruses))
|
|
|
|
else:
|
|
|
|
player.message(bot, "Il nome utente specificato non esiste.")
|
|
|
|
else:
|
|
|
|
player.message(bot, "Non puoi più usare il tuo potere oggi.")
|
2016-04-21 21:04:53 +00:00
|
|
|
|
2016-04-23 15:07:09 +00:00
|
|
|
def onendday(self, bot, game):
|
2016-04-21 21:04:53 +00:00
|
|
|
# Ripristina il potere
|
|
|
|
self.poweruses = 1
|
|
|
|
|
|
|
|
|
2016-04-21 18:20:26 +00:00
|
|
|
# Classi per i giocatori
|
|
|
|
class Player:
|
|
|
|
tid = int()
|
|
|
|
tusername = str()
|
|
|
|
role = Role() # Di base, ogni giocatore è un ruolo indefinito
|
|
|
|
alive = True
|
2016-04-22 17:21:50 +00:00
|
|
|
votingfor = None # Diventa un player se ha votato
|
2016-04-22 19:14:14 +00:00
|
|
|
votes = 0 # Voti. Aggiornato da updatevotes()
|
2016-04-21 18:20:26 +00:00
|
|
|
|
|
|
|
def message(self, bot, text):
|
|
|
|
bot.sendMessage(self.tid, text)
|
|
|
|
|
2016-04-22 19:14:14 +00:00
|
|
|
def kill(self):
|
|
|
|
self.alive = False
|
|
|
|
|
2016-04-21 18:20:26 +00:00
|
|
|
def __init__(self, tid, tusername):
|
|
|
|
self.tid = tid
|
|
|
|
self.tusername = tusername
|
|
|
|
|
|
|
|
|
|
|
|
# Classe di ogni partita
|
|
|
|
class Game:
|
|
|
|
adminid = int()
|
|
|
|
groupid = int()
|
|
|
|
players = list()
|
|
|
|
tokill = list() # Giocatori che verranno uccisi all'endday
|
|
|
|
phase = 'Join' # Fase di gioco: 'Join', 'Voting', 'Ended'
|
|
|
|
|
|
|
|
def __init__(self, groupid, adminid):
|
|
|
|
self.groupid = groupid
|
|
|
|
self.adminid = adminid
|
|
|
|
|
|
|
|
def message(self, bot, text):
|
|
|
|
bot.sendMessage(self.groupid, text)
|
|
|
|
|
|
|
|
def adminmessage(self, bot, text):
|
|
|
|
bot.sendMessage(self.adminid, text)
|
|
|
|
|
|
|
|
def mifiamessage(self, bot, text):
|
|
|
|
# Trova tutti i mifiosi nell'elenco dei giocatori
|
|
|
|
for player in self.players:
|
|
|
|
if isinstance(player.role, Mifioso):
|
|
|
|
player.message(bot, text)
|
|
|
|
# Inoltra il messaggio all'admin
|
|
|
|
self.adminmessage(bot, text)
|
|
|
|
|
2016-04-22 17:21:50 +00:00
|
|
|
def findplayerbyid(self, tid) -> Player:
|
|
|
|
# Trova tutti i giocatori con un certo id
|
|
|
|
for player in self.players:
|
|
|
|
if player.tid == tid:
|
|
|
|
return player
|
|
|
|
else:
|
|
|
|
return None
|
|
|
|
|
|
|
|
def findplayerbyusername(self, tusername) -> Player:
|
|
|
|
# Trova tutti i giocatori con un certo username
|
|
|
|
for player in self.players:
|
2016-04-23 15:07:09 +00:00
|
|
|
if player.tusername.lower() == tusername.lower():
|
2016-04-22 17:21:50 +00:00
|
|
|
return player
|
|
|
|
else:
|
|
|
|
return None
|
|
|
|
|
2016-04-23 16:26:32 +00:00
|
|
|
def assignroles(self, bot, mifia=0, investigatore=0):
|
2016-04-22 17:55:24 +00:00
|
|
|
import random
|
|
|
|
random.seed()
|
|
|
|
playersleft = self.players.copy()
|
|
|
|
random.shuffle(playersleft)
|
2016-04-23 16:26:32 +00:00
|
|
|
# Seleziona mifiosi
|
2016-04-22 17:55:24 +00:00
|
|
|
while mifia > 0:
|
|
|
|
try:
|
|
|
|
selected = playersleft.pop()
|
|
|
|
except IndexError:
|
|
|
|
raise IndexError("Non ci sono abbastanza giocatori!")
|
|
|
|
else:
|
|
|
|
selected.role = Mifioso()
|
|
|
|
mifia -= 1
|
2016-04-23 16:26:32 +00:00
|
|
|
# Seleziona detective
|
2016-04-22 17:55:24 +00:00
|
|
|
while investigatore > 0:
|
|
|
|
try:
|
|
|
|
selected = playersleft.pop()
|
|
|
|
except IndexError:
|
|
|
|
raise IndexError("Non ci sono abbastanza giocatori!")
|
|
|
|
else:
|
|
|
|
selected.role = Investigatore()
|
|
|
|
investigatore -= 1
|
|
|
|
# Assegna il ruolo di Royal a tutti gli altri
|
|
|
|
for player in playersleft:
|
|
|
|
player.role = Royal()
|
2016-04-23 16:26:32 +00:00
|
|
|
# Manda i ruoli assegnati a tutti
|
|
|
|
for player in self.players:
|
|
|
|
player.message(bot, "Ti è stato assegnato il ruolo di {0} {1}.".format(player.role.icon, player.role.name))
|
2016-04-22 17:55:24 +00:00
|
|
|
|
2016-04-22 19:14:14 +00:00
|
|
|
def updatevotes(self):
|
|
|
|
for player in self.players:
|
|
|
|
player.votes = 0
|
|
|
|
for player in self.players:
|
2016-04-23 15:37:43 +00:00
|
|
|
if player.votingfor is not None:
|
|
|
|
player.votingfor.votes += 1
|
2016-04-22 19:14:14 +00:00
|
|
|
|
|
|
|
def mostvotedplayer(self) -> Player:
|
|
|
|
mostvoted = None
|
|
|
|
self.updatevotes()
|
|
|
|
for player in self.players:
|
2016-04-23 15:37:43 +00:00
|
|
|
# Temo di aver fatto un disastro. Ma finchè va...
|
|
|
|
if mostvoted is None and player.votes == 0:
|
|
|
|
pass
|
|
|
|
elif (mostvoted is None and player.votes >= 1) or (player.votes > mostvoted.votes):
|
2016-04-22 19:14:14 +00:00
|
|
|
mostvoted = player
|
2016-04-23 15:37:43 +00:00
|
|
|
elif mostvoted is not None and player.votes == mostvoted.votes:
|
2016-04-22 19:14:14 +00:00
|
|
|
# Non sono sicuro che questo algoritmo sia effettivamente il più equo. Ma vabbè, non succederà mai
|
|
|
|
import random
|
|
|
|
mostvoted = random.choice([player, mostvoted])
|
|
|
|
return mostvoted
|
|
|
|
|
|
|
|
def endday(self, bot):
|
2016-04-23 15:07:09 +00:00
|
|
|
# TODO: Per mettere l'angelo bisogna dare una priorità a ogni ruolo.
|
2016-04-22 19:14:14 +00:00
|
|
|
for player in self.players:
|
2016-04-23 15:07:09 +00:00
|
|
|
player.role.onendday(bot, self)
|
2016-04-22 19:14:14 +00:00
|
|
|
lynched = self.mostvotedplayer()
|
|
|
|
if lynched is not None:
|
2016-04-22 19:20:08 +00:00
|
|
|
self.message(bot, "{0} era il più votato ed è stato ucciso dai Royal.\n"
|
2016-04-22 19:14:14 +00:00
|
|
|
"Era un {1} {2}.".format(lynched.tusername, lynched.role.icon, lynched.role.name))
|
|
|
|
lynched.kill()
|
2016-04-23 15:37:43 +00:00
|
|
|
else:
|
|
|
|
self.message(bot, "La Royal Games non è giunta a una decisione in questo giorno e non ha ucciso nessuno.")
|
|
|
|
for player in self.players:
|
|
|
|
player.votingfor = None
|
2016-04-23 16:26:32 +00:00
|
|
|
# Condizioni di vittoria
|
|
|
|
royal = 0
|
|
|
|
mifiosi = 0
|
|
|
|
for player in self.players:
|
|
|
|
if player.alive and isinstance(player.role, Mifioso):
|
|
|
|
mifiosi += 1
|
|
|
|
elif player.alive and (isinstance(player.role, Royal) or isinstance(player.role, Investigatore)):
|
|
|
|
royal += 1
|
|
|
|
if mifiosi >= royal:
|
|
|
|
self.message(bot, "I Mifiosi rimasti sono più dei Royal.\n"
|
|
|
|
"La Mifia vince!")
|
|
|
|
self.endgame()
|
|
|
|
elif mifiosi == 0:
|
|
|
|
self.message(bot, "Tutti i Mifiosi sono stati eliminati.\n"
|
|
|
|
"La Royal Games vince!")
|
|
|
|
self.endgame()
|
|
|
|
|
|
|
|
def endgame(self):
|
|
|
|
inprogress.remove(self)
|
2016-04-22 19:14:14 +00:00
|
|
|
|
2016-04-21 20:14:35 +00:00
|
|
|
# Partite in corso
|
|
|
|
inprogress = list()
|
|
|
|
|
2016-04-21 18:20:26 +00:00
|
|
|
|
2016-04-21 21:04:53 +00:00
|
|
|
# Trova una partita con un certo id
|
|
|
|
def findgamebyid(gid) -> Game:
|
|
|
|
for game in inprogress:
|
|
|
|
if game.groupid == gid:
|
|
|
|
return game
|
|
|
|
|
|
|
|
|
2016-04-21 17:52:01 +00:00
|
|
|
# Comandi a cui risponde il bot
|
2016-04-21 16:57:23 +00:00
|
|
|
def ping(bot, update):
|
2016-04-21 20:22:08 +00:00
|
|
|
bot.sendMessage(update.message.chat['id'], "Pong!")
|
2016-04-21 16:57:23 +00:00
|
|
|
|
2016-04-21 20:14:35 +00:00
|
|
|
|
|
|
|
def newgame(bot, update):
|
|
|
|
if update.message.chat['type'] != 'private':
|
|
|
|
g = Game(update.message.chat['id'], update.message.from_user['id'])
|
|
|
|
inprogress.append(g)
|
2016-04-21 21:04:53 +00:00
|
|
|
bot.sendMessage(update.message.chat['id'], "Partita creata: " + repr(g))
|
2016-04-21 20:14:35 +00:00
|
|
|
else:
|
2016-04-21 21:04:53 +00:00
|
|
|
bot.sendMessage(update.message.chat['id'], "Non puoi creare una partita in questo tipo di chat!")
|
|
|
|
|
|
|
|
|
|
|
|
def join(bot, update):
|
|
|
|
game = findgamebyid(update.message.chat['id'])
|
|
|
|
if game is not None:
|
|
|
|
if game.phase == 'Join':
|
2016-04-22 18:39:16 +00:00
|
|
|
p = game.findplayerbyid(update.message.from_user['id'])
|
|
|
|
if p is None:
|
|
|
|
p = Player(update.message.from_user['id'], update.message.from_user['username'])
|
|
|
|
game.players.append(p)
|
|
|
|
bot.sendMessage(update.message.chat['id'], "Unito alla partita: " + repr(p))
|
|
|
|
else:
|
|
|
|
bot.sendMessage(update.message.chat['id'], "Ti sei già unito alla partita: " + repr(p))
|
2016-04-22 17:21:50 +00:00
|
|
|
|
|
|
|
|
2016-04-23 15:37:43 +00:00
|
|
|
def debug(bot, update):
|
|
|
|
game = findgamebyid(update.message.chat['id'])
|
|
|
|
if game is None:
|
|
|
|
bot.sendMessage(update.message.chat['id'], "In questo gruppo non ci sono partite in corso.")
|
|
|
|
else:
|
|
|
|
if game.adminid == update.message.from_user['id']:
|
|
|
|
text = "Gruppo: {0}\n" \
|
|
|
|
"Creatore: {1}\n" \
|
2016-04-23 16:26:32 +00:00
|
|
|
"Fase: {2}\n" \
|
2016-04-23 15:37:43 +00:00
|
|
|
"Giocatori partecipanti:\n".format(game.groupid, game.adminid, game.phase)
|
|
|
|
game.updatevotes()
|
|
|
|
# Aggiungi l'elenco dei giocatori
|
|
|
|
for player in game.players:
|
|
|
|
if not player.alive:
|
|
|
|
text += "\U0001F480 {0}\n".format(player.tusername)
|
|
|
|
elif player.votingfor is not None:
|
|
|
|
text += "{0} {1} ({2}) vota per {3}\n"\
|
|
|
|
.format(player.role.icon, player.tusername, player.votes, player.votingfor.tusername)
|
|
|
|
else:
|
|
|
|
text += "{0} {1} ({2})\n".format(player.role.icon, player.tusername, player.votes)
|
|
|
|
bot.sendMessage(update.message.from_user['id'], text)
|
|
|
|
|
|
|
|
|
2016-04-22 17:21:50 +00:00
|
|
|
def status(bot, update):
|
|
|
|
game = findgamebyid(update.message.chat['id'])
|
|
|
|
if game is None:
|
|
|
|
bot.sendMessage(update.message.chat['id'], "In questo gruppo non ci sono partite in corso.")
|
|
|
|
else:
|
|
|
|
text = "Gruppo: {0}\n" \
|
|
|
|
"Creatore: {1}\n" \
|
2016-04-23 16:26:32 +00:00
|
|
|
"Fase: {2}\n" \
|
2016-04-22 17:21:50 +00:00
|
|
|
"Giocatori partecipanti:\n".format(game.groupid, game.adminid, game.phase)
|
2016-04-23 15:37:43 +00:00
|
|
|
game.updatevotes()
|
2016-04-22 17:21:50 +00:00
|
|
|
# Aggiungi l'elenco dei giocatori
|
|
|
|
for player in game.players:
|
2016-04-23 15:07:09 +00:00
|
|
|
if not player.alive:
|
2016-04-23 15:37:43 +00:00
|
|
|
text += "\U0001F480 {0}\n".format(player.tusername)
|
2016-04-23 15:07:09 +00:00
|
|
|
elif player.votingfor is not None:
|
2016-04-23 16:26:32 +00:00
|
|
|
text += "\U0001F610 {0} ({1}) vota per {2}\n"\
|
|
|
|
.format(player.tusername, player.votes, player.votingfor.tusername)
|
2016-04-22 17:21:50 +00:00
|
|
|
else:
|
2016-04-23 16:26:32 +00:00
|
|
|
text += "\U0001F610 {0} ({1})\n".format(player.tusername, player.votes)
|
|
|
|
bot.sendMessage(update.message.chat['id'], text)
|
2016-04-22 17:21:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
def endjoin(bot, update):
|
|
|
|
game = findgamebyid(update.message.chat['id'])
|
2016-04-22 18:43:23 +00:00
|
|
|
if game is not None and game.phase is 'Join' and update.message.from_user['id'] == game.adminid:
|
2016-04-22 17:21:50 +00:00
|
|
|
game.phase = 'Voting'
|
|
|
|
bot.sendMessage(update.message.chat['id'], "La fase di join è terminata.")
|
2016-04-23 16:26:32 +00:00
|
|
|
game.assignroles(bot, mifia=2, investigatore=1)
|
|
|
|
bot.sendMessage(update.message.chat['id'], "I ruoli sono stati assegnati.\n"
|
|
|
|
"Controlla la chat con @mifiabot.")
|
2016-04-22 17:21:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
def vote(bot, update):
|
|
|
|
game = findgamebyid(update.message.chat['id'])
|
|
|
|
if game is not None and game.phase is 'Voting':
|
|
|
|
player = game.findplayerbyid(update.message.from_user['id'])
|
2016-04-23 15:07:09 +00:00
|
|
|
if player is not None and player.alive:
|
2016-04-22 17:21:50 +00:00
|
|
|
target = game.findplayerbyusername(update.message.text.split(' ')[1])
|
|
|
|
if target is not None:
|
|
|
|
player.votingfor = target
|
|
|
|
bot.sendMessage(update.message.chat['id'], "Hai votato per uccidere {0}.".format(target.tusername))
|
|
|
|
else:
|
|
|
|
bot.sendMessage(update.message.chat['id'], "Il nome utente specificato non esiste.")
|
|
|
|
else:
|
2016-04-23 15:07:09 +00:00
|
|
|
bot.sendMessage(update.message.chat['id'], "Non puoi votare. Non sei nella partita o sei morto.")
|
2016-04-22 17:21:50 +00:00
|
|
|
else:
|
|
|
|
bot.sendMessage(update.message.chat['id'], "Nessuna partita in corso trovata.")
|
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):
|
|
|
|
game = findgamebyid(update.message.chat['id'])
|
|
|
|
if game is not None and game.phase is 'Voting' and update.message.from_user['id'] == game.adminid:
|
|
|
|
game.endday(bot)
|
|
|
|
|
|
|
|
|
2016-04-23 15:07:09 +00:00
|
|
|
def power(bot, update):
|
|
|
|
if update.message.chat['type'] == 'private':
|
|
|
|
# Ho un'idea su come farlo meglio. Forse.
|
|
|
|
cmd = update.message.text.split(' ', 2)
|
|
|
|
game = findgamebyid(int(cmd[1]))
|
|
|
|
if game is not None:
|
|
|
|
player = game.findplayerbyid(update.message.from_user['id'])
|
|
|
|
if player.alive:
|
|
|
|
player.role.power(bot, game, player, cmd[2])
|
|
|
|
else:
|
|
|
|
bot.sendMessage(update.message.chat['id'], "Sei morto e non puoi usare poteri.")
|
|
|
|
else:
|
|
|
|
bot.sendMessage(update.message.chat['id'], "Partita non trovata.")
|
|
|
|
else:
|
|
|
|
bot.sendMessage(update.message.chat['id'], "Per usare /power, scrivimi in chat privata a @mifiabot!")
|
|
|
|
|
2016-04-21 16:57:23 +00:00
|
|
|
updater.dispatcher.addTelegramCommandHandler('ping', ping)
|
2016-04-21 20:14:35 +00:00
|
|
|
updater.dispatcher.addTelegramCommandHandler('newgame', newgame)
|
2016-04-21 21:04:53 +00:00
|
|
|
updater.dispatcher.addTelegramCommandHandler('join', join)
|
2016-04-23 15:37:43 +00:00
|
|
|
updater.dispatcher.addTelegramCommandHandler('debug', debug)
|
2016-04-22 17:21:50 +00:00
|
|
|
updater.dispatcher.addTelegramCommandHandler('endjoin', endjoin)
|
|
|
|
updater.dispatcher.addTelegramCommandHandler('vote', vote)
|
2016-04-22 19:14:14 +00:00
|
|
|
updater.dispatcher.addTelegramCommandHandler('endday', endday)
|
2016-04-23 15:07:09 +00:00
|
|
|
updater.dispatcher.addTelegramCommandHandler('power', power)
|
2016-04-23 15:37:43 +00:00
|
|
|
updater.dispatcher.addTelegramCommandHandler('status', status)
|
2016-04-21 20:14:35 +00:00
|
|
|
updater.start_polling()
|
2016-04-22 17:21:50 +00:00
|
|
|
updater.idle()
|