changeset 562:66dd5ac002b7

Merge
author David Sharpe <decoydavid@gmail.com>
date Sat, 07 Sep 2013 22:15:56 +0200
parents 06ed0160cd92 (current diff) 57efcd81647b (diff)
children a68951a9fe40
files
diffstat 16 files changed, 411 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
Binary file data/images/objects/sokobox.png has changed
--- 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]
--- 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:
--- 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]
--- 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
--- 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
--- 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
--- 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:
--- 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'
--- 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
--- 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)
 
--- 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):
--- 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))
--- 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...")
--- /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 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="800"
+   height="800"
+   id="svg7373"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="sokobox.svg">
+  <defs
+     id="defs7375">
+    <linearGradient
+       id="linearGradient7907">
+      <stop
+         style="stop-color:#008080;stop-opacity:1;"
+         offset="0"
+         id="stop7909" />
+      <stop
+         style="stop-color:#004284;stop-opacity:1;"
+         offset="1"
+         id="stop7911" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient7897">
+      <stop
+         style="stop-color:#70d9ff;stop-opacity:1;"
+         offset="0"
+         id="stop7899" />
+      <stop
+         style="stop-color:#0082ff;stop-opacity:1;"
+         offset="1"
+         id="stop7901" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient7897"
+       id="linearGradient7905"
+       x1="20"
+       y1="732.36218"
+       x2="620"
+       y2="732.36218"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-1.7578735e-6,-2.7917969e-5)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient7907"
+       id="linearGradient7913"
+       x1="70"
+       y1="320"
+       x2="570"
+       y2="320"
+       gradientUnits="userSpaceOnUse" />
+    <filter
+       inkscape:collect="always"
+       id="filter7925"
+       color-interpolation-filters="sRGB">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="3"
+         id="feGaussianBlur7927" />
+    </filter>
+    <filter
+       inkscape:collect="always"
+       id="filter7929"
+       color-interpolation-filters="sRGB">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="2.5"
+         id="feGaussianBlur7931" />
+    </filter>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient7897"
+       id="linearGradient3105"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-1.7578735e-6,-2.7917969e-5)"
+       x1="20"
+       y1="732.36218"
+       x2="620"
+       y2="732.36218" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient7907"
+       id="linearGradient3107"
+       gradientUnits="userSpaceOnUse"
+       x1="70"
+       y1="320"
+       x2="570"
+       y2="320" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.7"
+     inkscape:cx="201.97732"
+     inkscape:cy="408.88484"
+     inkscape:document-units="px"
+     inkscape:current-layer="g3100"
+     showgrid="false"
+     inkscape:window-width="1339"
+     inkscape:window-height="768"
+     inkscape:window-x="27"
+     inkscape:window-y="0"
+     inkscape:window-maximized="0"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0" />
+  <metadata
+     id="metadata7378">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-110,-142.36219)">
+    <g
+       id="g3100"
+       transform="matrix(1.2903226,0,0,1.2903226,97.096778,-402.62128)">
+      <rect
+         style="fill:#002147;fill-opacity:1;stroke:none"
+         id="rect7915"
+         width="620"
+         height="620"
+         x="10"
+         y="422.36218" />
+      <rect
+         y="432.36218"
+         x="20"
+         height="600"
+         width="600"
+         id="rect7381"
+         style="fill:url(#linearGradient3105);fill-opacity:1;stroke:none;filter:url(#filter7925)" />
+      <path
+         id="rect7383"
+         transform="translate(0,412.36218)"
+         d="m 105,70 c 462.85716,463.85982 0.60658,-0.71084 465,465 l 0,-465 -465,0 z m -35,35 0,465 465,0 C 72.142858,106.14018 534.39346,570.71084 70,105 z"
+         style="fill:url(#linearGradient3107);fill-opacity:1;stroke:none;filter:url(#filter7929)"
+         inkscape:connector-curvature="0" />
+    </g>
+  </g>
+</svg>
--- 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()