diff --git a/bot/bot.go b/bot/bot.go index bb4b852..b45683d 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -22,6 +22,7 @@ const ( ApiURLSoTUserOverview = "https://www.seaofthieves.com/api/profilev2/overview" ApiURLSoTEventHub = "https://www.seaofthieves.com/event-hub" ApiURLRTTradeRoutes = "https://maps.seaofthieves.rarethief.com/js/trade_routes.js" + ApiURLSoTLedger = "https://www.seaofthieves.com/api/ledger/friends" AssetsBaseURL = "https://github.com/wneessen/arrgo/raw/main/assets" ) diff --git a/bot/format.go b/bot/format.go index 54f70ce..9c213ff 100644 --- a/bot/format.go +++ b/bot/format.go @@ -15,6 +15,7 @@ const ( IconShip = "⛵" IconVomit = "🤮" IconDistance = "📐" + IconGauge = "🌡️" ) // changeIcon returns either an increase or decrease icon based on the provided value diff --git a/bot/sc_handler_sot_ledger.go b/bot/sc_handler_sot_ledger.go new file mode 100644 index 0000000..e5b5501 --- /dev/null +++ b/bot/sc_handler_sot_ledger.go @@ -0,0 +1,180 @@ +package bot + +import ( + "encoding/json" + "fmt" + "github.com/bwmarrin/discordgo" + "regexp" + "strings" +) + +// SoTLedger represents the JSON structure of the Sea of Thieves leder positions within a season API response +type SoTLedger struct { + Current SoTCurrentLedger `json:"current"` +} + +// SoTCurrentLedger represents the JSON structure of the Sea of Thieves current leder within the overall +// ledger response +type SoTCurrentLedger struct { + Friends SoTFriendsLedger `json:"friends"` +} + +// SoTFriendsLedger represents the JSON structure of the Sea of Thieves friends positioning withing the current leder +type SoTFriendsLedger struct { + User SoTEmissaryLedger `json:"user"` +} + +// SoTEmissaryLedger represents the JSON structure of the Sea of Thieves ledger data +type SoTEmissaryLedger struct { + Name string + Band int `json:"band"` + BandTitle string + Rank int `json:"rank"` + Score int `json:"score"` + ToNextRank int `json:"toNextRank"` +} + +// SlashCmdSoTLedger handles the /ledger slash command +func (b *Bot) SlashCmdSoTLedger(s *discordgo.Session, i *discordgo.InteractionCreate) error { + eo := i.ApplicationCommandData().Options + if len(eo) <= 0 { + return fmt.Errorf("no option given") + } + rc, ok := eo[0].Value.(string) + if !ok { + return fmt.Errorf("provided option value is not a string") + } + + re, err := regexp.Compile(`^(?i:athena|hoarder|merchant|order|reaper)$`) + if err != nil { + return err + } + ema := re.FindStringSubmatch(rc) + if len(ema) != 1 { + return fmt.Errorf("failed to parse value string") + } + em := ema[0] + + r, err := b.NewRequester(i.Interaction) + if err != nil { + return err + } + + l, err := b.SoTGetLedger(r, em) + if err != nil { + return err + } + + var ef []*discordgo.MessageEmbedField + ef = append(ef, &discordgo.MessageEmbedField{ + Name: "Faction/Company", + Value: l.Name, + Inline: false, + }) + ef = append(ef, &discordgo.MessageEmbedField{ + Name: "Current Title", + Value: l.BandTitle, + Inline: false, + }) + ef = append(ef, &discordgo.MessageEmbedField{ + Name: "Emissary value", + Value: fmt.Sprintf("%s **%d**", IconAncientCoin, l.Score), + Inline: true, + }) + ef = append(ef, &discordgo.MessageEmbedField{ + Name: "Ledger position", + Value: fmt.Sprintf("%s **%d**", IconGauge, l.Rank), + Inline: true, + }) + ef = append(ef, &discordgo.MessageEmbedField{ + Name: "Next level in", + Value: fmt.Sprintf("%s **%d** points", IconIncrease, l.ToNextRank), + Inline: true, + }) + + e := []*discordgo.MessageEmbed{ + { + Title: "Your global ledger in Sea of Thieves:", + Thumbnail: &discordgo.MessageEmbedThumbnail{ + URL: fmt.Sprintf("%s/ledger/%s%d.png", AssetsBaseURL, em, 4-l.Band), + }, + Type: discordgo.EmbedTypeRich, + Fields: ef, + }, + } + if _, err := s.InteractionResponseEdit(i.Interaction, &discordgo.WebhookEdit{Embeds: &e}); err != nil { + return err + } + return nil +} + +// SoTGetLedger returns the parsed API response from the Sea of Thieves leaderboard ledger API +func (b *Bot) SoTGetLedger(rq *Requester, em string) (SoTEmissaryLedger, error) { + var l SoTEmissaryLedger + var al SoTLedger + hc, err := NewHTTPClient() + if err != nil { + return l, fmt.Errorf(ErrFailedHTTPClient, err) + } + c, err := rq.GetSoTRATCookie() + if err != nil { + return l, err + } + + urlfmt := "%s/%s?count=3" + var url string + switch strings.ToLower(em) { + case "athena": + url = fmt.Sprintf(urlfmt, ApiURLSoTLedger, "AthenasFortune") + case "hoarder": + url = fmt.Sprintf(urlfmt, ApiURLSoTLedger, "GoldHoarders") + case "merchant": + url = fmt.Sprintf(urlfmt, ApiURLSoTLedger, "MerchantAlliance") + case "order": + url = fmt.Sprintf(urlfmt, ApiURLSoTLedger, "OrderOfSouls") + case "reaper": + url = fmt.Sprintf(urlfmt, ApiURLSoTLedger, "ReapersBones") + default: + return l, fmt.Errorf("unknown emissary given") + } + + r, err := hc.HttpReq(url, ReqMethodGet, nil) + if err != nil { + return l, err + } + r.SetSOTRequest(c) + rd, _, err := hc.Fetch(r) + if err != nil { + return l, err + } + + if err := json.Unmarshal(rd, &al); err != nil { + return l, err + } + + l = al.Current.Friends.User + switch strings.ToLower(em) { + case "athena": + tl := []string{"Legend", "Guardian", "Voyager", "Seeker"} + l.Name = "Athena's Fortune" + l.BandTitle = tl[l.Band] + case "hoarder": + tl := []string{"Captain", "Marauder", "Seafarer", "Castaway"} + l.Name = "Gold Hoarders" + l.BandTitle = tl[l.Band] + case "merchant": + tl := []string{"Admiral", "Commander", "Cadet", "Sailor"} + l.Name = "Merchant Alliance" + l.BandTitle = tl[l.Band] + case "order": + tl := []string{"Grandee", "Chief", "Mercenary", "Apprentice"} + l.Name = "Order of Souls" + l.BandTitle = tl[l.Band] + case "reaper": + tl := []string{"Master", "Keeper", "Servant", "Follower"} + l.Name = "Reaper's Bones" + l.BandTitle = tl[l.Band] + } + + return l, nil +} diff --git a/bot/slashcmd.go b/bot/slashcmd.go index c088d1a..03ef5a0 100644 --- a/bot/slashcmd.go +++ b/bot/slashcmd.go @@ -320,7 +320,7 @@ func (b *Bot) SlashCommandHandler(s *discordgo.Session, i *discordgo.Interaction "overview": b.SlashCmdSoTOverview, "compare": b.SlashCmdSoTCompare, "dailydeeds": b.SlashCmdSoTDailyDeeds, - "ledger": b.SlashCmdSoTDailyDeeds, + "ledger": b.SlashCmdSoTLedger, } // Define list of slash commands that should use ephemeral messages diff --git a/go.sum b/go.sum index 512d50c..268381b 100644 --- a/go.sum +++ b/go.sum @@ -172,8 +172,6 @@ github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx2 github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= -github.com/bwmarrin/discordgo v0.26.0 h1:/AdFmxHXSHInYAZ7K0O3VEIXlVjGpztk/nuCr9o+JCs= -github.com/bwmarrin/discordgo v0.26.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= github.com/bwmarrin/discordgo v0.26.1 h1:AIrM+g3cl+iYBr4yBxCBp9tD9jR3K7upEjl0d89FRkE= github.com/bwmarrin/discordgo v0.26.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=