shoot.go (view raw)
1package main
2
3import (
4 "fmt"
5 "time"
6
7 "github.com/bwmarrin/discordgo"
8 "golang.org/x/exp/rand"
9)
10
11type Magazine struct {
12 size uint
13 left uint
14 last time.Time
15}
16
17var magazines = map[string]*Magazine{}
18
19func NewMagazine(size uint) *Magazine {
20 return &Magazine{size: size, left: size, last: time.Now()}
21}
22
23func (m *Magazine) Update() {
24 now := time.Now()
25 if m.last.YearDay() != now.YearDay() || m.last.Year() != now.Year() {
26 m.left = m.size
27 }
28}
29
30func (m *Magazine) Left() uint {
31 m.Update()
32 return m.left
33}
34
35func (m Magazine) Size() uint {
36 return m.size
37}
38
39func (m *Magazine) Shoot() bool {
40 if m.Left() <= 0 {
41 return false
42 }
43
44 m.last = time.Now()
45 m.left--
46 return true
47}
48
49func (m *Magazine) String() string {
50 return fmt.Sprintf("_%d/%d bullets left in your magazine._", m.Left(), m.Size())
51}
52
53func GetMagazine(userID string) (q *Magazine) {
54 q, ok := magazines[userID]
55 if ok {
56 return
57 }
58
59 q = NewMagazine(config.Values.MagazineSize)
60 magazines[userID] = q
61 return
62}
63
64func handleShoot(args []string, s *discordgo.Session, m *discordgo.MessageCreate) string {
65 const bustProbability = 50
66
67 response, guild, voiceChannelID := getVoiceChannelID(s, m)
68 if voiceChannelID == "" {
69 return response
70 }
71
72 killerID := m.Author.ID
73 var allMembers []string
74 for _, vs := range guild.VoiceStates {
75 if vs.ChannelID == voiceChannelID && vs.UserID != killerID {
76 member, err := s.State.Member(guild.ID, vs.UserID)
77 if err != nil {
78 logger.Errorf("could not get member info: %s", err)
79 continue
80 }
81 if !member.User.Bot {
82 allMembers = append(allMembers, vs.UserID)
83 }
84 }
85 }
86
87 if len(allMembers) == 0 {
88 return "There is no one else to shoot in your voice channel."
89 }
90
91 magazine := GetMagazine(killerID)
92 if !magazine.Shoot() {
93 return "💨 Too bad... You're out of bullets."
94 }
95
96 var victimID string
97 if rand.Intn(100) < bustProbability {
98 victimID = killerID
99 } else {
100 victimID = allMembers[rand.Intn(len(allMembers))]
101 }
102
103 err := s.GuildMemberMove(m.GuildID, victimID, nil)
104 if err != nil {
105 logger.Errorf("could not kick user: %s", err)
106 return "Failed to kick the user from the voice channel."
107 }
108
109 return "💥 *Bang!* <@" + victimID + "> was shot. " + magazine.String()
110}