From 879b482b7af625c0bcd5981432dd6a9cf226e145 Mon Sep 17 00:00:00 2001 From: Luther Wen Xu Date: Sat, 30 May 2020 21:31:50 +0800 Subject: [PATCH] feat: Implement level --- commands/level.go | 12 ++++++-- level/level.go | 73 +++++++++++++++++++++++++++++++++++++++++++++++ util/format.go | 32 +++++++++++++++++++++ 3 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 level/level.go diff --git a/commands/level.go b/commands/level.go index 895abfe..2004a9a 100644 --- a/commands/level.go +++ b/commands/level.go @@ -4,6 +4,7 @@ import ( "github.com/bwmarrin/discordgo" "gitea.teamortix.com/chanbakjsd/Milen/db" + "gitea.teamortix.com/chanbakjsd/Milen/level" "gitea.teamortix.com/chanbakjsd/Milen/util" ) @@ -24,11 +25,18 @@ func handleLevel(dg *discordgo.Session, m *discordgo.MessageCreate, arguments [] util.SendFailEmbed(dg, m.ChannelID, "Error", "Cannot find requested member.") return } + rank, level := level.GetLevelFromXP(xp) embed := &discordgo.MessageEmbed{ Fields: []*discordgo.MessageEmbedField{ &discordgo.MessageEmbedField{ - Name: "Active Time", - Value: util.FormatPlural(xp, "second", "seconds") + " (or " + util.FormatTime(xp) + ")", + Name: "Level", + Value: rank.String() + " " + util.FormatRomanNumeral(level), + Inline: true, + }, + &discordgo.MessageEmbedField{ + Name: "Active Time", + Value: util.FormatPlural(xp, "second", "seconds") + " (or " + util.FormatTime(xp) + ")", + Inline: true, }, &discordgo.MessageEmbedField{ Name: "Internal User ID", diff --git a/level/level.go b/level/level.go new file mode 100644 index 0000000..9e64164 --- /dev/null +++ b/level/level.go @@ -0,0 +1,73 @@ +package level + +type Rank uint8 + +const ( + RankRecruit Rank = iota + RankMember + RankApprentice + RankAdept + RankExperienced + RankVeteran + RankProfessional + RankElite + RankEpic + RankElder + RankLegend + RankInsane + RankGodlike + RankDemigod +) + +func (r Rank) String() string { + switch r { + case RankRecruit: + return "Recruit" + case RankMember: + return "Member" + case RankApprentice: + return "Apprentice" + case RankAdept: + return "Adept" + case RankExperienced: + return "Experienced" + case RankVeteran: + return "Veteran" + case RankProfessional: + return "Professional" + case RankElite: + return "Elite" + case RankEpic: + return "Epic" + case RankElder: + return "Elder" + case RankLegend: + return "Legend" + case RankInsane: + return "Insane" + case RankGodlike: + return "Godlike" + case RankDemigod: + return "Demigod" + } + return "Unknown" +} + +func GetLevelFromXP(xp int64) (Rank, int) { + // Level starting from 1 + level := int(xp/600 + 1) + rank := 0 + // Get highest power of 2 we can go without touching it. + // 3 => 1 (2^1=2) + // 4 => 1 (2^1=2) + // 5 => 2 (2^2=4) + for level > (1 << rank) { + if rank == int(RankDemigod) { + break + } + rank++ + } + rank-- + // Return it. + return Rank(rank), level - (1 << rank) + 1 +} diff --git a/util/format.go b/util/format.go index af0dd2b..023da9a 100644 --- a/util/format.go +++ b/util/format.go @@ -44,3 +44,35 @@ func FormatPlural(count int64, singular string, plural string) string { } return strconv.FormatInt(count, 10) + " " + plural } + +func FormatRomanNumeral(number int) string { + if number < 1 || number > 3999 { + return strconv.Itoa(number) + } + conversions := []struct { + value int + digit string + }{ + {1000, "M"}, + {900, "CM"}, + {500, "D"}, + {400, "CD"}, + {100, "C"}, + {90, "XC"}, + {50, "L"}, + {40, "XL"}, + {10, "X"}, + {9, "IX"}, + {5, "V"}, + {4, "IV"}, + {1, "I"}, + } + roman := "" + for _, conversion := range conversions { + for number >= conversion.value { + roman += conversion.digit + number -= conversion.value + } + } + return roman +}