2021-05-14 11:15:38 +00:00
package twitch
2021-05-02 12:29:43 +00:00
import (
"fmt"
2021-05-12 17:19:09 +00:00
"strconv"
2021-05-02 12:29:43 +00:00
"strings"
2021-05-02 17:39:46 +00:00
"time"
2021-05-02 12:29:43 +00:00
irc "github.com/gempir/go-twitch-irc/v2"
2021-05-02 17:39:46 +00:00
"github.com/strimertul/strimertul/modules/loyalty"
2021-05-02 12:29:43 +00:00
)
type AccessLevelType string
const (
ALTEveryone AccessLevelType = "everyone"
ALTVIP AccessLevelType = "vip"
ALTModerators AccessLevelType = "moderators"
ALTStreamer AccessLevelType = "streamer"
)
2021-05-14 11:15:38 +00:00
type BotCommandHandler func ( bot * Bot , message irc . PrivateMessage )
2021-05-02 12:29:43 +00:00
type BotCommand struct {
Description string
Usage string
AccessLevel AccessLevelType
Handler BotCommandHandler
}
var commands = map [ string ] BotCommand {
"!redeem" : {
Description : "Redeem a reward with loyalty points" ,
2021-05-18 13:29:21 +00:00
Usage : "!redeem <reward-id> [request text]" ,
2021-05-02 12:29:43 +00:00
AccessLevel : ALTEveryone ,
2021-05-12 17:19:09 +00:00
Handler : cmdRedeemReward ,
2021-05-02 12:29:43 +00:00
} ,
2021-05-03 08:35:11 +00:00
"!balance" : {
Description : "See your current point balance" ,
Usage : "!balance" ,
AccessLevel : ALTEveryone ,
Handler : cmdBalance ,
} ,
2021-05-12 17:19:09 +00:00
"!goals" : {
Description : "Check currently active community goals" ,
Usage : "!goals" ,
AccessLevel : ALTEveryone ,
Handler : cmdGoalList ,
} ,
"!contribute" : {
Description : "Contribute points to a community goal" ,
Usage : "!contribute <points> [<goal-id>]" ,
AccessLevel : ALTEveryone ,
Handler : cmdContributeGoal ,
} ,
2021-05-03 08:35:11 +00:00
}
2021-05-14 11:15:38 +00:00
func cmdBalance ( bot * Bot , message irc . PrivateMessage ) {
2021-05-03 08:35:11 +00:00
// Get user balance
2021-05-12 17:19:09 +00:00
balance := bot . Loyalty . GetPoints ( message . User . Name )
2021-05-12 23:46:03 +00:00
bot . Client . Say ( message . Channel , fmt . Sprintf ( "%s: You have %d %s!" , message . User . DisplayName , balance , bot . Loyalty . Config ( ) . Currency ) )
2021-05-02 12:29:43 +00:00
}
2021-05-14 11:15:38 +00:00
func cmdRedeemReward ( bot * Bot , message irc . PrivateMessage ) {
2021-05-02 12:29:43 +00:00
parts := strings . Fields ( message . Message )
if len ( parts ) < 2 {
return
}
redeemID := parts [ 1 ]
// Find reward
2021-05-12 23:46:03 +00:00
for _ , reward := range bot . Loyalty . Rewards ( ) {
2021-05-02 12:29:43 +00:00
if reward . ID != redeemID {
continue
}
2021-05-10 21:08:44 +00:00
// Reward not active, return early
if ! reward . Enabled {
return
}
2021-05-02 12:29:43 +00:00
// Get user balance
2021-05-12 17:19:09 +00:00
balance := bot . Loyalty . GetPoints ( message . User . Name )
2021-05-12 23:46:03 +00:00
config := bot . Loyalty . Config ( )
2021-05-02 12:29:43 +00:00
// Check if user can afford the reward
if balance - reward . Price < 0 {
2021-05-12 23:46:03 +00:00
bot . Client . Say ( message . Channel , fmt . Sprintf ( "I'm sorry %s but you cannot afford this (have %d %s, need %d)" , message . User . DisplayName , balance , config . Currency , reward . Price ) )
2021-05-02 12:29:43 +00:00
return
}
2021-05-18 13:29:21 +00:00
text := ""
if len ( parts ) > 2 {
text = strings . Join ( parts [ 2 : ] , " " )
}
2021-05-02 12:29:43 +00:00
// Perform redeem
2021-05-18 11:30:27 +00:00
if err := bot . Loyalty . PerformRedeem ( loyalty . Redeem {
2021-05-02 17:39:46 +00:00
Username : message . User . Name ,
DisplayName : message . User . DisplayName ,
When : time . Now ( ) ,
Reward : reward ,
2021-05-18 13:29:21 +00:00
RequestText : text ,
2021-05-02 17:39:46 +00:00
} ) ; err != nil {
2021-05-18 11:30:27 +00:00
bot . logger . WithError ( err ) . Error ( "error while performing redeem" )
2021-05-12 17:19:09 +00:00
return
}
2021-05-12 23:46:03 +00:00
bot . Client . Say ( message . Channel , fmt . Sprintf ( "HolidayPresent %s has redeemed %s! (new balance: %d %s)" , message . User . DisplayName , reward . Name , bot . Loyalty . GetPoints ( message . User . Name ) , config . Currency ) )
2021-05-12 17:19:09 +00:00
return
}
}
2021-05-14 11:15:38 +00:00
func cmdGoalList ( bot * Bot , message irc . PrivateMessage ) {
2021-05-12 23:46:03 +00:00
goals := bot . Loyalty . Goals ( )
if len ( goals ) < 1 {
2021-05-12 17:19:09 +00:00
bot . Client . Say ( message . Channel , fmt . Sprintf ( "%s: There are no active community goals right now :(!" , message . User . DisplayName ) )
return
}
msg := "Current goals: "
2021-05-12 23:46:03 +00:00
for _ , goal := range goals {
2021-05-12 17:19:09 +00:00
if ! goal . Enabled {
continue
}
2021-05-12 23:46:03 +00:00
msg += fmt . Sprintf ( "%s (%d/%d %s) [id: %s] | " , goal . Name , goal . Contributed , goal . TotalGoal , bot . Loyalty . Config ( ) . Currency , goal . ID )
2021-05-12 17:19:09 +00:00
}
msg += " Contribute with <!contribute POINTS GOALID>"
bot . Client . Say ( message . Channel , msg )
}
2021-05-14 11:15:38 +00:00
func cmdContributeGoal ( bot * Bot , message irc . PrivateMessage ) {
2021-05-12 23:46:03 +00:00
goals := bot . Loyalty . Goals ( )
2021-05-12 17:19:09 +00:00
// Set defaults if user doesn't provide them
points := int64 ( 100 )
goalIndex := - 1
hasGoals := false
// Get first unreached goal for default
2021-05-12 23:46:03 +00:00
for index , goal := range goals {
2021-05-12 17:19:09 +00:00
if ! goal . Enabled {
continue
}
hasGoals = true
if goal . Contributed < goal . TotalGoal {
goalIndex = index
break
2021-05-02 12:29:43 +00:00
}
2021-05-12 17:19:09 +00:00
}
2021-05-02 12:29:43 +00:00
2021-05-12 17:19:09 +00:00
// Do we not have any goal we can contribute to? Hooray I guess?
if goalIndex < 0 {
if hasGoals {
bot . Client . Say ( message . Channel , fmt . Sprintf ( "%s: All active community goals have been reached already! ShowOfHands" , message . User . DisplayName ) )
} else {
bot . Client . Say ( message . Channel , fmt . Sprintf ( "%s: There are no active community goals right now :(!" , message . User . DisplayName ) )
}
return
}
// Parse parameters if provided
parts := strings . Fields ( message . Message )
if len ( parts ) > 1 {
newpoints , err := strconv . ParseInt ( parts [ 1 ] , 10 , 64 )
if err == nil {
if newpoints <= 0 {
bot . Client . Say ( message . Channel , fmt . Sprintf ( "Nice try %s SoBayed" , message . User . DisplayName ) )
return
}
points = newpoints
}
if len ( parts ) > 2 {
found := false
goalID := parts [ 2 ]
// Find Goal index
2021-05-12 23:46:03 +00:00
for index , goal := range goals {
2021-05-12 17:19:09 +00:00
if ! goal . Enabled {
continue
}
if goal . ID == goalID {
goalIndex = index
found = true
break
}
}
// Invalid goal ID provided
if ! found {
bot . Client . Say ( message . Channel , fmt . Sprintf ( "%s: I couldn't find that goal ID :(" , message . User . DisplayName ) )
return
}
}
}
// Get user balance
balance := bot . Loyalty . GetPoints ( message . User . Name )
// If user specified more points than they have, pick the maximum possible
if points > balance {
points = balance
}
2021-05-02 12:29:43 +00:00
2021-05-12 17:19:09 +00:00
// Get goal
2021-05-12 23:46:03 +00:00
selectedGoal := goals [ goalIndex ]
2021-05-12 17:19:09 +00:00
// Check if goal was reached already
if selectedGoal . Contributed >= selectedGoal . TotalGoal {
bot . Client . Say ( message . Channel , fmt . Sprintf ( "%s: This goal was already reached! ヾ(•ω•`)o" , message . User . DisplayName ) )
return
}
// If remaining points are lower than what user is contributing, only take what's needed
remaining := selectedGoal . TotalGoal - selectedGoal . Contributed
if points > remaining {
points = remaining
}
// Remove points from user
if err := bot . Loyalty . TakePoints ( map [ string ] int64 { message . User . Name : points } ) ; err != nil {
bot . logger . WithError ( err ) . Error ( "error while taking points for redeem" )
2021-05-02 12:29:43 +00:00
return
}
2021-05-12 17:19:09 +00:00
// Add points to goal
if err := bot . Loyalty . ContributeGoal ( selectedGoal , message . User . Name , points ) ; err != nil {
bot . logger . WithError ( err ) . Error ( "error while contributing to goal" )
return
}
2021-05-12 23:46:03 +00:00
config := bot . Loyalty . Config ( )
2021-05-12 17:19:09 +00:00
newRemaining := selectedGoal . TotalGoal - selectedGoal . Contributed
2021-05-12 23:46:03 +00:00
bot . Client . Say ( message . Channel , fmt . Sprintf ( "ShowOfHands %s contributed %d %s to \"%s\"!! Only %d %s left!" , message . User . DisplayName , points , config . Currency , selectedGoal . Name , newRemaining , config . Currency ) )
2021-05-12 17:19:09 +00:00
// Check if goal was reached!
// TODO Replace this with sub from loyalty system or something?
if newRemaining <= 0 {
bot . Client . Say ( message . Channel , fmt . Sprintf ( "ShowOfHands The community goal \"%s\" was reached! ShowOfHands" , selectedGoal . Name ) )
}
2021-05-02 12:29:43 +00:00
}