package main import ( "fmt" "strings" "git.sunturtle.xyz/zephyr/horse/horse" "github.com/disgoorg/disgo/discord" ) func RenderSkill(id horse.SkillID, all map[horse.SkillID]horse.Skill, groups map[int32][4]horse.SkillID) discord.ContainerComponent { s, ok := all[id] if !ok { return discord.NewContainer(discord.NewTextDisplayf("invalid skill ID %v made it to RenderSkill", id)) } thumburl := fmt.Sprintf("https://gametora.com/images/umamusume/skill_icons/utx_ico_skill_%d.png", s.IconID) r := discord.NewContainer(discord.NewSection(discord.NewTextDisplayf("## %s\n%s", s.Name, s.Description)).WithAccessory(discord.NewThumbnail(thumburl))) var skilltype string switch { case s.Rarity == 3, s.Rarity == 4, s.Rarity == 5: // unique of various star levels r.AccentColor = 0xaca4d4 skilltype = "Unique Skill" case s.Rarity == 2: // rare (gold) r.AccentColor = 0xd7c25b skilltype = "Rare Skill" case s.GroupRate == -1: // negative (purple) skill r.AccentColor = 0x9151d4 skilltype = "Negative Skill" case !s.WitCheck: // should be passive (green) r.AccentColor = 0x66ae1c skilltype = "Passive Skill" case isDebuff(s): // debuff (red) r.AccentColor = 0xe34747 skilltype = "Debuff Skill" case s.Rarity == 1: // common (white) r.AccentColor = 0xcccccc skilltype = "Common Skill" } r.Components = append(r.Components, discord.NewSmallSeparator()) text := make([]string, 0, 3) abils := make([]string, 0, 3) for _, act := range s.Activations { text, abils = text[:0], abils[:0] if act.Precondition != "" { text = append(text, "Precondition: "+formatCondition(act.Precondition)) } text = append(text, "Condition: "+formatCondition(act.Condition)) var t string switch { case act.Duration < 0: // passive; do nothing case act.Duration == 0: t = "Instantaneous " case act.Duration >= 500e4: t = "Permanent " default: t = "For " + act.Duration.String() + "s, " } for _, a := range act.Abilities { abils = append(abils, a.String()) } t += strings.Join(abils, ", ") if act.Cooldown > 0 && act.Cooldown < 500e4 { t += " on " + act.Cooldown.String() + "s cooldown" } text = append(text, t) r.Components = append(r.Components, discord.NewTextDisplay(strings.Join(text, "\n"))) } l := discord.NewTextDisplayf("%s ・ SP cost %d ・ Grade value %d ・ [Conditions on GameTora](https://gametora.com/umamusume/skill-condition-viewer?skill=%d)", skilltype, s.SPCost, s.GradeValue, s.ID) r.Components = append(r.Components, discord.NewSmallSeparator(), l) rel := make([]horse.Skill, 0, 4) for _, id := range groups[s.Group] { if id != 0 { rel = append(rel, all[id]) } } if len(rel) > 1 { buttons := make([]discord.InteractiveComponent, 0, 4) for _, rs := range rel { b := discord.NewSecondaryButton(rs.Name, fmt.Sprintf("/skill/%d", rs.ID)) if rs.ID == id { b = b.AsDisabled() } buttons = append(buttons, b) } r.Components = append(r.Components, discord.NewActionRow(buttons...)) } return r } func formatCondition(s string) string { s = strings.ReplaceAll(s, "&", " & ") if strings.ContainsRune(s, '@') { return "```\n" + strings.ReplaceAll(s, "@", "\n@\n") + "```" } return "`" + s + "`" } func isDebuff(s horse.Skill) bool { for _, act := range s.Activations { for _, a := range act.Abilities { if a.Value < 0 { return true } } } return false } // TODO(zeph): autocomplete // if we want to backgroundify construction of an autocomplete map, // use sync.OnceValue and launch a goroutine in main to get the value and discard it