diff --git a/commands/commands.go b/commands/commands.go index 639bc28..594a5d3 100644 --- a/commands/commands.go +++ b/commands/commands.go @@ -22,6 +22,7 @@ var commands = []command{ command{"leaderboard", "", handleLeaderboard, 0, true}, command{"level", "", handleLevel, 0, false}, command{"recalclevel", "", handleRecalculateLevel, 0, false}, + command{"roll", "[[[number of dice]d]]", handleRoll, 0, false}, } func Event(dg *discordgo.Session, m *discordgo.MessageCreate) { diff --git a/commands/roll.go b/commands/roll.go new file mode 100644 index 0000000..cbdc533 --- /dev/null +++ b/commands/roll.go @@ -0,0 +1,60 @@ +package commands + +import ( + "strconv" + "strings" + + "github.com/bwmarrin/discordgo" + + "gitea.teamortix.com/chanbakjsd/Milen/util" +) + +func handleRoll(dg *discordgo.Session, m *discordgo.MessageCreate, arguments []string) { + if len(arguments) > 1 { + util.SendFailEmbed(dg, m.ChannelID, "Error", "Expected zero or one argument.") + return + } + var argument string + if len(arguments) == 0 { + argument = "6" + } else { + argument = arguments[0] + } + + split := strings.SplitN(argument, "d", 2) + if len(split) == 1 { + split = []string{"1", split[0]} + } + if split[0] == "" { + split[0] = "1" + } + + numberOfDice, err := strconv.Atoi(split[0]) + if err != nil || numberOfDice < 1 { + util.SendFailEmbed(dg, m.ChannelID, "Error", "Unknown dice format. Expected `[num]d[amount of sides]`.") + return + } + if numberOfDice > 5 { + util.SendFailEmbed(dg, m.ChannelID, "Error", "I only have five dice.") + return + } + numberOfSides, err := strconv.Atoi(split[1]) + if err != nil || numberOfSides < 1 { + util.SendFailEmbed(dg, m.ChannelID, "Error", "Unknown dice format. Expected `[num]d[amount of sides]`.") + return + } + if numberOfSides > 10000 { + util.SendFailEmbed(dg, m.ChannelID, "Error", "The largest dice I have only has 10000 sides.") + return + } + + result := make([]string, 0, numberOfDice) + for i := 0; i < numberOfDice; i++ { + result = append(result, strconv.Itoa(util.Rand.Intn(numberOfSides)+1)) + } + util.SendEmbed(dg, m.ChannelID, &discordgo.MessageEmbed{ + Title: "Roll Results", + Description: "Your roll results are: " + util.FormatCommaSeparatedList(result), + Color: 0x00D000, + }) +} diff --git a/util/format.go b/util/format.go index 023da9a..01f7788 100644 --- a/util/format.go +++ b/util/format.go @@ -23,21 +23,26 @@ func FormatTime(seconds int64) string { seconds %= 60 } listedTime = append(listedTime, FormatPlural(seconds, "second", "seconds")) - switch len(listedTime) { + return FormatCommaSeparatedList(listedTime) +} + +func FormatCommaSeparatedList(list []string) string { + switch len(list) { + case 0: + return "" case 1: - return listedTime[0] + return list[0] case 2: - return listedTime[0] + " and " + listedTime[1] + return list[0] + " and " + list[1] } - time := "" - for i := 0; i < len(listedTime)-2; i++ { - time += listedTime[i] + ", " + result := "" + for i := 0; i < len(list)-2; i++ { + result += list[i] + ", " } - time += listedTime[len(listedTime)-2] + ", and " - time += listedTime[len(listedTime)-1] - return time + result += list[len(list)-2] + ", and " + result += list[len(list)-1] + return result } - func FormatPlural(count int64, singular string, plural string) string { if count == 0 || count == 1 { return strconv.FormatInt(count, 10) + " " + singular diff --git a/util/rand.go b/util/rand.go new file mode 100644 index 0000000..4df0b59 --- /dev/null +++ b/util/rand.go @@ -0,0 +1,30 @@ +package util + +import ( + crand "crypto/rand" + mrand "math/rand" +) + +type src struct{} + +func (s src) Int63() int64 { + result := make([]byte, 8) + _, err := crand.Read(result) + if err != nil { + panic(err) + } + return int64(result[0]&0x7F)<<56 | + int64(result[1])<<48 | + int64(result[2])<<40 | + int64(result[3])<<32 | + int64(result[4])<<24 | + int64(result[5])<<16 | + int64(result[6])<<8 | + int64(result[7])<<0 +} + +func (s src) Seed(seed int64) { + // We don't do seeds here. +} + +var Rand = mrand.New(src{})