]> git.siccegge.de Git - ghextris.git/blob - ghextris.py
Update imports
[ghextris.git] / ghextris.py
1 #!/usr/bin/python2
2
3 # Gnome-hextris; a free rewrite of the xhextris game in Python for Gnome
4 # Copyright 2004 Mikko Rauhala <mjr@iki.fi>
5
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 # This will be overwritten for the installed version:
21 SHAREDIR = "."
22
23 VERSION="0.9.0"
24
25 import os
26 import sys
27
28 import pygtk
29 pygtk.require("2.0")
30
31 import gtk
32 import gnomecanvas
33 import gnome
34 import gnome.ui
35 import gobject
36 import gtk.glade
37
38 import gettext
39
40 import random
41
42 class Hextris:
43 def __init__(self):
44 self.pieceheight = 24
45 self.piecewidth = 26
46 self.piecenarrow = 14
47 # self.piecewidth = 20
48 # self.piecenarrow = 20
49 self.rows = 23
50 self.cols = 13 # Must be odd or weirdness ensues
51
52 self.width = (((self.cols/2)+2)*self.piecewidth +
53 ((self.cols/2)+1) * self.piecenarrow) + 2
54 self.height = (self.rows+1) * self.pieceheight + 2
55
56 self.colors = ("blue", "yellow", "red", "orange", "green", "purple",
57 "cyan", "gray45", "magenta", "lightblue")
58 self.deltax = (-1, -1, -1, 0, 0, 0, 0, 0, -1, -1)
59 self.deltay = (-1, -1, -1, 0, 0, 0, 0, 0, -1, -1)
60 self.pieces = (
61 (((0,), (0, 0, 1), (0, 0, 1), (0, 0, 1), (0, 0, 1)),
62 ((0,), (0, 0, 0, 1), (0, 1, 1), (1,)),
63 ((0,), (1, 1), (0, 0, 1, 1)),
64 ((0, 0, 1), (0, 0, 1), (0, 0, 1), (0, 0, 1)),
65 ((0,), (0, 0, 0, 1, 1), (0, 1, 1)),
66 ((0,), (0, 1), (0, 0, 1, 1), (0, 0, 0, 0, 1))),
67 (((0,), (0, 0, 1), (0, 0, 1, 1), (0, 0, 0, 1)),
68 ((0,), (0, 0, 0, 1), (0, 0, 1), (0, 1, 1)),
69 ((0,), (0,), (1, 1, 1, 1)),
70 ((0, 1), (0, 1), (0, 0, 1), (0, 0, 1)),
71 ((0, 0, 0, 1), (0, 0, 1), (0, 1, 1)),
72 ((0,), (0, 1, 0, 1), (0, 0, 1, 0, 1))),
73 (((0,), (0, 0, 1), (0, 1, 1), (0, 1)),
74 ((0,), (0, 1, 0, 1), (1, 0, 1, 0)),
75 ((0, 1), (0, 0, 1), (0, 0, 1, 1)),
76 ((0, 0, 0, 1), (0, 0, 0, 1), (0, 0, 1), (0, 0, 1)),
77 ((0,), (0,), (0, 1, 1, 1, 1)),
78 ((0,), (0, 1), (0, 0, 1), (0, 0, 1, 1))),
79 (((0, 1, 0), (0, 1, 0), (1, 0, 1)),
80 ((0,), (1, 1, 1), (0, 1, 0))),
81 (((0, 1), (1,), (1, 1)),
82 ((0, 1), (1, 0, 1), (1,)),
83 ((0, 1), (1, 0, 1), (0, 0, 1)),
84 ((0, 1), (0, 0, 1), (0, 1, 1)),
85 ((0,), (0, 0, 1), (1, 1, 1)),
86 ((0,), (1,), (1, 1, 1))),
87 (((0,), (0, 1), (1, 1, 1)),
88 ((0,), (1, 1), (1, 1, 0)),
89 ((0, 1), (1, 1), (1,)),
90 ((0, 1), (1, 1, 1)),
91 ((0, 1), (0, 1, 1), (0, 0, 1)),
92 ((0,), (0, 1, 1), (0, 1, 1))),
93 (((0, 1), (0, 1), (0, 1, 1)),
94 ((0,), (0, 1, 1), (1, 1)),
95 ((0,), (1, 1), (1, 0, 1)),
96 ((0, 1), (1, 1), (0, 1)),
97 ((0, 1), (0, 1, 1), (1,)),
98 ((0,), (1, 1, 1), (0, 0, 1))),
99 (((0, 1), (0, 1), (1, 1)),
100 ((0,), (1, 1, 1), (1,)),
101 ((0, 1), (1, 1), (0, 0, 1)),
102 ((0, 1), (0, 1, 1), (0, 1)),
103 ((0,), (0, 1, 1), (1, 0, 1)),
104 ((0,), (1, 1), (0, 1, 1))),
105 (((0,), (0, 0, 1), (0, 0, 1), (0, 0, 1, 1)),
106 ((0,), (0, 0, 0, 1), (0, 1, 1), (0, 1)),
107 ((0,), (0, 1), (1, 0, 1, 1)),
108 ((0, 1), (0, 0, 1), (0, 0, 1), (0, 0, 1)),
109 ((0, 0, 0, 1), (0, 0, 0, 1), (0, 1, 1)),
110 ((0,), (0, 1), (0, 0, 1, 1, 1))),
111 (((0,), (0, 0, 1), (0, 0, 1), (0, 1, 1)),
112 ((0,), (0, 0, 0, 1), (1, 1, 1)),
113 ((0, 1), (0, 1), (0, 0, 1, 1)),
114 ((0, 0, 0, 1), (0, 0, 1), (0, 0, 1), (0, 0, 1)),
115 ((0,), (0, 0, 0, 1), (0, 1, 1, 0, 1)),
116 ((0,), (0, 1), (0, 0, 1, 1), (0, 0, 0, 1)))
117 )
118
119 self.attitude = 0
120 self.speed_orig = 400
121 self.speed = 400
122 self.speed_ratio = 0.99
123 self.speed_reset = False
124 self.paused = False
125 self.lost = True
126 self.score = 0
127 self.hiscore = 0
128 self.nextnum = 0
129
130 self.running = False
131
132 self.nextpiece = False
133 self.board = False
134 self.rowgroups = []
135
136 def draw_hexagon(self, group, color):
137 pts = []
138 pts.append ((self.piecewidth - self.piecenarrow)/2)
139 pts.append (0)
140 pts.append (self.piecewidth - pts[0])
141 pts.append (0)
142 pts.append (self.piecewidth)
143 pts.append (self.pieceheight/2)
144 pts.append (pts[2])
145 pts.append (self.pieceheight)
146 pts.append (pts[0])
147 pts.append (pts[7])
148 pts.append (0)
149 pts.append (pts[5])
150 pts.append (pts[0])
151 pts.append (pts[1])
152 item = group.add ("GnomeCanvasPolygon", points = pts, fill_color = color,
153 outline_color = "black", width_units = 1)
154 return item
155
156 def draw_piece(self, group, matrix, color):
157 for i in range(len(matrix)):
158 for j in range(len(matrix[i])):
159 if matrix[i][j] != 0:
160 g = group.add("GnomeCanvasGroup",
161 x = (j*(self.piecewidth+self.piecenarrow)/2),
162 y = ((i * (self.pieceheight)) +
163 ((j%2) * self.pieceheight/2)))
164 self.draw_hexagon(g, color)
165
166 def place_piece(self, group, matrix, color, x, y):
167 piecegroup = group.add("GnomeCanvasGroup",
168 x = (x+1)*((self.piecewidth+self.piecenarrow)/2),
169 y = ((y * self.pieceheight) -
170 (((x%2)+1) * self.pieceheight/2)))
171 self.draw_piece(piecegroup, matrix, color)
172 return piecegroup
173
174 def init_board(self):
175 board = self.canvas.root()
176 for i in range(self.rows+1):
177 for j in [0, 1]:
178 boardhex = board.add("GnomeCanvasGroup",
179 x = j * (self.piecewidth*(self.cols/2+1) +
180 self.piecenarrow*(self.cols/2+1)),
181 y = i * self.pieceheight)
182 self.draw_hexagon(boardhex, "gray")
183 for i in range(self.cols/2):
184 boardhex = board.add("GnomeCanvasGroup",
185 x = (i+1) * (self.piecewidth +
186 self.piecenarrow),
187 y = self.rows * self.pieceheight)
188 self.draw_hexagon(boardhex, "gray")
189 for i in range(self.cols/2+1):
190 boardhex = board.add("GnomeCanvasGroup",
191 x = (i * (self.piecewidth + self.piecenarrow)+
192 (self.piecewidth + self.piecenarrow)/2),
193 y = ((self.rows*2-1) * self.pieceheight)/2)
194 self.draw_hexagon(boardhex, "gray")
195
196 def on_new_activate(self, event):
197 self.speed = self.speed_orig
198 self.score = 0
199 self.attitude = 0
200 self.lost = False
201 self.paused = False
202
203 self.update_appbar()
204
205 if self.board != False:
206 self.board.destroy()
207 self.board = self.canvas.root().add("GnomeCanvasGroup", x = 0, y = 0)
208
209 self.field = []
210 for i in range(self.rows):
211 self.field.append([])
212 for j in range(self.cols):
213 self.field[i].append(0)
214
215 self.rowgroups = []
216 for i in range(self.rows):
217 self.rowgroups.append(self.board.add("GnomeCanvasGroup", x = 0,
218 y = i * self.pieceheight))
219
220 self.nextnum = random.randint(0, 9)
221 self.next_piece()
222
223 if self.running == False:
224 gobject.timeout_add(self.speed, self.timer_handler)
225 self.running = True
226 else:
227 self.speed_reset = True
228
229 return True
230
231 def on_about_activate(self, event):
232 aTree = gtk.glade.XML(self.glade, "about")
233 about = aTree.get_widget("about")
234 about.set_property("name", "Ghextris")
235 about.set_property("version", VERSION)
236 return True
237
238 def on_pause_game_activate(self, event):
239 if self.lost == True:
240 return False
241 if self.paused == True:
242 self.paused = False
243 else:
244 self.paused = True
245 return True
246
247 def on_quit_activate(self, event):
248 gtk.main_quit()
249
250 def main(self):
251 gnome.init("Ghextris", VERSION)
252 gettext.install("ghextris")
253 self.glade = os.path.join(SHAREDIR, "ghextris.glade")
254
255 wTree = gtk.glade.XML(self.glade, "GhextrisApp")
256 dic = {"on_new_activate": self.on_new_activate,
257 "on_pause_game_activate": self.on_pause_game_activate,
258 "on_quit_activate": self.on_quit_activate,
259 "on_about_activate": self.on_about_activate}
260 wTree.signal_autoconnect(dic)
261
262 win = wTree.get_widget("GhextrisApp")
263 self.canvas = wTree.get_widget("canvas")
264 preview = wTree.get_widget("previewcanvas")
265 appbar = wTree.get_widget("appbar").get_children()[0]
266 self.appbar = appbar.get_children()[0]
267
268 win.connect('destroy', self.on_quit_activate)
269
270 self.canvas.set_size_request(self.width, self.height)
271 self.canvas.set_scroll_region(0, 0, self.width, self.height)
272 self.canvas.show()
273
274 preview.set_size_request(self.piecewidth * 4, self.pieceheight * 5)
275 preview.show()
276 self.preview = preview.root()
277
278 win.connect("key-press-event", self.key_handler)
279 self.init_board()
280
281 random.seed()
282
283 self.update_appbar()
284
285 win.show()
286
287 def next_piece(self):
288 self.piecenum = self.nextnum
289 self.nextnum = random.randint(0, 9)
290 self.attitude = 0
291 self.piece_x = (self.cols/2)-1 + self.deltax[self.piecenum]
292 self.piece_y = -3 + self.deltax[self.piecenum]
293 self.piece = self.place_piece(self.board, self.pieces[self.piecenum][0],
294 self.colors[self.piecenum%(len(self.colors)+1)],
295 self.piece_x, self.piece_y)
296
297 if self.nextpiece != False:
298 self.nextpiece.destroy()
299 self.nextpiece = self.place_piece(self.preview,
300 self.pieces[self.nextnum][0],
301 self.colors[self.nextnum%(len(self.colors)+1)],
302 self.deltax[self.nextnum],
303 self.deltay[self.nextnum])
304
305 def timer_handler(self):
306 if self.lost == True:
307 self.running = False
308 return False
309
310 if self.paused == True:
311 return True
312 self.piece_y += 1
313
314 if self.check_collisions() == True:
315 self.piece_y -= 1
316 self.update_field()
317 if self.top_occupied() != True:
318 self.next_piece()
319 else:
320 self.lost = True
321 if self.hiscore < self.score:
322 self.hiscore = self.score
323 self.update_appbar()
324 self.running = False
325 return False
326 else:
327 self.piece.move(0, self.pieceheight)
328
329 if self.speed_reset == True:
330 self.speed_reset = False
331 gobject.timeout_add(int(self.speed), self.timer_handler)
332 return False
333
334 return True
335
336 def update_appbar(self):
337 self.appbar.set_text("%s: %d | %s: %d" % (_("Score"), self.score,
338 _("High score"),
339 self.hiscore))
340
341 def key_handler(self, widget, event=None):
342 if self.lost == True:
343 return False
344
345 if event.keyval == gtk.keysyms.p and self.lost == False:
346 if self.paused == True:
347 self.paused = False
348 else:
349 self.paused = True
350 return True
351
352 if self.paused == True:
353 return False
354
355 if event.keyval == gtk.keysyms.Up or event.keyval == gtk.keysyms.Down:
356 if event.keyval == gtk.keysyms.Up:
357 attitude_change = 1
358 else:
359 attitude_change = -1
360 old_attitude = self.attitude
361 self.attitude = ((self.attitude + attitude_change +
362 len(self.pieces[self.piecenum])) %
363 len(self.pieces[self.piecenum]))
364 if self.check_collisions() == True:
365 self.attitude = old_attitude
366 return True
367
368 self.piece.destroy()
369 self.piece = self.place_piece(self.board,
370 self.pieces[self.piecenum][self.attitude],
371 self.colors[self.piecenum%(len(self.colors)+1)],
372 self.piece_x, self.piece_y);
373 return True
374
375 if event.keyval == gtk.keysyms.Left or event.keyval == gtk.keysyms.Right:
376 if event.keyval == gtk.keysyms.Left:
377 deltax = -1
378 else:
379 deltax = 1
380 self.piece_x += deltax
381
382 deltay = 0
383 if self.piece_x%2 == 0:
384 deltay += self.pieceheight/2
385 else:
386 deltay -= self.pieceheight/2
387
388 if self.check_collisions() == True:
389 if deltay > 0:
390 self.piece_x -= deltax
391 return True
392 self.piece_y += 1
393 deltay += self.pieceheight
394 if self.check_collisions() == True:
395 self.piece_x -= deltax
396 self.piece_y -= 1
397 return True
398
399 self.piece.move(deltax*(self.piecewidth+self.piecenarrow)/2, deltay)
400 return True
401
402 if event.keyval == gtk.keysyms.space:
403 orig_piece_y = self.piece_y
404 while self.check_collisions() == False:
405 self.piece_y += 1
406 self.piece_y -= 1
407 self.piece.move(0, self.pieceheight*(self.piece_y - orig_piece_y))
408 self.score += self.piece_y - orig_piece_y
409 if self.score > self.hiscore:
410 self.hiscore = self.score
411 self.update_field()
412 if self.top_occupied() != True:
413 self.next_piece()
414 else:
415 self.lost = True
416 if self.hiscore < self.score:
417 self.hiscore = self.score
418 self.update_appbar()
419
420 return True
421
422 return False
423
424 def check_collisions(self):
425 for i in range(len(self.pieces[self.piecenum][self.attitude])):
426 for j in range(len(self.pieces[self.piecenum][self.attitude][i])):
427 if self.pieces[self.piecenum][self.attitude][i][j] != 0:
428 if j%2 == 0 and self.piece_x%2 == 1:
429 deltay = -1
430 else:
431 deltay = 0
432 if j + self.piece_x < 0 or j + self.piece_x >= self.cols:
433 return True
434 if ((i + self.piece_y + deltay > 0) and
435 (i + self.piece_y + deltay >= self.rows or
436 self.field[i + self.piece_y + deltay][j + self.piece_x] != 0)):
437 return True
438 return False
439
440 def update_field(self):
441 for i in range(len(self.pieces[self.piecenum][self.attitude])):
442 for j in range(len(self.pieces[self.piecenum][self.attitude][i])):
443 if self.pieces[self.piecenum][self.attitude][i][j] != 0:
444 if j%2 == 0 and self.piece_x%2 == 1:
445 deltay = -1
446 else:
447 deltay = 0
448 if i+self.piece_y+deltay >= 0:
449 self.field[i + self.piece_y + deltay][j + self.piece_x] = 1
450 self.place_piece(self.rowgroups[i+self.piece_y+deltay],
451 ((0, 1,),),
452 self.colors[self.piecenum%(len(self.colors)+1)],
453 j + self.piece_x - 1, 0)
454 self.piece.destroy()
455 self.collapse_rows()
456
457 def collapse_rows(self):
458 row_points = 50
459 for i in range(self.rows):
460 row_full = True
461 for j in range(self.cols):
462 if self.field[i][j] == 0:
463 row_full = False
464 break
465
466 if row_full == True:
467 row_points *= 2
468 self.speed *= self.speed_ratio
469 self.speed_reset = True
470 self.rowgroups[i].destroy()
471 for j in range(i-1, -1, -1):
472 self.rowgroups[j].move(0, self.pieceheight)
473 self.rowgroups[j+1] = self.rowgroups[j]
474 self.field[j+1] = self.field[j]
475 self.field[0] = []
476 for j in range(self.cols):
477 self.field[0].append(0)
478 self.rowgroups[0] = self.board.add("GnomeCanvasGroup", x = 0,
479 y = 0)
480 if row_points > 50:
481 self.score += row_points
482 if self.score > self.hiscore:
483 self.hiscore = self.score
484 self.update_appbar()
485
486 def top_occupied(self):
487 for i in range(self.cols):
488 if self.field[0][i] != 0:
489 return True
490 return False
491
492 if __name__ == '__main__':
493 h = Hextris()
494 h.main()
495 gtk.main()