diff options
Diffstat (limited to 'bubbob/player.py')
-rw-r--r-- | bubbob/player.py | 1213 |
1 files changed, 1213 insertions, 0 deletions
diff --git a/bubbob/player.py b/bubbob/player.py new file mode 100644 index 0000000..3a336a9 --- /dev/null +++ b/bubbob/player.py @@ -0,0 +1,1213 @@ +from __future__ import generators +import random, math, time +import gamesrv +import images +import boards +import bubbles +from boards import * +from images import ActiveSprite +from mnstrmap import GreenAndBlue, LetterBubbles, PlayerBubbles +from mnstrmap import DigitsMisc + +KEEPALIVE = 5*60 # seconds +CheatDontDie = 0 + + +class Dragon(ActiveSprite): + priority = 1 + mdef = PlayerBubbles + fly_counter = 0 +## glueddown = None + + DCAP = { + 'hspeed': 1, + 'firerate': 2, + 'shootthrust': 8.0, + 'infinite_shield': 1, + 'shield': 50, + 'gravity': 0.21, + 'bubbledelay': 0, + 'shootbubbles': (), + 'pinball': 0, +## 'nojump': 0, + 'autofire': 0, + 'ring': 0, + 'hotstuff': 0, + 'left2right': 1, + 'slippy': 0, + 'vslippy': 0.0, + 'lookforward': 1, + 'fly': 0, + 'jumpdown': 0, + 'flower': 1, + 'bigflower': None, + 'overlayglasses': 0, + 'teleport': 0, + 'breakwalls': 0, + 'carrying': (), + 'key_left': 'key_left', + 'key_right': 'key_right', + 'key_jump': 'key_jump', + 'key_fire': 'key_fire', + } + SAVE_CAP = {'hspeed': 1, + 'firerate': 2, + 'shootthrust': 8.0 / 1.5, + 'flower': -1} + + def __init__(self, bubber, x, y, dir, dcap=DCAP): + self.bubber = bubber + self.dir = dir + icobubber = dcap.get('bubbericons', bubber) + ActiveSprite.__init__(self, icobubber.icons[0, dir], x, y) + self.fire = 0 + self.up = 0.0 + self.watermoveable = 0 + self.dcap = dcap.copy() + self.dcap.update(self.bubber.pcap) + BubPlayer.DragonList.append(self) + self.gen.append(self.normal_movements()) + self.overlaysprite = None + self.overlayyoffset = 4 + self.hatsprite = None + self.hatangle = 1 + self.isdying = 0 + self.lifegained = 0 + self.playing_fish = False + if BubPlayer.SuperSheep: + self.become_monster('Sheep', immed=1) + elif BubPlayer.SuperFish: + self.become_fish() + + def kill(self): + try: + BubPlayer.DragonList.remove(self) + except ValueError: + pass + try: + self.bubber.dragons.remove(self) + except ValueError: + pass + ActiveSprite.kill(self) + if self.hatsprite is not None: + if self.hatsprite.alive: + self.hatsprite.kill() + self.hatsprite = None + + def die(self): + if (self in BubPlayer.DragonList and not self.dcap['shield'] + and not CheatDontDie): + BubPlayer.DragonList.remove(self) + self.gen = [self.dying()] + self.play(images.Snd.Die) + #wasting = boards.curboard.wastingplay + #if wasting is not None: + # wasting[self.bubber] = len(wasting) + + def dying(self, can_loose_letter=1): + self.isdying = 1 + if self.hatsprite is not None: + if self.hatsprite.alive: + dxy = [3*self.dir, -7] + self.hatsprite.gen = [self.hatsprite.parabolic(dxy)] + self.hatsprite = None + lst = [bonus for timeout, bonus in self.dcap['carrying'] + if hasattr(bonus, 'buildoutcome')] + #if random.random() > 0.2] + if lst: + # loose some bonuses + from bonuses import BonusMaker + for bonus in lst: + self.bubber.givepoints(-bonus.points) + BonusMaker(self.x, self.y, [bonus.nimage], + outcome=bonus.buildoutcome()) + elif self.bubber.letters and random.random() > 0.59 and can_loose_letter: + # loose a letter + lst = range(6) + random.shuffle(lst) + for l in lst: + lettername = bubbles.extend_name(l) + if lettername in self.bubber.letters: + s = self.bubber.letters[lettername] + del self.bubber.letters[lettername] + if isinstance(s, ActiveSprite): + s.kill() + scoreboard() + s = bubbles.LetterBubble(self.bubber.pn, l) + s.move(self.x, self.y) + break + icons = self.getcurrenticons() + for i in range(2, 32): + mode = 5 + ((i>>1) & 3) + self.seticon(icons[mode, self.dir]) + yield None + self.kill() + if not self.bubber.dragons: + self.bubber.bubberdie() + # self.bubber.badpoints = self.bubber.points // 3 + + def killing(self): + self.kill() + if 0: + yield None + + def carrybonus(self, bonus, timeout=500): + timeout += BubPlayer.FrameCounter + lst = list(self.dcap['carrying']) + lst.append((timeout, bonus)) + lst.sort() + self.dcap['carrying'] = lst + + def listcarrybonuses(self): + return [bonus for timeout, bonus in self.dcap['carrying']] + +## def moebius(self): +## self.dir = -self.dir +## self.dcap['left2right'] *= -1 + + def monstervisible(self): + return not self.dcap['ring'] and not self.dcap['shield'] + + def getcurrenticons(self, imgtransform=''): + if self.playing_fish: + imgtransform = 'fish' + icobubber = self.dcap.get('bubbericons', self.bubber) + try: + return icobubber.transformedicons[imgtransform] + except KeyError: + icons = icobubber.transformedicons[imgtransform] = {} + icobubber.loadicons(imgtransform) + return icons + + def normal_movements(self): + yfp = 0.0 + hfp = 0 + angryticks = 0 + mytime = 0 + privatetime = 0 + while 1: + dcap = self.dcap + self.poplist = [self] + carrying = dcap['carrying'] + while carrying and carrying[0][0] < BubPlayer.FrameCounter: + timeout, bonus = carrying.pop(0) + if bonus.endaction: + bonus.endaction(self) + del bonus + + bubber = self.bubber + wannafire = bubber.getkey(dcap, 'key_fire') + wannajump = bubber.getkey(dcap, 'key_jump') + wannago = bubber.wannago(dcap) + bottom_up = self.bottom_up() + onground1 = (onground,underground)[bottom_up] + + if dcap['autofire']: + wannafire = 1 + if dcap['pinball']: + wannajump = 1 + if dcap['pinball'] > 1: + if self.up: + self.up *= 0.982 ** dcap['pinball'] + if dcap['hotstuff']: + if not wannago: + if self.dir * (random.random()-0.07) < 0: + wannago = -1 + else: + wannago = 1 + wannafire = 1 + if self.fire > (11 // dcap['hotstuff']): + self.fire = 0 +## if dcap['hotstuff'] > 1 and random.random() < 0.4: +## from bubbles import FireDrop +## FireDrop(self.x + HALFCELL, self.y + HALFCELL) + if wannago: + self.dir = wannago * dcap['lookforward'] + if self.x & 1: + self.step(self.dir, 0) + if dcap['slippy']: + vx = dcap['vslippy'] + if wannago: + vx += wannago * 0.05 + else: + vx *= 0.95 + if vx < 0.0: + wannago = -1 + else: + wannago = 1 + dcap['vslippy'] = vx + mytime = (mytime+dcap['lookforward']) % 12 + hfp += abs(vx) + else: + hfp += dcap['hspeed'] + +## if self.glueddown: +## if wannajump or not dcap['nojump']: +## del self.glueddown +## else: +## # glued gliding movements +## self.step(self.x & 1, self.y & 1) +## if wannago: +## mytime = (mytime+dcap['lookforward']) % 12 +## else: +## hfp = 0 +## while hfp > 0 and self.glueddown: +## gx, gy = self.glueddown +## dx = wannago*gy +## dy = -wannago*gx +## x0 = (self.x + gx + dx) // CELL + 1 +## y0 = (self.y + gy + dy) // CELL + 1 +## if ' ' == bget(x0+dx, y0+dy) == bget(x0+dx-gx, y0+dy-gy): +## self.step(2*dx, 2*dy) +## # detached from this wall? +## x1 = (self.x + gx + dx) // CELL + 1 +## y1 = (self.y + gy + dy) // CELL + 1 +## if (' ' == bget(x1-dx+gx, y1-dy+gy) +## == bget(x0 +gx, y0 +gy) +## == bget(x0+dx+gx, y0+dy+gy)): +## if bget(x0-dx+gx, y0-dy+gy) != ' ': +## # rotate around the corner +## self.glueddown = -dx, -dy +## self.step(2*gx, 2*gy) +## else: +## del self.glueddown +## elif bget(x0-gx, y0-gy) == ' ': +## # attach to the wall into which we are running +## if (self.x*dx | self.y*dy) % CELL != 0: +## if ((((self.x-2*dx)*dx | (self.y-2*dy)*dy) & +## ((self.x-4*dx)*dx | (self.y-4*dy)*dy)) +## % CELL == 0): +## self.step(-2*dx, -2*dy) +## else: +## del self.glueddown +## else: +## self.glueddown = dx, dy +## else: +## del self.glueddown +## self.vertical_warp() +## hfp -= 0.82 # slightly faster than usual + # normal left or right movements + breakwalls = dcap['breakwalls'] + while hfp > 0: + hfp -= 1 + dir = 0 + if wannago == -1: + x0 = (self.x+1)//CELL + y0 = (self.y+4 - bottom_up*(CELL+4)) // CELL + 1 + y0bis = (self.y+CELL-1) // CELL + 1 - bottom_up + if bget(x0,y0) == ' ' == bget(x0,y0bis): + dir = -1 + elif breakwalls: + self.breakwalls(x0, y0bis, -1) + elif wannago == 1: + x0 = (self.x-3)//CELL + 2 + y0 = self.y // CELL + 1 - bottom_up + y0bis = (self.y+CELL-1) // CELL + 1 - bottom_up + if bget(x0,y0) == ' ' == bget(x0,y0bis): + dir = +1 + elif breakwalls: + self.breakwalls(x0, y0bis, 1) + self.step(2*dir, 0) + if dir: + mytime = (mytime+dcap['lookforward']) % 12 + else: + f = - dcap['vslippy'] * (dcap['slippy']+1)/3.0 + dcap['vslippy'] = max(min(f, 10.0), -10.0) + hfp = 0 + onbubble = None + if not dcap['infinite_shield']: + touching = images.touching(self.x+1, self.y+1, 30, 30) + touching.reverse() + for s in touching: + if s.touched(self): + onbubble = s + elif bubber.key_left or bubber.key_right or bubber.key_jump or bubber.key_fire: + dcap['infinite_shield'] = 0 + + dir = self.dir + icons = self.getcurrenticons('vflip' * bottom_up) + + if self.playing_fish: + mode = self.one_fish_frame(onground1, bottom_up) + elif self.up: + # going up + mode = 9 + self.up -= dcap['gravity'] + if (self.up,-self.up)[bottom_up] < 4.0: + self.up = 0.0 + mode = 10 + else: + ny = self.y + yfp - self.up + self.move(self.x, int(ny)) + yfp = ny - self.y + self.vertical_warp() + if wannago and dcap['teleport']: + for t in self.teleport(wannago, icons, 0): + yield t + else: + # going down or staying on ground + if wannajump and onbubble: + ground = True + onbubble.dragon_jumped = True, bottom_up + else: + ground = onground1(self.x, self.y) + if ground: + if wannajump: + self.play(images.Snd.Jump) + if dcap['jumpdown'] and not onbubble: + self.step(0, (1, -1)[bottom_up]) + mode = 10 + bubber.emotic(self, 4) + else: + yfp = 0.0 + self.up = (7.5,-7.5)[bottom_up] + mode = 9 + else: + mode = mytime // 4 + if wannago and dcap['teleport']: + for t in self.teleport(wannago, icons): + yield t + else: + mode = 10 + if dcap['fly']: + self.fly_counter += 1 + if self.fly_counter < dcap['fly']: + ny = self.y + else: + del self.fly_counter + ny = self.y+(1,-1)[bottom_up] + else: + ny = (self.y+(4,-1)[bottom_up]) & ~3 + nx = self.x + if nx < 32: + nx += 2 + elif nx > boards.bwidth - 64: + nx -= 2 + self.move(nx, ny) + self.vertical_warp() + if wannago and dcap['teleport']: + for t in self.teleport(wannago, icons, 0): + yield t + + if wannafire and not self.fire: + self.firenow() + self.hatangle = 1 + if self.fire: + if self.fire <= 5: + mode = 3 + self.hatangle = 2 + elif self.fire <= 10: + mode = 4 + self.hatangle = 3 + self.fire += 1 + if self.fire >= 64 // dcap['firerate']: + self.fire = 0 + + s = dcap['shield'] + if s: + if dcap['infinite_shield'] and s < 20: + s += 4 + s -= 1 + if dcap['overlayglasses']: + self.overlayyoffset = ({3: 2, 4: 0, + 9: 3, 10: 5}.get(mode, 4) + + self.playing_fish * 2) + elif s & 2: + mode = 11 + dcap['shield'] = s + if dcap['ring']:# and random.random() > 0.1: + if dcap['ring'] > 1: + mode = 12 + else: + mode = 11 + self.seticon(icons[mode, dir]) + self.watermoveable = not wannajump + + privatetime += BubPlayer.PlayersPrivateTime + while privatetime >= 100: + yield None + privatetime -= 100 + + if self.angry: + if angryticks == 0: + s = ActiveSprite(icons[11, self.dir], self.x, self.y) + s.gen.append(s.die([None], speed=10)) + angryticks = 6 + angryticks -= 1 + #if BubPlayer.Moebius and BubPlayer.FrameCounter % 5 == 0: + # s = ActiveSprite(icons[11, -self.dir], + # boards.bwidth - 2*CELL - self.x, self.y) + # s.gen.append(s.die([None], speed=2)) + + def teleport(self, wannago, icons, max_delta_y=CELL): + #if self.dcap['shield']: + # return + from bonuses import Bonus, Megabonus + best_dx = boards.bwidth + centerx = self.x + self.ico.w // 2 + basey = (self.y + self.ico.h + 8) & ~15 + for s in images.ActiveSprites: + if (isinstance(s, Bonus) and s.touchable + and abs(s.y+s.ico.h - basey) <= max_delta_y + and s.is_on_ground()): + dx = (s.x + (wannago < 0 and s.ico.w)) - centerx + if dx*wannago > 0: + dx = abs(dx) + CELL + if dx < best_dx: + best_dx = dx + best = s + if not (42 <= best_dx < boards.bwidth): + return + self.play(images.Snd.Shh) + self.up = 0.0 + s = best + dx = best_dx + basey = s.y+s.ico.h + desty = basey - self.ico.h + dy_dx = float(desty - self.y) / dx + self.dir = wannago + ico = images.make_darker(icons[0, wannago], True) + # speed up + fx = self.x + fy = self.y + curdx = 0.0 + stepx = 2.0 + t = 0 + while 1: + if curdx < 0.5*dx: + stepx *= 1.13 + else: + stepx /= 1.13 + fx += wannago * stepx + fy += dy_dx * stepx + curdx += stepx + if curdx >= dx or stepx < 2.0: + fx += wannago * (dx - curdx) + break + self.move(int(fx), int(fy), ico) + # make the target bonus bounce a bit + if s.alive: + dy = (t & 7) * 4 + if dy > 16: + dy = 32-dy + s.move(s.x, basey - s.ico.h - dy) + t += 1 + yield None + self.move(int(fx), desty) + self.dcap['shield'] = 50 + + def breakwalls(self, x, y0, dir): + if self.dcap['breakwalls'] > BubPlayer.FrameCounter: + return # wait before breaking more walls + if not (2 <= x < boards.curboard.width-2): + return + ys = [] + for y in (y0, y0-1): + if 0 <= y < boards.curboard.height and bget(x, y) == '#': + ys.append(y) + if len(ys) == 2: + from bonuses import DustStar + dir *= self.dcap['hspeed'] + for y in ys: + w = boards.curboard.killwall(x, y) + s = ActiveSprite(w.ico, w.x, w.y) + dxy = [dir+random.random()-0.5, + -random.random()*3.0] + DustStar(w.x, w.y, dxy[0], dxy[1], big=0) + s.gen.append(s.parabolic(dxy)) + self.dcap['breakwalls'] = BubPlayer.FrameCounter + 40 + + def enter_new_board(self): + self.playing_fish = False + self.lifegained = 0 + + def become_fish(self): + self.playing_fish = True + icons = self.getcurrenticons() + self.seticon(icons[11, self.dir]) + + def one_fish_frame(self, onground1, bottom_up): + if self.bubber.getkey(self.dcap, 'key_jump'): + # swimming up + self.step(0, (-2, 2)[bottom_up]) + else: + if random.random() < 0.05: + bubbles.FishBubble(self) + if not onground1(self.x, self.y): + # swimming down + ny = (self.y+(2,-1)[bottom_up]) & ~1 + self.move(self.x, ny) + self.vertical_warp() + return ((BubPlayer.FrameCounter // 3) % 6) * 0.5 + + def to_front(self): + ActiveSprite.to_front(self) + if self.dcap['overlayglasses']: + ico = images.sprget(('glasses', self.dir)) + y = self.y + self.overlayyoffset + if self.overlaysprite is None or not self.overlaysprite.alive: + self.overlaysprite = images.ActiveSprite(ico, self.x, y) + else: + self.overlaysprite.to_front() + self.overlaysprite.move(self.x, y, ico) + self.overlaysprite.gen = [self.overlaysprite.die([None])] + + def bottom_up(self): + return self.dcap['gravity'] < 0.0 + + def watermove(self, x, y): + # for WaterCell.flooding() + if self in BubPlayer.DragonList and self.watermoveable: + self.watermoveable = 0 + self.move(x, y) + self.up = 0.0 + if self.dcap['shield'] < 6: + self.dcap['shield'] = 6 + if self.fire <= 10: + self.fire = 11 + + def become_monster(self, clsname, big=0, immed=0): + if self in BubPlayer.DragonList: + BubPlayer.DragonList.remove(self) + + import monsters, mnstrmap + mcls = getattr(monsters, clsname) + mdef = getattr(mnstrmap, clsname) + m = mcls(mdef, self.x, self.y, self.dir, in_list=self.bubber.dragons) + m.become_monster(self.bubber, self.dcap, big, immed) + self.seticon(m.ico) + self.gen = [self.killing()] + + def become_bubblingeyes(self, bubble): + if self in BubPlayer.DragonList: + self.bubber.emotic(self, 4) + BubPlayer.DragonList.remove(self) + + import bubbles + bubble.to_front() + m = bubbles.BubblingEyes(self.bubber, self.dcap, bubble) + self.bubber.dragons.append(m) + self.gen = [self.killing()] + return 1 + else: + return 0 + + def firenow(self): + self.fire = 1 + #if boards.curboard.wastingplay is None: + shootbubbles = self.dcap['shootbubbles'] + special_bubbles = shootbubbles and shootbubbles.pop() + thrustfactors = None + N = self.dcap['flower'] + if N == 1: + angles = [0] + elif N > 1: + angles = [i*(2.0*math.pi/N) for i in range(N)] + self.dcap['flower'] = N*2//3 + elif N > -16: # triple fire, possibly cumulative + angles = [0] + for i in range(1, -N+1): + angles.append(i * 0.19) + angles.append(i * -0.19) + else: # heptuple fire + c = 0.17 + a = math.sqrt(1-c+c*c) + alpha = math.atan2(math.sqrt(3)/2*c, 1-c/2) + b = math.sqrt(1+c+c*c) + beta = math.atan2(math.sqrt(3)/2*c, 1+c/2) + angles = [0, 0, 0, alpha, -alpha, beta, -beta] + thrustfactors = [1, 1-c, 1+c, a, a, b, b] + dir = self.dir + x = self.x +## if self.glueddown: +## gx, gy = self.glueddown +## dir = dir*gy +## if not dir: +## dir = 1 +## delta = self.dir*gx * math.pi/2 +## angles = [angle-delta for angle in angles] +## x -= 16 + if self.dcap['hotstuff'] > 1: + base = (random.random()-0.5)*math.pi + angles = [a + base for a in angles] + if self.dcap['bigflower'] is not None: + N = 45 + angle = BubPlayer.FrameCounter - self.dcap['bigflower'] + if not (0 <= angle < N): + self.dcap['bigflower'] = BubPlayer.FrameCounter + angle = 0 + angles = [-angle * (2.0*math.pi/N) * self.dir] + thrustfactors = None + self.fire = max(1, 64 // self.dcap['firerate'] - 2) + if self.dcap['autofire'] >= 1: + self.dcap['autofire'] -= 1 + if not thrustfactors: + thrustfactors = [None] * len(angles) + import bonuses + for angle, thrustfactor in zip(angles, thrustfactors): + args = (self, x + 4*dir, self.y, dir, + special_bubbles, angle, thrustfactor, + self.dcap['shootthrust']) + bonuses.record_shot(args) + bubbles.DragonBubble(*args) + #else: + # from monsters import DragonShot + # DragonShot(self) + +class BubPlayer(gamesrv.Player): + # global state + FrameCounter = 0 + PlayerList = [] + DragonList = [] + MonsterList = [] + LimitScore = 0 + LimitScoreColor = None + LimitTime = None + PlayersPrivateTime = 100 + SuperSheep = False + SuperFish = False + #HighScore = 0 + #HighScoreColor = None + + INIT_BOARD_CAP = { + #'LatestLetsGo': -999, + 'BubblesBecome': None, + 'MegaBonus': None, + 'BaseFrametime': 1.0, + 'LeaveBonus': None, +## 'Moebius': 0, + 'OverridePlayerIcon': None, + 'DisplayPoints': None, + 'SuperSheep': False, + 'SuperFish' : False, + } + TRANSIENT_DATA = ('_client', 'key_left', 'key_right', + 'key_jump', 'key_fire', 'pn', 'nameicons', + 'icons', 'transformedicons', + 'standardplayericon', 'iconnames') + + FISH_MODE_MAP = {0: ('', 0), # swim + 0.5: ('', 1), + 1: ('', 2), + 1.5: ('', 3), + 2: ('', 2), + 2.5: ('', 1), + 3: ('', 4), # lancer de bulle + 4: ('', 5), + 5: ('', 3), # mort + 6: ('cw', 3), + 7: ('rot180', 3), + 8: ('ccw', 3), + 9: ('', 3), # saut, montant + 10: ('', 3), # saut, descend + 11: ('', 6), # shielded + 12: 'black', + } + + def __init__(self, n): + self.pn = n + self.icons = {} + self.transformedicons = {'': self.icons} + self.standardplayericon = images.sprget(GreenAndBlue.players[n][3]) + self.iconnames = { + (0, -1): GreenAndBlue.players[n][0], # walk + (0, +1): GreenAndBlue.players[n][3], + (1, -1): GreenAndBlue.players[n][1], + (1, +1): GreenAndBlue.players[n][4], + (2, -1): GreenAndBlue.players[n][2], + (2, +1): GreenAndBlue.players[n][5], + (3, -1): GreenAndBlue.players[n][6], # lancer de bulle + (3, +1): GreenAndBlue.players[n][8], + (4, -1): GreenAndBlue.players[n][7], + (4, +1): GreenAndBlue.players[n][9], + (5, -1): GreenAndBlue.players[n][0], # mort + (5, +1): GreenAndBlue.players[n][0], + (6, -1): GreenAndBlue.players[n][11], + (6, +1): GreenAndBlue.players[n][10], + (7, -1): GreenAndBlue.players[n][12], + (7, +1): GreenAndBlue.players[n][12], + (8, -1): GreenAndBlue.players[n][10], + (8, +1): GreenAndBlue.players[n][11], + (9, -1): GreenAndBlue.jumping_players[n][2], # saut, montant + (9, +1): GreenAndBlue.jumping_players[n][3], + (10,-1): GreenAndBlue.jumping_players[n][0], # saut, descend + (10,+1): GreenAndBlue.jumping_players[n][1], + (11,-1): 'shield-left', # shielded + (11,+1): 'shield-right', + (12,-1): 'black', # totally invisible + (12,+1): 'black', + } + self.nameicons = [] + self.team = -1 + self.reset() + + def reset(self): + self.letters = {} + #self.bonbons = 0 + self.points = 0 + self.nextextralife = gamesrv.game.extralife + self.lives = boards.get_lives() + self.lifegained = 0 + #self.badpoints = 0 + self.pcap = {} + self.dragons = [] + self.keepalive = None + self.stats = {'bubble': 0, 'die': 0} + + def loadicons(self, flip): + icons = self.transformedicons[flip] + if flip == 'fish': + for dir in (-1, 1): + for key, value in self.FISH_MODE_MAP.items(): + if value == 'black': + flip = '' + else: + flip, index = value + value = GreenAndBlue.fish[self.pn][index] + if dir > 0: + flip = flip or 'hflip' + icons[key, dir] = images.sprget((flip, value)) + else: + for key, value in self.iconnames.items(): + icons[key] = images.sprget((flip, value)) + + def setplayername(self, name): + name = name.strip() + for t in [0, 1]: + if name.endswith('(%d)' % (t+1)): + self.team = t + name = name[:-3].strip() + #print "New player in team", t, "with name", name + break + else: + self.team = -1 + #print "New player with no team:", name + icons = [images.sprcharacterget(c) for c in name] + self.nameicons = [ico for ico in icons if ico is not None][:16] + self.nameicons.reverse() + scoreboard() + + def playerjoin(self): + n = self.pn + if not self.icons: + self.loadicons(flip='') + self.keepalive = None + if self.points or self.letters: + print 'New player continues at position #%d.' % n + else: + print 'New player is at position #%d.' % n + self.reset() + self.key_left = 0 + self.key_right = 0 + self.key_jump = 0 + self.key_fire = 0 + players = [p for p in BubPlayer.PlayerList + if p.isplaying() and p is not self] + self.enterboard(players) + scoreboard() + #if BubPlayer.LatestLetsGo < BubPlayer.FrameCounter - 30: + images.Snd.LetsGo.play() + #BubPlayer.LatestLetsGo = BubPlayer.FrameCounter + + def playerleaves(self): + print 'Closing position #%d.' % self.pn + self.savecaps() + self.zarkoff() + self.keepalive = time.time() + KEEPALIVE + scoreboard() + + def sameteam(self, other): + return self.team != -1 and self.team == other.team + + def enterboard(self, players): + players = [p for p in players if not p.sameteam(self)] + leftplayers = [p for p in players if p.start_left] + rightplayers = [p for p in players if not p.start_left] + self.start_left = (len(leftplayers) + random.random() < + len(rightplayers) + random.random()) + self.lifegained = 0 + + def savecaps(self): + self.pcap = {} + dragons = self.dragons + if dragons: + for key, minimum in Dragon.SAVE_CAP.items(): + self.pcap[key] = max(minimum, + max([d.dcap[key] for d in dragons])) + + def zarkoff(self): + for d in self.dragons[:]: + d.kill() + del self.dragons[:] + + def zarkon(self): + if self.key_left + self.key_right >= 1999997: + for dragon in self.dragons: + self.emotic(dragon, 6) + self.key_left = self.key_right = 900000 + if self.key_left: self.key_left -= 1 + if self.key_right: self.key_right -= 1 + if self.key_jump: self.key_jump -= 1 + if self.key_fire: self.key_fire -= 1 + #if self.badpoints and not (self.FrameCounter & 7): + # percent = (int(self.points*0.0000333)+1) * 100 + # decr = min(self.badpoints, percent) + # self.badpoints -= decr + # self.givepoints(-decr) + if boards.curboard and not self.dragons and self.lives != 0: + #wasting = boards.curboard.wastingplay + #if wasting is not None and self in wasting: + # return + if self.start_left: + x0 = 3*CELL + dir = 1 + else: + x0 = boards.bwidth - 5*CELL + dir = -1 + y = boards.bheight - 3*CELL + for x in [x0, x0+4*dir, x0+8*dir, x0+12*dir, x0+16*dir, + x0-4*dir, x0-8*dir, x0]: + if onground(x,y): + for d in BubPlayer.DragonList: + if d.y == y and abs(d.x-x) <= 5: + break + else: + break + self.dragons.append(Dragon(self, x, y, dir)) + for key in self.pcap.keys(): + if key not in ('teleport', 'jumpdown'): + del self.pcap[key] + + def kLeft(self): + if self.key_left <= 1: + self.key_left = 1000000 + def kmLeft(self): + self.key_left = (self.key_left == 1000000) + def kRight(self): + if self.key_right <= 1: + self.key_right = 1000000 + def kmRight(self): + self.key_right = (self.key_right == 1000000) + def kJump(self): + if self.key_jump <= 1: + self.key_jump = 1000000 + def kmJump(self): + self.key_jump = (self.key_jump == 1000000) + def kFire(self): + if self.key_fire <= 1: + self.key_fire = 1000000 + def kmFire(self): + self.key_fire = (self.key_fire == 1000000) + + def bubberdie(self): + self.stats['die'] += 1 + if self.lives is not None and self.lives > 0: + self.lives -= 1 + scoreboard() + + def getkey(self, dcap, key_name): + return getattr(self, dcap[key_name]) + + def setkey(self, dcap, key_name, value): + setattr(self, dcap[key_name], value) + + def wannago(self, dcap): + return dcap['left2right'] * cmp(self.getkey(dcap, 'key_right'), + self.getkey(dcap, 'key_left')) + + def turn_single_shot(self, dcap): + for name in ('key_left', 'key_right'): + n = self.getkey(dcap, name) + if n < 999997 and n != 1: + self.setkey(dcap, name, 0) + wannago = self.wannago(dcap) + for name in ('key_left', 'key_right'): + self.setkey(dcap, name, 0) + return wannago + + def givepoints(self, points): + self.points += points + if self.points < 0: + self.points = 0 + while self.points >= self.nextextralife: + if self.lives is not None and self.lives > 0: + if gamesrv.game.lifegainlimit is None or self.lifegained < gamesrv.game.lifegainlimit: + if self.dragons: + dragon = random.choice(self.dragons) + dragon.play(images.Snd.Extralife) + else: + images.Snd.Extralife.play() + self.lives += 1 + self.lifegained += 1 + self.nextextralife += gamesrv.game.extralife + if self.LimitScoreColor is not None and self.points >= self.LimitScore: + boards.replace_boardgen(boards.game_over(), 1) + #if self.points > BubPlayer.HighScore: + # BubPlayer.HighScore = self.points + # BubPlayer.HighScoreColor = self.pn + scoreboard() + + def giveletter(self, l, promize=100000): + + #logf = open('log', 'a') + #print >> logf 'giveletter %d:' % self.pn, l + #logf.close() + + lettername = bubbles.extend_name(l) + if lettername not in self.letters: + self.letters[lettername] = 1 +## nimage = getattr(LetterBubbles, lettername) +## x0, y0 = self.infocoords() +## s = images.ActiveSprite(images.sprget(nimage[1]), x0+l*(CELL-1), y0 - 3*CELL) +## s.gen.append(s.cyclic([nimage[1], nimage[2], nimage[1], nimage[0]], 7)) + scoreboard() + if len(self.letters) == 6: + import monsters + monsters.argh_em_all() + import bonuses + if self.dragons: + for i in range(3): + dragon = random.choice(self.dragons) + bonuses.starexplosion(dragon.x, dragon.y, 1) + for lettername in self.letters: + dragon = random.choice(self.dragons) + nimages = getattr(LetterBubbles, lettername) + bonuses.Parabolic2(dragon.x, dragon.y, nimages) + dragon = random.choice(self.dragons) + dragon.play(images.Snd.Extralife) + music = [images.music_old] + boards.replace_boardgen(boards.last_monster_killed(460, music)) + self.givepoints(promize) + + def emotic(self, dragon, strenght): + bottom_up = hasattr(dragon, 'bottom_up') and dragon.bottom_up() + vshift = getattr(dragon, 'up', 0.0) + for i in range(7): + angle = math.pi/6 * i + dx, dy = -math.cos(angle), -math.sin(angle) + nx = random.randrange(3,12)*dx + ny = random.randrange(3,9)*dy - 12 + if bottom_up: + dy = -dy + ny = -ny + e = ActiveSprite(images.sprget(('vflip'*bottom_up, ('emotic', i))), + int(dragon.x + 8 + nx), + int(dragon.y + 8 + ny - vshift)) + e.gen.append(e.straightline((3.3+random.random())*dx, (2.3+random.random())*dy)) + e.gen.append(e.die([None], strenght)) + + +def upgrade(p): + p.__class__ = BubPlayer + p.key_left = 0 + p.key_right = 0 + p.key_jump = 0 + p.key_fire = 0 + p.dragons = [] + + +def xyiconumber(digits, x, y, pts, lst, width=7): + if pts >= 10**width: + pts = 10**width-1 + for l in range(width): + ico = images.sprget(digits[pts % 10]) + lst.append((x + (ico.w+1)*(width-1-l), y, ico)) + pts = pts//10 + if not pts: + break + return lst[-1][0] + +def scoreboard(reset=0, inplace=0, compresslimittime=0): + endgame = 1 + if reset: + for p in BubPlayer.PlayerList: + if inplace: + for s in p.letters.values(): + if isinstance(s, ActiveSprite): + s.kill() + if len(p.letters) == 6: + p.letters.clear() + for key in p.letters: + p.letters[key] = 2 + brd = boards.curboard + if not brd or not gamesrv.sprites_by_n: + return + lst = [] + bubblesshown = {} + plist = [] + teamslist = [[], []] + teamspoints = [0, 0] + for p in BubPlayer.PlayerList: + if p.isplaying(): + if p.lives != 0: + endgame = 0 + else: + if not p.keepalive: + continue + if p.keepalive < time.time(): + p.reset() + continue + if BubPlayer.DisplayPoints is not None: + points = BubPlayer.DisplayPoints(p) + else: + points = p.points + if p.team == -1: + plist.append((points, p, None)) + else: + teamslist[p.team].append((points,p)) + teamspoints[p.team] += points + teamslist[0].sort() + teamslist[1].sort() + plist.append((teamspoints[0], None, teamslist[0])) + plist.append((teamspoints[1], None, teamslist[1])) + plist.sort() + x0 = boards.bwidth + y0 = boards.bheight + for score, p, t in plist: + if p: + if p.lives == 0: + ico = images.sprget(GreenAndBlue.gameover[p.pn][0]) + elif p.icons: + if p.isplaying(): + mode = 0 + else: + mode = 11 + ico = BubPlayer.OverridePlayerIcon or p.icons[mode, -1] + lst.append((x0+9*CELL-ico.w, y0-ico.h, ico)) + #if boards.curboard.wastingplay is None: + for l in range(6): + name = bubbles.extend_name(l) + if name in p.letters: + x, y = x0+l*(CELL-1), y0-3*CELL + imglist = getattr(LetterBubbles, name) + ico = images.sprget(imglist[1]) + if gamesrv.game.End in (0, 1): + s = p.letters[name] + if (isinstance(s, ActiveSprite) and + BubPlayer.FrameCounter <= s.timeout): + s.move(x, y) + bubblesshown[s] = 1 + continue + if s == 1: + s = ActiveSprite(ico, x, y) + s.setimages(s.cyclic([imglist[0], imglist[1], + imglist[2], imglist[1]])) + s.timeout = BubPlayer.FrameCounter + 500 + p.letters[name] = s + bubblesshown[s] = 1 + continue + lst.append((x, y, ico)) + ## else: + ## ico = images.sprget(Bonuses.blue_sugar) + ## lst.append((x0+12, y0-3*CELL-8, ico)) + ## xyiconumber(DigitsMisc.digits_white, x0-19, y0-3*CELL+5, + ## p.bonbons, lst) + xyiconumber(GreenAndBlue.digits[p.pn], x0+2, y0-18, score, lst) + if p.lives is not None and p.lives > 0: + xyiconumber(DigitsMisc.digits_white, x0+7*CELL, y0-18, + p.lives, lst, width=2) + x = x0+13*HALFCELL + for ico in p.nameicons: + x -= 7 + lst.append((x, y0-35, ico)) + y0 -= 7*HALFCELL + else: # Team + for pscore, p in t: + if p.lives == 0: + ico = images.sprget(GreenAndBlue.gameover[p.pn][0]) + elif p.icons: + if p.isplaying(): + mode = 0 + else: + mode = 11 + ico = BubPlayer.OverridePlayerIcon or p.icons[mode, -1] + lst.append((x0+9*CELL-ico.w, y0-ico.h, ico)) + for l in range(6): + name = bubbles.extend_name(l) + if name in p.letters: + x, y = x0+l*(CELL-1), y0-2*CELL + imglist = getattr(LetterBubbles, name) + ico = images.sprget(imglist[1]) + if gamesrv.game.End in (0, 1): + s = p.letters[name] + if (isinstance(s, ActiveSprite) and + BubPlayer.FrameCounter <= s.timeout): + s.move(x, y) + bubblesshown[s] = 1 + continue + if s == 1: + s = ActiveSprite(ico, x, y) + s.setimages(s.cyclic([imglist[0], imglist[1], + imglist[2], imglist[1]])) + s.timeout = BubPlayer.FrameCounter + 500 + p.letters[name] = s + bubblesshown[s] = 1 + continue + lst.append((x, y, ico)) + x = x0+13*HALFCELL + for ico in p.nameicons: + x -= 7 + lst.append((x, y0-19, ico)) + y0 -= 4*HALFCELL + if t != []: + xyiconumber(GreenAndBlue.digits[t[-1][1].pn], x0+2, y0-18, score, lst) + ico = images.sprget(('hat', p.team, -1, 1)) + lst.append((x0+9*CELL-ico.w, y0-ico.h+16, ico)) + y0 -= 5*HALFCELL + for p in BubPlayer.PlayerList: + for name, s in p.letters.items(): + if isinstance(s, ActiveSprite) and s not in bubblesshown: + p.letters[name] = 2 + s.kill() + compressable = len(lst) + #if BubPlayer.HighScoreColor is not None: + # x = xyiconumber(GreenAndBlue.digits[BubPlayer.HighScoreColor], + # x0+2*CELL, HALFCELL, BubPlayer.HighScore, lst) + # ico = images.sprget(GreenAndBlue.players[BubPlayer.HighScoreColor][3]) + # lst.append((x-5*HALFCELL, 1, ico)) + if BubPlayer.LimitScoreColor is not None: + xyiconumber(GreenAndBlue.digits[BubPlayer.LimitScoreColor], + x0+2*CELL, HALFCELL, BubPlayer.LimitScore, lst) + if BubPlayer.LimitTime is not None: + seconds = int(BubPlayer.LimitTime) + xyiconumber(DigitsMisc.digits_white, x0+2*CELL, HALFCELL, + seconds // 60, lst, width=3) + ico = images.sprget('colon') + lst.append((x0+5*CELL-1, HALFCELL+1, ico)) + seconds = seconds % 60 + ico = images.sprget(DigitsMisc.digits_white[seconds // 10]) + lst.append((x0+6*CELL, HALFCELL, ico)) + ico = images.sprget(DigitsMisc.digits_white[seconds % 10]) + lst.append((x0+6*CELL+ico.w, HALFCELL, ico)) + ymin = HALFCELL + ico.h + elif compresslimittime: + ico = images.sprget(DigitsMisc.digits_white[0]) + ymin = HALFCELL + ico.h + else: + ymin = 0 + if not brd.bonuslevel: + if brd.num < 99: + xyiconumber(DigitsMisc.digits_white, 2, 2, brd.num+1, lst, width=2) + else: + xyiconumber(DigitsMisc.digits_white, 2, 2, brd.num+1, lst, width=3) + + # compress the scoreboard vertically if it doesn't fit + ymin += HALFCELL + if y0 < ymin: + factor = float(boards.bheight-ymin) / (boards.bheight-y0) + shift = ymin - y0*factor + 0.5 + for i in range(compressable): + x, y, ico = lst[i] + lst[i] = x, int((y+ico.h)*factor+shift)-ico.h, ico + + brd.writesprites('scoreboard', lst) + + if gamesrv.game.End in (0, 1): + gamesrv.game.End = endgame + + +# initialize global board data +def reset_global_board_state(): + for key, value in BubPlayer.INIT_BOARD_CAP.items(): + setattr(BubPlayer, key, value) +reset_global_board_state() |