summaryrefslogtreecommitdiff
path: root/bubbob/monsters.py
diff options
context:
space:
mode:
authorDiego Roversi <diegor@tiscali.it>2019-09-08 18:12:27 +0200
committerDiego Roversi <diegor@tiscali.it>2019-09-08 18:12:27 +0200
commit1d9925c287b318ec21343e2682b51ab6a36ae8db (patch)
tree17d1c0ac21eea6f291146520afa8381db4586fb4 /bubbob/monsters.py
initial commit from cvs 1.6.2
Diffstat (limited to 'bubbob/monsters.py')
-rw-r--r--bubbob/monsters.py937
1 files changed, 937 insertions, 0 deletions
diff --git a/bubbob/monsters.py b/bubbob/monsters.py
new file mode 100644
index 0000000..88983d0
--- /dev/null
+++ b/bubbob/monsters.py
@@ -0,0 +1,937 @@
+from __future__ import generators
+import random
+import gamesrv
+import images
+import boards
+from boards import *
+from images import ActiveSprite
+from mnstrmap import GreenAndBlue, Bonuses, Ghost
+from player import BubPlayer
+import bonuses
+
+
+class Monster(ActiveSprite):
+ touchable = 1
+ special_prob = 0.2
+ shootcls = None
+ vx = 2
+ vy = 0
+ vdir = -1
+ is_ghost = 0
+ MonsterBonus = bonuses.MonsterBonus
+
+ def __init__(self, mnstrdef, x=None, y=None, dir=None, in_list=None):
+ self.mdef = mnstrdef
+ self.ptag = None
+ if dir is None: dir = mnstrdef.dir
+ if x is None: x = mnstrdef.x*CELL
+ if y is None: y = mnstrdef.y*CELL
+ self.dir = dir
+ ActiveSprite.__init__(self, images.sprget(self.imgrange()[0]), x, y)
+ self.gen.append(self.waiting())
+ if in_list is None:
+ in_list = BubPlayer.MonsterList
+ self.in_list = in_list
+ self.in_list.append(self)
+ self.no_shoot_before = 0
+ #images.ActiveSprites.remove(self)
+
+ def unlist(self):
+ try:
+ self.in_list.remove(self)
+ return 1
+ except ValueError:
+ return 0
+
+ def kill(self):
+ self.unlist()
+ ActiveSprite.kill(self)
+
+ def tagdragon(self):
+ lst = bonuses.getvisibledragonlist()
+ if lst:
+ return random.choice(lst)
+ else:
+ return None
+
+ def imgrange(self):
+ if self.is_ghost:
+ if self.dir > 0:
+ return Ghost.right
+ else:
+ return Ghost.left
+ elif self.angry:
+ if self.dir > 0:
+ return self.mdef.right_angry
+ else:
+ return self.mdef.left_angry
+ else:
+ if self.dir > 0:
+ return self.mdef.right
+ else:
+ return self.mdef.left
+
+ def imgrange1(self):
+ # normally this is self.imgrange()[1]
+ lst = self.imgrange()
+ return lst[len(lst) > 1]
+
+ def resetimages(self, is_ghost=0):
+ self.is_ghost = is_ghost
+ if self.gen:
+ self.setimages(self.cyclic(self.imgrange(), 3))
+ else: # frozen monster
+ self.seticon(images.sprget(self.imgrange()[0]))
+
+ def blocked(self):
+ if self.dir < 0:
+ x0 = (self.x-1)//16
+ else:
+ x0 = (self.x+33)//16
+ y0 = self.y // 16 + 1
+ y1 = (self.y + 31) // 16
+ return bget(x0,y0) == '#' or bget(x0,y1) == '#'
+
+ def tryhstep(self):
+ if self.blocked():
+ self.dir = -self.dir
+ self.resetimages()
+ return 0
+ else:
+ self.step(self.vx*self.dir, 0)
+ return 1
+
+ def vblocked(self):
+ if self.vdir < 0:
+ y0 = self.y//16
+ else:
+ y0 = (self.y+1)//16 + 2
+ x0 = self.x // 16
+ x1 = self.x // 16 + 1
+ x2 = (self.x+31) // 16
+ return bget(x0,y0) == '#' or bget(x1,y0) == '#' or bget(x2,y0) == '#'
+
+ def tryvstep(self):
+ if self.vblocked():
+ self.vdir = -self.vdir
+ return 0
+ else:
+ self.step(0, self.vy*self.vdir)
+ self.vertical_warp()
+ return 1
+
+ def waiting(self, delay=20):
+ for i in range(delay):
+ yield None
+ self.resetimages()
+ self.gen.append(self.default_mode())
+
+ def overlapping(self):
+ if self.in_list is BubPlayer.MonsterList:
+ for s in self.in_list:
+ if (-6 <= s.x-self.x <= 6 and -6 <= s.y-self.y < 6 and
+ #s.dir == self.dir and s.vdir == self.vdir and
+ s.vx == self.vx and s.vy == self.vy and
+ (not s.angry) == (not self.angry)):
+ return s is not self
+ return 0
+
+ def walking(self):
+ while onground(self.x, self.y):
+ yield None
+ if random.random() < 0.2 and self.overlapping():
+ yield None
+ x1 = self.x
+ if self.dir > 0:
+ x1 += self.vx
+ if (x1 & 15) < self.vx and random.random() < self.special_prob:
+ self.move(x1 & -16, self.y)
+ if self.special():
+ return
+ self.tryhstep()
+ if self.seedragon():
+ self.gen.append(self.hjumping())
+ else:
+ self.gen.append(self.falling())
+
+ def seedragon(self, dragon=None):
+ dragon = dragon or self.tagdragon()
+ if dragon is None:
+ return False
+ return abs(dragon.y - self.y) < 16 and self.dir*(dragon.x-self.x) > 0
+
+ def special(self):
+ dragon = self.tagdragon()
+ if dragon is None:
+ return 0
+ if self.seedragon(dragon) and self.shoot():
+ return 1
+ if dragon.y < self.y-CELL:
+ #and abs(dragon.x-self.x) < 2*(self.y-dragon.y):
+ for testy in range(self.y-2*CELL, self.y-6*CELL, -CELL):
+ if onground(self.x, testy):
+ if random.random() < 0.5:
+ ndir = self.dir
+ elif dragon.x < self.x:
+ ndir = -1
+ else:
+ ndir = 1
+ self.gen.append(self.vjumping(testy, ndir))
+ return 1
+ return 0
+
+ def shooting(self, pause):
+ for i in range(pause):
+ yield None
+ self.shootcls(self)
+ yield None
+ self.gen.append(self.default_mode())
+
+ def shoot(self, pause=10):
+ if (self.shootcls is None or
+ self.no_shoot_before > BubPlayer.FrameCounter):
+ return 0
+ else:
+ self.gen.append(self.shooting(pause))
+ self.no_shoot_before = BubPlayer.FrameCounter + 29
+ return 1
+
+ def falling(self):
+ bubber = getattr(self, 'bubber', None)
+ while not onground(self.x, self.y):
+ yield None
+ ny = self.y + 3
+ if (ny & 15) > 14:
+ ny = (ny//16+1)*16
+ elif (ny & 15) < 3:
+ ny = (ny//16)*16
+ nx = self.x
+ if nx < 32:
+ nx += 1 + (self.vx-1) * (bubber is not None)
+ elif nx > boards.bwidth - 64:
+ nx -= 1 + (self.vx-1) * (bubber is not None)
+ elif bubber:
+ dx = bubber.wannago(self.dcap)
+ if dx and dx != self.dir:
+ self.dir = dx
+ self.resetimages()
+ self.setimages(None)
+ if dx and not self.blocked():
+ nx += self.vx*dx
+ self.seticon(images.sprget(self.imgrange1()))
+ self.move(nx, ny)
+ if self.y >= boards.bheight:
+ self.vertical_warp()
+ if bubber:
+ nextgen = self.playing_monster
+ else:
+ nextgen = self.walking
+ self.gen.append(nextgen())
+
+## def moebius(self):
+## self.dir = -self.dir
+## self.resetimages()
+## if hasattr(self, 'dcap'):
+## self.dcap['left2right'] *= -1
+
+ def hjumping(self):
+ y0 = self.y
+ vspeed = -2.2
+ ny = y0-1
+ while ny <= y0 and not self.blocked():
+ self.move(self.x+2*self.dir, int(ny))
+ yield None
+ vspeed += 0.19
+ ny = self.y + vspeed
+ self.gen.append(self.default_mode())
+
+ def vjumping(self, limity, ndir):
+ self.setimages(None)
+ yield None
+ self.dir = -self.dir
+ self.seticon(images.sprget(self.imgrange()[0]))
+ for i in range(9):
+ yield None
+ self.dir = -self.dir
+ self.seticon(images.sprget(self.imgrange()[0]))
+ for i in range(4):
+ yield None
+ self.dir = ndir
+ self.seticon(images.sprget(self.imgrange1()))
+ for ny in range(self.y-4, limity-4, -4):
+ self.move(self.x, ny)
+ if ny < -32:
+ self.vertical_warp()
+ yield None
+ self.resetimages()
+ self.gen.append(self.default_mode())
+
+ def regular(self):
+ return self.still_playing() and self.touchable and not self.is_ghost
+
+ def still_playing(self):
+ return (self.in_list is BubPlayer.MonsterList and
+ self in self.in_list)
+
+ def touched(self, dragon):
+ if self.gen:
+ self.killdragon(dragon)
+ if self.is_ghost and not hasattr(self, 'bubber'):
+ self.gen = [self.default_mode()]
+ self.resetimages()
+ else:
+ self.argh(getattr(self, 'poplist', None)) # frozen monster
+
+ def killdragon(self, dragon):
+ dragon.die()
+
+ def in_bubble(self, bubble):
+ if not hasattr(self.mdef, 'jailed'):
+ return
+ self.untouchable()
+ self.angry = []
+ bubble.move(self.x, self.y)
+ if not hasattr(bubble, 'withmonster'):
+ bubble.to_front()
+ self.to_front()
+ img = self.mdef.jailed
+ self.gen = [self.bubbling(bubble)]
+ self.setimages(self.cyclic([img[1], img[2], img[1], img[0]], 4))
+
+ def bubbling(self, bubble):
+ counter = 0
+ while not hasattr(bubble, 'poplist'):
+ self.move(bubble.x, bubble.y)
+ yield None
+ counter += 1
+ if counter == 50 and hasattr(self, 'bubber'):
+ bubble.setimages(bubble.bubble_red())
+ if bubble.poplist is None:
+ self.touchable = 1
+ self.angry = [self.genangry()]
+ self.resetimages()
+ self.gen.append(self.default_mode())
+ else:
+ previous_len = len(BubPlayer.MonsterList)
+ self.argh(bubble.poplist)
+ dragon = bubble.poplist[0]
+ if dragon is not None:
+ if previous_len and not BubPlayer.MonsterList:
+ points = 990
+ else:
+ points = 90
+ dragon.bubber.givepoints(points)
+
+ def argh(self, poplist=None, onplace=0):
+ if self not in self.in_list:
+ return
+ if not poplist:
+ poplist = [None]
+ poplist.append(self)
+ level = len(poplist) - 2
+ bonuses.BonusMaker(self.x, self.y, self.mdef.dead, onplace=onplace,
+ outcome=(self.MonsterBonus, level))
+ self.kill()
+
+ def freeze(self, poplist):
+ # don't freeze monsters largely out of screen, or they'll never come in
+ if self.regular() and -self.ico.h < self.y < boards.bheight:
+ self.gen = []
+ self.poplist = poplist
+
+ def flying(self):
+ blocked = 0
+ while 1:
+ if random.random() < 0.2 and self.overlapping():
+ yield None
+ hstep = self.tryhstep()
+ vstep = self.tryvstep()
+ if hstep or vstep:
+ blocked = 0
+ elif blocked:
+ # blocked! go up or back to the play area
+ if self.x < 32:
+ self.step(self.vy, 0)
+ elif self.x > boards.bwidth - 64:
+ self.step(-self.vy, 0)
+ else:
+ self.step(0, -self.vy)
+ self.vertical_warp()
+ else:
+ blocked = 1
+ yield None
+
+ def becoming_monster(self, big=0, immed=0):
+ if big:
+ self.is_ghost = 1
+ self.seticon(images.sprget(self.imgrange()[0]))
+ images.Snd.Hell.play()
+ for i in range(5):
+ ico = self.ico
+ self.seticon(self.bubber.icons[11 + immed, self.dir])
+ yield None
+ yield None
+ self.seticon(ico)
+ yield None
+ yield None
+ self.resetimages(is_ghost=big)
+ self.gen.append(self.playing_monster())
+
+ def become_monster(self, bubber, saved_caps, big=0, immed=0):
+ self.timeoutgen = self.back_to_dragon()
+ self.default_mode = self.playing_monster
+ self.bubber = bubber
+ self.dcap = saved_caps
+ self.gen = [self.becoming_monster(big, immed)]
+
+ def back_to_dragon(self):
+ for t in range(259):
+ yield None
+ if bonuses.getdragonlist():
+ yield None
+ yield None
+ yield None
+ from player import Dragon
+ d = Dragon(self.bubber, self.x, self.y, self.dir, self.dcap)
+ d.dcap['shield'] = 50
+ self.bubber.dragons.append(d)
+ self.kill()
+
+ def playing_monster(self):
+ if self.timeoutgen not in self.gen:
+ self.gen.append(self.timeoutgen)
+ bubber = self.bubber
+ while self.is_ghost:
+ # ghost
+ self.angry = []
+ key, dx, dy = max([(bubber.key_left, -1, 0),
+ (bubber.key_right, 1, 0),
+ (bubber.key_jump, 0, -1),
+ (bubber.key_fire, 0, 1)])
+ if key:
+ if dx and self.dir != dx:
+ self.dir = dx
+ self.resetimages(is_ghost=1)
+ nx = self.x + 10*dx
+ ny = self.y + 9*dy
+ if nx < 0: nx = 0
+ if nx > boards.bwidth-2*CELL: nx = boards.bwidth-2*CELL
+ if ny < -CELL: ny = -CELL
+ if ny > boards.bheight-CELL: ny = boards.bheight-CELL
+ self.move(nx, ny)
+ yield None
+ if self.vy:
+ # flying monster
+ while 1:
+ dx = bubber.wannago(self.dcap)
+ if dx and dx != self.dir:
+ self.dir = dx
+ self.resetimages()
+ if bubber.key_jump and bubber.key_jump > bubber.key_fire:
+ dy = self.vdir = -1
+ elif bubber.key_fire:
+ dy = self.vdir = 1
+ else:
+ dy = 0
+ hstep = dx and self.tryhstep()
+ vstep = dy and self.tryvstep()
+ if dx and dy and not (hstep or vstep):
+ # blocked?
+ self.dir = -self.dir
+ self.vdir = -self.vdir
+ blocked = self.blocked() and self.vblocked()
+ self.dir = -self.dir
+ self.vdir = -self.vdir
+ if blocked:
+ # completely blocked! accept move or force back to
+ # play area
+ if self.x < 32:
+ self.step(self.vy, 0)
+ elif self.x > boards.bwidth - 64:
+ self.step(-self.vy, 0)
+ else:
+ self.step(self.vx*dx, self.vy*dy)
+ self.vertical_warp()
+ yield None
+ elif not isinstance(self, Springy):
+ # walking monster
+ jumping_y = 0
+ imgsetter = self.imgsetter
+ while onground(self.x, self.y) or jumping_y:
+ dx = bubber.wannago(self.dcap)
+ if dx and dx != self.dir:
+ self.dir = dx
+ self.resetimages()
+ imgsetter = self.imgsetter
+ if dx and not self.blocked():
+ self.step(self.vx*dx, 0)
+ if not jumping_y:
+ self.setimages(imgsetter)
+ else:
+ self.seticon(images.sprget(self.imgrange1()))
+ self.setimages(None)
+ else:
+ self.setimages(None)
+ dx = 0
+ yield None
+ if not jumping_y:
+ wannafire = bubber.key_fire
+ wannajump = bubber.key_jump
+ if wannafire and self.shoot(1):
+ return
+ if wannajump:
+ jumping_y = CELL
+ if jumping_y:
+ self.step(0, -4)
+ if self.y < -32:
+ self.vertical_warp()
+ if onground(self.x, self.y):
+ jumping_y = 0
+ else:
+ jumping_y -= 1
+ self.gen.append(self.falling())
+ else:
+ # springy
+ if not onground(self.x, self.y):
+ self.gen.append(self.falling())
+ return
+ prevx = self.x
+ for t in self.walking():
+ dx = bubber.wannago(self.dcap)
+ if dx:
+ if dx != self.dir:
+ self.dir = dx
+ self.resetimages()
+ if self.blocked() and (self.x-prevx)*dx <= 0:
+ dx = 0
+ self.move(prevx + self.vx*dx, self.y)
+ yield None
+ prevx = self.x
+
+ def become_ghost(self):
+ self.gen = [self.ghosting()]
+ self.resetimages(is_ghost=1)
+
+ def ghosting(self):
+ counter = 0
+ while counter < 5:
+ for i in range(50):
+ yield None
+ dragon = self.tagdragon()
+ if dragon is None:
+ counter += 1
+ else:
+ counter = 0
+ px, py = dragon.x, dragon.y
+ if abs(px-self.x) < abs(py-self.y):
+ dx = 0
+ if py > self.y:
+ dy = 1
+ else:
+ dy = -1
+ else:
+ dy = 0
+ if px > self.x:
+ dx = 1
+ else:
+ dx = -1
+ self.dir = dx
+ self.resetimages(is_ghost=1)
+ dx *= 10
+ dy *= 9
+ distance = 1E10
+ while 1:
+ self.angry = []
+ self.step(dx, dy)
+ yield None
+ dist1 = (px-self.x)*(px-self.x)+(py-self.y)*(py-self.y)
+ if dist1 > distance:
+ break
+ distance = dist1
+ self.angry = []
+ self.gen = [self.default_mode()]
+ self.resetimages()
+
+ default_mode = falling
+
+
+def argh_em_all():
+ poplist = [None]
+ for s in images.ActiveSprites[:]:
+ if isinstance(s, Monster):
+ s.argh(poplist)
+
+def freeze_em_all():
+ poplist = [None]
+ for s in images.ActiveSprites:
+ if isinstance(s, Monster):
+ s.freeze(poplist)
+
+
+class MonsterShot(ActiveSprite):
+ speed = 6
+ touchable = 1
+
+ def __init__(self, owner, dx=CELL, dy=0):
+ self.owner = owner
+ self.speed = owner.dir * self.speed
+ if owner.dir < 0:
+ nimages = owner.mdef.left_weapon
+ else:
+ nimages = owner.mdef.right_weapon
+ ActiveSprite.__init__(self, images.sprget(nimages[0]),
+ owner.x, owner.y + dy)
+ self.step((owner.ico.w - self.ico.w) // 2,
+ (owner.ico.h - self.ico.h) // 2)
+ if not self.blocked():
+ self.step(dx*owner.dir, 0)
+ if len(nimages) > 1:
+ self.setimages(self.cyclic(nimages, 3))
+ self.gen.append(self.moving())
+
+ def blocked(self):
+ if self.speed < 0:
+ x0 = (self.x-self.speed-8)//16
+ else:
+ x0 = (self.x+self.ico.w+self.speed-8)//16
+ y0 = (self.y+8) // 16 + 1
+ return not (' ' == bget(x0,y0) == bget(x0+1,y0))
+
+ def moving(self):
+ while not self.blocked():
+ yield None
+ self.step(self.speed, 0)
+ self.hitwall()
+
+ def hitwall(self):
+ self.untouchable()
+ self.gen.append(self.die(self.owner.mdef.decay_weapon, 2))
+
+ def touched(self, dragon):
+ dragon.die()
+
+
+class BoomerangShot(MonsterShot):
+ speed = 8
+
+ def hitwall(self):
+ self.gen.append(self.moveback())
+
+ def moveback(self):
+ owner = self.owner
+ if self.speed > 0:
+ nimages = owner.mdef.left_weapon
+ else:
+ nimages = owner.mdef.right_weapon
+ self.setimages(self.cyclic(nimages, 3))
+ while (owner.x-self.x) * self.speed < 0:
+ yield None
+ self.step(-self.speed, 0)
+ if self.blocked():
+ break
+ self.kill()
+
+class FastShot(MonsterShot):
+ speed = 15
+
+
+class DownShot(MonsterShot):
+
+ def __init__(self, owner):
+ MonsterShot.__init__(self, owner, 0, CELL)
+
+ def moving(self):
+ while self.y < boards.bheight:
+ yield None
+ self.step(0, 7)
+ self.kill()
+
+
+##class DragonShot(MonsterShot):
+## speed = 8
+
+## def __init__(self, owner):
+## MonsterShot.__init__(self, owner)
+## self.untouchable()
+## self.gen.append(self.touchdelay(4))
+
+## def touched(self, dragon):
+## if dragon is not self.owner:
+## if dragon.bubber.bonbons == 0:
+## dragon.die()
+## else:
+## from player import scoreboard
+## from bonuses import Sugar1, Sugar2
+## from bonuses import BonusMaker
+## if random.random() < 0.2345:
+## start = 1
+## else:
+## start = 0
+## loose = min(2, dragon.bubber.bonbons)
+## for i in range(start, loose):
+## cls = random.choice([Sugar1, Sugar2])
+## BonusMaker(self.x, self.y, [cls.nimage],
+## outcome=(cls,))
+## dragon.bubber.bonbons -= loose
+## scoreboard()
+## dragon.dcap['shield'] = 25
+## self.owner.play(images.Snd.Yippee)
+## self.kill()
+
+## def blocked(self):
+## return self.x < -self.ico.w or self.x >= gamesrv.game.width
+## #return self.x < CELL or self.x >= boards.bwidth - 3*CELL
+
+
+class Nasty(Monster):
+ pass
+
+class Monky(Monster):
+ shootcls = MonsterShot
+
+class Ghosty(Monster):
+ default_mode = Monster.flying
+ vy = 2
+
+class Flappy(Monster):
+ default_mode = Monster.flying
+ vy = 1
+
+class Springy(Monster):
+ spring_down = 0
+ def imgrange(self):
+ if self.spring_down and not self.is_ghost:
+ if self.angry:
+ if self.dir > 0:
+ r = self.mdef.right_jump_angry
+ else:
+ r = self.mdef.left_jump_angry
+ else:
+ if self.dir > 0:
+ r = self.mdef.right_jump
+ else:
+ r = self.mdef.left_jump
+ return [r[self.spring_down-1]]
+ else:
+ return Monster.imgrange(self)
+ def walking(self):
+ self.spring_down = 1
+ self.resetimages()
+ for t in range(2+self.overlapping()):
+ yield None
+ self.spring_down = 2
+ self.resetimages()
+ for t in range(4+2*self.overlapping()):
+ yield None
+ self.spring_down = 1
+ self.resetimages()
+ for t in range(2+self.overlapping()):
+ yield None
+ self.spring_down = 0
+ self.resetimages()
+ g = 10.0/43
+ vy = -20*g
+ yf = self.y
+ for t in range(40):
+ yf += vy
+ vy += g
+ if self.blocked():
+ self.dir = -self.dir
+ self.resetimages()
+ nx = self.x + self.dir*self.vx
+ if self.y//16 < int(yf)//16:
+ if onground(self.x, (self.y//16+1)*16):
+ break
+ if onground(nx, (self.y//16+1)*16):
+ self.move(nx, self.y)
+ break
+ nx, yf = vertical_warp(nx, yf)
+ self.move(nx, int(yf))
+## if moebius:
+## self.moebius()
+ yield None
+ self.gen.append(self.falling())
+
+class Orcy(Monster):
+ shootcls = FastShot
+
+class Gramy(Monster):
+ shootcls = BoomerangShot
+ vx = 3
+
+class Blitzy(Monster):
+ shootcls = DownShot
+ vx = 3
+
+ def seedragon(self, dragon=None):
+ return 0
+
+ def special(self):
+ if random.random() < 0.3:
+ self.shootcls(self)
+ return 0
+
+ def shoot(self, pause=0):
+ # no pause (only used when controlled by the player)
+ if self.no_shoot_before > BubPlayer.FrameCounter:
+ pass
+ else:
+ self.shootcls(self)
+ self.no_shoot_before = BubPlayer.FrameCounter + 29
+ return 0
+
+MonsterClasses = [c for c in globals().values()
+ if type(c)==type(Monster) and issubclass(c, Monster)]
+MonsterClasses.remove(Monster)
+
+
+class Butterfly(Monster):
+ MonsterBonus = bonuses.IceMonsterBonus
+ fly_away = False
+
+ def waiting(self, delay=0):
+ return Monster.waiting(self, delay)
+
+ def imgrange(self):
+ self.angry = []
+ return Monster.imgrange(self)
+
+ def killdragon(self, dragon):
+ if self.is_ghost:
+ Monster.killdragon(self, dragon)
+ else:
+ self.fly_away = True, dragon.x
+
+ def flying(self):
+ repeat = 0
+ while 1:
+ r = random.random()
+ if self.x < 64:
+ bump = self.dir < 0
+ elif self.x > boards.bwidth - 64:
+ bump = self.dir > 0
+ elif self.fly_away:
+ wannago = self.x - self.fly_away[1]
+ if self.x < 100:
+ wannago = 1
+ elif self.x > boards.bwidth - 100:
+ wannago = -1
+ bump = self.dir * wannago < 0
+ if repeat:
+ self.fly_away = False
+ repeat = 0
+ else:
+ repeat = 1
+ else:
+ bump = r < 0.07
+ if bump:
+ self.dir = -self.dir
+ self.resetimages()
+ elif r > 0.92:
+ self.vdir = -self.vdir
+ self.step(self.dir * (2 + (r < 0.5)), self.vdir * 2)
+ self.vertical_warp()
+ if not repeat:
+ yield None
+
+ default_mode = flying
+
+
+class Sheep(Monster):
+
+ def playing_monster(self):
+ from bonuses import Bonus
+ bubber = self.bubber
+ vy = None
+ imgsetter = self.imgsetter
+ poplist = [None]
+ while 1:
+ dx = bubber.wannago(self.dcap)
+ if dx and dx != self.dir:
+ self.dir = dx
+ self.resetimages()
+ imgsetter = self.imgsetter
+ if dx and vy is None:
+ self.setimages(imgsetter)
+ else:
+ self.setimages(None)
+ if vy is not None:
+ if vy < 0:
+ n = 1
+ else:
+ n = 3
+ self.seticon(images.sprget(self.imgrange()[n]))
+ if dx and not self.blocked():
+ self.step(self.vx*dx, 0)
+ yield None
+ impulse = 0.0
+ wannajump = bubber.key_jump
+ if vy is not None:
+ vy += 0.33
+ if vy > 12.0:
+ vy = 12.0
+ yf = self.y + yfp + vy
+ yfp = yf - int(yf)
+ delta = int(yf) - self.y
+ if delta > 0:
+ by_y = {}
+ for s in images.ActiveSprites:
+ if isinstance(s, Bonus) and s.touchable:
+ if abs(s.x - self.x) <= 22:
+ by_y[s.y] = s
+ for monster in BubPlayer.MonsterList:
+ if abs(monster.x - self.x) <= 22:
+ if monster.regular():
+ by_y[monster.y] = monster
+ for ny in range(self.y - 1, self.y + delta + 1):
+ self.move(self.x, ny)
+ self.vertical_warp()
+ if onground(self.x, self.y):
+ poplist = [None]
+ impulse = vy
+ vy = None
+ break
+ key = self.y + 29
+ if key in by_y:
+ s = by_y[key]
+ if isinstance(s, Monster):
+ self.play(images.Snd.Extra)
+ s.argh(poplist)
+ elif isinstance(s, Bonus):
+ s.reallytouched(self)
+ yfp = 0.0
+ vy = -3.3
+ break
+ else:
+ self.step(0, delta)
+ self.vertical_warp()
+ if vy is None:
+ if onground(self.x, self.y):
+ if wannajump:
+ yfp = 0.0
+ vy = - max(1.0, impulse) - 2.02
+ impulse = 0.0
+ self.play(images.Snd.Jump)
+ else:
+ yfp = vy = 0.0
+ if impulse > 8.1:
+ break
+ self.play(images.Snd.Pop)
+ for n in range(2):
+ for letter in 'abcdefg':
+ ico = images.sprget(('sheep', letter))
+ nx = self.x + random.randrange(-1, self.ico.w - ico.w + 2)
+ ny = self.y + random.randrange(0, self.ico.h - ico.h + 2)
+ dxy = [random.random() * 5.3 - 2.65, random.random() * 4 - 4.4]
+ s = images.ActiveSprite(ico, nx, ny)
+ s.gen.append(s.parabolic(dxy))
+ s.gen.append(s.die([None], random.randrange(35, 54)))
+ self.move(-99, 0)
+ for t in range(68):
+ yield None
+ self.kill()
+
+ default_mode = falling = playing_monster
+
+ def argh(self, *args, **kwds):
+ pass