~alaxa27/ultimate-smash-friends/mirror_trunk

« back to all changes in this revision

Viewing changes to pkg/ultimate-smash-friends_1.0-beta-1/usr/lib/usf_modules/controls.py

  • Committer: gaby
  • Date: 2009-11-30 17:03:16 UTC
  • Revision ID: gaby@ks22672.kimsufi.com-20091130170316-6lm3v7q0torulfab
adding code package

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
################################################################################
 
2
# copyright 2008 Gabriel Pettier <gabriel.pettier@gmail.com>                   #
 
3
#                                                                              #
 
4
# This file is part of UltimateSmashFriends                                    #
 
5
#                                                                              #
 
6
# UltimateSmashFriends is free software: you can redistribute it and/or modify #
 
7
# it under the terms of the GNU General Public License as published by the Free#
 
8
# Software Foundation, either version 3 of the License, or (at your option) any#
 
9
# later version.                                                               #
 
10
#                                                                              #
 
11
# UltimateSmashFriends is distributed in the hope that it will be useful, but  #
 
12
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or#
 
13
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for    #
 
14
# more details.                                                                #
 
15
#                                                                              #
 
16
# You should have received a copy of the GNU General Public License along with #
 
17
# UltimateSmashFriends.  If not, see <http://www.gnu.org/licenses/>.           #
 
18
################################################################################
 
19
 
 
20
# standards import
 
21
import time
 
22
import pygame
 
23
from pygame.locals import (
 
24
        KEYDOWN,
 
25
        KEYUP,
 
26
        MOUSEMOTION,
 
27
        MOUSEBUTTONUP,
 
28
        MOUSEBUTTONDOWN,
 
29
        USEREVENT,
 
30
        )
 
31
# my imports
 
32
import config
 
33
from debug_utils import LOG
 
34
import game
 
35
 
 
36
class Sequence (object):
 
37
    """
 
38
    Used to bind an animation of a player to a sequence of key.
 
39
    """
 
40
    def __init__(self, player, keys, action, condition=None):
 
41
        self.player = player
 
42
        self.keys = keys
 
43
        self.action = action
 
44
        self.condition = condition
 
45
 
 
46
    def compare(self, seq, game_instance):
 
47
        if self.condition == ""\
 
48
        or len(game_instance.players) > self.player\
 
49
            and game_instance.players[self.player].entity_skin.current_animation\
 
50
            in self.condition :
 
51
            keyseq = [i[0] for i in seq]
 
52
            return self.keys == keyseq[-len(self.keys):]
 
53
        else:
 
54
            return False
 
55
 
 
56
    def __str__():
 
57
        return [str(i) for i in self.keys]
 
58
 
 
59
class Controls (object):
 
60
    """
 
61
    Catch pygame keyboard events and decides of the interraction with the game,
 
62
    game menu and entity instances. Key configuration are taken from
 
63
    sequences.cfg. This class can update and save configuration.
 
64
 
 
65
    """
 
66
    def __init__(self):
 
67
        #loaders.load_keys()
 
68
        self.keys = config.keyboard_config
 
69
        self.sequences = []
 
70
        self.player_sequences = [[],[],[],[]]
 
71
        sequences_file = open('sequences.cfg', 'r')
 
72
        sequence_tmpl = []
 
73
        condition = ""
 
74
        for i in sequences_file.readlines():
 
75
            if i=='\n' or i[0] == '#':
 
76
                continue
 
77
            if i[0] == '=':
 
78
                condition=i.split('=')[1].split('\n')[0].split(',')
 
79
                continue
 
80
            tmp = i.replace(' ','').split('\n')[0].split(':')
 
81
            sequence_tmpl.append([condition[:], tmp[0].split('+'), tmp[1]])
 
82
        sequences_file.close()
 
83
 
 
84
        for player in range(4):
 
85
            for condition,seq,act in sequence_tmpl:
 
86
                tab=["PL"+str(player)+'_'+btn for btn in seq]
 
87
                self.sequences.append(Sequence(player-1, tab, act, condition))
 
88
 
 
89
            for i in range(4): self.player_sequences.append([])
 
90
 
 
91
    def getKeyByAction(self, action):
 
92
        if action in self.keys.values():
 
93
            return config.reverse_keymap[
 
94
                self.keys.keys()[
 
95
                        self.keys.values().index(action)
 
96
                        ]
 
97
            ]
 
98
 
 
99
    def assignKey(self, action):
 
100
        while True:
 
101
            event = pygame.event.wait()
 
102
            if event.type == KEYDOWN:
 
103
                try:
 
104
                    self.keys.pop(eval(self.getKeyByAction(action)))
 
105
                except TypeError:
 
106
                    pass
 
107
                self.keys[event.key] = action
 
108
                break
 
109
 
 
110
    def save(self):
 
111
        str_conf = """
 
112
# this file contain keybindings of players and of the general game
 
113
# everything on a line after a # is a comment and is ignored
 
114
# you can start a comment with a ; too.
 
115
 
 
116
# The syntax of a binding is simple. the first part is the player concerned.
 
117
# to bind for the player one, start with "PL1" then a '_' and the action concerned.
 
118
# a complete list of actions will be inserted here later (#TODO).
 
119
 
 
120
# The second part of the line is the code of the key associated with the action.
 
121
# Theses are pygame names, and you can find a list at pygame website:
 
122
# http://www.pygame.org/docs/ref/key.html
 
123
 
 
124
# please also see online documentation of keybindings here:
 
125
# http://code.google.com/p/ultimate-smash-friends/wiki/KeysConfiguration
 
126
                    """
 
127
        conf = []
 
128
        for key in self.keys.keys():
 
129
            conf.append("%s : %s\n" % ( self.keys[key], config.reverse_keymap[key]))
 
130
 
 
131
        # we sort the keys configuration by player so the file is easier to read.
 
132
        conf.sort()
 
133
        str_conf += ''.join(conf)
 
134
        file=open('UltimateSmashFriends.cfg','w')
 
135
        file.write(str_conf)
 
136
        file.close()
 
137
 
 
138
    def reload(self):
 
139
        self.keys = config.load_key_config()
 
140
 
 
141
    def handle_menu_key( self, state, key, game):
 
142
        ret = "menu"
 
143
        if state is KEYDOWN:
 
144
            if key in self.keys :
 
145
                #LOG().log(self.keys[key])
 
146
                if self.keys[key] == "MENU_TOGGLE":
 
147
                    ret = "game"
 
148
                elif self.keys[key] == "QUIT":
 
149
                    if config.config['CONFIRM_EXIT']:
 
150
                        pygame.event.post(
 
151
                                pygame.event.Event(
 
152
                                    USEREVENT,
 
153
                                    key=self.keys[key]
 
154
                                    )
 
155
                                )
 
156
                    else:
 
157
                        pygame.event.post(
 
158
                                pygame.event.Event(QUIT)
 
159
                        )
 
160
                elif self.keys[key] == "TOGGLE_FULLSCREEN":
 
161
                    pygame.display.toggle_fullscreen()
 
162
 
 
163
                elif self.keys[key] == "VALIDATE":
 
164
                    pygame.event.post(
 
165
                            pygame.event.Event(
 
166
                                USEREVENT,
 
167
                                key=self.keys[key]
 
168
                                )
 
169
                            )
 
170
                else: pygame.event.post(
 
171
                        pygame.event.Event(
 
172
                            USEREVENT,
 
173
                            player = int(self.keys[key].split('_')[0][-1]),
 
174
                            key = self.keys[key].split('_')[1]
 
175
                                          )
 
176
                                        )
 
177
        return ret
 
178
 
 
179
    def handle_game_key( self, state, key, game_instance ):
 
180
        ret = "game"
 
181
        if state is KEYDOWN:
 
182
            if key in self.keys:
 
183
                #FIXME: test if the player is not an AI.
 
184
                try:
 
185
                    self.player_sequences[int(self.keys[key].split('_')\
 
186
                                [0][-1])].append((self.keys[key],time.time()))
 
187
                except:
 
188
                    pass # fail when the key not associated to a player eg:
 
189
                         # toggle_menu
 
190
                if isinstance(game_instance, game.NetworkClientGame):
 
191
                    game_instance.client.send(key,'down')
 
192
 
 
193
                elif isinstance(game_instance, game.NetworkServerGame):
 
194
                    pass
 
195
                else:
 
196
                    if self.keys[key] == "QUIT":
 
197
                        ret = "menu"
 
198
                        #pygame.event.set_grab(False)
 
199
                    elif self.keys[key] == "TOGGLE_FULLSCREEN":
 
200
                        pygame.display.toggle_fullscreen()
 
201
 
 
202
                    for player in game_instance.players:
 
203
                        pl = "PL"+str(player.num)
 
204
                        the_key = self.keys[key]
 
205
                        if pl not in the_key: continue
 
206
                        if "_LEFT" in the_key:
 
207
                            player.walking_vector[0] = config.config['WALKSPEED']
 
208
                            player.reversed = True
 
209
 
 
210
                        elif "_RIGHT" in the_key:
 
211
                            player.walking_vector[0] = config.config['WALKSPEED']
 
212
                            player.reversed = False
 
213
 
 
214
                    #test sequences
 
215
                    for sequence in self.player_sequences:
 
216
                        for i in self.sequences:
 
217
                            if i.compare( sequence, game_instance ):
 
218
                                game_instance.players[i.player].entity_skin.change_animation\
 
219
                                        (
 
220
                                          i.action,
 
221
                                          game_instance,
 
222
                                          params={
 
223
                                                    'entity':game_instance.players[i.player]
 
224
                                                 }
 
225
                                        )
 
226
 
 
227
        elif state is KEYUP:
 
228
            if isinstance(game_instance,  game.NetworkClientGame):
 
229
                game_instance.client.send(key,'up')
 
230
 
 
231
            elif isinstance(game_instance, game.NetworkServerGame):
 
232
                pass
 
233
            else:
 
234
                for player in game_instance.players:
 
235
                    if key not in self.keys : break
 
236
                    pl = "PL"+str(player.num)
 
237
                    if pl not in self.keys[key]: continue
 
238
                    if key in self.keys :
 
239
                        if "_LEFT" in self.keys[key]:
 
240
                            player.walking_vector[0] = 0
 
241
                            if player.entity_skin.current_animation == "walk":
 
242
                                player.entity_skin.change_animation(
 
243
                                        "static",
 
244
                                        game_instance,
 
245
                                        params={'entity': player}
 
246
                                        )
 
247
                        elif "_RIGHT" in self.keys[key]:
 
248
                            player.walking_vector[0] = 0
 
249
                            if player.entity_skin.current_animation == "walk":
 
250
                                player.entity_skin.change_animation(
 
251
                                        "static",
 
252
                                        game_instance,
 
253
                                        params={'entity': player}
 
254
                                        )
 
255
        return ret
 
256
 
 
257
    def poll(self, game_instance, menu, state):
 
258
        """
 
259
        This function manages key events aquiered from local keyboard or sent
 
260
        by clients in the case of a networkk game.
 
261
 
 
262
        """
 
263
        if isinstance(game_instance, game.NetworkServerGame):
 
264
            while True:
 
265
                k = game_instance.server.fetch()
 
266
                if k == None: break
 
267
                else: self.handle_game_key( "game", k, game_instance )
 
268
 
 
269
        else:
 
270
            pygame.event.pump()
 
271
            for event in pygame.event.get( [ KEYDOWN, KEYUP ] ):
 
272
                if state is "game":
 
273
                    if game is not None:
 
274
                        state = self.handle_game_key( event.type, event.key, game_instance)
 
275
                    # forget other events
 
276
                    pygame.event.clear()
 
277
 
 
278
                elif state is "menu":
 
279
                    state = self.handle_menu_key( event.type, event.key, menu )
 
280
 
 
281
            # eliminate unwanted events that fill the pool and break the controls.
 
282
            pygame.event.clear( [MOUSEMOTION, MOUSEBUTTONUP, MOUSEBUTTONDOWN] )
 
283
 
 
284
            # clean sequences from outdated keys
 
285
            for index, sequence in enumerate(self.player_sequences):
 
286
                limit_time = time.time()-.500
 
287
                # clean the entire sequence if the last key is outdated.
 
288
                if sequence != [] and sequence[-1][1] < limit_time:
 
289
                    self.player_sequences[index] = []
 
290
 
 
291
        return state
 
292