# HG changeset patch # User David Sharpe # Date 1378584956 -7200 # Node ID 66dd5ac002b76623ce27bfdbf311f3e435d10666 # Parent 06ed0160cd92d4a87d1cf059e0ecc4ff70961b9d# Parent 57efcd81647b547b0668d372903f11396940994f Merge diff -r 06ed0160cd92 -r 66dd5ac002b7 data/images/objects/sokobox.png Binary file data/images/objects/sokobox.png has changed diff -r 06ed0160cd92 -r 66dd5ac002b7 data/levels/alientunnel2 --- a/data/levels/alientunnel2 Sat Sep 07 22:15:04 2013 +0200 +++ b/data/levels/alientunnel2 Sat Sep 07 22:15:56 2013 +0200 @@ -76,8 +76,8 @@ - [1100, 800] - [1100, 1000] - door_switch - classname: Bulkhead - name: switch_bulkhead + classname: Hatch + name: switch_hatch lines: - - [1100, 800] - [1100, 400] diff -r 06ed0160cd92 -r 66dd5ac002b7 data/levels/crew --- a/data/levels/crew Sat Sep 07 22:15:04 2013 +0200 +++ b/data/levels/crew Sat Sep 07 22:15:56 2013 +0200 @@ -100,6 +100,16 @@ - [900, 900] classname: PatrollingAlien name: patrol_10 +- args: + - [1588, 2196] + - 300 + classname: RunAndGunAlien + name: mess_alien_1 +- args: + - [1760, 2000] + - 300 + classname: RunAndGunAlien + name: mess_alien_2 game_objects: - args: - [730, 936] @@ -127,7 +137,8 @@ - null - [2017, 1922] - -28 - classname: Door + - mess_door_puzzle + classname: PuzzleDoor name: store_enter - args: - [1997, 1928] @@ -315,6 +326,27 @@ - keycard_black classname: collectable.KeyCard name: keycard_black +- args: + - [220, 1720] + - Please wear goggles at all times while swimming. + classname: Note + name: wear_goggles +- args: + - [1688, 2320] + - Please keep the mess tidy. + classname: Note + name: mess_tidy +- args: + - [1940, 2048] + classname: FloorSwitch + name: mess_switch_1 +- args: + - [1860, 1892] + classname: FloorSwitch + name: mess_switch_2 +- args: [mess_switch_1, mess_switch_2] + classname: puzzle.StateLogicalAndPuzzler + name: mess_door_puzzle lines: [] polygons: 1: diff -r 06ed0160cd92 -r 66dd5ac002b7 data/levels/finale --- a/data/levels/finale Sat Sep 07 22:15:04 2013 +0200 +++ b/data/levels/finale Sat Sep 07 22:15:56 2013 +0200 @@ -1,5 +1,10 @@ base_tile: tiles/alien_tile.png -enemies: [] +enemies: +- args: + - [1400, 1400] + - 500 + classname: Queen + name: queen game_objects: - args: - [2100, 700] diff -r 06ed0160cd92 -r 66dd5ac002b7 data/levels/hangar --- a/data/levels/hangar Sat Sep 07 22:15:04 2013 +0200 +++ b/data/levels/hangar Sat Sep 07 22:15:56 2013 +0200 @@ -90,8 +90,8 @@ - [280, 1160] - [280, 1260] - maint_output - classname: Bulkhead - name: maint_bulkhead + classname: Hatch + name: maint_hatch - args: [maint_switch_1, maint_switch_2, maint_toggle_1, maint_toggle_2] classname: puzzle.StateLogicalAndPuzzler name: maint_output diff -r 06ed0160cd92 -r 66dd5ac002b7 data/levels/level1 --- a/data/levels/level1 Sat Sep 07 22:15:04 2013 +0200 +++ b/data/levels/level1 Sat Sep 07 22:15:56 2013 +0200 @@ -46,8 +46,8 @@ - [800, 680] - [900, 680] - door_switch - classname: Bulkhead - name: switch_bulkhead + classname: Hatch + name: switch_hatch - args: - [410, 400] - level2 diff -r 06ed0160cd92 -r 66dd5ac002b7 data/levels/sheep --- a/data/levels/sheep Sat Sep 07 22:15:04 2013 +0200 +++ b/data/levels/sheep Sat Sep 07 22:15:56 2013 +0200 @@ -32,8 +32,8 @@ - [700, 700] - [800, 700] - sheep_pen - classname: Bulkhead - name: sheep_bulkhead + classname: Hatch + name: sheep_hatch - args: - [750, 750] - keycard_green diff -r 06ed0160cd92 -r 66dd5ac002b7 data/levels/start --- a/data/levels/start Sat Sep 07 22:15:04 2013 +0200 +++ b/data/levels/start Sat Sep 07 22:15:56 2013 +0200 @@ -1,5 +1,5 @@ base_tile: tiles/floor.png -enemies: +enemies: [] game_objects: - args: - [725, 300] @@ -31,6 +31,56 @@ - Go through this door to continue the game classname: Note name: note_continue +- args: + - [225, 300] + classname: FloorSwitch + name: cockpit_switch +- args: + - [225, 250] + - [225, 350] + - cockpit_switch + classname: Hatch + name: cockpit_hatch +- args: + - [300, 225] + classname: FloorSwitch + name: room_1_switch +- args: + - [250, 225] + - [350, 225] + - room_1_switch + classname: Hatch + name: room_1_hatch +- args: + - [550, 225] + classname: FloorSwitch + name: room_2_switch +- args: + - [500, 225] + - [600, 225] + - room_2_switch + classname: Hatch + name: room_2_hatch +- args: + - [300, 375] + classname: FloorSwitch + name: room_3_switch +- args: + - [250, 375] + - [350, 375] + - room_3_switch + classname: Hatch + name: room_3_hatch +- args: + - [550, 375] + classname: FloorSwitch + name: room_4_switch +- args: + - [500, 375] + - [600, 375] + - room_4_switch + classname: Hatch + name: room_4_hatch lines: [] polygons: 1: diff -r 06ed0160cd92 -r 66dd5ac002b7 nagslang/enemies.py --- a/nagslang/enemies.py Sat Sep 07 22:15:04 2013 +0200 +++ b/nagslang/enemies.py Sat Sep 07 22:15:56 2013 +0200 @@ -305,6 +305,43 @@ ("attack_range", "distance")] +class Queen(RunAndGunAlien): + enemy_type = "queen" + impulse_factor = 180 + health = 500 + enemy_damage = 50 + is_moving = True + spawn_time = 10 + spawn_size = 5 + spawn_class = ChargingAlien + spawn_class_args = (200,) + + def __init__(self, space, world, position, attack_range=100): + super(Queen, self).__init__(space, world, position, attack_range) + self.add_timer('spawn', self.spawn_time) + + def spawn(self, result): + if not self.check_timer('spawn'): + self.start_timer('spawn', self.spawn_time) + for i in range(self.spawn_size): + result.add += (self.spawn_class(self.get_space(), + self.world, self.physicser.position, + *self.spawn_class_args),) + + def attack(self, result): + self.ranged_attack(300, ACID_SPEED, ACID_DAMAGE, 'acid', 1, result) + + def update(self, dt): + result = super(Queen, self).update(dt) + self.spawn(result) + return result + + @classmethod + def requires(cls): + return [("name", "string"), ("position", "coordinates"), + ("attack_range", "distance")] + + class Sheep(Enemy): # Only because we don't have a DeliciousCreature class. is_moving = True # Always walking. enemy_type = 'sheep' diff -r 06ed0160cd92 -r 66dd5ac002b7 nagslang/game_object.py --- a/nagslang/game_object.py Sat Sep 07 22:15:04 2013 +0200 +++ b/nagslang/game_object.py Sat Sep 07 22:15:56 2013 +0200 @@ -359,6 +359,25 @@ ("state_source", "puzzler")] +class SokoBox(GameObject): + def __init__(self, space, position): + body = make_body(1, pymunk.inf, position) + self.shape = pymunk.Poly( + body, [(-40, -40), (40, -40), (40, 40), (-40, 40)]) + self.shape.friction = 0.5 + self.shape.collision_type = COLLISION_TYPE_FURNITURE + super(Box, self).__init__( + SingleShapePhysicser(space, self.shape), + render.ImageRenderer( + resources.get_image('objects', 'sokobox.png')), + ) + + @classmethod + def requires(cls): + return [("name", "string"), ("position", "coordinates"), + ("state_source", "puzzler")] + + class BaseDoor(GameObject): zorder = ZORDER_FLOOR is_open = True @@ -480,7 +499,7 @@ ("angle", "degrees"), ("key_item", "item name")] -class Bulkhead(GameObject): +class Hatch(GameObject): zorder = ZORDER_FLOOR def __init__(self, space, end1, end2, key_state=None): @@ -491,9 +510,9 @@ puzzler = puzzle.YesPuzzler() else: puzzler = puzzle.StateProxyPuzzler(key_state) - super(Bulkhead, self).__init__( + super(Hatch, self).__init__( SingleShapePhysicser(space, self.shape), - render.BulkheadRenderer(), + render.HatchRenderer(), puzzler, ) @@ -626,6 +645,12 @@ self._ticks = 0 self.shape.collision_type = COLLISION_TYPE_SWITCH self.shape.sensor = True + renderer = self._fix_image(outline) + super(HostileTerrain, self).__init__( + SingleShapePhysicser(space, self.shape), + renderer) + + def _fix_image(self, outline): if len(self.tiles) > 1: tile_images = [resources.get_image('tiles', x) for x in self.tiles] @@ -636,9 +661,10 @@ tile_image = resources.get_image('tiles', self.tiles[0]) renderer = render.TiledRenderer(outline, tile_image, self.tile_alpha) - super(HostileTerrain, self).__init__( - SingleShapePhysicser(space, self.shape), - renderer) + return renderer + + def update_image(self, new_outline): + self.renderer = self._fix_image(new_outline) def collide_with_protagonist(self, protagonist): # We're called every frame we're colliding, so diff -r 06ed0160cd92 -r 66dd5ac002b7 nagslang/mutators.py --- a/nagslang/mutators.py Sat Sep 07 22:15:04 2013 +0200 +++ b/nagslang/mutators.py Sat Sep 07 22:15:56 2013 +0200 @@ -57,10 +57,28 @@ return image +class ImageCentre(Mutator): + def __init__(self, size): + super(ImageCentre, self).__init__(ImageCentre.centre, size) + + @classmethod + def centre(cls, image, size): + if image.get_size() == size: + return image + surf = pygame.surface.Surface(size, pygame.locals.SRCALPHA, image) + surf.blit(image, ((size[0] - image.get_width()) / 2, + (size[1] - image.get_height()) / 2)) + return surf + + def rotator(angle): return Mutator(rotate, angle) +def scaler(size): + return Mutator(scale, size) + + # Identity mutator NULL = Mutator(lambda x: x) diff -r 06ed0160cd92 -r 66dd5ac002b7 nagslang/render.py --- a/nagslang/render.py Sat Sep 07 22:15:04 2013 +0200 +++ b/nagslang/render.py Sat Sep 07 22:15:56 2013 +0200 @@ -47,8 +47,8 @@ pass -class BulkheadRenderer(Renderer): - def draw_bulkhead_line(self, surface, a, b): +class HatchRenderer(Renderer): + def draw_hatch_line(self, surface, a, b): ai, bi = extend_line(a, b, -2) a, b, ai, bi = points_to_pygame(surface, (a, b, ai, bi)) pygame.draw.line( @@ -62,12 +62,12 @@ offset = vec_from_angle((shape.b - shape.a).angle, 10) ai = shape.a + offset bi = shape.b - offset - self.draw_bulkhead_line(surface, shape.a, ai) - self.draw_bulkhead_line(surface, bi, shape.b) + self.draw_hatch_line(surface, shape.a, ai) + self.draw_hatch_line(surface, bi, shape.b) else: mid = shape.a + (shape.b - shape.a) / 2 - self.draw_bulkhead_line(surface, shape.a, mid) - self.draw_bulkhead_line(surface, mid, shape.b) + self.draw_hatch_line(surface, shape.a, mid) + self.draw_hatch_line(surface, mid, shape.b) def image_pos(image, pos): diff -r 06ed0160cd92 -r 66dd5ac002b7 nagslang/screens/area.py --- a/nagslang/screens/area.py Sat Sep 07 22:15:04 2013 +0200 +++ b/nagslang/screens/area.py Sat Sep 07 22:15:56 2013 +0200 @@ -4,6 +4,8 @@ import pymunk import pymunk.pygame_util +from nagslang.resources import resources +from nagslang.mutators import ImageCentre, scaler from nagslang.options import options from nagslang.constants import ( COLLISION_TYPE_WALL, COLLISION_TYPE_PLAYER, CALLBACK_COLLIDERS, @@ -256,6 +258,7 @@ overlay.render(surface, render_rect.topleft, max_width) break self.render_health_bar(surface) + self.render_inventory(surface) def tick_protagonist(self): dx, dy = self.keys.get_direction() @@ -281,7 +284,7 @@ self._level.overlay_drawables.remove(drawable.overlay) def render_health_bar(self, surface, damage_experienced=None): - bar_surface = pygame.Surface((110, 50)).convert(surface) + bar_surface = pygame.Surface((110, 40)).convert(surface) if damage_experienced: health_box_colour = pygame.color.THECOLORS['red'] else: @@ -291,8 +294,31 @@ health_colour = pygame.color.THECOLORS['red'] else: health_colour = pygame.color.THECOLORS['violetred3'] - rect = pygame.Rect(5, 5, self.protagonist.get_health_level(), 40) + rect = pygame.Rect(5, 5, self.protagonist.get_health_level(), 30) pygame.draw.rect(bar_surface, health_colour, rect, 0) bar_surface.set_alpha(192) y_pos = surface.get_height() - 20 - bar_surface.get_height() surface.blit(bar_surface, (20, y_pos)) + + def render_inventory(self, surface): + items = len(self.world.inventory) + if not items: + return + padding = 4 + img_size = 64 + size = 32 + inv_surf = pygame.Surface( + (padding + (size + padding) * items, + (2 * padding + size))) + inv_surf = inv_surf.convert(surface) + inv_surf.set_alpha(192) + inv_surf.fill(pygame.color.THECOLORS['white']) + for index, item in enumerate(sorted(self.world.inventory)): + img = resources.get_image( + 'objects', item + '.png', + transforms=(ImageCentre((img_size, img_size)), + scaler((size, size)))) + inv_surf.blit(img, (padding + index * (size + padding), padding)) + y_pos = surface.get_height() - 20 - inv_surf.get_height() + x_pos = 130 + padding + surface.blit(inv_surf, (x_pos, y_pos)) diff -r 06ed0160cd92 -r 66dd5ac002b7 nagslang/screens/base.py --- a/nagslang/screens/base.py Sat Sep 07 22:15:04 2013 +0200 +++ b/nagslang/screens/base.py Sat Sep 07 22:15:56 2013 +0200 @@ -1,5 +1,7 @@ """A screen or area in which action happens.""" +import sys + from pygame import event import pymunk @@ -29,4 +31,11 @@ def tick(self, seconds): """Step the given amount of time.""" - self.space.step(seconds) + try: + self.space.step(seconds) + except AssertionError: + # TODO: Find the source of these + print >> sys.stderr, ( + 'Caught a pymunk assertion error. ' + "We don't know what causes these on level change. " + "Hopefully we can ignore them...") diff -r 06ed0160cd92 -r 66dd5ac002b7 source/images/objects/sokobox.svg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/images/objects/sokobox.svg Sat Sep 07 22:15:56 2013 +0200 @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff -r 06ed0160cd92 -r 66dd5ac002b7 tools/area_editor.py --- a/tools/area_editor.py Sat Sep 07 22:15:04 2013 +0200 +++ b/tools/area_editor.py Sat Sep 07 22:15:56 2013 +0200 @@ -633,7 +633,7 @@ if self.move_obj: corrected_pos = self._level_coordinates(ev.pos) snapped_pos = self.snap_to_grid(corrected_pos) - self._update_pos(self.move_obj, snapped_pos) + self._move_obj(self.move_obj, snapped_pos) if old_pos != self.mouse_pos and (self.cur_poly or self._draw_lines or self._move_point_mode or self._move_poly_mode): @@ -660,8 +660,6 @@ if obj is not None: if obj.movable(): self.move_obj = obj - data = self.level.lookup[obj] - print data elif self.move_obj_mode and ev.button == 1 and self.move_obj: self._update_pos(self.move_obj, snapped_pos) self.move_obj = None @@ -873,6 +871,23 @@ new_cls, None): edit_dlg.cleanup() + def _move_obj(self, obj, new_pos): + new_coords = self.level.point_to_pymunk(new_pos) + shape = obj.get_shape() + shape.body.position = (new_coords[0], new_coords[1]) + data = self.level.lookup[obj] + args = data['args'] + old_coords = list(args[0]) + param_defs = obj.requires()[1:] # chop off name + for i, (_key, key_type) in enumerate(param_defs): + if i > len(args): + break + if key_type == "polygon (convex)": + new_outline = self.level.translate_poly( + args[i], old_coords, new_coords) + obj.update_image(new_outline) + self.invalidate() + def _update_pos(self, obj, new_pos): data = self.level.lookup[obj] new_coords = self.level.point_to_pymunk(new_pos) @@ -887,7 +902,6 @@ if key_type == "polygon (convex)": args[i] = self.level.translate_poly( args[i], old_coords, new_coords) - print args[i] self.level.reset_objs() self.invalidate()