2020-06-21 19:51:33 +02:00
package main
import (
2021-11-13 03:40:43 +01:00
"crypto/rand"
"encoding/hex"
2020-06-21 19:54:07 +02:00
"encoding/json"
2021-11-06 16:33:16 +01:00
"fmt"
"regexp"
"strconv"
"time"
2020-06-21 19:54:07 +02:00
2020-06-21 19:51:33 +02:00
tb "gopkg.in/tucnak/telebot.v2"
)
2021-11-06 16:33:16 +01:00
type Bot struct {
bot * tb . Bot
Config * TelegramConfig
}
2021-12-04 05:49:20 +01:00
type BotActionEntry struct {
Action string
2021-11-13 03:40:43 +01:00
CompanyID uint8
UserID int
Time time . Time
}
2021-12-04 05:49:20 +01:00
var botActionMap map [ string ] * BotActionEntry
2021-11-13 03:40:43 +01:00
2021-11-06 16:33:16 +01:00
func ( b * Bot ) Start ( ) {
var err error
b . bot , err = tb . NewBot ( tb . Settings {
Token : b . Config . Token ,
URL : b . Config . URL ,
Poller : & tb . LongPoller { Timeout : 10 * time . Second } ,
} )
failError ( err , "Bot.Start() : registering bot" )
2021-12-04 05:49:20 +01:00
botActionMap = make ( map [ string ] * BotActionEntry )
2021-11-13 03:40:43 +01:00
2021-11-06 16:33:16 +01:00
b . BotHandlers ( )
}
func ( b * Bot ) SendUser ( id int64 , msg string ) {
u := tb . User {
ID : int ( id ) ,
}
_ , err := b . bot . Send ( & u , msg )
logErrorDebug ( err , "Bot.SendUser()" )
}
func ( b * Bot ) SendChat ( chatID int64 , text string ) {
opt := tb . SendOptions {
ParseMode : tb . ModeDefault ,
}
ch := tb . Chat {
ID : chatID ,
}
_ , err := b . bot . Send ( & ch , text , & opt )
logErrorDebug ( err , "Bot.SendChat()" )
}
2020-06-21 19:51:33 +02:00
2021-12-05 11:23:08 +01:00
func ( b * Bot ) SendChatImage ( chatID int64 , image string ) {
opt := tb . SendOptions {
ParseMode : tb . ModeDefault ,
}
ch := tb . Chat {
ID : chatID ,
}
photo := & tb . Photo { File : tb . FromDisk ( image ) }
_ , err := b . bot . Send ( & ch , photo , & opt )
logErrorDebug ( err , "Bot.SendChatImage()" )
}
2021-11-06 16:33:16 +01:00
func ( b * Bot ) BotHandlers ( ) {
2020-06-22 11:02:04 +02:00
2021-11-06 16:33:16 +01:00
b . bot . Handle ( "/pause" , botPause )
b . bot . Handle ( "/unpause" , botUnpause )
b . bot . Handle ( "/register" , botRegister )
2021-11-09 06:24:42 +01:00
b . bot . Handle ( "/deregister" , botDeregister )
2021-11-06 16:33:16 +01:00
b . bot . Handle ( "/delete" , botDelete )
2021-12-08 12:50:55 +01:00
b . bot . Handle ( "/offline" , botOffline )
2021-11-06 16:33:16 +01:00
b . bot . Handle ( "/companies" , botCompanies )
b . bot . Handle ( "/clients" , botClients )
2021-12-04 05:49:20 +01:00
2021-11-10 05:56:53 +01:00
b . bot . Handle ( "/passwd" , botPasswd )
2021-11-13 06:44:57 +01:00
b . bot . Handle ( "/say" , botSay )
2021-11-28 11:31:49 +01:00
b . bot . Handle ( "/help" , botHelp )
2021-12-05 08:41:47 +01:00
2021-11-28 14:41:00 +01:00
b . bot . Handle ( "/version" , botVersion )
2021-12-05 08:41:47 +01:00
b . bot . Handle ( "/save" , botSave )
2020-06-21 19:51:33 +02:00
2021-12-04 05:49:20 +01:00
b . bot . Handle ( "/reset" , botReset )
b . bot . Handle ( "/ready" , botReady )
b . bot . Handle ( "/start" , botStart )
b . bot . Handle ( "/players" , botPlayers )
2021-12-28 16:02:18 +01:00
b . bot . Handle ( "/remove" , botRemove )
2021-12-04 05:49:20 +01:00
b . bot . Handle ( "/give" , botGive )
b . bot . Handle ( "/take" , botTake )
b . bot . Handle ( "/transfer" , botTransfer )
2021-12-05 11:23:08 +01:00
b . bot . Handle ( "/value" , botGraphValue )
2021-12-06 14:55:59 +01:00
b . bot . Handle ( "/value_delta" , botGraphValueDelta )
2021-12-12 07:31:43 +01:00
b . bot . Handle ( "/deliveries" , botGraphDeliveries )
2021-12-09 14:42:44 +01:00
b . bot . Handle ( "/money" , botGraphMoney )
b . bot . Handle ( "/income" , botGraphIncome )
b . bot . Handle ( "/loan" , botGraphLoan )
b . bot . Handle ( "/perf" , botGraphPerf )
2021-12-06 14:55:59 +01:00
b . bot . Handle ( "/planes" , botGraphPlanes )
2021-12-06 15:36:27 +01:00
b . bot . Handle ( "/busses" , botGraphBusses )
b . bot . Handle ( "/trains" , botGraphTrains )
2021-12-08 15:23:12 +01:00
b . bot . Handle ( "/lorries" , botGraphLorries )
b . bot . Handle ( "/ships" , botGraphShips )
2021-12-05 11:23:08 +01:00
2021-11-06 16:33:16 +01:00
b . bot . Handle ( tb . OnPhoto , botPhoto )
b . bot . Handle ( tb . OnChannelPost , botChannelPost )
b . bot . Handle ( tb . OnQuery , botQuery )
b . bot . Handle ( tb . OnText , botText )
b . bot . Handle ( tb . OnDocument , botDocument )
go func ( ) {
time . Sleep ( time . Second )
b . SendUser ( b . Config . AdminID , fmt . Sprintf ( "Started (%s)" , version ) )
} ( )
b . bot . Start ( )
2020-06-21 19:51:33 +02:00
}
2021-12-08 13:15:14 +01:00
func botHelp ( m * tb . Message ) {
msg := ""
msg = fmt . Sprintf ( "%s/pause - pause the game\r\n" , msg )
msg = fmt . Sprintf ( "%s/unpause - unpause the game\r\n" , msg )
msg = fmt . Sprintf ( "%s/register - register company\r\n" , msg )
msg = fmt . Sprintf ( "%s/deregister - deregister company\r\n" , msg )
msg = fmt . Sprintf ( "%s/delete - delete company\r\n" , msg )
msg = fmt . Sprintf ( "%s/companies - list companies\r\n" , msg )
msg = fmt . Sprintf ( "%s/clients - list clients\r\n" , msg )
msg = fmt . Sprintf ( "%s/give - give time to player\r\n" , msg )
msg = fmt . Sprintf ( "%s/take - take time from player\r\n" , msg )
msg = fmt . Sprintf ( "%s/transfer - transfer time between players\r\n" , msg )
msg = fmt . Sprintf ( "%s/passwd - change passwd\r\n" , msg )
msg = fmt . Sprintf ( "%s/say - send msg to the game\r\n" , msg )
msg = fmt . Sprintf ( "%s/reset - reset the game\r\n" , msg )
msg = fmt . Sprintf ( "%s/start - start the game\r\n" , msg )
msg = fmt . Sprintf ( "%s/ready - set player as ready\r\n" , msg )
msg = fmt . Sprintf ( "%s/players - list players\r\n" , msg )
msg = fmt . Sprintf ( "%s/offline - set player offline\r\n" , msg )
msg = fmt . Sprintf ( "%s/value - value graph\r\n" , msg )
msg = fmt . Sprintf ( "%s/value_delta - delta value graph\r\n" , msg )
2021-12-12 07:31:43 +01:00
msg = fmt . Sprintf ( "%s/deliveries - deliveries graph\r\n" , msg )
2021-12-09 14:42:44 +01:00
msg = fmt . Sprintf ( "%s/money - money graph\r\n" , msg )
msg = fmt . Sprintf ( "%s/income - income graph\r\n" , msg )
msg = fmt . Sprintf ( "%s/loan - loan graph\r\n" , msg )
msg = fmt . Sprintf ( "%s/perf - perf graph\r\n" , msg )
2021-12-08 13:15:14 +01:00
msg = fmt . Sprintf ( "%s/busses - busses graph\r\n" , msg )
msg = fmt . Sprintf ( "%s/trains - trains graph\r\n" , msg )
msg = fmt . Sprintf ( "%s/planes - planes graph\r\n" , msg )
2021-12-09 14:42:44 +01:00
msg = fmt . Sprintf ( "%s/lorries - lorries graph\r\n" , msg )
msg = fmt . Sprintf ( "%s/ships - ships graph\r\n" , msg )
2021-12-08 13:15:14 +01:00
msg = fmt . Sprintf ( "%s/version - version\r\n" , msg )
msg = fmt . Sprintf ( "%s/help - this\r\n" , msg )
bot . SendChat ( m . Chat . ID , msg )
return
}
2020-06-22 11:02:04 +02:00
func botPause ( m * tb . Message ) {
2021-11-06 16:33:16 +01:00
for userID , cc := range cfg . Clients {
if userID == m . Sender . ID {
if co , ok := srv . Status . Companies [ cc . CompanyID ] ; ok {
if clt , ok2 := srv . Status . Clients [ co . ClientID ] ; ok2 {
clt . Paused = true
2021-11-08 07:27:49 +01:00
if ! srv . Status . Paused {
srv . Pause ( )
} else {
bot . SendChat ( bot . Config . ChatID , "Game already paused." )
}
return
2021-11-06 16:33:16 +01:00
}
}
2020-06-22 11:13:07 +02:00
}
2021-11-06 16:33:16 +01:00
}
2021-11-08 07:27:49 +01:00
bot . SendChat ( bot . Config . ChatID , "You are not playing and cannot pause the game." )
2020-06-22 11:02:04 +02:00
return
}
func botUnpause ( m * tb . Message ) {
2021-11-06 16:33:16 +01:00
PrintText ( m )
for userID , cc := range cfg . Clients {
if userID == m . Sender . ID {
if co , ok := srv . Status . Companies [ cc . CompanyID ] ; ok {
if clt , ok2 := srv . Status . Clients [ co . ClientID ] ; ok2 {
clt . Paused = false
2021-11-08 07:27:49 +01:00
if ! srv . NeedPause ( ) {
srv . Unpause ( )
} else {
bot . SendChat ( bot . Config . ChatID , fmt . Sprintf ( "Cannot unpause : %s" , srv . NeedPauseReason ( ) ) )
}
return
2021-11-06 16:33:16 +01:00
}
}
2020-06-22 11:09:11 +02:00
}
2021-11-06 16:33:16 +01:00
}
2021-11-08 07:27:49 +01:00
bot . SendChat ( bot . Config . ChatID , "You are not playing and cannot unpause the game." )
2021-11-06 16:33:16 +01:00
return
}
2021-12-08 12:50:55 +01:00
func botOffline ( m * tb . Message ) {
if m . Sender . ID != int ( cfg . Telegram . AdminID ) {
bot . SendChat ( m . Chat . ID , "Only the admin can use this command." )
return
}
2021-12-08 12:54:01 +01:00
r := regexp . MustCompile ( "^\\/offline @(?P<Username>[a-zA-Z0-9]+)" )
2021-12-08 12:50:55 +01:00
if ! r . MatchString ( m . Text ) {
bot . SendChat ( m . Chat . ID , "Wrong format." )
return
}
uStr := r . ReplaceAllString ( m . Text , "${Username}" )
var u int
for ccID , cc := range cfg . Clients {
if cc . Username == uStr {
u = ccID
}
}
if u == 0 {
bot . SendChat ( m . Chat . ID , "No such user found." )
return
}
cc := cfg . Clients [ u ]
cc . Online = false
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "@%s is now offline." , uStr ) )
}
2021-11-06 16:33:16 +01:00
func botDelete ( m * tb . Message ) {
2021-11-28 14:41:00 +01:00
r := regexp . MustCompile ( "\\/delete (?P<CompanyID>[0-9]+)" )
2021-11-13 03:40:43 +01:00
id := uint8 ( 255 )
if r . MatchString ( m . Text ) {
2021-11-06 16:33:16 +01:00
ID64 , _ := strconv . ParseInt ( r . ReplaceAllString ( m . Text , "${CompanyID}" ) , 10 , 64 )
2021-11-13 03:40:43 +01:00
if m . Sender . ID == int ( bot . Config . AdminID ) {
id = uint8 ( ID64 )
} else if cc , ok := cfg . Clients [ m . Sender . ID ] ; ok && cc . CompanyID == uint8 ( ID64 ) {
id = cc . CompanyID
2021-11-12 02:17:25 +01:00
} else {
2021-11-13 03:40:43 +01:00
bot . SendChat ( m . Chat . ID , "Not authorized to delete" )
return
2021-11-12 02:17:25 +01:00
}
2021-11-13 03:40:43 +01:00
} else if cc , ok := cfg . Clients [ m . Sender . ID ] ; ok {
id = cc . CompanyID
2020-06-22 11:13:07 +02:00
} else {
2021-11-13 03:40:43 +01:00
bot . SendChat ( m . Chat . ID , "User not registered" )
return
}
if id == 255 {
bot . SendChat ( m . Chat . ID , "No company registered" )
return
}
if co , ok := srv . Status . Companies [ id ] ; ok {
b := make ( [ ] byte , 8 )
_ , err := rand . Read ( b )
logErrorDebug ( err , "botDelete : rand.Read" )
if err != nil {
bot . SendChat ( m . Chat . ID , "internal error" )
return
}
c := hex . EncodeToString ( b )
2021-12-04 05:49:20 +01:00
d := & BotActionEntry {
Action : "DeleteCompany" ,
2021-11-13 03:40:43 +01:00
CompanyID : id ,
UserID : m . Sender . ID ,
Time : time . Now ( ) ,
}
2021-12-04 05:49:20 +01:00
botActionMap [ c ] = d
2021-11-13 03:40:43 +01:00
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Press /delete_%s to delete '%s'" , c , co . Name ) )
} else {
bot . SendChat ( m . Chat . ID , "Company doesn't exist" )
2021-11-06 16:33:16 +01:00
}
return
}
2021-12-04 06:24:45 +01:00
func botActuallyDelete ( m * tb . Message ) {
r := regexp . MustCompile ( "^\\/delete_(?P<Ref>[a-f0-9]{16})$" )
ref := r . ReplaceAllString ( m . Text , "${Ref}" )
a , ok := botActionMap [ ref ]
if ! ok {
bot . SendChat ( m . Chat . ID , "No corresponding request." )
return
}
if a . Action != "DeleteCompany" {
bot . SendChat ( m . Chat . ID , "Not a delete request." )
return
}
if a . UserID != m . Sender . ID {
bot . SendChat ( m . Chat . ID , "Requesting user has to confirm himself." )
return
}
if time . Now ( ) . Sub ( a . Time ) > time . Minute {
bot . SendChat ( m . Chat . ID , "Request expired." )
} else {
srv . DeleteCompany ( a . CompanyID )
bot . SendChat ( m . Chat . ID , "Company deleted." )
}
delete ( botActionMap , ref )
return
}
2021-11-06 16:33:16 +01:00
func botCompanies ( m * tb . Message ) {
str := "Companies :"
for k , v := range srv . Status . Companies {
2021-11-10 07:55:31 +01:00
str = str + "\r\n" + fmt . Sprintf ( " - %s (%d - %t)" , v . Name , k , v . Protected )
2021-11-06 16:33:16 +01:00
}
bot . SendChat ( m . Chat . ID , str )
}
func botClients ( m * tb . Message ) {
str := "Clients :"
for k , v := range srv . Status . Clients {
str = str + "\r\n" + fmt . Sprintf ( " - %s (%d) : company #%d" , v . Name , k , v . CompanyID )
}
bot . SendChat ( m . Chat . ID , str )
}
2021-12-04 05:49:20 +01:00
func botReset ( m * tb . Message ) {
if m . Sender . ID != int ( cfg . Telegram . AdminID ) {
bot . SendChat ( m . Chat . ID , "Only the admin can use this command." )
return
}
2021-12-04 06:24:45 +01:00
if ! cfg . Game . Started {
bot . SendChat ( m . Chat . ID , "Game is not started." )
return
}
2021-12-04 05:49:20 +01:00
b := make ( [ ] byte , 8 )
_ , err := rand . Read ( b )
logErrorDebug ( err , "botReset : rand.Read" )
if err != nil {
bot . SendChat ( m . Chat . ID , "internal error" )
return
}
c := hex . EncodeToString ( b )
d := & BotActionEntry {
Action : "ResetGame" ,
CompanyID : 0 ,
UserID : m . Sender . ID ,
Time : time . Now ( ) ,
}
botActionMap [ c ] = d
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Press /reset_%s to reset the game" , c ) )
return
}
2021-12-04 06:24:45 +01:00
func botActuallyReset ( m * tb . Message ) {
r := regexp . MustCompile ( "^\\/reset_(?P<Ref>[a-f0-9]{16})$" )
ref := r . ReplaceAllString ( m . Text , "${Ref}" )
a , ok := botActionMap [ ref ]
if ! ok {
bot . SendChat ( m . Chat . ID , "No corresponding request." )
return
}
if a . Action != "ResetGame" {
bot . SendChat ( m . Chat . ID , "Not a reset request." )
return
}
if a . UserID != m . Sender . ID {
bot . SendChat ( m . Chat . ID , "Requesting user has to confirm himself." )
return
}
if time . Now ( ) . Sub ( a . Time ) > time . Minute {
bot . SendChat ( m . Chat . ID , "Request expired." )
} else {
2021-12-05 08:41:47 +01:00
cfg . Save ( "backup." + * configFlag )
2021-12-04 06:24:45 +01:00
cfg . Game . Started = false
2021-12-10 14:22:10 +01:00
cfg . StatsMonthly = make ( map [ int ] map [ string ] * StatMonthly )
cfg . StatsDaily = make ( map [ int ] map [ string ] * StatDaily )
2021-12-04 06:39:15 +01:00
for _ , cc := range cfg . Clients {
cc . Ready = false
cc . CompanyID = 255
cc . Online = false
cc . TimeLeft = 0
}
2021-12-04 06:24:45 +01:00
bot . SendChat ( m . Chat . ID , "Game resetted." )
}
delete ( botActionMap , ref )
return
}
2021-12-04 05:49:20 +01:00
func botStart ( m * tb . Message ) {
2021-12-04 06:24:45 +01:00
if cfg . Game . Started {
bot . SendChat ( m . Chat . ID , "Game already started." )
2021-12-04 05:49:20 +01:00
return
}
2021-12-04 06:24:45 +01:00
actuallyReady := true
for _ , cc := range cfg . Clients {
if ! cc . Ready {
actuallyReady = false
}
}
if m . Sender . ID != int ( cfg . Telegram . AdminID ) && ! actuallyReady {
2021-12-29 02:24:05 +01:00
bot . SendChat ( m . Chat . ID , "Not all players are ready (see /players). Only the admin can force the start." )
2021-12-29 02:21:24 +01:00
return
2021-12-04 06:24:45 +01:00
}
2021-12-04 05:49:20 +01:00
b := make ( [ ] byte , 8 )
_ , err := rand . Read ( b )
logErrorDebug ( err , "botStart : rand.Read" )
if err != nil {
bot . SendChat ( m . Chat . ID , "internal error" )
return
}
c := hex . EncodeToString ( b )
d := & BotActionEntry {
Action : "StartGame" ,
CompanyID : 0 ,
UserID : m . Sender . ID ,
Time : time . Now ( ) ,
}
botActionMap [ c ] = d
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Press /start_%s to actually start game" , c ) )
return
}
2021-12-04 06:24:45 +01:00
func botActuallyStart ( m * tb . Message ) {
r := regexp . MustCompile ( "^\\/start_(?P<Ref>[a-f0-9]{16})$" )
ref := r . ReplaceAllString ( m . Text , "${Ref}" )
a , ok := botActionMap [ ref ]
if ! ok {
bot . SendChat ( m . Chat . ID , "No corresponding request." )
return
}
if a . Action != "StartGame" {
bot . SendChat ( m . Chat . ID , "Not a game start request." )
return
}
if a . UserID != m . Sender . ID {
bot . SendChat ( m . Chat . ID , "Requesting user has to confirm himself." )
return
}
if time . Now ( ) . Sub ( a . Time ) > time . Minute {
bot . SendChat ( m . Chat . ID , "Request expired." )
} else {
cfg . Game . Started = true
cfg . Game . StartDate = time . Now ( )
for _ , cc := range cfg . Clients {
cc . Ready = true
2021-12-04 06:39:15 +01:00
cc . TimeLeft = cfg . Game . StartingAllotment
2021-12-04 06:24:45 +01:00
}
bot . SendChat ( m . Chat . ID , "Game started !" )
}
delete ( botActionMap , ref )
return
}
2021-12-04 05:49:20 +01:00
func botReady ( m * tb . Message ) {
2021-12-04 06:24:45 +01:00
if cfg . Game . Started {
bot . SendChat ( m . Chat . ID , "Game is already started." )
return
}
2021-12-04 05:49:20 +01:00
cc , ok := cfg . Clients [ m . Sender . ID ]
if ! ok {
bot . SendChat ( m . Chat . ID , "Player not registered" )
return
}
ready := 0
waiting := 0
for _ , cc2 := range cfg . Clients {
if cc2 . Ready {
ready ++
} else {
waiting ++
}
}
if cc . Ready {
cc . Ready = false
2021-12-04 06:24:45 +01:00
ready --
waiting ++
2021-12-04 05:49:20 +01:00
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Player not ready anymore. Only %d players ready now." , ready ) )
} else {
cc . Ready = true
2021-12-04 06:24:45 +01:00
ready ++
waiting --
2021-12-04 05:49:20 +01:00
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Player is now ready. Still waiting for %d players." , waiting ) )
}
return
}
2021-11-06 16:33:16 +01:00
func botPlayers ( m * tb . Message ) {
2021-12-04 05:49:20 +01:00
if cfg . Game . Started {
botPlayersStarted ( m )
} else {
botPlayersWaiting ( m )
}
return
}
2021-12-28 16:02:18 +01:00
func botRemove ( m * tb . Message ) {
if m . Sender . ID != int ( cfg . Telegram . AdminID ) {
bot . SendChat ( m . Chat . ID , "Only the admin can use this command." )
return
}
r := regexp . MustCompile ( "^\\/remove (?P<Username>[a-zA-Z0-9]+)" )
for _ , cc := range cfg . Clients {
if cc . Username == r . ReplaceAllString ( m . Text , "${Username}" ) {
delete ( cfg . Clients , cc . UserID )
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "%s deleted." , cc . Username ) )
return
}
}
bot . SendChat ( m . Chat . ID , "No such player." )
return
}
2021-12-04 05:49:20 +01:00
func botPlayersStarted ( m * tb . Message ) {
2021-11-08 15:24:34 +01:00
d1 := time . Now ( ) . Sub ( cfg . Game . StartDate )
days := int ( time . Duration ( d1 . Hours ( ) ) / 24 )
d2 := time . Duration ( days + 1 ) * ( time . Hour ) * 24 - d1
2021-11-28 14:25:35 +01:00
str := fmt . Sprintf ( "Update in %s\r\n" , d2 . Round ( time . Second ) )
2021-11-08 14:51:21 +01:00
2021-11-06 16:33:16 +01:00
online := ""
for _ , cc := range cfg . Clients {
if cc . Online {
2021-11-26 01:29:09 +01:00
if co , ok := srv . Status . Companies [ cc . CompanyID ] ; ok {
2021-11-28 14:25:35 +01:00
online = online + fmt . Sprintf ( " - %s (%s) : %s" , cc . Username , cc . TimeLeft . Round ( time . Second ) , co . Name ) + "\r\n"
2021-11-26 01:29:09 +01:00
} else {
2021-11-28 14:25:35 +01:00
online = online + fmt . Sprintf ( " - %s (%s) : none" , cc . Username , cc . TimeLeft . Round ( time . Second ) ) + "\r\n"
2021-11-26 01:29:09 +01:00
}
2021-11-06 16:33:16 +01:00
}
}
offline := ""
for _ , cc := range cfg . Clients {
2021-11-26 01:29:09 +01:00
if co , ok := srv . Status . Companies [ cc . CompanyID ] ; ok && ! cc . Online {
2021-11-28 14:25:35 +01:00
offline = offline + fmt . Sprintf ( " - %s (%s) : %s" , cc . Username , cc . TimeLeft . Round ( time . Second ) , co . Name ) + "\r\n"
2021-11-26 01:29:09 +01:00
} else {
2021-11-28 14:25:35 +01:00
offline = offline + fmt . Sprintf ( " - %s (%s) : none" , cc . Username , cc . TimeLeft . Round ( time . Second ) ) + "\r\n"
2021-11-06 16:33:16 +01:00
}
}
2021-11-08 14:51:21 +01:00
2021-11-06 16:33:16 +01:00
if len ( online ) > 0 {
str = str + "Players online :\r\n" + online
}
if len ( offline ) > 0 {
str = str + "Players offline :\r\n" + offline
}
2021-11-08 14:51:21 +01:00
2021-11-06 16:33:16 +01:00
bot . SendChat ( m . Chat . ID , str )
}
2021-12-04 05:49:20 +01:00
func botPlayersWaiting ( m * tb . Message ) {
msg := "Player status :\r\n"
ready := ""
waiting := ""
for _ , cc := range cfg . Clients {
if cc . Ready {
ready = ready + fmt . Sprintf ( " - %s" , cc . Username ) + "\r\n"
} else {
waiting = waiting + fmt . Sprintf ( " - %s" , cc . Username ) + "\r\n"
}
}
if len ( ready ) > 0 {
msg = msg + "Players ready :\r\n" + ready
}
if len ( waiting ) > 0 {
msg = msg + "Waiting for :\r\n" + waiting
}
bot . SendChat ( m . Chat . ID , msg )
}
2021-11-09 10:45:01 +01:00
func botGive ( m * tb . Message ) {
2021-11-13 03:40:43 +01:00
if m . Sender . ID != int ( cfg . Telegram . AdminID ) {
bot . SendChat ( m . Chat . ID , "Only the admin can use this command." )
return
}
2021-11-28 14:41:00 +01:00
r := regexp . MustCompile ( "^\\/give @(?P<Username>[a-zA-Z0-9]+) (?P<Duration>[a-z0-9]+)" )
2021-11-13 03:40:43 +01:00
if ! r . MatchString ( m . Text ) {
bot . SendChat ( m . Chat . ID , "Wrong format." )
return
}
uStr := r . ReplaceAllString ( m . Text , "${Username}" )
var u int
for ccID , cc := range cfg . Clients {
if cc . Username == uStr {
u = ccID
}
}
if u == 0 {
bot . SendChat ( m . Chat . ID , "No such user found." )
return
}
dStr := r . ReplaceAllString ( m . Text , "${Duration}" )
d , err := time . ParseDuration ( dStr )
logErrorDebug ( err , "botGive : time.ParseDuration" )
if err != nil {
bot . SendChat ( m . Chat . ID , "Cannot parse duration." )
}
cc := cfg . Clients [ u ]
cc . TimeLeft += d
2021-11-28 14:25:35 +01:00
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "@%s now has %s left." , uStr , cc . TimeLeft . Round ( time . Second ) ) )
2021-11-09 10:45:01 +01:00
}
2021-11-28 14:41:00 +01:00
func botVersion ( m * tb . Message ) {
bot . SendChat ( m . Chat . ID , version )
return
}
2021-12-05 08:41:47 +01:00
func botSave ( m * tb . Message ) {
if m . Sender . ID != int ( cfg . Telegram . AdminID ) {
bot . SendChat ( m . Chat . ID , "Only the admin can use this command." )
return
}
2021-12-05 09:20:12 +01:00
r := regexp . MustCompile ( "^\\/save (?P<Filename>[a-zA-Z0-9._\\/]+)" )
2021-12-05 08:41:47 +01:00
if ! r . MatchString ( m . Text ) {
bot . SendChat ( m . Chat . ID , "Wrong usage." )
return
}
filename := r . ReplaceAllString ( m . Text , "${Filename}" )
err := cfg . Save ( filename + ".json" )
logErrorDebug ( err , "botSave : Config.Save(%s)" , filename + ".json" )
if err != nil {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Error : %s" , err ) )
} else {
bot . SendChat ( m . Chat . ID , "Saved." )
}
return
}
2021-11-28 11:31:49 +01:00
func botTransfer ( m * tb . Message ) {
2021-11-28 14:41:00 +01:00
r := regexp . MustCompile ( "^\\/transfer @(?P<Username>[a-zA-Z0-9]+) (?P<Duration>[a-z0-9]+)" )
if ! r . MatchString ( m . Text ) {
bot . SendChat ( m . Chat . ID , "Wrong usage." )
return
}
2021-11-28 11:31:49 +01:00
ccFrom , ok := cfg . Clients [ m . Sender . ID ]
if ! ok {
bot . SendChat ( m . Chat . ID , "Client not registered." )
return
}
dStr := r . ReplaceAllString ( m . Text , "${Duration}" )
d , err := time . ParseDuration ( dStr )
logErrorDebug ( err , "botTransfer : time.ParseDuration" )
if err != nil {
bot . SendChat ( m . Chat . ID , "Cannot parse duration." )
return
}
if ccFrom . TimeLeft < d {
bot . SendChat ( m . Chat . ID , "Not enough time left for user." )
return
}
uStr := r . ReplaceAllString ( m . Text , "${Username}" )
var toID int
for ccID , cc := range cfg . Clients {
if cc . Username == uStr {
toID = ccID
}
}
if toID == 0 {
bot . SendChat ( m . Chat . ID , "No such user found." )
return
}
ccTo := cfg . Clients [ toID ]
ccTo . TimeLeft += d
ccFrom . TimeLeft -= d
2021-11-28 14:25:35 +01:00
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "@%s now has %s left.\r\n@%s has %s left." , uStr , ccTo . TimeLeft . Round ( time . Second ) , ccFrom . Username , ccFrom . TimeLeft . Round ( time . Second ) ) )
2021-11-28 11:31:49 +01:00
}
2021-11-09 10:45:01 +01:00
func botTake ( m * tb . Message ) {
2021-11-13 03:40:43 +01:00
if m . Sender . ID != int ( cfg . Telegram . AdminID ) {
bot . SendChat ( m . Chat . ID , "Only the admin can use this command." )
return
}
2021-11-28 14:41:00 +01:00
r := regexp . MustCompile ( "^\\/take @(?P<Username>[a-zA-Z0-9]+) (?P<Duration>[a-z0-9]+)" )
2021-11-13 03:40:43 +01:00
if ! r . MatchString ( m . Text ) {
bot . SendChat ( m . Chat . ID , "Wrong format." )
return
}
uStr := r . ReplaceAllString ( m . Text , "${Username}" )
var u int
for ccID , cc := range cfg . Clients {
if cc . Username == uStr {
u = ccID
}
}
if u == 0 {
bot . SendChat ( m . Chat . ID , "No such user found." )
return
}
dStr := r . ReplaceAllString ( m . Text , "${Duration}" )
d , err := time . ParseDuration ( dStr )
logErrorDebug ( err , "botGive : time.ParseDuration" )
if err != nil {
bot . SendChat ( m . Chat . ID , "Cannot parse duration." )
2021-11-28 11:31:49 +01:00
return
2021-11-13 03:40:43 +01:00
}
cc := cfg . Clients [ u ]
cc . TimeLeft -= d
2021-11-28 14:25:35 +01:00
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "@%s now has %s left." , uStr , cc . TimeLeft . Round ( time . Second ) ) )
2021-11-09 10:45:01 +01:00
}
2021-11-13 06:44:57 +01:00
func botSay ( m * tb . Message ) {
r := regexp . MustCompile ( "^\\/say( )+(?P<Message>.+)$" )
if ! r . MatchString ( m . Text ) {
bot . SendChat ( m . Chat . ID , "No message provided" )
return
}
msg := r . ReplaceAllString ( m . Text , "${Message}" )
2021-11-13 07:23:40 +01:00
px := PacketAdminRCon {
Packet : Packet { PType : AdminPacketAdminRCon } ,
2021-11-13 07:38:39 +01:00
Command : fmt . Sprintf ( "say \"@%s says : %s\"" , m . Sender . Username , msg ) ,
2021-11-13 06:44:57 +01:00
}
srv . Send ( px . Bytes ( ) )
return
}
2021-11-10 05:56:53 +01:00
func botPasswd ( m * tb . Message ) {
cc , ok := cfg . Clients [ m . Sender . ID ]
if ! ok {
bot . SendChat ( m . Chat . ID , "User not registered." )
return
}
2021-11-10 06:41:37 +01:00
if cc . CompanyID == 255 {
bot . SendChat ( m . Chat . ID , "No company registered." )
return
}
co , ok := srv . Status . Companies [ cc . CompanyID ]
if ! ok {
bot . SendChat ( m . Chat . ID , "Registered company doesn't exist." )
cc . CompanyID = 255
return
}
2021-11-10 06:02:52 +01:00
r := regexp . MustCompile ( "^\\/passwd( )+(?P<Passwd>[^ ]+)$" )
2021-11-10 06:41:37 +01:00
if ! r . MatchString ( m . Text ) {
2021-11-10 05:56:53 +01:00
bot . SendChat ( m . Chat . ID , "No passwd provided" )
2021-11-10 06:41:37 +01:00
return
2021-11-10 05:56:53 +01:00
}
2021-11-10 06:41:37 +01:00
// we have a parameter
cc . Passwd = r . ReplaceAllString ( m . Text , "${Passwd}" )
err := bot . bot . Delete ( m )
logErrorDebug ( err , "botPasswd : Delete" )
2021-11-10 07:43:55 +01:00
srv . SetPasswd ( co . CompanyExtlID , cc . Passwd )
2021-11-10 06:41:37 +01:00
bot . SendUser ( int64 ( m . Sender . ID ) , fmt . Sprintf ( "Passwd set to \"%s\"" , cc . Passwd ) )
2021-11-10 05:56:53 +01:00
return
}
2021-11-09 06:24:42 +01:00
func botDeregister ( m * tb . Message ) {
2021-11-28 14:41:00 +01:00
r := regexp . MustCompile ( "^\\/deregister @(?P<Username>[a-zA-Z0-9]+)$" )
if r . MatchString ( m . Text ) {
if m . Sender . ID != int ( cfg . Telegram . AdminID ) {
bot . SendChat ( m . Chat . ID , "Not admin." )
return
}
uStr := r . ReplaceAllString ( m . Text , "${Username}" )
var uID int
for ccID , cc := range cfg . Clients {
if cc . Username == uStr {
uID = ccID
}
}
if uID == 0 {
bot . SendChat ( m . Chat . ID , "No such user found." )
return
}
cc := cfg . Clients [ uID ]
if cc . CompanyID != 255 {
for coID , co := range srv . Status . Companies {
if coID == cc . CompanyID {
cc . CompanyID = 255
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Deregistered from %s. %s playable left." , co . Name , cc . TimeLeft . Round ( time . Second ) ) )
return
}
}
logInfoAlert ( "botRegister : %s : no such CompanyID : %d" , cc . Username , cc . CompanyID )
cc . CompanyID = 255
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Registered company didn't exist anymore. %s playable left." , cc . TimeLeft . Round ( time . Second ) ) )
return
}
return
}
2021-11-09 06:24:42 +01:00
cc , ok := cfg . Clients [ m . Sender . ID ]
if ! ok {
cc = & ClientConfig {
UserID : m . Sender . ID ,
Username : m . Sender . Username ,
CompanyID : 255 ,
TimeLeft : 0 ,
}
cfg . Clients [ m . Sender . ID ] = cc
bot . SendChat ( m . Chat . ID , "User isn't registered." )
return
}
if cc . CompanyID != 255 {
for coID , co := range srv . Status . Companies {
if coID == cc . CompanyID {
cc . CompanyID = 255
2021-11-28 14:25:35 +01:00
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Deregistered from %s. %s playable left." , co . Name , cc . TimeLeft . Round ( time . Second ) ) )
2021-11-09 06:24:42 +01:00
return
}
}
logInfoAlert ( "botRegister : %s : no such CompanyID : %d" , cc . Username , cc . CompanyID )
cc . CompanyID = 255
2021-11-28 14:25:35 +01:00
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Registered company didn't exist anymore. %s playable left." , cc . TimeLeft . Round ( time . Second ) ) )
2021-11-09 06:24:42 +01:00
return
}
return
}
2021-11-06 16:33:16 +01:00
func botRegister ( m * tb . Message ) {
cc , ok := cfg . Clients [ m . Sender . ID ]
if ! ok {
cc = & ClientConfig {
UserID : m . Sender . ID ,
Username : m . Sender . Username ,
CompanyID : 255 ,
2021-11-09 06:24:42 +01:00
TimeLeft : 0 ,
2021-12-04 06:39:15 +01:00
Ready : cfg . Game . Started ,
2021-11-06 16:33:16 +01:00
}
cfg . Clients [ m . Sender . ID ] = cc
2021-11-09 06:24:42 +01:00
} else {
if cc . CompanyID != 255 {
for coID , co := range srv . Status . Companies {
if coID == cc . CompanyID {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Already registered %s. Please /deregister first." , co . Name ) )
return
}
}
logInfoAlert ( "botRegister : %s : no such CompanyID : %d" , cc . Username , cc . CompanyID )
cc . CompanyID = 255
}
2021-11-06 16:33:16 +01:00
}
2021-11-09 06:24:42 +01:00
2021-11-06 16:33:16 +01:00
coList := make ( map [ uint8 ] struct { } )
for coID , _ := range srv . Status . Companies {
coList [ coID ] = struct { } { }
2020-06-22 11:09:11 +02:00
}
2021-11-06 16:33:16 +01:00
for _ , c := range cfg . Clients {
if c . CompanyID != 255 {
if _ , ok := coList [ c . CompanyID ] ; ! ok {
logInfoAlert ( "botRegister : %s : no such CompanyID : %d" , c . Username , c . CompanyID )
c . CompanyID = 255
} else {
delete ( coList , c . CompanyID )
}
}
}
2021-11-09 06:24:42 +01:00
2021-11-06 16:33:16 +01:00
if len ( coList ) == 0 {
bot . SendChat ( m . Chat . ID , "No company to register" )
return
}
2021-11-09 06:24:42 +01:00
r := regexp . MustCompile ( "^\\/register( )+(?P<Company>[a-zA-Z\\.\\-0-9 ]+)$" )
if r . MatchString ( m . Text ) {
// we have a parameter
coName := r . ReplaceAllString ( m . Text , "${Company}" )
for coID , co := range srv . Status . Companies {
if co . Name == coName {
for _ , c := range cfg . Clients {
if c . CompanyID == coID {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Company %s is already registered to @%s" , coName , c . Username ) )
return
}
}
cc . CompanyID = coID
if cc . TimeLeft == 0 {
days := int ( time . Now ( ) . Sub ( cfg . Game . StartDate ) . Hours ( ) / 24 )
cc . TimeLeft = cfg . Game . StartingAllotment + cfg . Game . DailyAllotment * time . Duration ( days )
}
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "@%s registered %s (with %s playable)" , cc . Username , srv . Status . Companies [ cc . CompanyID ] . Name , cc . TimeLeft ) )
return
}
}
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Can't find company %s" , coName ) )
return
}
2021-11-06 16:33:16 +01:00
if len ( coList ) == 1 {
for id , _ := range coList {
cc . CompanyID = id
2021-12-04 06:39:15 +01:00
if cc . TimeLeft == 0 && cfg . Game . Started {
2021-11-09 06:24:42 +01:00
days := int ( time . Now ( ) . Sub ( cfg . Game . StartDate ) . Hours ( ) / 24 )
cc . TimeLeft = cfg . Game . StartingAllotment + cfg . Game . DailyAllotment * time . Duration ( days )
2021-12-04 06:39:15 +01:00
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "@%s registered %s (with %s playable)" , cc . Username , srv . Status . Companies [ cc . CompanyID ] . Name , cc . TimeLeft . Round ( time . Second ) ) )
} else {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "@%s registered %s" , cc . Username , srv . Status . Companies [ cc . CompanyID ] . Name ) )
2021-11-09 06:24:42 +01:00
}
2021-11-06 16:33:16 +01:00
return
}
}
bot . SendChat ( m . Chat . ID , "More than one company unregistered. Wait for bot update (poke @tiennou)" )
2020-06-22 11:02:04 +02:00
return
}
2020-06-21 19:51:33 +02:00
func PrintText ( m * tb . Message ) {
logInfoDebug ( "[%d] %s(%d) | %s(%d) : %s\n" , m . ID , m . Chat . Title , m . Chat . ID , m . Sender . Username , m . Sender . ID , m . Text )
return
}
func botPhoto ( m * tb . Message ) {
logInfoDebug ( "botPhoto :" , m . Text )
// photos only
}
func botDocument ( m * tb . Message ) {
logInfoDebug ( "botDocument : %s (%d bytes)\n" , m . Document . FileName , m . Document . File . FileSize )
// documents only
}
func botChannelPost ( m * tb . Message ) {
PrintText ( m )
b , _ := json . Marshal ( m )
2020-06-21 19:54:07 +02:00
logInfoDebug ( "botChannelPost : %s\n" , string ( b ) )
2020-06-21 19:51:33 +02:00
// channel posts only
}
func botQuery ( q * tb . Query ) {
logInfoDebug ( "botQuery" )
// incoming inline queries
}
func botText ( m * tb . Message ) {
2021-12-04 05:49:20 +01:00
2021-11-28 14:41:00 +01:00
r := regexp . MustCompile ( "^\\/delete_(?P<Ref>[a-f0-9]{16})$" )
2021-11-13 03:40:43 +01:00
if r . MatchString ( m . Text ) {
2021-12-04 06:24:45 +01:00
botActuallyDelete ( m )
2021-12-04 05:49:20 +01:00
return
}
r = regexp . MustCompile ( "^\\/reset_(?P<Ref>[a-f0-9]{16})$" )
if r . MatchString ( m . Text ) {
2021-12-04 06:24:45 +01:00
botActuallyReset ( m )
2021-12-04 05:49:20 +01:00
return
}
r = regexp . MustCompile ( "^\\/start_(?P<Ref>[a-f0-9]{16})$" )
if r . MatchString ( m . Text ) {
2021-12-04 06:24:45 +01:00
botActuallyStart ( m )
2021-11-13 03:40:43 +01:00
return
}
2021-12-04 05:49:20 +01:00
2020-06-21 19:51:33 +02:00
PrintText ( m )
}