import random, math import gamesrv import images import boards from boards import * from images import ActiveSprite from mnstrmap import GreenAndBlue, LetterBubbles, Stars from mnstrmap import Lightning, Water, Fire, SpinningBalls, PlayerBubbles bubble_wind = { '<': (-1, 0), '>': (+1, 0), '^': ( 0,-1), 'v': ( 0,+1), 'x': ( 0, 0), } class Bubble(ActiveSprite): exploding_bubbles = list(range(131,136)) red_bubbles = [156, 157, 156, 155] white_bubbles = [164, 165, 164, 163] pink_bubbles = [172, 173, 172, 171] check_onbubble = ([(0,-1)], [(0,1)]) touchable = 1 warp = 0 default_windless = None catch_dragons = None nimages = GreenAndBlue.normal_bubbles def touched(self, dragon): dx, dy = dragon.x, dragon.y o = [] if abs(self.x - dx) >= 25: if self.x < dx: o.append((1,0)) else: o.append((-1,0)) if abs(self.y - dy) >= 25: if self.y < dy: o.append((0,1)) else: o.append((0,-1)) if o: self.obstacle = o elif (self.catch_dragons and abs(self.x - dx) < 15 and abs(self.y - dy) < 15): if dragon not in self.catch_dragons: self.catch_dragons.append(dragon) ## elif not self.pop(getattr(dragon, 'poplist', None)): ## if self.x < dx: ## o.append((1,0)) ## else: ## o.append((-1,0)) ## if self.y < dy: ## o.append((0,1)) ## else: ## o.append((0,-1)) ## self.obstacle = o else: self.pop(getattr(dragon, 'poplist', None)) return o == self.check_onbubble[dragon.bottom_up()] def can_catch_dragons(self, author, catch_myself=0): self.catch_dragons = [author] if catch_myself: self.catch_dragons.append(author) self.move(author.x, author.y) self.gen.append(self.catching_dragons()) def catching_dragons(self): from player import Dragon yield None # time to catch several dragons dragons = [d for d in self.catch_dragons if isinstance(d, Dragon)] self.catch_dragons = None if len(dragons) >= 2: import bonuses author = dragons.pop(0) imglist = [self.nimages[d.dcap.get('bubbericons', d.bubber).pn][i] for d in dragons for i in [1,2,1,0]] self.setimages(self.cyclic(imglist)) self.warp = 1 caught = [(bonus.points, bonus) for d in dragons if d.bubber is not author.bubber for bonus in d.listcarrybonuses() if isinstance(bonus, CatchNote)] caught.sort() # count caught dragons, excluding team mates, but including self count = 0 for d in dragons: if (d.bubber is author.bubber or not d.bubber.sameteam(author.bubber)): count += 1 if count: if count == 1: points = 250 else: self.play(images.Snd.Extra) if count == 2: points = 10000 elif count == 3: points = 30000 else: points = 70000 caught.append((points, CatchNote(points))) caught = caught[-3:] for points, bonus in caught: author.carrybonus(bonus, 111) bonuses.points(self.x, self.y-HALFCELL, author, points) for d in dragons: d.become_bubblingeyes(self) s_catch = author.bubber.stats.setdefault('catch', {}) s_catch[d.bubber] = s_catch.get(d.bubber, 0) + 1 def pop(self, poplist=None): if self.touchable: self.play(images.Snd.Pop) self.poplist = poplist self.untouchable() self.gen = [self.die(Bubble.exploding_bubbles)] if poplist: dragon = poplist[0] points = self.popped(dragon) if dragon: dragon.bubber.givepoints(points) dragon.bubber.stats['bubble'] += 1 self.gen.append(self.poprec()) return 1 else: return 0 def popped(self, dragon): return 10 def poprec(self): yield None for s in self.touching(0): if isinstance(s, Bubble): s.pop(self.poplist) def normal_movements(self, dx=0, dy=-1, timeout=800): self.obstacle = [] time = 0 touchbubble = timeout = (timeout or 0) * 2 while 1: del self.obstacle[:] yield None timeout -= 2 if not timeout: self.setimages(self.bubble_red()) if timeout > touchbubble: continue if timeout&2: for s in self.touching(13+(timeout&6)): if isinstance(s, Bubble) and s is not self: if (s.x-self.x)*dx > 0 or (s.y-self.y)*dy > 0: touchbubble = timeout - (timeout&12) - 3 break if timeout > touchbubble: continue if (dx,dy) not in self.obstacle: if dx==dy==0: if len(self.obstacle)==1: dx1, dy1 = self.obstacle[0] self.step(-dx1, -dy1) else: self.step(dx, dy) if self.y < -32 or self.y >= boards.bheight: if not self.warp: self.poplist = None self.kill() return self.vertical_warp() ## dx = -dx w = wget(self.x, self.y) if w != ' ': dx, dy = bubble_wind[w] elif self.default_windless: dx, dy = self.default_windless if dx == dy == 0: # this is the same as the whole loop but runs faster while len(self.obstacle) != 1: del self.obstacle[:] yield None timeout -= 2 if not timeout: self.setimages(self.bubble_red()) def bubble_red(self, speed=5): for n in self.imgseq(Bubble.white_bubbles, repeat=3): yield n for n in self.imgseq(Bubble.pink_bubbles, repeat=4): yield n for n in self.imgseq(Bubble.red_bubbles, repeat=4): yield n for n in self.imgseq([Bubble.pink_bubbles[0], Bubble.red_bubbles[0]], speed=2, repeat=10): yield n self.pop() def startnormalbubble(self, dx=0, dy=-1, timeout=800): self.touchable = 1 self.gen.append(self.normal_movements(dx=dx, dy=dy, timeout=timeout)) imglist = GreenAndBlue.normal_bubbles[self.d.bubber.pn] self.setimages(self.cyclic([imglist[1], imglist[2], imglist[1], imglist[0]])) def startsnookerbubble(self, timeout, hspeed, monsterpoplist=None): self.gen.append(self.snooker_movements(dir=hspeed, timeout=timeout)) self.gen.append(self.kill_touching_monsters(monsterpoplist)) colorname = random.choice(Stars.COLORS) imglist = [('smstar', colorname, k) for k in range(2)] self.to_front() s = images.ActiveSprite(images.sprget(imglist[-1]), self.x, self.y) s.setimages(s.cyclic(imglist, speed=2)) s.gen.append(s.following(self)) def to_front(): Bubble.to_front(self) s.to_front() self.to_front = to_front def snooker_movements(self, dir, dy=0.3, timeout=500): icons = [images.sprget(n) for n in GreenAndBlue.normal_bubbles[self.d.bubber.pn]] icotimeout = 0 ico = icons[1] yfrac = 0.0 self.dragon_jumped = False for i in range(timeout): hspeed = random.randrange(2, 4) if ico is not icons[1]: icotimeout += 1 if icotimeout >= 16: ico = icons[1] icotimeout = 0 elif abs(dy) > 16: if dy > 0: dy = 16.0 else: dy = -16.0 self.touchable = 1 if self.dragon_jumped: self.untouchable() if self.dragon_jumped[1]: # bottom-up dragon dy = -abs(dy) else: dy = abs(dy) self.dragon_jumped = False stepx = 0 y1 = (self.y + 27) // CELL if dir < 0: x1 = (self.x + 5) // CELL if bget(x1, y1) == ' ' == bget(x1, y1-1): stepx = -hspeed else: ico = icons[0] dir = 1 else: x1 = (self.x + 26) // CELL if bget(x1, y1) == ' ' == bget(x1, y1-1): stepx = hspeed else: ico = icons[0] dir = -1 x = self.x deltay = yfrac if x < 32: x += hspeed dir = 1 elif x > boards.bwidth - 64: x -= hspeed dir = -1 else: x += stepx dy += 0.21 deltay = yfrac + dy y = self.y while deltay >= 1.0: deltay -= 1.0 if onground(x, y-4): ico = icons[2] deltay = -deltay dy = -abs(dy) else: y += 1 while deltay < 0.0: deltay += 1.0 if underground(x, y+4): ico = icons[2] dy = abs(dy) * 0.95 break y -= 1 self.move(x, y, ico) self.vertical_warp() yfrac = deltay yield None self.pop() def kill_touching_monsters(self, poplist=None): from monsters import Monster poplist = poplist or [self.d] while 1: yield None for s in self.touching(10): if isinstance(s, Monster): s.argh(poplist) yield None class NormalBubble(Bubble): warp = 1 def __init__(self, dragon, x, y, timeout=800): imglist1 = GreenAndBlue.new_bubbles[dragon.bubber.pn] Bubble.__init__(self, images.sprget(imglist1[0]), x, y) self.d = dragon self.startnormalbubble(timeout=timeout) class SnookerBubble(Bubble): warp = 1 touchable = 0 def __init__(self, dragon, x, y, timeout=500): imglist1 = GreenAndBlue.new_bubbles[dragon.bubber.pn] Bubble.__init__(self, images.sprget(imglist1[0]), x, y) self.d = dragon self.startsnookerbubble(timeout=timeout, hspeed=dragon.dir) class BigBubbleCatcher(ActiveSprite): numlist = [(PlayerBubbles.explosion[2], 1), (PlayerBubbles.explosion[1], 2), (PlayerBubbles.explosion[0], 2), (PlayerBubbles.bubble[1], 5), (PlayerBubbles.appearing[4], 3), (PlayerBubbles.appearing[3], 3), (PlayerBubbles.appearing[2], 2), (PlayerBubbles.appearing[1], 2), (PlayerBubbles.appearing[0], 2)] def __init__(self, dragon, target, timeout): img = images.sprget(PlayerBubbles.explosion[2]) ActiveSprite.__init__(self, img, -img.w, 0) self.dragon = dragon self.target = target self.timeout = timeout self.gen.append(self.follow()) self.recenter(PlayerBubbles.explosion[2]) for imgnum, delay in self.numlist: images.sprget(imgnum) # preload def recenter(self, imgnum): s = self.target if not s.alive or not s.touchable: self.kill() else: img = images.sprget(imgnum) self.move(s.x + (s.ico.w - img.w) // 2, s.y + (s.ico.h - img.h) // 2, img) def follow(self): for imgnum, delay in self.numlist: for t in range(delay): self.recenter(imgnum) yield None self.recenter(imgnum) if self.alive: s = self.target s.in_bubble(NormalBubble(self.dragon, s.x, s.y, self.timeout)) self.kill() class CatchNote: def __init__(self, points): self.points = points def endaction(self, dragon): pass class DragonBubble(Bubble): touchable = 0 def __init__(self, d, x, y, dir, special_bubble=None, angle=0, thrustfactor=None, shootthrust=None): self.d = d pn = d.bubber.pn imglist1 = GreenAndBlue.new_bubbles[pn] imglist2 = GreenAndBlue.normal_bubbles[pn] if angle: asin, acos = math.sin(angle), math.cos(angle) else: asin, acos = 0, 1 Bubble.__init__(self, images.sprget(imglist1[0]), x + 12*dir, y) self.setimages(self.imgseq(imglist1[1:] + imglist2[2:3], 4)) if shootthrust is None: shootthrust = d.dcap['shootthrust'] hspeed = dir * shootthrust if thrustfactor is not None: negative = hspeed < 0 hspeed = (abs(hspeed) - 4.0) * thrustfactor + 4.0 if negative: hspeed = -hspeed self.gen.append(self.throw_bubble(hspeed, special_bubble, (acos,asin))) def throw_bubble(self, hspeed, special_bubble=None, xxx_todo_changeme=(1,0)): (acos,asin) = xxx_todo_changeme from monsters import Monster nx = self.x ny = self.y stop = 0 withmonster = 0 specialangle = (acos,asin) != (1,0) if special_bubble == 'BigFireBubble': if not specialangle: BigFireBubble(self.x, self.y, hspeed, self.d) self.kill() return self.warp = 0 monsterpoplist = [self.d] while abs(hspeed) >= 4.0: touched_monsters = [s for s in self.touching(9) if isinstance(s, Monster)] if touched_monsters: if special_bubble == 'SnookerBubble': for monster in touched_monsters: monster.argh(monsterpoplist) else: monster = random.choice(touched_monsters) in_bubble = monster.in_bubble(self) withmonster = self.withmonster = 1 if in_bubble is None: self.warp = 1 try: key = monster.mdef.jailed[0] except AttributeError: pass else: s_monster = self.d.bubber.stats.setdefault( 'monster', {}) s_monster[key] = s_monster.get(key, 0) + 1 break if specialangle: nx, ny = vertical_warp(nx + hspeed*acos, ny + hspeed*asin) ## if moebius: ## acos = -acos else: nx += hspeed hspeed *= 0.965 xc = int(nx-3.8)//CELL+1 yc = (self.y+HALFCELL)//CELL if bget(xc,yc) == '#' == bget(xc, yc+1): stop += 1 if stop <= 1: self.move(int(nx+0.5), int(ny+0.5)) yield None if special_bubble == 'SnookerBubble': if stop > 1: hspeed = -hspeed self.startsnookerbubble(self.d.dcap['bubbledelay'] or 800, hspeed, monsterpoplist) return if not withmonster: from bonuses import Bonus, BonusMaker touched_bonuses = [s for s in self.touching(15) if isinstance(s, Bonus) and s.bubblable] if touched_bonuses: random.choice(touched_bonuses).in_bubble(self) withmonster = 1 else: touched_bonuses = [s for s in self.touching(7) if isinstance(s, BonusMaker)] if touched_bonuses: bonusmaker = random.choice(touched_bonuses) if bonusmaker.in_bubble(self): withmonster = 1 if not self.alive: return if special_bubble: cls = globals()[special_bubble] if not withmonster: b = cls(self.d.bubber.pn) b.move(self.x, self.y) b.can_catch_dragons(self.d, hspeed == 0) self.kill() return bubbledelay = self.d.dcap['bubbledelay'] if bubbledelay: timeout = 1 if bubbledelay > 1: self.gen.append(self.delayed_pop(7)) else: timeout = 800 self.startnormalbubble(timeout=timeout) if not withmonster: self.can_catch_dragons(self.d, hspeed == 0) def delayed_pop(self, delay): for i in range(delay): yield None self.pop() class FishBubble(Bubble): touchable = 0 def __init__(self, dragon): ico = images.sprget(GreenAndBlue.new_bubbles[dragon.bubber.pn][0]) Bubble.__init__(self, ico, dragon.x + dragon.dir*12, dragon.y) timeout = random.randrange(50, 150) self.gen.append(self.normal_movements(timeout=timeout)) self.gen.append(self.fuzz()) def fuzz(self): while 1: prevx = self.x yield None yield None yield None if prevx == self.x: self.step(random.choice([-1, 1]), 0) def bubble_red(self, *args, **kwds): self.gen.append(self.die([])) class BubblingEyes(ActiveSprite): def __init__(self, bubber, saved_caps, bubble): ico = images.sprget(('eyes', 0, 0)) ActiveSprite.__init__(self, ico, bubble.x, bubble.y) self.bubber = bubber self.dcap = saved_caps self.gen = [self.playing_bubble(bubble)] def bottom_up(self): return self.dcap['gravity'] < 0.0 def playing_bubble(self, bubble): from player import Dragon bottom_up = self.bottom_up() flip = 'vflip'*bottom_up timer = 0 red = 0 normalbub = bubble.imgsetter redblinker = bubble.cyclic([Bubble.pink_bubbles[0], Bubble.red_bubbles[0]], 2) bubber = self.bubber ndir = random.choice([-1, 1]) prev_dx_dy = None while not hasattr(bubble, 'poplist'): dx = bubber.wannago(self.dcap) if dx: ndir = dx if bubber.key_jump: dy = -1 else: dy = 0 if bubber.key_fire: red += 1 if red > 20: d = Dragon(bubber, self.x, self.y, ndir, self.dcap) Bubble.pop(bubble, [d]) # hack to pop SolidBubbles too d.kill() break if bubble.imgsetter is not redblinker: normalbub = bubble.imgsetter bubble.setimages(redblinker) else: #red = 0 if bubble.imgsetter is redblinker: bubble.setimages(normalbub) key = ('eyes', dx, dy) if timer < 50: if (timer % 9) < 3: key = 'eyes-blink' elif random.random() < 0.1: key = 'eyes-blink' timer += 1 if bubble.x <= 3*HALFCELL and dx < 0: dx = 0 if bubble.x >= boards.bwidth - 7*HALFCELL and dx > 0: dx = 0 if bottom_up: dy = -dy nx = bubble.x + dx ny = bubble.y + dy if timer&1: nx += dx else: ny += dy nx, ny = vertical_warp(nx, ny) bubble.move(nx, ny) self.move(nx+dx, ny+dy, images.sprget((flip, key))) ## if moebius: ## self.dcap['left2right'] *= -1 if dx == dy == 0: bubble.default_windless = prev_dx_dy else: prev_dx_dy = dx, dy bubble.default_windless = 0, 0 yield None # jumping out of the bubble if bottom_up: kw = {'gravity': -0.3} else: kw = {} from player import BubPlayer bi = self.dcap.get('bubbericons', bubber) if BubPlayer.SuperFish and 'fish' in bi.transformedicons: self.setimages(None) self.seticon(bi.transformedicons['fish'][0, +1]) else: self.setimages(self.cyclic( [(flip, n) for n in GreenAndBlue.comming[bi.pn]], 2)) dxy = [(random.random()-0.5) * 9.0, (random.random()+0.5) * (-5.0,5.0)[bottom_up]] for n in self.parabolic(dxy, 1, **kw): yield n if dxy[1] * (1,-1)[bottom_up] >= 4.0: break if dxy[0] < 0: ndir = -1 else: ndir = 1 d = Dragon(bubber, self.x, self.y, ndir, self.dcap) d.dcap['shield'] = 50 bubber.dragons.append(d) self.kill() def kill(self): try: self.bubber.dragons.remove(self) except ValueError: pass ActiveSprite.kill(self) class BonusBubble(Bubble): max = None timeout = None flip = '' def __init__(self, pn, nimages=None, top=None): if nimages is None: nimages = self.nimages[pn] b = boards.curboard if top is None: top = b.top if top == 0: testline = b.walls[-1] x, y = self.findhole(testline), boards.bheight dx, dy = 0, -1 elif top == 1: testline = b.walls[0] x, y = self.findhole(testline), -2*CELL dx, dy = 0, 1 elif top == 2: x, y = -2*CELL, random.randint(2*CELL, boards.bheight-4*CELL) dx, dy = 1, 0 else: # top == 3: x, y = (boards.bwidth - CELL, random.randint(2*CELL, boards.bheight-4*CELL)) dx, dy = -1, 0 Bubble.__init__(self, images.sprget((self.flip, nimages[0])), x, y) self.gen.append(self.normal_movements(dx=dx, dy=dy, timeout=self.timeout)) if len(nimages) == 3: nimages = [nimages[1], nimages[2], nimages[1], nimages[0]] if len(nimages) > 1: self.setimages(self.cyclic([(self.flip, n) for n in nimages])) def findhole(self, testline): holes = [x for x in range(len(testline)-1) if testline[x:x+2]==' '] if not holes: holes = list(range(2, len(testline)-3)) return random.choice(holes) * CELL def thrown_bubble(self, x, y, hspeed, acossin): self.untouchable() self.move(x, y) self.gen = [self.throwing_bubble(hspeed, acossin, self.imgsetter)] def throwing_bubble(self, hspeed, xxx_todo_changeme1, restore_img): (acos,asin) = xxx_todo_changeme1 nx = self.x ny = self.y while abs(hspeed) >= 4.0: nx, ny = vertical_warp(nx + hspeed*acos, ny + hspeed*asin) ## if moebius: ## acos = -acos if nx <= CELL: acos = abs(acos) if nx >= boards.bwidth-3*CELL: acos = -abs(acos) hspeed *= 0.965 self.move(int(nx+0.5), int(ny+0.5)) yield None self.touchable = 1 self.gen.append(self.normal_movements(timeout=self.timeout)) self.setimages(restore_img) class PlainBubble(BonusBubble): timeout = 500 def condition(): return boards.curboard.holes def extend_name(l): text = 'extend' return text[:l] + text[l].upper() + text[l+1:] class LetterBubble(BonusBubble): max = 2 def condition(): return boards.curboard.letter def __init__(self, pn, l=None): if l is None: l = random.randint(0,5) self.l = l lettername = extend_name(self.l) BonusBubble.__init__(self, pn, nimages=getattr(LetterBubbles, lettername)) def popped(self, dragon): if dragon: dragon.bubber.giveletter(self.l) return 50 class FireFlame(ActiveSprite): timeout = 17 def __init__(self, x0, y0, poplist, dirs=None, countdown=0, flip=''): ico = images.sprget((flip, Fire.ground[0])) ActiveSprite.__init__(self, ico, x0*CELL, y0*CELL) if not countdown: dirs = [] self.poplist = poplist self.gen.append(self.burning(dirs, countdown)) self.setimages(self.cyclic([(flip, n) for n in Fire.ground], 1)) def burning(self, dirs, countdown): from monsters import Monster x0 = self.x//CELL y0 = self.y//CELL for dir in dirs: if bget(x0+dir, y0+1) == '#' and bget(x0+dir, y0) == ' ': FireFlame(x0+dir, y0, self.poplist, [dir], countdown-1) for i in range(self.timeout): yield None if self.poplist: for s in self.touching(0): if isinstance(s, Monster): s.argh(self.poplist) yield None self.kill() class FireDrop(ActiveSprite): def __init__(self, x, y, poplist=None): ActiveSprite.__init__(self, images.sprget(Fire.drop), x, y) self.poplist = poplist or [None] self.gen.append(self.dropping()) def dropping(self): x0 = self.x//CELL while bget(x0, self.y//CELL) == '#' or bget(x0, self.y//CELL+1) != '#': if self.y >= boards.bheight: self.kill() return self.move(self.x, (self.y + 8) & ~7) yield None y0 = self.y//CELL #if bget(x0-1, y0) == ' ': FireFlame(x0, y0, self.poplist, [-1, 1], 5) self.kill() class FireBubble(BonusBubble): max = 4 nimages = GreenAndBlue.fire_bubbles def condition(): return boards.curboard.fire def popped(self, dragon): if dragon: x0 = self.x // CELL + 1 y0 = self.y // CELL + 1 if bget(x0, y0) == '#': x1 = (self.x + HALFCELL) // CELL if x1 == x0: tries = [x1+1, x1-1] else: tries = [x1, x1+2] for x1 in tries: if bget(x1, y0) == ' ': x0 = x1 break FireDrop(x0*CELL, self.y) return 10 ##class BombBubble(FireBubble): ## flip = 'vflip' ## def popped(self, dragon): ## if dragon: ## import bonuses ## bonuses.bomb_explosion(self.x, self.y + CELL, starmul=1) ## return 100 ##class WaterCell(ActiveSprite): ## ICONS = { ## ( 0,1, None) : Water.bottom, ## ( 1,0, None) : Water.start_left, ## (-1,0, None) : Water.start_right, ## ( 0,0, None) : Water.bottom, ## (0,1, 0,1) : Water.v_flow, ## (0,1, 1,0) : Water.bl_corner, ## (0,1, -1,0) : Water.br_corner, ## (-1,0, 0,1) : Water.tl_corner, ## (-1,0, 1,0) : Water.start_right, ## #(-1,0, -1,0) : Water.h_flow, ## (1,0, 0,1) : Water.tr_corner, ## #(1,0, 1,0) : Water.h_flow, ## (1,0, -1,0) : Water.start_left, ## (0,0, 0,1) : Water.top, ## (0,0, 1,0) : Water.top, ## (0,0, -1,0) : Water.top, ## (None, 0,1) : Water.top, ## (None, -1,0) : Water.start_left, ## (None, 1,0) : Water.start_right, ## (None, 0,0) : Water.top, ## } ## def __init__(self, x, y): ## ActiveSprite.__init__(self, images.sprget(Water.top), x, y) ## self.touchable = 1 ## def ready(self, celllist): ## self.gen.append(self.flooding(celllist)) ## def flooding(self, celllist): ## from monsters import Monster ## x0 = self.x // 16 ## y0 = self.y // 16 ## ping = 0 ## dir = random.choice([-1, 1]) ## take_with_us = [[] for cell in celllist] ## poplist = [None] ## icons = {} ## for key, value in self.ICONS.items(): ## icons[key] = images.sprget(value) ## icodef = images.sprget(Water.h_flow) ## stop = 0 ## while not stop: ## dx = dy = 0 ## if bget(x0, y0+1) == ' ': ## dy = y0*16 < boards.bheight ## ping = 0 ## elif bget(x0+dir, y0) == ' ': ## dx = dir ## elif bget(x0-dir, y0) == ' ': ## ping += 1 ## if ping < 3: ## dir = -dir ## dx = dir ## # change the head icon ## head = celllist[0] ## second = celllist[1] ## head.seticon(icons.get((x0-second.x//16, y0-second.y//16, ## dx, dy), icodef)) ## # move the tail to the new head position ## x0 += dx ## y0 += dy ## newhead = celllist.pop() ## celllist.insert(0, newhead) ## newhead.move(x0*16, y0*16, icons.get((dx,dy, None), icodef)) ## # change the new tail icon ## tail = celllist[-1] ## second = celllist[-2] ## tail.seticon(icons.get((None, (second.x-tail.x)//16, ## (second.y-tail.y)//16), icodef)) ## # take monsters with us ## for i in range(0, len(celllist), 3): ## for s in celllist[i].touching(0): ## if isinstance(s, Monster): ## s.untouchable() ## s.gen = [] ## take_with_us[i].append(s) ## elif isinstance(s, Bubble): ## s.pop(poplist) ## yield 0 ## stop = dx == dy == 0 ## for cell, takelist in zip(celllist, take_with_us): ## stop &= cell.x == newhead.x and cell.y == newhead.y ## for s in takelist: ## if s.alive: ## s.move(x2bounds(cell.x-8), cell.y-16) ## if stop: ## s.argh(poplist, onplace=1) ## for c in celllist: ## c.kill() ## def touched(self, dragon): ## dragon.watermove(x2bounds(self.x-HALFCELL), self.y-CELL+1) ## return 1 class WaterCell(ActiveSprite): TESTLIST = [(-CELL,0), (CELL,0), (0,CELL), (0,-CELL)] ICONS = [Water.v_flow, Water.start_left, Water.start_right, Water.h_flow, Water.top, Water.tr_corner, Water.tl_corner, Water.h_flow, Water.bottom, Water.br_corner, Water.bl_corner, Water.h_flow, Water.v_flow, Water.v_flow, Water.v_flow, Water.v_flow] def __init__(self, x, y, dir, watercells, poplist, repeat): ActiveSprite.__init__(self, images.sprget(Water.top), x, y) self.poplist = poplist self.take_with_me = [] self.ping = 0 self.repeat = repeat self.watercells = watercells self.touchable = repeat % 3 == 1 if (x, y, dir) not in watercells: watercells[x,y,dir] = self if None not in watercells or not watercells[None].alive: self.in_charge() else: watercells[x,y,dir].join(self) def join(self, other): self.take_with_me += other.take_with_me self.ping = min(self.ping, other.ping) self.repeat += other.repeat self.touchable = self.touchable or other.touchable del other.take_with_me[:] other.kill() def in_charge(self): self.gen = [self.flooding()] self.watercells[None] = self def kill(self): from monsters import Monster for s in self.take_with_me[:]: if isinstance(s, Monster) and s.alive: s.argh(self.poplist, onplace=1) del self.take_with_me[:] ActiveSprite.kill(self) if not self.watercells[None].alive: del self.watercells[None] for s in list(self.watercells.values()): if s.alive: s.in_charge() break def flooding(self): from monsters import Monster watercells = self.watercells while watercells[None] is self: new = [] nwatercells = {None: self} for key, s in list(watercells.items()): if key: x, y, dir = key if s.repeat: new.append((x, y, dir, watercells, s.poplist, s.repeat-1)) s.repeat = 0 x0 = x // CELL y0 = y // CELL if bget(x0, y0+1) == ' ': if y >= boards.bheight: s.kill() continue s.ping = 0 y += CELL elif bget(x0+dir, y0) == ' ': x += dir*CELL elif bget(x0-dir, y0) == ' ': s.ping += 1 if s.ping == 3: s.kill() continue dir = -dir x += dir*CELL else: s.kill() continue key = x, y, dir if key in nwatercells: nwatercells[key].join(s) else: nwatercells[key] = s watercells.clear() watercells.update(nwatercells) for args in new: WaterCell(*args) for key, s in list(watercells.items()): if key: x, y, dir = key flag = 0 for k in range(4): dx, dy = s.TESTLIST[k] if ((x+dx, y+dy, -1) in watercells or (x+dx, y+dy, 1) in watercells): flag += 1< 0: imgs = PlayerBubbles.right_weapon else: imgs = PlayerBubbles.left_weapon ActiveSprite.__init__(self, images.sprget(imgs[-1]), x, y) self.setimages(self.cyclic(imgs, 2)) self.author = author self.gen.append(self.moving(hspeed)) self.play(images.Snd.Shh) def moving(self, hspeed): from monsters import Monster if abs(hspeed) < 3: if hspeed > 0: hspeed = 3 else: hspeed = -3 fx = self.x poplist = [self.author] while 1: fx += hspeed self.move(int(fx), self.y) xc = int(fx)//CELL + 1 yc = (self.y+HALFCELL)//CELL if bget(xc,yc) == '#' == bget(xc, yc+1): break yield None for s in self.touching(4): if isinstance(s, Monster): s.argh(poplist) self.kill() def touched(self, dragon): if dragon is not self.author: import bonuses bonuses.repulse_dragon(dragon) class SpinningBall(ActiveSprite): def __init__(self, x, y, poplist): ActiveSprite.__init__(self, images.sprget(SpinningBalls.free[-1]), x,y) self.poplist = poplist self.gen.append(self.dropping()) imgs = SpinningBalls.free if random.random() < 0.5: imgs = list(imgs) imgs.reverse() self.setimages(self.cyclic(imgs, random.randrange(2,5))) self.touchable = 1 def dropping(self): from monsters import Monster for ny in range(self.y, boards.bheight, 5): self.move(self.x, ny) yield None for s in self.touching(0): if isinstance(s, Monster): s.argh(self.poplist) elif isinstance(s, Bubble): s.pop(self.poplist) self.kill() def touched(self, dragon): dragon.die() class StarBubble(BonusBubble): timeout = 250 def __init__(self, pn): self.colorname = random.choice(Stars.COLORS) BonusBubble.__init__(self, pn, [('starbub', self.colorname, i) for i in range(3)]) ## def __init__(self, pn): ## BonusBubble.__init__(self, pn) ## self.colorname = random.choice(Stars.COLORS) ## starimg = [('smstar', self.colorname, 0), ## ('smstar', self.colorname, 1)] ## smallstar = ActiveSprite(images.sprget(starimg[-1]), ## self.x+8, self.y+8) ## smallstar.setimages(smallstar.cyclic(starimg)) ## smallstar.gen.append(smallstar.following(self, 8, 8)) def popped(self, dragon): if dragon: from bonuses import BonusMaker, AllOutcomes, Parabolic2 BonusMaker(self.x, self.y, getattr(Stars, self.colorname), outcome=random.choice(AllOutcomes)) for i in range(2): Parabolic2(self.x, self.y, [('smstar', self.colorname, i) for i in range(2)]) return 100 class MonsterBubble(BonusBubble): timeout = 100 def __init__(self, pn, mcls): import monsters, mnstrmap BonusBubble.__init__(self, pn) mdef = getattr(mnstrmap, mcls.__name__) m = mcls(mdef, self.x, self.y, 1) m.in_bubble(self) class MoreBubblesBubble(BonusBubble): def can_catch_dragons(self, author, catch_myself=0): # at this point, explode the bubble into more bubbles d = author for angle in [math.pi, math.pi/2, -math.pi/2, 0]: for factor in [0.2, 0.55, 0.9, 1.25, 1.6]: DragonBubble(d, self.x, self.y, d.dir, angle = angle, thrustfactor = factor) self.pop() Classes = ([PlainBubble] * 7 + [FireBubble, WaterBubble, LightningBubble] * 4 + [LetterBubble]) def newbubble(): #force=0): #if force: #cls = PlainBubble #else: cls = random.choice(Classes) if not cls.__dict__['condition'](): return if cls.max is not None: others = [s for s in images.ActiveSprites if isinstance(s, cls)] if len(others) >= cls.max: return sendbubble(cls) def newforcedbubble(): choices = [PlainBubble] * 5 for cls in [FireBubble, WaterBubble, LightningBubble]: if cls.__dict__['condition'](): n = 4 else: n = 1 choices.extend([cls] * n) cls = random.choice(choices) return sendbubble(cls) def sendbubble(cls, *args, **kw): from player import BubPlayer players = [p for p in BubPlayer.PlayerList if p.isplaying()] if not players: return None pn = random.choice(players).pn return cls(pn, *args, **kw) def newbonusbubble(): boards.curboard.top = random.choice([0,0,0, 1,1,1, 2,2, 3,3]) r = random.random() if r < 0.14: sendbubble(random.choice(Classes)) elif r < 0.16: from player import BubPlayer import monsters mcls = random.choice(monsters.MonsterClasses) for d in BubPlayer.DragonList: sendbubble(MonsterBubble, mcls) else: sendbubble(StarBubble)