mirror of
https://github.com/abakh/nbsdgames.git
synced 2025-02-02 15:07:27 -05:00
938 lines
29 KiB
Python
938 lines
29 KiB
Python
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
|