diff options
Diffstat (limited to 'bubbob/ext4/__init__.py')
-rw-r--r-- | bubbob/ext4/__init__.py | 440 |
1 files changed, 440 insertions, 0 deletions
diff --git a/bubbob/ext4/__init__.py b/bubbob/ext4/__init__.py new file mode 100644 index 0000000..1efa86e --- /dev/null +++ b/bubbob/ext4/__init__.py @@ -0,0 +1,440 @@ +from __future__ import generators +import os, math, random +import images, gamesrv +from images import ActiveSprite +from boards import CELL, HALFCELL, bget +from mnstrmap import GreenAndBlue +from bubbles import BubblingEyes, Bubble +from bonuses import Bonus, points + +LocalDir = os.path.basename(os.path.dirname(__file__)) + + +localmap = { + 't-brick1': ('image1-%d.ppm', (0, 0, 16, 16)), + 't-brick2': ('image1-%d.ppm', (16, 0, 16, 16)), + } + +music = gamesrv.getmusic(os.path.join(LocalDir, 'music.wav')) + + +class BrickEyes(BubblingEyes): + + Patterns = [[(-2,0), (-1,0), (0,0), (1,0)], + [(-2,0), (-1,0), (0,0), (0,-1)], + [(-1,-1), (-1,0), (0,0), (1,0)], + [(-1,0), (0,0), (0,-1), (1,0)], + [(-1,-1), (0,-1), (0,0), (1,0)], + [(-2,0), (-1,0), (-1,-1), (0,-1)], + [(-1,-1), (-1,0), (0,-1), (0,0)]] + + def __init__(self, tetris, bubber, saved_caps, olddragon): + BubblingEyes.__init__(self, bubber, saved_caps, olddragon) + self.tetris = tetris + self.bricks = [] + + def playing_bubble(self, oldsprite): + import boards + self.pat = random.choice(self.Patterns) + self.orientation = 1,0 + xmin = 2 - min([x for x,y in self.pat]) + xmax = boards.width-3 - max([x for x,y in self.pat]) + x = int(random.normalvariate(oldsprite.x, boards.bwidth/4)) + x = (x+HALFCELL) // CELL + if x<xmin: x=xmin + if x>xmax: x=xmax + y = -1 + self.tx = x + self.ty = y + self.move((x-1)*CELL, (y-1)*CELL) + for i in range(5): + yield None + self.bricks = [Brick(self.bubber, px, py) + for px, py in self.brick_positions()] + self.gen.append(self.step_control()) + self.gen.append(self.rotate_control()) + self.gen.append(self.fall_control()) + self.gen.append(self.move_eyes()) + + def bottom_up(self): + return 0 + + def kill(self): + for b in self.bricks: + b.stop(self.tetris) + b.remove() + self.bricks = [] + BubblingEyes.kill(self) + + def brick_positions(self): + ox, oy = self.orientation + result = [] + cx = self.tx*CELL - HALFCELL + cy = self.ty*CELL - HALFCELL + for px, py in self.pat: + px = px*CELL + HALFCELL + py = py*CELL + HALFCELL + result.append((cx+px*ox-py*oy, cy+px*oy+py*ox)) + return result + + def save_position(self): + return self.tx, self.ty, self.orientation + + def restore_position(self, p): + self.tx, self.ty, self.orientation = p + + def moved(self, old_position): + for b in self.bricks: + b.set(' ') + try: + for px, py in self.brick_positions(): + if bget(px//CELL, py//CELL) != ' ': + self.restore_position(old_position) + return 0 + for b, (px, py) in zip(self.bricks, self.brick_positions()): + b.follow(px, py) + finally: + for b in self.bricks: + b.set('!') # note: we need '!' < '#' + return 1 + + def onground(self): + for b in self.bricks: + if b.gen: # brick still moving + return 0 + for px, py in self.brick_positions(): + if bget(px//CELL, py//CELL+1) >= '#': + return 1 + return 0 + + def step_control(self): + while 1: + while not self.bubber.wannago(self.dcap): + yield None + pos = self.save_position() + self.tx += self.bubber.wannago(self.dcap) + if self.moved(pos): + for i in range(4): + yield None + yield None + + def fall_control(self): + delay = 1 + while 1: + for i in range(delay and 14): + if self.bubber.key_fire: + break + yield None + pos = self.save_position() + self.ty += 1 + delay = self.moved(pos) + if delay: + for i in range(3): + yield None + elif self.onground() and self.tetris.ready: + self.gen = [self.stopping()] + yield None + + def rotate_control(self): + while 1: + while not self.bubber.key_jump: + yield None + pos = self.save_position() + ox, oy = self.orientation + self.orientation = oy, -ox + if self.moved(pos): + for i in range(7): + yield None + yield None + + def stopping(self): + self.move(self.x, -self.ico.h) + positions = [(py//CELL, px//CELL) for px, py in self.brick_positions() + if py >= 0] + positions.sort() + positions = [(px, py) for py, px in positions] + for b in self.bricks: + b.stop(self.tetris) + if b.ty < 0: + b.remove() + self.bricks = [] + staticbricks = self.tetris.staticbricks + pts = 500 + while 1: + for px, py in positions: + y = py + x1 = px + while (x1-1, y) in staticbricks: + x1 -= 1 + if bget(x1-1, y) != '#': + continue + x2 = px + while (x2, y) in staticbricks: + x2 += 1 + if bget(x2, y) != '#': + continue + if x2-x1 < 2: + continue + # full line + ico = images.sprget(Bubble.exploding_bubbles[0]) + self.tetris.score[self.bubber] = self.tetris.score.get( + self.bubber, 0) + 1 + xlist = range(x1, x2) + for x in xlist: + s = ActiveSprite(ico, + x*CELL + random.randrange(CELL) - CELL, + y*CELL + random.randrange(CELL) - CELL) + s.gen.append(s.die(Bubble.exploding_bubbles)) + s = staticbricks[x, y] + points(x*CELL + HALFCELL, y*CELL + HALFCELL, s, pts) + s.remove() + if pts == 500: + self.play(images.Snd.Fruit) + elif pts == 4000: + self.play(images.Snd.Extralife) + else: + self.play(images.Snd.Extra) + pts *= 2 + for y in range(py-1, -1, -1): + if not [x for x in xlist if (x, y) in staticbricks]: + break + for t in range(4): + yield None + if [x for x in xlist if (x, y+1) in staticbricks]: + break + for x in xlist: + if (x, y) in staticbricks: + staticbricks[x, y].shiftdown() + yield None + break + else: + break + if self.tetris.ready < 2: + self.gen.append(self.playing_bubble(self)) + + def move_eyes(self): + while 1: + tx = (self.tx-1) * CELL + ty = (self.ty-1) * CELL + for i in range(3): + if tx < self.x: + dx = -1 + elif tx > self.x: + dx = +1 + else: + dx = 0 + if ty > self.y: + dy = +1 + else: + dy = 0 + self.step(2*dx, 2*dy) + key = ('eyes', dx, 0) + self.seticon(images.sprget(key)) + yield None + + +class Brick(ActiveSprite): + + def __init__(self, bubber, x, y): + ico = images.sprget(('t-brick1', bubber.pn)) + ActiveSprite.__init__(self, ico, x, y) + self.tx = x//CELL + self.ty = y//CELL + self.bubber = bubber + + def follow(self, x, y): + self.tx = x//CELL + self.ty = y//CELL + self.gen = [self.following(x, y)] + + def following(self, nx, ny): + dx = (nx - self.x) / 7.0 + dy = (ny - self.y) / 7.0 + for i in range(6, 0, -1): + self.move(nx - int(i*dx), ny - int(i*dy)) + yield None + self.move(nx, ny) + + def set(self, c): + x, y = self.tx, self.ty + if 0 <= x < curboard.width and 0 <= y < curboard.height: + line = curboard.walls[y] + curboard.walls[y] = line[:x] + c + line[x+1:] + + def stop(self, tetris): + self.set('X') + self.seticon(images.sprget(('t-brick2', self.bubber.pn))) + images.ActiveSprites.remove(self) + tetris.staticbricks[self.tx, self.ty] = self + self.staticbricks = tetris.staticbricks + + def remove(self): + del self.staticbricks[self.tx, self.ty] + self.set(' ') + gamesrv.Sprite.kill(self) + + def shiftdown(self): + del self.staticbricks[self.tx, self.ty] + self.set(' ') + self.ty += 1 + self.set('X') + self.staticbricks[self.tx, self.ty] = self + self.step(0, CELL) + + +class Tetris: + + def bgen(self, limittime = 90.1): # 1:30 + import boards + from player import BubPlayer + + self.score = {} + for t in boards.initsubgame(music, self.displaypoints): + yield t + + tc = boards.TimeCounter(limittime) + self.ready = 0 + self.staticbricks = {} + finished = 0 + for t in self.frame(): + t = boards.normal_frame() + self.build_eyes() + yield t + tc.update(t) + if tc.time == 0.0: + self.ready = 2 + finished += not self.still_playing() + if finished > 16: + break + if (BubPlayer.FrameCounter & 15) == 7: + for s in images.ActiveSprites: + if isinstance(s, Bubble): + s.pop() + elif isinstance(s, Bonus): + s.kill() + + tc.restore() + for t in boards.result_ranking(self.score): + self.remove_eyes() + yield t + for s in self.staticbricks.values(): + s.remove() + + def displaypoints(self, bubber): + return self.score.get(bubber, 0) + + def frame(self): + heights = {1: curboard.height, + curboard.width-2: curboard.height} + ymax = curboard.height-1 + maxheight = curboard.height*3//4 + for x in range(2, curboard.width-2): + if bget(x, ymax) == ' ': + curboard.putwall(x, ymax) + height = 1 + for y in range(ymax-1, -1, -1): + if bget(x, y) == '#': + if height == maxheight: + curboard.killwall(x, y) + else: + height += 1 + heights[x] = height + xlist = range(2, curboard.width-2) + random.shuffle(xlist) + for x in xlist: + h = heights[x] + x1 = x2 = x + while heights[x1-1] == h: + x1 -= 1 + while heights[x2] == h: + x2 += 1 + parts = (x2-x1) // 8 + if not parts: + continue + left = 0 + if heights[x1-1] > h: + x1 -= 1 + left += 1 + right = parts+1 + if heights[x2] > h: + x2 += 1 + right -= 1 + for p in range(left, right): + x = x1 + ((x2-x1-1)*p+parts//2)//parts + y = ymax + for i in range(2): + while bget(x, y) == '#': + y -= 1 + if y >= 3: + curboard.putwall(x, y) + heights[x] += 1 + curboard.reorder_walls() + + walls_by_pos = curboard.walls_by_pos + moves = 1 + s = 8.0 + while moves: + moves = 0 + for y in range(curboard.height-3, -1, -1): + for x in range(2, curboard.width-2): + if ((y,x) in walls_by_pos and + (y+1,x) not in walls_by_pos): + y0 = y + while (y0-1,x) in walls_by_pos: + y0 -= 1 + w = curboard.killwall(x, y0, 0) + curboard.putwall(x, y+1, w) + moves = 1 + curboard.reorder_walls() + for i in range(int(s)+2): + yield None + s *= 0.95 + self.ready = 1 + while 1: + yield None + + def build_eyes(self): + from player import BubPlayer + for p in BubPlayer.PlayerList: + dragons = [d for d in p.dragons if not isinstance(d, BrickEyes)] + if dragons and len(p.dragons) == len(dragons): + dragon = random.choice(dragons) + eyes = BrickEyes(self, p, dragon.dcap, dragon) + p.dragons.append(eyes) + #p.emotic(dragon, 4) + for d in dragons: + d.kill() + + def still_playing(self): + from player import BubPlayer + for p in BubPlayer.PlayerList: + for d in p.dragons: + if d.gen: + return 1 + return 0 + + def remove_eyes(self): + from player import BubPlayer + for p in BubPlayer.PlayerList: + for d in p.dragons: + d.kill() + +# This game is suitable for at least min_players players +min_players = 1 + +def run(): + global curboard + import boards + from boards import curboard + boards.replace_boardgen(Tetris().bgen()) + +def setup(): + from player import BubPlayer + for key, (filename, rect) in localmap.items(): + filename = os.path.join(LocalDir, filename) + if filename.find('%d') >= 0: + for p in BubPlayer.PlayerList: + images.sprmap[key, p.pn] = (filename % p.pn, rect) + else: + images.sprmap[key] = (filename, rect) +setup() |