~ubuntu-branches/ubuntu/maverick/gcompris/maverick

« back to all changes in this revision

Viewing changes to src/boards/python/gnumch.py

  • Committer: Bazaar Package Importer
  • Author(s): Marc Gariepy, Marc Gariepy, Stephane Graber
  • Date: 2010-01-04 17:42:49 UTC
  • mfrom: (1.1.14 upstream)
  • Revision ID: james.westby@ubuntu.com-20100104174249-7bupatd9dtxyhvs4
Tags: 9.0-0ubuntu1
[Marc Gariepy]
* New upstream release (9.0).
* Remove cache.c from POTFILES to avoid FTBFS
* Remove unneeded rm in debian/rules (file no longer exists upstream)

[Stephane Graber]
* Bump Debian standards to 3.8.3
* Add patch system (dpatch)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: utf-8 -*-
2
 
#  gcompris - gnumch
3
 
#
4
 
# Time-stamp: <2007-08-22 01:26:11 bruno>
5
 
#
6
 
# Copyright (C) 2005 Joe Neeman
7
 
#
8
 
#   This program is free software; you can redistribute it and/or modify
9
 
#   it under the terms of the GNU General Public License as published by
10
 
#   the Free Software Foundation; either version 3 of the License, or
11
 
#   (at your option) any later version.
12
 
#
13
 
#   This program is distributed in the hope that it will be useful,
14
 
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
#   GNU General Public License for more details.
17
 
#
18
 
#   You should have received a copy of the GNU General Public License
19
 
#   along with this program; if not, see <http://www.gnu.org/licenses/>.
20
 
#
21
 
 
22
 
import gobject
23
 
import gnomecanvas
24
 
import gcompris
25
 
import gcompris.utils
26
 
import gcompris.skin
27
 
import gcompris.bonus
28
 
import gcompris.score
29
 
import gcompris.anim
30
 
import gcompris.sound
31
 
import gobject
32
 
import gtk
33
 
import gtk.gdk
34
 
import random
35
 
import math
36
 
from gcompris import gcompris_gettext as _
37
 
 
38
 
class Number:
39
 
    def __init__(self, text, good):
40
 
        self.text = text
41
 
        self.good = good
42
 
 
43
 
class Square:
44
 
    def __init__(self, x, y):
45
 
        self.num = None
46
 
        self.pic = game.rootitem.add( gnomecanvas.CanvasText,
47
 
                                      text = "",
48
 
                                      font = gcompris.skin.get_font("gcompris/content"),
49
 
                                      x = x,
50
 
                                      y = y )
51
 
 
52
 
    def setNum(self, num):
53
 
        self.num = num
54
 
        if num != None:
55
 
            self.pic.set( text = num.text )
56
 
        else:
57
 
            self.pic.set( text = "" )
58
 
 
59
 
class Level:
60
 
    def __init__(self, title, numlist):
61
 
        self.title = title
62
 
        self.numbers = numlist
63
 
 
64
 
# the following class goes unused: is is only here to document the Levelset interface.
65
 
class Levelset:
66
 
    def __init__(self):
67
 
        pass
68
 
 
69
 
    def getError(self, num):
70
 
        pass
71
 
 
72
 
    def getTitle(self):
73
 
        pass
74
 
 
75
 
    def setLevel(self, level, sublevel):
76
 
        pass
77
 
 
78
 
    def getNumber(self):
79
 
        pass
80
 
 
81
 
def isPrime(n):
82
 
    if n == 1:
83
 
        return 0
84
 
    for i in range(2, int(math.sqrt(n) + 1) ):
85
 
        if (n % i) == 0:
86
 
            return 0
87
 
    return 1
88
 
 
89
 
def makeNumList(nums):
90
 
    if len(nums) == 0:
91
 
        return ""
92
 
    fmt = '%d'
93
 
    if len(nums) >= 2:
94
 
        for i in range(1, len(nums)-1):
95
 
            fmt += _(', %d')
96
 
        fmt += _(' and %d')
97
 
    return fmt
98
 
 
99
 
def getFactors(n):
100
 
    f = []
101
 
    for i in range(1, n/2 + 1):
102
 
        if n%i == 0:
103
 
            f.append(i)
104
 
    f.append(n)
105
 
    return f
106
 
 
107
 
class PrimeLevelset:
108
 
    def __init__(self):
109
 
        self.numlevels = 1
110
 
        self.num_sublevels = 9
111
 
        self.level_max = [ 3, 5, 7, 11, 13, 17, 19, 23, 29 ]
112
 
        self.curlevel = 1
113
 
        self.cur_sublevel = 1
114
 
 
115
 
    def getError(self, num):
116
 
        fmt = _('%d is divisible by %s.')
117
 
        n = int(num.text)
118
 
 
119
 
        if n == 1:
120
 
            return _("1 is not a prime number.")
121
 
 
122
 
        factors = []
123
 
        for i in range(2, n/2 + 1):
124
 
            if n % i == 0:
125
 
                factors.append(i)
126
 
        s = makeNumList(factors) % tuple(factors)
127
 
        return fmt % (n,s)
128
 
 
129
 
    def getTitle(self):
130
 
        return _('Primes less than %d') % ( self.level_max[self.cur_sublevel-1] + 1 )
131
 
 
132
 
    def setLevel(self, level, sublevel):
133
 
        self.cur_sublevel = level
134
 
        self.cur_sublevel = sublevel
135
 
 
136
 
    def getNumber(self):
137
 
        n = random.randint( 1, self.level_max[self.cur_sublevel-1] )
138
 
        return Number( str(n), isPrime(n) )
139
 
 
140
 
class FactorLevelset:
141
 
    def __init__(self):
142
 
        self.num_sublevels = 9
143
 
        self.numlevels = 1
144
 
        self.level_multiple = [ 4, 6, 8, 10, 12, 15, 18, 20, 24 ]
145
 
        self.curlevel = 1
146
 
        self.cur_sublevel = 1
147
 
        self.factors = []
148
 
        self.nonfactors = []
149
 
 
150
 
    def getError(self, num):
151
 
        # Translators: You can swap %(x)y elements in the string.
152
 
        fmt = _('Multiples of %(d1)d include %(s)s,\nbut %(d2)d is not a multiple of %(d3)d.')
153
 
        n = int(num.text)
154
 
        mults = []
155
 
        for i in range(2, 5):
156
 
            mults.append(n*i)
157
 
        return fmt % { 'd1': n,
158
 
                       's': makeNumList(mults) % tuple(mults),
159
 
                       'd2': self.level_multiple[self.cur_sublevel-1],
160
 
                       'd3': n }
161
 
 
162
 
    def getTitle(self):
163
 
        return _('Factors of %d') % ( self.level_multiple[self.cur_sublevel-1] )
164
 
 
165
 
    def setLevel(self, level, sublevel):
166
 
        self.curlevel = level
167
 
        self.cur_sublevel = sublevel
168
 
        self.factors = []
169
 
        self.nonfactors = []
170
 
        for i in range(1, self.level_multiple[sublevel-1]+1):
171
 
            if self.level_multiple[sublevel-1] % i == 0:
172
 
                self.factors.append(i)
173
 
            else:
174
 
                self.nonfactors.append(i)
175
 
 
176
 
    def getNumber(self):
177
 
        if random.randint(0,1):
178
 
            # choose a good number
179
 
            n = self.factors[ random.randint(0, len(self.factors)-1) ]
180
 
            num = Number( str(n), 1 )
181
 
        else:
182
 
            # choose a wrong number
183
 
            n = self.nonfactors[ random.randint(0, len(self.nonfactors)-1) ]
184
 
            num = Number( str(n), 0 )
185
 
        return num
186
 
 
187
 
class MultipleLevelset:
188
 
    def __init__(self):
189
 
        self.numlevels = 4
190
 
        self.num_sublevels = 9
191
 
        self.min_mult = 4
192
 
        self.curlevel = 1
193
 
        self.cur_sublevel = 1
194
 
 
195
 
    def getError(self, num):
196
 
        fmt = _('%s are the factors of %d.')
197
 
        n = int(num.text)
198
 
 
199
 
        factors = []
200
 
        for i in range(1, n/2+1):
201
 
            if n % i == 0:
202
 
                factors.append(i)
203
 
        factors.append(n)
204
 
        s = makeNumList(factors) % tuple(factors)
205
 
        return fmt % (s, n)
206
 
 
207
 
    def getTitle(self):
208
 
        return _('Multiples of %d') % ( self.cur_sublevel+1 )
209
 
 
210
 
    def setLevel(self, level, sublevel):
211
 
        self.curlevel = level
212
 
        self.cur_sublevel = sublevel
213
 
 
214
 
    def getNumber(self):
215
 
        if random.randint(0,1):
216
 
            # choose a good number
217
 
            n = (self.cur_sublevel+1) * random.randint(1, self.min_mult + self.curlevel*2)
218
 
            num = Number( str(n), 1 )
219
 
        else:
220
 
            # choose a wrong number
221
 
            n = (self.cur_sublevel+1) * random.randint(1, self.min_mult + self.curlevel*2) - random.randint(1, self.cur_sublevel)
222
 
            num = Number( str(n), 0 )
223
 
        return num
224
 
 
225
 
# for all expression-based levels, we add a value field to the Number
226
 
class ExpressionLevelset(object):
227
 
    def __init__(self):
228
 
        self.numlevels = 7
229
 
        self.num_sublevels = 7
230
 
        self.levelops = [ [self.getPlus],
231
 
                          [self.getMinus],
232
 
                          [self.getPlus, self.getMinus],
233
 
                          [self.getTimes],
234
 
                          [self.getPlus, self.getMinus, self.getTimes],
235
 
                          [self.getDivide],
236
 
                          [self.getPlus, self.getMinus, self.getTimes, self.getDivide]
237
 
                        ]
238
 
        self.curlevel = 1
239
 
        self.cur_sublevel = 1
240
 
 
241
 
    def getError(self, num):
242
 
        fmt = _('%s = %d')
243
 
        return fmt % (num.text, num.value)
244
 
 
245
 
    def getNumberWithAnswer(self, answer):
246
 
        fn = random.choice( self.levelops[self.curlevel-1] )
247
 
        num = fn(answer)
248
 
        num.value = answer
249
 
        return num
250
 
 
251
 
    def getPlus(self, answer):
252
 
        n = random.randint(0, answer)
253
 
        num = Number( _(u'%d + %d') % (n, answer-n), 1 )
254
 
        return num
255
 
 
256
 
    def getMinus(self, answer):
257
 
        n = random.randint(answer, answer*2)
258
 
        num = Number( _(u'%d \u2212 %d') % (n, n-answer), 1 )
259
 
        return num
260
 
 
261
 
    def getTimes(self, answer):
262
 
        n = random.choice( getFactors(answer) )
263
 
        return Number( _(u'%d \u00d7 %d') % (n, answer/n), 1 )
264
 
 
265
 
    def getDivide(self, answer):
266
 
        n = random.randint(1, 5)
267
 
        return Number( _(u'%d \u00f7 %d') % (answer*n, n), 1 )
268
 
 
269
 
class EqualityLevelset(ExpressionLevelset):
270
 
    def __init__(self):
271
 
        super(EqualityLevelset, self).__init__()
272
 
        self.answermin = 5
273
 
 
274
 
    def getTitle(self):
275
 
        return _('Equal to %d') % (self.answer,)
276
 
 
277
 
    def setLevel(self, level, sublevel):
278
 
        self.curlevel = level
279
 
        self.cur_sublevel = sublevel
280
 
        self.answer = self.answermin + self.cur_sublevel
281
 
 
282
 
    def getNumber(self):
283
 
        if random.randint(0, 1):
284
 
            # correct number
285
 
            num = self.getNumberWithAnswer(self.answer)
286
 
            num.good = 1
287
 
        else:
288
 
            # wrong number
289
 
            ans = random.choice( range(self.answermin, self.answer) + range(self.answer+1, self.answer*2) )
290
 
            num = self.getNumberWithAnswer(ans)
291
 
            num.good = 0
292
 
        return num
293
 
 
294
 
class InequalityLevelset(EqualityLevelset):
295
 
    def getTitle(self):
296
 
        return _('Not equal to %d') % (self.answer,)
297
 
 
298
 
    def getNumber(self):
299
 
        num = super(InequalityLevelset, self).getNumber()
300
 
        if num.good:
301
 
            num.good = 0
302
 
        else:
303
 
            num.good = 1
304
 
        return num
305
 
 
306
 
class Player(object):
307
 
 
308
 
    def __init__(self):
309
 
        self.move_stepnum = 0
310
 
        self.x = self.y = self.x_old = self.y_old = -1
311
 
        self.moving = self.exists = False
312
 
        self.action_start = 0
313
 
        self.anim = None
314
 
        self.velocity = []
315
 
 
316
 
        self.movestep_timer = 0
317
 
        self.munch_timer = 0
318
 
 
319
 
        # food chain status
320
 
        self.foodchain = 0
321
 
 
322
 
    # These are defined in Muncher and Troggle
323
 
    def spawn(self):
324
 
        pass
325
 
 
326
 
    def die(self):
327
 
        if self.movestep_timer != 0:
328
 
            gobject.source_remove(self.movestep_timer)
329
 
            self.movestep_timer = 0
330
 
        if self.munch_timer != 0:
331
 
            gobject.source_remove(self.munch_timer)
332
 
            self.munch_timer = 0
333
 
 
334
 
    def getEaten(self):
335
 
        pass
336
 
 
337
 
    def isAt(self, x, y):
338
 
        return self.exists and not self.moving and (self.x == x and self.y == y)
339
 
 
340
 
    def isNear(self, x, y):
341
 
        return self.exists and (    (self.x == x and self.y == y)
342
 
                                or  (self.moving and self.x_old == x
343
 
                                                 and self.y_old == y)
344
 
                               )
345
 
 
346
 
    def move_step(self):
347
 
        if self.move_stepnum < game.num_moveticks-1:
348
 
            self.move_stepnum += 1
349
 
            x_old = self.anim.gnomecanvas.get_property("x")
350
 
            y_old = self.anim.gnomecanvas.get_property("y")
351
 
            x = self.anim.gnomecanvas.get_property("x") + self.velocity[0]*game.sw/game.num_moveticks
352
 
            y = self.anim.gnomecanvas.get_property("y") + self.velocity[1]*game.sh/game.num_moveticks
353
 
            ret = True
354
 
        else:
355
 
            self.move_stepnum = 0
356
 
            x = game.sw * self.x + game.left
357
 
            y = game.sh * self.y + game.top
358
 
            self.stop()
359
 
            self.movestep_timer = 0
360
 
            ret = False
361
 
 
362
 
        self.anim.gnomecanvas.set(x=x, y=y)
363
 
        return ret
364
 
 
365
 
    def move(self, x_old, y_old, x, y):
366
 
        gcompris.sound.play_ogg("sounds/smudge.wav")
367
 
        self.x_old = x_old
368
 
        self.y_old = y_old
369
 
        self.x = x
370
 
        self.y = y
371
 
        self.velocity = [x-x_old, y-y_old]
372
 
        self.anim.gnomecanvas.set(x=(self.x_old * game.sw + game.left),
373
 
                                   y=(self.y_old * game.sh + game.top))
374
 
        self.moving = True
375
 
 
376
 
        # it takes game.num_moveticks iterations of duration game.move_tick to move squares
377
 
        if x != x_old or y != y_old:
378
 
            self.anim.setState(1)
379
 
            self.movestep_timer = game.timeout_add(game.move_tick, self.move_step)
380
 
        else:
381
 
            self.stop()
382
 
 
383
 
    def startMunching(self):
384
 
        gcompris.sound.play_ogg("sounds/eat.wav")
385
 
        self.anim.setState(2)
386
 
        self.munch_timer = game.timeout_add(game.munch_time, self.stopMunching)
387
 
        return False
388
 
 
389
 
    def stopMunching(self):
390
 
        self.munch_timer = 0
391
 
        self.anim.setState(0)
392
 
        return False
393
 
 
394
 
    def stop(self):
395
 
        self.anim.setState(0)
396
 
        self.moving = False
397
 
 
398
 
        # work out eating stuff
399
 
        for p in game.players:
400
 
            if p.isAt(self.x, self.y) and p != self:
401
 
                if self.foodchain >= p.foodchain:
402
 
                    p.getEaten()
403
 
                    self.startMunching()
404
 
                else:
405
 
                    self.getEaten()
406
 
                    p.startMunching()
407
 
 
408
 
 
409
 
class Muncher(Player):
410
 
    def __init__(self):
411
 
        super(Muncher, self).__init__()
412
 
        self.lives = 1
413
 
        self.anim = gcompris.anim.CanvasItem(game.munchanimation, game.rootitem)
414
 
        self.spare = gcompris.anim.CanvasItem(game.munchanimation, game.rootitem)
415
 
        self.anim.gnomecanvas.hide()
416
 
        self.key_queue = []
417
 
        self.spare.gnomecanvas.set(x=0, y=0)
418
 
 
419
 
    def spawn(self):
420
 
        if self.lives >= 1:
421
 
            self.spare.gnomecanvas.show()
422
 
        elif self.lives == 0:
423
 
            self.spare.gnomecanvas.hide()
424
 
        else:
425
 
            game.loseGame()
426
 
        self.key_queue = []
427
 
        game.hide_message()
428
 
        self.exists = True
429
 
        self.move(0,0,0,0)
430
 
        self.anim.gnomecanvas.show()
431
 
 
432
 
    def die(self):
433
 
        super(Muncher, self).die()
434
 
        self.lives -= 1
435
 
        self.exists = False
436
 
        self.anim.gnomecanvas.hide()
437
 
        self.key_queue = []
438
 
 
439
 
    def getEaten(self):
440
 
        game.show_message( _("You were eaten by a Troggle.\nPress <Return> to continue.") )
441
 
        self.die()
442
 
 
443
 
    def push_key(self, key):
444
 
        if self.exists:
445
 
            if self.moving:
446
 
                self.key_queue.append(key)
447
 
            elif len(self.key_queue) == 0:
448
 
                self.handle_key(key)
449
 
            else:
450
 
                self.key_queue.append(key)
451
 
                self.handle_key(self.key_queue.pop(0))
452
 
        else:
453
 
            if key == gtk.keysyms.Return:
454
 
                self.spawn()
455
 
 
456
 
    def handle_key(self, key):
457
 
        if key == gtk.keysyms.Left:
458
 
            if self.x > 0:
459
 
                self.move(self.x, self.y, (self.x-1), self.y)
460
 
            else:
461
 
                self.stop()
462
 
        elif key == gtk.keysyms.Right:
463
 
            if self.x < game.width - 1:
464
 
                self.move(self.x, self.y, (self.x+1), self.y)
465
 
            else:
466
 
                self.stop()
467
 
        elif key == gtk.keysyms.Up:
468
 
            if self.y > 0:
469
 
                self.move(self.x, self.y, self.x, (self.y-1))
470
 
            else:
471
 
                self.stop()
472
 
        elif key == gtk.keysyms.Down:
473
 
            if self.y < game.height - 1:
474
 
                self.move(self.x, self.y, self.x, (self.y+1))
475
 
            else:
476
 
                self.stop()
477
 
        elif key == gtk.keysyms.space:
478
 
            self.munch()
479
 
            if len( self.key_queue ) > 0: # we don't need to wait for munching to finish to start the next action
480
 
                self.handle_key( self.key_queue.pop(0) )
481
 
 
482
 
    def munch(self):
483
 
        num = game.squares[self.x][self.y].num
484
 
        if num == None:
485
 
            return
486
 
        if num.good:
487
 
            self.startMunching()
488
 
        else:
489
 
            game.show_message( _("You ate a wrong number.\n") +game.levelset.getError(num) +
490
 
                               _("\nPress <Return> to continue.") )
491
 
            self.die()
492
 
        game.setNum(self.x, self.y, None)
493
 
 
494
 
    def stop(self):
495
 
        super(Muncher, self).stop()
496
 
        if len(self.key_queue) > 0:
497
 
            key = self.key_queue.pop(0)
498
 
            self.handle_key(key)
499
 
 
500
 
 
501
 
class Troggle(Player):
502
 
    def __init__(self):
503
 
        super(Troggle, self).__init__()
504
 
        self.anim = gcompris.anim.CanvasItem(game.munchanimation, game.rootitem)
505
 
 
506
 
        self.nextspawn_timer = 0
507
 
        self.nextmove_timer = 0
508
 
        self.warn_timer = 0
509
 
 
510
 
        self.foodchain = 1
511
 
 
512
 
    def spawn(self):
513
 
        self.nextspawn_timer = 0
514
 
        self.warn_timer = 0
515
 
        self.exists = True
516
 
        index = random.randint(0, (len( game.troganimation )-1) * game.board.sublevel / game.board.number_of_sublevel)
517
 
        self.anim.swapAnimation(game.troganimation[index])
518
 
        self.getMove = game.trogmoves[index]
519
 
        self.onMove = game.onmove[index]
520
 
        self.onStop = game.onstop[index]
521
 
        if random.randint(0,1) == 0:
522
 
            if random.randint(0,1) == 0:
523
 
                self.x_old = -1
524
 
                self.x = 0
525
 
            else:
526
 
                self.x_old = game.width
527
 
                self.x = game.width - 1
528
 
            self.y = self.y_old = random.randint(0, game.height-1)
529
 
        else:
530
 
            if random.randint(0,1) == 0:
531
 
                self.y_old = -1
532
 
                self.y = 0
533
 
            else:
534
 
                self.y_old = game.height
535
 
                self.y = game.height - 1
536
 
            self.x = self.x_old = random.randint(0, game.width-1)
537
 
        self.move(self.x_old, self.y_old, self.x, self.y)
538
 
        self.anim.gnomecanvas.show()
539
 
        game.hide_trogwarning()
540
 
 
541
 
    def die(self):
542
 
        super(Troggle, self).die()
543
 
        self.exists = 0
544
 
        self.anim.gnomecanvas.hide()
545
 
 
546
 
        time = game.trog_spawn_time()
547
 
        self.nextspawn_timer = game.timeout_add( time + game.trogwarn_time, self.spawn )
548
 
        self.warn_timer = game.timeout_add( time, game.show_trogwarning )
549
 
        if self.nextmove_timer != 0:
550
 
            gobject.source_remove(self.nextmove_timer)
551
 
            self.nextmove_timer = 0
552
 
 
553
 
    def getEaten(self):
554
 
        self.die()
555
 
 
556
 
    def move(self, a, b, c, d):
557
 
        if self.onMove != None and (a != c or b != d) and game.onBoard(a, b):
558
 
            self.x = a
559
 
            self.y = b
560
 
            self.onMove(self)
561
 
        super(Troggle, self).move(a, b, c, d)
562
 
 
563
 
    def stop(self):
564
 
        self.moving = False
565
 
        if self.x < 0 or self.x >= game.width or self.y < 0 or self.y >= game.height:
566
 
            self.die()
567
 
        else:
568
 
            super(Troggle, self).stop()
569
 
            self.nextmove_timer = game.timeout_add(game.trog_wait, self.getTrogMove)
570
 
            if self.onStop != None:
571
 
                self.onStop(self)
572
 
 
573
 
    def getTrogMove(self):
574
 
        self.nextmove_timer = 0
575
 
        x_old = self.x
576
 
        y_old = self.y
577
 
        x, y = self.getMove(self)
578
 
        self.move(x_old, y_old, x, y)
579
 
 
580
 
    # the troggle move types
581
 
    def trogMove_straight(self):
582
 
        x = self.x + (self.x - self.x_old)
583
 
        y = self.y + (self.y - self.y_old)
584
 
        return x, y
585
 
 
586
 
    def trogMove_random(self):
587
 
        x = self.x
588
 
        y = self.y
589
 
        r = random.randint(0,3)
590
 
        if r >= 1: # move straight
591
 
            x += self.x - self.x_old
592
 
            y += self.y - self.y_old
593
 
        elif r == 2: # turn left
594
 
            x += self.y - self.y_old
595
 
            y -= self.x - self.x_old
596
 
        else: # turn right
597
 
            x -= self.y - self.y_old
598
 
            y += self.x - self.x_old
599
 
        return x, y
600
 
 
601
 
    def trogMove_chase(self):
602
 
        x = self.x
603
 
        y = self.y
604
 
        dx = game.muncher.x - x
605
 
        dy = game.muncher.y - y
606
 
        if dx == 0 and dy == 0:
607
 
            return self.trogMove_straight()
608
 
        if not game.muncher.exists or abs(dx) > game.width/2 or abs(dy) > game.height/2:
609
 
            return self.trogMove_straight()
610
 
        if abs(dx) > abs(dy) or (abs(dx) == abs(dy) and random.randint(0,1) == 0):
611
 
            x += dx / abs(dx)
612
 
        else:
613
 
            y += dy / abs(dy)
614
 
        return x, y
615
 
 
616
 
    def trogMove_run(self):
617
 
        x = self.x
618
 
        y = self.y
619
 
        dx = game.muncher.x - x
620
 
        dy = game.muncher.y - y
621
 
        if not game.muncher.exists or abs(dx) > game.width/2 or abs(dy) > game.height/2:
622
 
            return self.trogMove_random()
623
 
        if abs(dx) > abs(dy) or (abs(dx) == abs(dy) and random.randint(0,1) == 0):
624
 
            x -= dx / abs(dx)
625
 
        else:
626
 
            y -= dy / abs(dy)
627
 
        return x, y
628
 
 
629
 
    def onMove_create(self):
630
 
        game.setNum( self.x, self.y, game.levelset.getNumber() )
631
 
 
632
 
    def onStop_munch(self):
633
 
        if game.squares[self.x][self.y].num != None:
634
 
            self.startMunching()
635
 
            game.setNum( self.x, self.y, None )
636
 
 
637
 
class Gcompris_gnumch:
638
 
    def __init__(self, board):
639
 
        global game
640
 
        game = self
641
 
 
642
 
        self.board = board
643
 
        self.board.disable_im_context = True
644
 
        self.scrw = gcompris.BOARD_WIDTH
645
 
        self.scrh = gcompris.BOARD_HEIGHT
646
 
        self.width = 6
647
 
        self.height = 6
648
 
 
649
 
        self.sw = self.scrw / (self.width + 1)
650
 
        self.sh = self.scrh / (self.width + 1)
651
 
        self.left = self.scrw - (self.sw * self.width)
652
 
        self.top = self.scrh - (self.sh * self.height)
653
 
 
654
 
        self.munchanimation = gcompris.anim.Animation("gnumch/muncher.txt")
655
 
        self.troganimation = []
656
 
        self.trogmoves = [Troggle.trogMove_straight, Troggle.trogMove_random,
657
 
                          Troggle.trogMove_run, Troggle.trogMove_random,
658
 
                          Troggle.trogMove_chase]
659
 
        self.onmove = [ None, Troggle.onMove_create, None, None, None ]
660
 
        self.onstop = [ None, None, None, Troggle.onStop_munch, None ]
661
 
        for file in [ "gnumch/reggie.txt",
662
 
                      "gnumch/diaper.txt",
663
 
                      "gnumch/fraidy.txt",
664
 
                      "gnumch/eater.txt",
665
 
                      "gnumch/smarty.txt" ]:
666
 
            self.troganimation.append( gcompris.anim.Animation(file) )
667
 
 
668
 
        self.goodies = 0
669
 
        self.paused = 0
670
 
        self.stopped = 0
671
 
        if board.mode == "primes":
672
 
            self.levelset = PrimeLevelset()
673
 
        elif board.mode == "factors":
674
 
            self.levelset = FactorLevelset()
675
 
        elif board.mode == "multiples":
676
 
            self.levelset = MultipleLevelset()
677
 
        elif board.mode == "equality":
678
 
            self.levelset = EqualityLevelset()
679
 
        elif board.mode == "inequality":
680
 
            self.levelset = InequalityLevelset()
681
 
        else:
682
 
            print "Warning: no levelset type specified, defaulting to primes"
683
 
            self.levelset = PrimeLevelset()
684
 
 
685
 
        print "Gcompris_gnumch __init__."
686
 
 
687
 
        # config options
688
 
        self.move_tick = 30
689
 
        self.num_moveticks = 10
690
 
        self.munch_time = 400
691
 
        self.trog_wait = 1000
692
 
        self.trogwarn_time = 1000
693
 
        self.trogspawn_min = 3000
694
 
        self.trogspawn_max = 10000
695
 
 
696
 
    def start(self):
697
 
        self.board.level = 1
698
 
        self.board.maxlevel = self.levelset.numlevels
699
 
        self.board.sublevel = 1
700
 
        self.board.number_of_sublevel = self.levelset.num_sublevels
701
 
        self.trog_wait = 1900
702
 
 
703
 
        gcompris.bar_set(0)
704
 
        gcompris.set_background(self.board.canvas.root(), gcompris.skin.image_to_skin("gcompris-bg.jpg"))
705
 
        gcompris.bar_set_level(self.board)
706
 
 
707
 
        pixmap = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin("button_reload.png"))
708
 
        if(pixmap):
709
 
            gcompris.bar_set_repeat_icon(pixmap)
710
 
            gcompris.bar_set(gcompris.BAR_LEVEL | gcompris.BAR_REPEAT_ICON)
711
 
        else:
712
 
            gcompris.bar_set(gcompris.BAR_LEVEL | gcompris.BAR_REPEAT)
713
 
 
714
 
        # create our rootitem. We put each canvas item here so at the end we only
715
 
        # need to destroy the rootitem
716
 
        self.rootitem = self.board.canvas.root().add(gnomecanvas.CanvasGroup,
717
 
                                                     x=0.0,
718
 
                                                     y=0.0)
719
 
 
720
 
        # draw the board on top of the background
721
 
        for i in range(0,self.width+1):
722
 
            self.rootitem.add(gnomecanvas.CanvasLine,
723
 
                              points = (i*self.sw + self.left, self.top,
724
 
                                        i*self.sw + self.left, self.scrh),
725
 
                              fill_color_rgba = 0x000000FFL,
726
 
                              width_units = 3.0)
727
 
        for i in range(0,self.height+1):
728
 
            self.rootitem.add(gnomecanvas.CanvasLine,
729
 
                              points = (self.left, self.top + i*self.sh,
730
 
                                        self.scrw, self.top + i*self.sh),
731
 
                              fill_color_rgba = 0x000000FFL,
732
 
                              width_units = 3.0)
733
 
 
734
 
        # munchers and troggles
735
 
        self.players = []
736
 
        self.muncher = Muncher()
737
 
        self.troggles = [Troggle(), Troggle(), Troggle()]
738
 
 
739
 
        self.players[:] = self.troggles
740
 
        self.players.append(self.muncher)
741
 
 
742
 
        # create the squares
743
 
        self.squares = []
744
 
        for i in range(0, self.width):
745
 
            tmp = []
746
 
            for j in range(0, self.height):
747
 
                s = Square(self.left + self.sw*i + self.sw/2, self.top + self.sh*j + self.sh/2)
748
 
                s.pic.raise_to_top()
749
 
                tmp.append( s )
750
 
            self.squares.append(tmp)
751
 
 
752
 
        # so that the troggles get clipped to the board area
753
 
        self.rootitem.add(gnomecanvas.CanvasRect,
754
 
                          x1=0, y1=0,
755
 
                          x2=self.scrw, y2=self.top,
756
 
                          fill_color_rgba = 0xFFFFFFFFL)
757
 
        self.rootitem.add(gnomecanvas.CanvasRect,
758
 
                          x1=0, y1=0,
759
 
                          x2=self.left, y2=self.scrh,
760
 
                          fill_color_rgba = 0xFFFFFFFFL)
761
 
 
762
 
        # the board title
763
 
        self.title = self.rootitem.add(gnomecanvas.CanvasText,
764
 
                                       text = "",
765
 
                                       font = gcompris.skin.get_font("gcompris/board/title bold"),
766
 
                                       x = self.scrw/2,
767
 
                                       y = self.top/2)
768
 
 
769
 
        # the message
770
 
        self.message_back = self.rootitem.add(gnomecanvas.CanvasRect,
771
 
                                        x1=0, y1=0, x2=1, y2=1,
772
 
                                        fill_color_rgba = 0x60F06060L)
773
 
        self.message = self.rootitem.add(gnomecanvas.CanvasText,
774
 
                                        text = "",
775
 
                                        justification = gtk.JUSTIFY_CENTER,
776
 
                                        font = gcompris.skin.get_font("gcompris/board/title bold"),
777
 
                                        x = self.scrw/2,
778
 
                                        y = self.scrh/2)
779
 
        self.message.hide()
780
 
 
781
 
        # the trogwarning
782
 
        self.trogwarning = self.rootitem.add(gnomecanvas.CanvasText,
783
 
                                        text = _("T\nR\nO\nG\nG\nL\nE"),
784
 
                                        justification = gtk.JUSTIFY_CENTER,
785
 
                                        font = gcompris.skin.get_font("gcompris/board/title bold"),
786
 
                                        x = self.left/2,
787
 
                                        y = self.scrh/2)
788
 
        self.trogwarning.hide()
789
 
        self.trogwarning_num = 0
790
 
 
791
 
        # the spare life
792
 
        self.muncher.spare.gnomecanvas.raise_to_top()
793
 
 
794
 
        self.startGame()
795
 
 
796
 
    def show_trogwarning(self):
797
 
        self.trogwarning_num += 1
798
 
        if self.trogwarning_num == 1:
799
 
            self.trogwarning.show()
800
 
 
801
 
    def hide_trogwarning(self):
802
 
        self.trogwarning_num -= 1
803
 
        if self.trogwarning_num == 0:
804
 
            self.trogwarning.hide()
805
 
 
806
 
    def show_message(self, text):
807
 
        self.message.set( text = text )
808
 
        w = self.message.get_property("text-width")
809
 
        h = self.message.get_property("text-height")
810
 
        self.message_back.set( x1 = (self.scrw - w)/2, y1 = (self.scrh - h)/2,
811
 
                               x2 = (self.scrw + w)/2, y2 = (self.scrh + h)/2 )
812
 
        self.message_back.show()
813
 
        self.message.show()
814
 
 
815
 
    def hide_message(self):
816
 
        self.message.hide()
817
 
        self.message_back.hide()
818
 
 
819
 
    def set_level(self, level):
820
 
        self.board.level = level;
821
 
        self.board.sublevel = 1;
822
 
        gcompris.bar_set_level(self.board);
823
 
        self.trog_wait = 2000 - self.board.level*100
824
 
        self.stopGame()
825
 
        self.startGame()
826
 
 
827
 
    def trog_spawn_time(self):
828
 
        return random.randint(self.trogspawn_min, self.trogspawn_max)
829
 
 
830
 
    def setNum(self, x, y, new):
831
 
        change = 0
832
 
        if new == None or not new.good:
833
 
            change -= 1
834
 
        else:
835
 
            change += 1
836
 
        if self.squares[x][y].num == None or not self.squares[x][y].num.good:
837
 
            change += 1
838
 
        else:
839
 
            change -= 1
840
 
 
841
 
        change /= 2
842
 
        self.goodies += change
843
 
        if self.goodies == 0:
844
 
            self.winGame()
845
 
        self.squares[x][y].setNum(new)
846
 
 
847
 
    def key_press(self, keyval, commit_str, preedit_str):
848
 
        self.muncher.push_key(keyval)
849
 
        return True
850
 
 
851
 
    def stopGame(self):
852
 
        self.stopped = 1
853
 
        if self.muncher.munch_timer != 0:
854
 
            gobject.source_remove(self.muncher.munch_timer)
855
 
        if self.muncher.movestep_timer != 0:
856
 
            gobject.source_remove(self.muncher.movestep_timer)
857
 
 
858
 
        for t in self.troggles:
859
 
            for timer in [t.munch_timer, t.movestep_timer, t.nextmove_timer, t.nextspawn_timer, t.warn_timer]:
860
 
                if timer != 0:
861
 
                    gobject.source_remove(timer)
862
 
 
863
 
    def startGame(self):
864
 
        self.stopped = 0
865
 
        self.levelset.setLevel(self.board.level, self.board.sublevel)
866
 
        self.title.set(text = self.levelset.getTitle())
867
 
        self.trogwarning_num = 1
868
 
        self.hide_trogwarning()
869
 
        self.goodies = 0
870
 
        self.won_level = 0
871
 
        for col in self.squares:
872
 
            for s in col:
873
 
                s.setNum( self.levelset.getNumber() )
874
 
                if s.num.good:
875
 
                    self.goodies += 1
876
 
 
877
 
        self.muncher.lives = 1
878
 
        for i in range(0, len(self.troggles)):
879
 
            if i < self.board.sublevel-1:
880
 
                self.troggles[i].die()
881
 
            else: # don't move them into the spawning queue
882
 
                self.troggles[i].exists = 0
883
 
                self.troggles[i].anim.gnomecanvas.hide()
884
 
        self.muncher.spawn()
885
 
 
886
 
    def winGame(self):
887
 
        self.stopGame()
888
 
        self.won_level = 1
889
 
        gcompris.bonus.display(gcompris.bonus.WIN, gcompris.bonus.TUX)
890
 
 
891
 
    def loseGame(self):
892
 
        self.stopGame()
893
 
        gcompris.bonus.display(gcompris.bonus.LOOSE, gcompris.bonus.TUX)
894
 
 
895
 
    def onBoard(self, x, y):
896
 
        return x >= 0 and x < self.width and y >= 0 and y < self.height
897
 
 
898
 
    def pause(self, p):
899
 
        self.paused = p
900
 
 
901
 
        if p == 0:
902
 
            if self.won_level:
903
 
                # if we are paused, then unpaused it means that they beat the sublevel
904
 
                self.increment_level()
905
 
            else:
906
 
                self.set_level(self.board.level)
907
 
 
908
 
    def increment_level(self):
909
 
        self.board.sublevel += 1
910
 
        if self.board.sublevel > self.board.number_of_sublevel:
911
 
            self.set_level( self.board.level % self.board.maxlevel + 1)
912
 
        else:
913
 
            self.startGame();
914
 
 
915
 
 
916
 
    def repeat(self):
917
 
        self.stopGame()
918
 
        self.startGame()
919
 
 
920
 
    def timeout_add(self, t, fn):
921
 
        if not self.paused and not self.stopped:
922
 
            return gobject.timeout_add(t, fn)
923
 
        else:
924
 
            return 0
925
 
 
926
 
    def end(self):
927
 
        for i in range(0, len(self.troggles)):
928
 
            self.troggles[i].anim.destroy()
929
 
        if self.muncher.anim:
930
 
            self.muncher.anim.destroy()
931
 
        self.stopGame()
932
 
        self.rootitem.destroy()