1
################################################################################
2
# copyright 2008 Gabriel Pettier <gabriel.pettier@gmail.com> #
4
# This file is part of UltimateSmashFriends #
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#
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 #
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
################################################################################
23
from pygame.locals import (
33
from debug_utils import LOG
36
class Sequence (object):
38
Used to bind an animation of a player to a sequence of key.
40
def __init__(self, player, keys, action, condition=None):
44
self.condition = condition
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\
51
keyseq = [i[0] for i in seq]
52
return self.keys == keyseq[-len(self.keys):]
57
return [str(i) for i in self.keys]
59
class Controls (object):
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.
68
self.keys = config.keyboard_config
70
self.player_sequences = [[],[],[],[]]
71
sequences_file = open('sequences.cfg', 'r')
74
for i in sequences_file.readlines():
75
if i=='\n' or i[0] == '#':
78
condition=i.split('=')[1].split('\n')[0].split(',')
80
tmp = i.replace(' ','').split('\n')[0].split(':')
81
sequence_tmpl.append([condition[:], tmp[0].split('+'), tmp[1]])
82
sequences_file.close()
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))
89
for i in range(4): self.player_sequences.append([])
91
def getKeyByAction(self, action):
92
if action in self.keys.values():
93
return config.reverse_keymap[
95
self.keys.values().index(action)
99
def assignKey(self, action):
101
event = pygame.event.wait()
102
if event.type == KEYDOWN:
104
self.keys.pop(eval(self.getKeyByAction(action)))
107
self.keys[event.key] = action
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.
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).
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
124
# please also see online documentation of keybindings here:
125
# http://code.google.com/p/ultimate-smash-friends/wiki/KeysConfiguration
128
for key in self.keys.keys():
129
conf.append("%s : %s\n" % ( self.keys[key], config.reverse_keymap[key]))
131
# we sort the keys configuration by player so the file is easier to read.
133
str_conf += ''.join(conf)
134
file=open('UltimateSmashFriends.cfg','w')
139
self.keys = config.load_key_config()
141
def handle_menu_key( self, state, key, game):
144
if key in self.keys :
145
#LOG().log(self.keys[key])
146
if self.keys[key] == "MENU_TOGGLE":
148
elif self.keys[key] == "QUIT":
149
if config.config['CONFIRM_EXIT']:
158
pygame.event.Event(QUIT)
160
elif self.keys[key] == "TOGGLE_FULLSCREEN":
161
pygame.display.toggle_fullscreen()
163
elif self.keys[key] == "VALIDATE":
170
else: pygame.event.post(
173
player = int(self.keys[key].split('_')[0][-1]),
174
key = self.keys[key].split('_')[1]
179
def handle_game_key( self, state, key, game_instance ):
183
#FIXME: test if the player is not an AI.
185
self.player_sequences[int(self.keys[key].split('_')\
186
[0][-1])].append((self.keys[key],time.time()))
188
pass # fail when the key not associated to a player eg:
190
if isinstance(game_instance, game.NetworkClientGame):
191
game_instance.client.send(key,'down')
193
elif isinstance(game_instance, game.NetworkServerGame):
196
if self.keys[key] == "QUIT":
198
#pygame.event.set_grab(False)
199
elif self.keys[key] == "TOGGLE_FULLSCREEN":
200
pygame.display.toggle_fullscreen()
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
210
elif "_RIGHT" in the_key:
211
player.walking_vector[0] = config.config['WALKSPEED']
212
player.reversed = False
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\
223
'entity':game_instance.players[i.player]
228
if isinstance(game_instance, game.NetworkClientGame):
229
game_instance.client.send(key,'up')
231
elif isinstance(game_instance, game.NetworkServerGame):
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(
245
params={'entity': player}
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(
253
params={'entity': player}
257
def poll(self, game_instance, menu, state):
259
This function manages key events aquiered from local keyboard or sent
260
by clients in the case of a networkk game.
263
if isinstance(game_instance, game.NetworkServerGame):
265
k = game_instance.server.fetch()
267
else: self.handle_game_key( "game", k, game_instance )
271
for event in pygame.event.get( [ KEYDOWN, KEYUP ] ):
274
state = self.handle_game_key( event.type, event.key, game_instance)
275
# forget other events
278
elif state is "menu":
279
state = self.handle_menu_key( event.type, event.key, menu )
281
# eliminate unwanted events that fill the pool and break the controls.
282
pygame.event.clear( [MOUSEMOTION, MOUSEBUTTONUP, MOUSEBUTTONDOWN] )
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] = []