git init
This commit is contained in:
commit
4b8ae1f252
105
application/bot.go
Normal file
105
application/bot.go
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var s *discordgo.Session
|
||||||
|
|
||||||
|
var prefix = os.Getenv("COMMAND_PREFIX")
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
token := os.Getenv("DISCORD_TOKEN")
|
||||||
|
var err error
|
||||||
|
s, err = discordgo.New("Bot " + token)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Invalid bot parameters: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
s.AddHandler(func(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||||||
|
data := i.ApplicationCommandData()
|
||||||
|
if h, ok := slashCommandHandlers[data.Name]; ok {
|
||||||
|
h(s, i, parseOptions(data.Options))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
s.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||||
|
if m.Author.ID == s.State.User.ID {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
messageContent := strings.Split(m.Content, " ")
|
||||||
|
if !strings.HasPrefix(messageContent[0], prefix) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
messageContent[0] = messageContent[0][len(prefix):]
|
||||||
|
var response string
|
||||||
|
if fun, ok := dotCommandHandlers[messageContent[0]]; ok {
|
||||||
|
response = fun(messageContent[1:])
|
||||||
|
}
|
||||||
|
_, err := s.ChannelMessageSendComplex(m.ChannelID, &discordgo.MessageSend{
|
||||||
|
Content: response,
|
||||||
|
Reference: m.Reference(),
|
||||||
|
AllowedMentions: &discordgo.MessageAllowedMentions{
|
||||||
|
RepliedUser: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error sending message: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type optionMap = map[string]*discordgo.ApplicationCommandInteractionDataOption
|
||||||
|
|
||||||
|
func parseOptions(options []*discordgo.ApplicationCommandInteractionDataOption) (om optionMap) {
|
||||||
|
om = make(optionMap)
|
||||||
|
for _, opt := range options {
|
||||||
|
om[opt.Name] = opt
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s.AddHandler(func(s *discordgo.Session, i *discordgo.Ready) {
|
||||||
|
log.Printf("Logged in as: %v#%v", s.State.User.Username, s.State.User.Discriminator)
|
||||||
|
})
|
||||||
|
err := s.Open()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Cannot open Discord session: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Adding commands")
|
||||||
|
registeredCommands := make([]*discordgo.ApplicationCommand, len(commands))
|
||||||
|
for i, v := range commands {
|
||||||
|
cmd, err := s.ApplicationCommandCreate(s.State.User.ID, "", v)
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf("Cannot create '%v' command: %v", v.Name, err)
|
||||||
|
}
|
||||||
|
registeredCommands[i] = cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func(s *discordgo.Session) {
|
||||||
|
err := s.Close()
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
}
|
||||||
|
}(s)
|
||||||
|
|
||||||
|
stop := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(stop, os.Interrupt)
|
||||||
|
log.Println("Press Ctrl+C to exit")
|
||||||
|
<-stop
|
||||||
|
|
||||||
|
log.Println("Shutting down...")
|
||||||
|
for _, v := range registeredCommands {
|
||||||
|
err := s.ApplicationCommandDelete(s.State.User.ID, "", v.ID)
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf("Cannot delete '%v' command: %v", v.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
104
application/commands.go
Normal file
104
application/commands.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
"treerazer/dice"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
commands = []*discordgo.ApplicationCommand{
|
||||||
|
{
|
||||||
|
Name: "roll",
|
||||||
|
Description: "Roll dice",
|
||||||
|
Options: []*discordgo.ApplicationCommandOption{
|
||||||
|
{
|
||||||
|
Name: "dice",
|
||||||
|
Description: "Dice to roll",
|
||||||
|
Type: discordgo.ApplicationCommandOptionString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
slashCommandHandlers = map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate, opts optionMap){
|
||||||
|
"roll": func(s *discordgo.Session, i *discordgo.InteractionCreate, opts optionMap) {
|
||||||
|
err := s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||||
|
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||||
|
Data: &discordgo.InteractionResponseData{
|
||||||
|
Content: roll(opts),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error responding to interaction: %s\n", err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
dotCommandHandlers = map[string]func([]string) string{
|
||||||
|
"roll": func(s []string) string {
|
||||||
|
if len(s) == 0 {
|
||||||
|
return "Error rolling dice: no expression provided"
|
||||||
|
}
|
||||||
|
if len(s) > 1 {
|
||||||
|
return "Error rolling dice: dice expression should have no spaces"
|
||||||
|
}
|
||||||
|
opts := optionMap{
|
||||||
|
"dice": &discordgo.ApplicationCommandInteractionDataOption{
|
||||||
|
Type: discordgo.ApplicationCommandOptionString,
|
||||||
|
Value: s[0],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return roll(opts)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func roll(opts optionMap) string {
|
||||||
|
var exp string
|
||||||
|
if v, ok := opts["dice"]; ok {
|
||||||
|
exp = v.StringValue()
|
||||||
|
} else {
|
||||||
|
return "Error rolling dice: no expression provided"
|
||||||
|
}
|
||||||
|
d, err := dice.CreateFromExp(exp)
|
||||||
|
if err != nil {
|
||||||
|
return "Error rolling dice: " + err.Error()
|
||||||
|
}
|
||||||
|
roll, err := d.Roll()
|
||||||
|
if err != nil {
|
||||||
|
ret := fmt.Sprintf("Error rolling dice: %s", err)
|
||||||
|
fmt.Println(ret)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
var ret strings.Builder
|
||||||
|
_, err = fmt.Fprint(&ret, "Rolled dice: `")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("Error rolling dice: %s", err)
|
||||||
|
}
|
||||||
|
total := 0
|
||||||
|
for i, die := range roll {
|
||||||
|
_, err = fmt.Fprintf(&ret, "%v", die.Result)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("Error rolling dice: %s", err)
|
||||||
|
}
|
||||||
|
if i < len(roll)-1 {
|
||||||
|
fmt.Fprint(&ret, ", ")
|
||||||
|
}
|
||||||
|
total += die.Result
|
||||||
|
}
|
||||||
|
_, err = fmt.Fprint(&ret, "`")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("Error rolling dice: %s", err)
|
||||||
|
}
|
||||||
|
_, err = fmt.Fprintf(&ret, "\nTotal: %v", total)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("Error rolling dice: %s", err)
|
||||||
|
}
|
||||||
|
if ret.Len() < 2000 {
|
||||||
|
return ret.String()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Too many dice to display. Omitting.\nTotal: %v", total)
|
||||||
|
}
|
||||||
175
dice/dice.go
Normal file
175
dice/dice.go
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
package dice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math/rand/v2"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DieExp struct {
|
||||||
|
Size int
|
||||||
|
Count int
|
||||||
|
Add int
|
||||||
|
KeepHigh int
|
||||||
|
KeepLow int
|
||||||
|
Explode bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type DieResult struct {
|
||||||
|
Size int
|
||||||
|
Result int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d DieExp) Roll() ([]DieResult, error) {
|
||||||
|
results := make([]DieResult, 0)
|
||||||
|
var err error
|
||||||
|
|
||||||
|
for i := 0; i < d.Count; i++ {
|
||||||
|
results, err = addDice(d, results)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.KeepHigh != 0 {
|
||||||
|
highResults := make([]DieResult, 0)
|
||||||
|
for i := 0; i < d.KeepHigh; i++ {
|
||||||
|
var high int
|
||||||
|
for j, val := range results {
|
||||||
|
if results[high].Result > val.Result {
|
||||||
|
fmt.Printf("Result %v higher than %v\n", results[high].Result, results[j].Result)
|
||||||
|
high = j
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Result %v lower than %v\n", results[high].Result, results[j].Result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
highResults = append(highResults, results[high])
|
||||||
|
results = append(results[:high], results[high+1:]...)
|
||||||
|
}
|
||||||
|
results = highResults
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.KeepLow > len(results) {
|
||||||
|
return results, errors.New("keep low higher than remaining results")
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.KeepLow != 0 {
|
||||||
|
lowResults := make([]DieResult, 0)
|
||||||
|
for i := 0; i < d.KeepLow; i++ {
|
||||||
|
var low int
|
||||||
|
for j, val := range results {
|
||||||
|
if results[low].Result < val.Result {
|
||||||
|
fmt.Printf("Result %v lower than %v\n", results[low].Result, results[j].Result)
|
||||||
|
low = j
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Result %v higher than %v\n", results[low].Result, results[j].Result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lowResults = append(lowResults, results[low])
|
||||||
|
results = append(results[:low], results[low+1:]...)
|
||||||
|
}
|
||||||
|
results = lowResults
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.Explode {
|
||||||
|
var neededExplosions int
|
||||||
|
for _, result := range results {
|
||||||
|
if result.Result == result.Size {
|
||||||
|
neededExplosions++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for explosions := 0; explosions < neededExplosions; explosions++ {
|
||||||
|
alreadyRolled := len(results)
|
||||||
|
results, err = addDice(d, results)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, result := range results[alreadyRolled:] {
|
||||||
|
if result.Result == result.Size {
|
||||||
|
neededExplosions++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateFromExp(exp string) (DieExp, error) {
|
||||||
|
d := DieExp{
|
||||||
|
Count: 1,
|
||||||
|
KeepHigh: 0,
|
||||||
|
KeepLow: 0,
|
||||||
|
Explode: false,
|
||||||
|
}
|
||||||
|
match := regexp.MustCompile("[0-9]*d[0-9]+([hl][0-9]+)*e?([+-][0-9]+)?")
|
||||||
|
countMatch := regexp.MustCompile("^[0-9]*")
|
||||||
|
sizeMatch := regexp.MustCompile("d[0-9]+")
|
||||||
|
highMatch := regexp.MustCompile("h[0-9]+")
|
||||||
|
lowMatch := regexp.MustCompile("l[0-9]+")
|
||||||
|
explodeMatch := regexp.MustCompile("e")
|
||||||
|
addMatch := regexp.MustCompile("[+\\-][0-9]+")
|
||||||
|
match.Longest()
|
||||||
|
countMatch.Longest()
|
||||||
|
sizeMatch.Longest()
|
||||||
|
highMatch.Longest()
|
||||||
|
lowMatch.Longest()
|
||||||
|
matched := match.FindString(exp)
|
||||||
|
if len(matched) != len(exp) {
|
||||||
|
return DieExp{}, errors.New("dice expression invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
countString := countMatch.FindString(exp)
|
||||||
|
if len(countString) != 0 {
|
||||||
|
count, _ := strconv.Atoi(countString)
|
||||||
|
d.Count = count
|
||||||
|
}
|
||||||
|
|
||||||
|
sizeString := sizeMatch.FindString(exp)
|
||||||
|
if len(sizeString) != 0 {
|
||||||
|
size, _ := strconv.Atoi(sizeString[1:])
|
||||||
|
d.Size = size
|
||||||
|
}
|
||||||
|
|
||||||
|
highString := highMatch.FindString(exp)
|
||||||
|
if len(highString) != 0 {
|
||||||
|
high, _ := strconv.Atoi(highString[1:])
|
||||||
|
d.KeepHigh = high
|
||||||
|
}
|
||||||
|
|
||||||
|
lowString := lowMatch.FindString(exp)
|
||||||
|
if len(lowString) != 0 {
|
||||||
|
low, _ := strconv.Atoi(lowString[1:])
|
||||||
|
d.KeepLow = low
|
||||||
|
}
|
||||||
|
|
||||||
|
if explodeMatch.MatchString(exp) {
|
||||||
|
d.Explode = true
|
||||||
|
}
|
||||||
|
|
||||||
|
addString := addMatch.FindString(exp)
|
||||||
|
if len(addString) != 0 {
|
||||||
|
add, _ := strconv.Atoi(addString[1:])
|
||||||
|
if addString[0] == '-' {
|
||||||
|
add = 0 - add
|
||||||
|
}
|
||||||
|
d.Add = add
|
||||||
|
}
|
||||||
|
|
||||||
|
return d, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addDice(d DieExp, results []DieResult) ([]DieResult, error) {
|
||||||
|
if d.Size < 2 {
|
||||||
|
return nil, errors.New("dice size is too small. Should be at least 2")
|
||||||
|
}
|
||||||
|
if len(results) > 1000 {
|
||||||
|
return nil, errors.New("too many dice rolled. This may be caused by a dice explosion that got out of hand")
|
||||||
|
}
|
||||||
|
result := DieResult{
|
||||||
|
Size: d.Size,
|
||||||
|
Result: rand.IntN(d.Size) + 1,
|
||||||
|
}
|
||||||
|
return append(results, result), nil
|
||||||
|
}
|
||||||
256
dice/dice_test.go
Normal file
256
dice/dice_test.go
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
package dice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDieExp_roll(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
Size int
|
||||||
|
Count int
|
||||||
|
KeepHigh int
|
||||||
|
KeepLow int
|
||||||
|
Explode bool
|
||||||
|
}
|
||||||
|
type results struct {
|
||||||
|
min int
|
||||||
|
max int
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
want results
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "simple roll",
|
||||||
|
fields: fields{
|
||||||
|
Size: 6,
|
||||||
|
Count: 1,
|
||||||
|
KeepHigh: 0,
|
||||||
|
KeepLow: 0,
|
||||||
|
Explode: false,
|
||||||
|
},
|
||||||
|
want: results{
|
||||||
|
min: 1,
|
||||||
|
max: 6,
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "explode d1",
|
||||||
|
fields: fields{
|
||||||
|
Size: 1,
|
||||||
|
Count: 1,
|
||||||
|
KeepHigh: 0,
|
||||||
|
KeepLow: 0,
|
||||||
|
Explode: true,
|
||||||
|
},
|
||||||
|
want: results{
|
||||||
|
min: 1,
|
||||||
|
max: 1,
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "larger roll",
|
||||||
|
fields: fields{
|
||||||
|
Size: 1000,
|
||||||
|
Count: 5,
|
||||||
|
KeepHigh: 0,
|
||||||
|
KeepLow: 0,
|
||||||
|
Explode: false,
|
||||||
|
},
|
||||||
|
want: results{
|
||||||
|
min: 5,
|
||||||
|
max: 5000,
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
d := DieExp{
|
||||||
|
Size: tt.fields.Size,
|
||||||
|
Count: tt.fields.Count,
|
||||||
|
KeepHigh: tt.fields.KeepHigh,
|
||||||
|
KeepLow: tt.fields.KeepLow,
|
||||||
|
Explode: tt.fields.Explode,
|
||||||
|
}
|
||||||
|
got, err := d.Roll()
|
||||||
|
total := 0
|
||||||
|
for _, v := range got {
|
||||||
|
total += v.Result
|
||||||
|
}
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("roll() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ((total < tt.want.min) || (total > tt.want.max)) && (!tt.wantErr) {
|
||||||
|
t.Errorf("roll() got = %v, want between %v and %v", total, tt.want.min, tt.want.max)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDieExp_roll_keep_high(t *testing.T) {
|
||||||
|
d := DieExp{
|
||||||
|
Size: 20,
|
||||||
|
Count: 10,
|
||||||
|
KeepHigh: 2,
|
||||||
|
KeepLow: 0,
|
||||||
|
Explode: false,
|
||||||
|
}
|
||||||
|
got, err := d.Roll()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("roll() error = %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(got) != 2 {
|
||||||
|
t.Errorf("roll() got = %v, want length 2", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDieExp_roll_keep_low(t *testing.T) {
|
||||||
|
d := DieExp{
|
||||||
|
Size: 20,
|
||||||
|
Count: 10,
|
||||||
|
KeepHigh: 0,
|
||||||
|
KeepLow: 2,
|
||||||
|
Explode: false,
|
||||||
|
}
|
||||||
|
got, err := d.Roll()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("roll() error = %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(got) != 2 {
|
||||||
|
t.Errorf("roll() got = %v, want length 2", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDieExp_roll_keep_high_low(t *testing.T) {
|
||||||
|
d := DieExp{
|
||||||
|
Size: 20,
|
||||||
|
Count: 10,
|
||||||
|
KeepHigh: 5,
|
||||||
|
KeepLow: 2,
|
||||||
|
Explode: false,
|
||||||
|
}
|
||||||
|
got, err := d.Roll()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("roll() error = %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(got) != 2 {
|
||||||
|
t.Errorf("roll() got = %v, want length 2", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDieExp_roll_keep_low_too_high(t *testing.T) {
|
||||||
|
d := DieExp{
|
||||||
|
Size: 20,
|
||||||
|
Count: 2,
|
||||||
|
KeepHigh: 0,
|
||||||
|
KeepLow: 5,
|
||||||
|
Explode: false,
|
||||||
|
}
|
||||||
|
_, err := d.Roll()
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("expected roll error, got nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateFromExp(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
exp string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want DieExp
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "test 1",
|
||||||
|
args: args{
|
||||||
|
exp: "1d20",
|
||||||
|
},
|
||||||
|
want: DieExp{
|
||||||
|
Size: 20,
|
||||||
|
Count: 1,
|
||||||
|
KeepHigh: 0,
|
||||||
|
KeepLow: 0,
|
||||||
|
Explode: false,
|
||||||
|
Add: 0,
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "test 2",
|
||||||
|
args: args{
|
||||||
|
exp: "d20",
|
||||||
|
},
|
||||||
|
want: DieExp{
|
||||||
|
Size: 20,
|
||||||
|
Count: 1,
|
||||||
|
KeepHigh: 0,
|
||||||
|
KeepLow: 0,
|
||||||
|
Explode: false,
|
||||||
|
Add: 0,
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "test 3",
|
||||||
|
args: args{
|
||||||
|
exp: "3d20h2l1e+1",
|
||||||
|
},
|
||||||
|
want: DieExp{
|
||||||
|
Size: 20,
|
||||||
|
Count: 3,
|
||||||
|
KeepHigh: 2,
|
||||||
|
KeepLow: 1,
|
||||||
|
Explode: true,
|
||||||
|
Add: 1,
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "test 4",
|
||||||
|
args: args{
|
||||||
|
exp: "3d20h2l1e+1t",
|
||||||
|
},
|
||||||
|
want: DieExp{},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "test 5",
|
||||||
|
args: args{
|
||||||
|
exp: "3d20h2l1e-20",
|
||||||
|
},
|
||||||
|
want: DieExp{
|
||||||
|
Size: 20,
|
||||||
|
Count: 3,
|
||||||
|
KeepHigh: 2,
|
||||||
|
KeepLow: 1,
|
||||||
|
Explode: true,
|
||||||
|
Add: -20,
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := CreateFromExp(tt.args.exp)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("CreateFromExp() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("CreateFromExp() got = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
10
go.mod
Normal file
10
go.mod
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
module treerazer
|
||||||
|
|
||||||
|
go 1.23.0
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/bwmarrin/discordgo v0.28.1 // indirect
|
||||||
|
github.com/gorilla/websocket v1.4.2 // indirect
|
||||||
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
|
||||||
|
)
|
||||||
12
go.sum
Normal file
12
go.sum
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
github.com/bwmarrin/discordgo v0.28.1 h1:gXsuo2GBO7NbR6uqmrrBDplPUx2T3nzu775q/Rd1aG4=
|
||||||
|
github.com/bwmarrin/discordgo v0.28.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
|
||||||
|
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||||
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
|
||||||
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
Loading…
x
Reference in New Issue
Block a user