Mercurial > mamba
view mamba/sprites.py @ 342:868a53b96c29
Protect against malformed sprite lines
author | Neil Muller <drnlmuller@gmail.com> |
---|---|
date | Fri, 16 Sep 2011 22:02:38 +0200 |
parents | c44821def687 |
children | ff1c39075452 |
line wrap: on
line source
from pygame.sprite import Sprite from pygame import Rect from mamba.data import load_tile_image from mamba.constants import TILE_SIZE, UP, DOWN, LEFT, RIGHT from mamba.engine import FlipArrowsEvent from mamba.sound import load_sound, play_sound from mamba import mutators COLOURS = { 'red': mutators.RED, 'blue': mutators.BLUE, 'yellow': mutators.YELLOW, } def colour_with_fittings(image_name, tileset, colour): fittings_mutator = mutators.Overlay("%s-fittings" % (image_name,), tileset) return image_name, (COLOURS[colour], fittings_mutator) def get_detail_mutator(image_name, tileset): return mutators.Overlay("%s-detail" % (image_name,), tileset) def tile_sizify(pos): ts_x, ts_y = TILE_SIZE p_x, p_y = pos return (ts_x * p_x, ts_y * p_y) def find_sprite(class_name): cls = globals()[class_name] assert isinstance(cls, type) and issubclass(cls, Sprite) return cls class SpriteImageVariants(object): VARIANTS = { '....': ('-0', ()), 'X...': ('-1', (mutators.R90,)), '.X..': ('-1', (mutators.R270,)), '..X.': ('-1', (mutators.NULL,)), '...X': ('-1', (mutators.R180,)), 'XX..': ('-2o', (mutators.NULL,)), '..XX': ('-2o', (mutators.R90,)), 'X.X.': ('-2a', (mutators.R180,)), 'X..X': ('-2a', (mutators.R270,)), '.XX.': ('-2a', (mutators.R90,)), '.X.X': ('-2a', (mutators.NULL,)), '.XXX': ('-3', (mutators.R90,)), 'X.XX': ('-3', (mutators.R270,)), 'XX.X': ('-3', (mutators.NULL,)), 'XXX.': ('-3', (mutators.R180,)), 'XXXX': ('', ()), } def __init__(self, base_image_name): self.base_image_name = base_image_name def __call__(self, top, bottom, left, right): variant_str = ''.join('X' if d else '.' for d in [top, bottom, left, right]) variant_suffix, mutators = self.VARIANTS[variant_str] return (self.base_image_name + variant_suffix, mutators) class SolidSpriteImageVariants(SpriteImageVariants): VARIANTS = { '....': ('-0', ()), 'X...': ('-1', (mutators.R270,)), '.X..': ('-1', (mutators.R90,)), '..X.': ('-1', (mutators.NULL,)), '...X': ('-1', (mutators.R180,)), 'XX..': ('', ()), '..XX': ('', ()), 'X.X.': ('-2a', (mutators.R180,)), 'X..X': ('-2a', (mutators.R90,)), '.XX.': ('-2a', (mutators.R270,)), '.X.X': ('-2a', (mutators.NULL,)), '.XXX': ('', ()), 'X.XX': ('', ()), 'XX.X': ('', ()), 'XXX.': ('', ()), 'XXXX': ('', ()), } class BaseSprite(Sprite): tileset = 'common' variants_class = None variants = None name = None alive = True def __init__(self, tileset=None, image_name=None, name=None, mutators=()): super(BaseSprite, self).__init__() if name is not None: self.name = name if tileset is not None: self.tileset = tileset if image_name is not None: self.image_name = image_name self.image = self.load_image(image_name, mutators=mutators) def load_image(self, image_name, mutators=()): return load_tile_image(image_name, self.tileset, mutators) def set_tile_pos(self, tile_pos): self.tile_pos = tile_pos self.rect = Rect(tile_sizify(tile_pos), TILE_SIZE) def get_variant(self, top, bottom, left, right): if self.variants is None: self.variants = self.variants_class(self.image_name) return self.variants(top, bottom, left, right) def use_variant(self, *args): if self.variants_class is not None: self.image = self.load_image(*self.get_variant(*args)) class TileSprite(BaseSprite): def __init__(self, tile_char, solid=False, **kw): super(TileSprite, self).__init__(**kw) self.tile_char = tile_char self.solid = solid def get_solid(self, snake, segment): return self.solid def interact(self, world, segment): if self.get_solid(world.snake, segment): world.snake.crash('You hit a %s' % self.name) class SingleImageTileSprite(TileSprite): image_name = None # subclasses will override this def __init__(self, **kw): kw.setdefault('image_name', self.image_name) kw.setdefault('name', self.name) super(SingleImageTileSprite, self).__init__(**kw) class DoorSprite(TileSprite): name = 'door' def __init__(self, colour, **kw): self.colour = colour super(DoorSprite, self).__init__(**kw) self.image = self.load_image( *colour_with_fittings("door", self.tileset, colour)) def get_solid(self, snake, segment): return COLOURS[self.colour] != segment.colour class DirectionalTile(SingleImageTileSprite): def __init__(self, direction=RIGHT, **kw): super(DirectionalTile, self).__init__(**kw) self.set_direction(direction) def set_direction(self, direction): self.direction = direction mutator = { UP: mutators.UP, DOWN: mutators.DOWN, LEFT: mutators.LEFT, RIGHT: mutators.RIGHT, }[direction] self.image = self.load_image(self.image_name, (mutator,)) def get_solid(self, snake, segment): dx, dy = self.direction sx, sy = segment.orientation if not (dx + sx or dy + sy): return True return False class ArrowSprite(DirectionalTile): image_name = 'arrow-r' name = 'arrow' def rotate(self): self.set_direction({LEFT: UP, UP: RIGHT, RIGHT: DOWN, DOWN: LEFT}[self.direction]) class FlipArrows(SingleImageTileSprite): image_name = 'flip-arrows' name = 'flip' def interact(self, snake, segment): FlipArrowsEvent.post() class EntrySprite(DirectionalTile): image_name = 'arrow-r' name = 'entrance' class ExitSprite(SingleImageTileSprite): image_name = 'exit' name = 'exit' def interact(self, world, segment): world.snake.exit_level() class TunnelSprite(DirectionalTile): image_name = 'tunnel-r' name = 'tunnel entrance' tileset = 'lab' def __init__(self, other_id, direction): direction = { 'north': UP, 'south': DOWN, 'east': LEFT, 'west': RIGHT, }[direction] super(TunnelSprite, self).__init__(tile_char=None, direction=direction) self.other_id = other_id def interact(self, world, segment): head = world.snake.head if segment is head and head.orientation == self.direction: other = world.get_sprite(self.other_id) head.shift_tile_and_pixels((other.tile_pos, self.direction)) class PuddleSprite(SingleImageTileSprite): image_name = 'puddle' name = 'puddle' variants_class = SolidSpriteImageVariants def __init__(self, variant=(0, 0, 0, 0), **kw): super(PuddleSprite, self).__init__(**kw) self.image = self.load_image(*self.get_variant(*variant)) def get_solid(self, snake, segment): if snake.can_swim(): return False return True def interact(self, world, segment): segment.set_colour(segment.GREEN) super(PuddleSprite, self).interact(world, segment) class FireSprite(SingleImageTileSprite): image_name = 'fire' name = 'fire' variants_class = SolidSpriteImageVariants detail = 'fire-detail' def __init__(self, variant=(0, 0, 0, 0), **kw): super(FireSprite, self).__init__(**kw) self.image = self.load_image(*self.get_variant(*variant)) def load_image(self, image_name, mutators=()): mutators += (get_detail_mutator(self.image_name, self.tileset),) return super(FireSprite, self).load_image(image_name, mutators) def get_solid(self, snake, segment): if snake.flame_retardant(): return False return True def interact(self, world, segment): segment.set_colour(segment.GREEN) super(FireSprite, self).interact(world, segment) class EdibleTile(SingleImageTileSprite): sound_name = 'squeak.ogg' def __init__(self, **kw): if self.sound_name: load_sound(self.sound_name, self.sound_name) super(EdibleTile, self).__init__(**kw) def interact(self, world, segment): if not segment.is_head: return if self.sound_name: play_sound(self.sound_name) world.snake.head.mouth_open() self.eat(world.snake) self.alive = False self.kill() def eat(self, snake): pass class BigMouse(EdibleTile): image_name = "rat-big" def eat(self, snake): snake.add_segment() class SmallMouse(EdibleTile): image_name = "rat-small" def eat(self, snake): snake.remove_segment() class Frog(EdibleTile): image_name = "frog" def eat(self, snake): snake.mutate('amphibious') class Snail(EdibleTile): image_name = "snail" def eat(self, snake): snake.adjust_speed(-15) class Lizard(EdibleTile): image_name = "lizard" def eat(self, snake): snake.adjust_speed(15) class Salamander(EdibleTile): image_name = "salamander" def eat(self, snake): snake.mutate('flame-retardant') class Painter(TileSprite): def __init__(self, colour, **kw): super(Painter, self).__init__(**kw) self.colour = colour self.image = self.load_image( *colour_with_fittings("spray", self.tileset, colour)) def interact(self, world, segment): segment.set_colour(COLOURS[self.colour])