summaryrefslogtreecommitdiffstats
path: root/main.py
blob: 19941354f5839c885c05b476a2537799a89f2e63 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Author: Zaran <zaran.krleza@gmail.com>

import irclib
import sys

class MatchState:
    gametypes = { 'duel':2,
                  'ctf':8,
                  'ictf':8,
                  'ca':8 }
    
    def __init__(self):
        state = {}
        for gt in MatchState.gametypes:
            state[gt] = set()
        self._state = state

    def __str__(self):
        matchlist = [ "{}: {}/{}".format(k, len(v), self.__class__.gametypes[k])
                 for k,v in self._state.items() ]
        return "|".join(matchlist)

    def _remove_from_gametype(self, nickname, gametype):
        if gametype in self._state:
            self._state[gametype].discard(nickname)
        
    def _add_to_gametype(self, nickname, gametype):
        """Internal: add a nickname to a given gametype"""
        if gametype in self._state:
            self._state[gametype].add(nickname)

    def add(self,nickname,gametypes=None):
        """Add a nickname to a list of gametypes or to all gametypes
        if the list is not specified"""
        if (gametypes is None) or (len(gametypes) == 0):
            for gt in self._state:
                self._add_to_gametype(nickname,gt)
        else:
            for gt in gametypes:
                self._add_to_gametype(nickname,gt)
                
    def remove(self,nickname,gametypes=None):
        if (gametypes is None) or (len(gametypes) == 0):
            for gt in self._state:
                self._remove_from_gametype(nickname,gt)
        else:
            for gt in gametypes:
                self._remove_from_gametype(nickname,gt)

    def rename(self, oldnick, newnick):
        for pl in self._state.values():
            if oldnick in pl:
                pl.remove(oldnick)
                pl.add(newnick)

    def player_list(self,gametypes=None):
        result = {}
        if (gametypes is None) or (len(gametypes) == 0):
            for gt in self._state:
                result[gt] = list(self._state[gt])
        else:
            for gt in gametypes:
                if gt in self._state[gt]:
                    result[gt] = list(self._state[gt])
        return result

    def check_match_begin(self):
        gametype = None
        player_list = None
        for gt in self._state:
            if len(self._state[gt]) == self.__class__.gametypes[gt]:
                player_list = list(self._state[gt])
                gametype = gt
                self._state[gt] = set()
                for player in player_list:
                    self.remove(player)
                break
        return gametype, player_list
            
class IRCMatchBot(irclib.SimpleIRCClient):

    def __init__(self, target):
        irclib.SimpleIRCClient.__init__(self)
        self.target = target
        self.matchState = MatchState()

    def update_topic(self):
        """Set the channel topic to the match state"""
        self.connection.topic(self.target, str(self.matchState))

    def on_welcome(self, connection, event):
        connection.join(self.target)

    def on_join(self, connection, event):
        pass

    def on_mode(self, connection, event):
        if connection.get_nickname() in event.arguments():
            self.update_topic()

    def on_pubmsg(self, connection, event):
        nick = irclib.nm_to_n(event.source())
        words = event.arguments()[0].split(None,1)
        command = words[0]
        if command[0] == '!':
            command = command[1:]
            if (len(words) > 1) and (len(words[1]) > 0):
                args = words[1]
            else:
                args = None
            self.do_command(connection,nick,command,args)
            
    def do_command(self, c, nick, command, args):
        if command == "help":
            c.privmsg(nick, "Je suis le bot de Pickup de #warsow.fr")
            c.privmsg(nick, "")
        elif (command == "add") or (command == "remove") or (command == "list"):
            if args is None:
                gtlist = None
            else:
                gtlist = [gt.strip() for gt in args.split(',')]
            if command == "add":
                self.matchState.add(nick, gtlist)
                gametype, player_list = self.matchState.check_match_begin()
                if gametype is not None:
                    c.privmsg( self.target,
                               "Un {} est sur le point de commencer. Liste des joueurs : {}"
                               .format( gametype, ", ".join(player_list) ) )
                self.update_topic()
            elif command == "remove":
                self.matchState.remove(nick, gtlist)
                self.update_topic()
            elif command == "list":
                result = self.matchState.player_list(gtlist)
                for gt in result:
                    if len(result[gt]) > 0:
                        c.privmsg(nick, "{}: {}".format(gt, ", ".join(result[gt])))
        else:
            c.privmsg(nick, "Cette commande n'existe pas, tape !help pour obtenir de l'aide")

    def on_part(self, c, e):
        nick = irclib.nm_to_n(e.source())
        self.matchState.remove(nick, None)
        self.update_topic()

    def on_quit(self, c, e):
        self.on_part(c,e)

    def on_disconnect(self, connection, event):
        sys.exit(0)

    def on_nick(self,c,e):
        old_nick = irclib.nm_to_n(e.source())
        new_nick  = e.target()
        self.matchState.rename(old_nick, new_nick)

def main():
    if len(sys.argv) != 4:
        print "Usage: " + sys.argv[0] + " <server[:port]> <nickname> <channel>"
        sys.exit(1)

    s = sys.argv[1].split(":", 1)
    server = s[0]
    if len(s) == 2:
        try:
            port = int(s[1])
        except ValueError:
            print "Error: Erroneous port."
            sys.exit(1)
    else:
        port = 6667
    nickname = sys.argv[2]
    channel = sys.argv[3]

    c = IRCMatchBot(channel)
    try:
        c.connect(server, port, nickname)
    except irclib.ServerConnectionError, x:
        print x
        sys.exit(1)
    c.start()

if __name__ == "__main__":
    main()