changeset 65:e856b604b650

Changed "import bGrease" to "import parpg.bGrease".
author KarstenBock@gmx.net
date Wed, 21 Sep 2011 16:10:14 +0200
parents b73050f98411
children 58d58bf2e567
files bGrease/collision.py bGrease/component/__init__.py bGrease/component/field.py bGrease/component/general.py bGrease/controller/__init__.py bGrease/impl/mode.py bGrease/impl/world.py bGrease/renderer/__init__.py bGrease/renderer/vector.py bGrease/world.py components/CharacterStatistics.py components/__init__.py components/change_map.py components/containable.py components/container.py components/description.py components/dialogue.py components/equip.py components/equipable.py components/fifeagent.py components/lockable.py components/usable.py gamemodel.py mode.py systems/gamerulessystem.py systems/scriptingsystem.py world.py
diffstat 27 files changed, 2124 insertions(+), 2131 deletions(-) [+]
line wrap: on
line diff
--- a/bGrease/collision.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/bGrease/collision.py	Wed Sep 21 16:10:14 2011 +0200
@@ -1,528 +1,527 @@
-#############################################################################
-#
-# Copyright (c) 2010 by Casey Duncan and contributors
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the MIT License
-# A copy of the license should accompany this distribution.
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-#
-#############################################################################
-"""
-**Grease collision detection systems**
-
-Grease uses two-phase broad and narrow collision detection. *Broad-phase*
-collision systems are used to efficiently identify pairs that may be colliding
-without resorting to a brute-force check of all possible pairs. *Narrow-phase*
-collision systems use the pairs generated by the broad-phase and perform more
-precise collision tests to determine if a collision has actually occurred. The
-narrow-phase system also calculates more details about each collision,
-including collision point and normal vector for use in collision response.
-
-A typical collision detection system consists of a narrow-phase system that
-contains a broad-phased system. The narrow-phase system is usually the only
-
-one that the application directly interacts with, though the application is
-free to use the broad-phased system directly if desired. This could be
-useful in cases where speed, rather than precision is paramount.
-
-The narrow-phase system can be assigned handler objects to run after
-collision detection. These can perform tasks like handling collision response
-or dispatching collision events to application handlers.
-
-Note that broad-phase systems can return false positives, though they should
-never return false negatives. Do not assume that all pairs returned by a
-broad-phase system are actually in collision.
-"""
-
-__version__ = '$Id$'
-
-from bGrease.geometry import Vec2d
-from bisect import bisect_right
-
-
-class Pair(tuple):
-	"""Pair of entities in collision. This is an ordered sequence of two
-	entities, that compares and hashes unordered.
-	
-	Also stores additional collision point and normal vectors
-	for each entity.
-
-	Sets of ``Pair`` objects are exposed in the ``collision_pairs``
-	attribute of collision systems to indicate the entity pairs in
-	collision.
-	"""
-	info = None
-	"""A sequence of (entity, collision point, collision normal)
-	for each entity in the pair
-	"""
-
-	def __new__(cls, entity1, entity2, point=None, normal=None):
-		pair = tuple.__new__(cls, (entity1, entity2))
-		return pair
-	
-	def __hash__(self):
-		return hash(self[0]) ^ hash(self[1])
-	
-	def __eq__(self, other):
-		other = tuple(other)
-		return tuple(self) == other or (self[1], self[0]) == other
-	
-	def __repr__(self):
-		return '%s%r' % (self.__class__.__name__, tuple(self))
-	
-	def set_point_normal(self, point0, normal0, point1, normal1):
-		"""Set the collision point and normal for both entities"""
-		self.info = (
-			(self[0], point0, normal0),
-			(self[1], point1, normal1),
-		)
-
-
-class BroadSweepAndPrune(object):
-	"""2D Broad-phase sweep and prune bounding box collision detector
-
-	This algorithm is efficient for collision detection between many
-	moving bodies. It has linear algorithmic complexity and takes
-	advantage of temporal coherence between frames. It also does
-	not suffer from bad worst-case performance (like RDC can). 
-	Unlike spacial hashing, it does not need to be optimized for 
-	specific space and body sizes.
-
-	Other algorithms may be more efficient for collision detection with
-	stationary bodies, bodies that are always evenly distributed, or ad-hoc
-	queries.
-
-	:param collision_component: Name of the collision component used by this
-		system, defaults to 'collision'. This component supplies each
-		entities' aabb and collision masks.
-	:type collision_component: str
-	"""
-	world = None
-	"""|World| object this system belongs to"""
-
-	collision_component = None
-	"""Name of world's collision component used by this system"""
-
-	LEFT_ATTR = "left"
-	RIGHT_ATTR = "right"
-	TOP_ATTR = "top"
-	BOTTOM_ATTR = "bottom"
-
-	def __init__(self, collision_component='collision'):
-		self.collision_component = collision_component
-		self._by_x = None
-		self._by_y = None
-		self._collision_pairs = None
-	
-	def set_world(self, world):
-		"""Bind the system to a world"""
-		self.world = world
-	
-	def step(self, dt):
-		"""Update the system for this time step, updates and sorts the 
-		axis arrays.
-		"""
-		component = getattr(self.world.components, self.collision_component)
-		LEFT = self.LEFT_ATTR
-		RIGHT = self.RIGHT_ATTR
-		TOP = self.TOP_ATTR
-		BOTTOM = self.BOTTOM_ATTR
-		if self._by_x is None:
-			# Build axis lists from scratch
-			# Note we cache the box positions here
-			# so that we can perform hit tests efficiently
-			# it also isolates us from changes made to the 
-			# box positions after we run
-			by_x = self._by_x = []
-			append_x = by_x.append
-			by_y = self._by_y = []
-			append_y = by_y.append
-			for data in component.itervalues():
-				append_x([data.aabb.left, LEFT, data])
-				append_x([data.aabb.right, RIGHT, data])
-				append_y([data.aabb.bottom, BOTTOM, data])
-				append_y([data.aabb.top, TOP, data])
-		else:
-			by_x = self._by_x
-			by_y = self._by_y
-			removed = []
-			for entry in by_x:
-				entry[0] = getattr(entry[2].aabb, entry[1])
-			for entry in by_y:
-				entry[0] = getattr(entry[2].aabb, entry[1])
-			# Removing entities is inefficient, but expected to be rare
-			if component.deleted_entities:
-				deleted_entities = component.deleted_entities
-				deleted_x = []
-				deleted_y = []
-				for i, (_, _, data) in enumerate(by_x):
-					if data.entity in deleted_entities:
-						deleted_x.append(i)
-				deleted_x.reverse()
-				for i in deleted_x:
-					del by_x[i]
-				for i, (_, _, data) in enumerate(by_y):
-					if data.entity in deleted_entities:
-						deleted_y.append(i)
-				deleted_y.reverse()
-				for i in deleted_y:
-					del by_y[i]
-			# Tack on new entities
-			for entity in component.new_entities:
-				data = component[entity]
-				by_x.append([data.aabb.left, LEFT, data])
-				by_x.append([data.aabb.right, RIGHT, data])
-				by_y.append([data.aabb.bottom, BOTTOM, data])
-				by_y.append([data.aabb.top, TOP, data])
-				
-		# Tim-sort is highly efficient with mostly sorted lists.
-		# Because positions tend to change little each frame
-		# we take advantage of this here. Obviously things are
-		# less efficient with very fast moving, or teleporting entities
-		by_x.sort()
-		by_y.sort()
-		self._collision_pairs = None
-	
-	@property
-	def collision_pairs(self):
-		"""Set of candidate collision pairs for this timestep"""
-		if self._collision_pairs is None:
-			if self._by_x is None:
-				# Axis arrays not ready
-				return set()
-
-			LEFT = self.LEFT_ATTR
-			RIGHT = self.RIGHT_ATTR
-			TOP = self.TOP_ATTR
-			BOTTOM = self.BOTTOM_ATTR
-			# Build candidates overlapping along the x-axis
-			component = getattr(self.world.components, self.collision_component)
-			xoverlaps = set()
-			add_xoverlap = xoverlaps.add
-			discard_xoverlap = xoverlaps.discard
-			open = {}
-			for _, side, data in self._by_x:
-				if side is LEFT:
-					for open_entity, (from_mask, into_mask) in open.iteritems():
-						if data.from_mask & into_mask or from_mask & data.into_mask:
-							add_xoverlap(Pair(data.entity, open_entity))
-					open[data.entity] = (data.from_mask, data.into_mask)
-				elif side is RIGHT:
-					del open[data.entity]
-
-			if len(xoverlaps) <= 10 and len(xoverlaps)*4 < len(self._by_y):
-				# few candidates were found, so just scan the x overlap candidates
-				# along y. This requires an additional sort, but it should
-				# be cheaper than scanning everyone and its simpler
-				# than a separate brute-force check
-				entities = set([entity for entity, _ in xoverlaps] 
-					+ [entity for _, entity in xoverlaps])
-				by_y = []
-				for entity in entities:
-					data = component[entity]
-					# We can use tuples here, which are cheaper to create
-					by_y.append((data.aabb.bottom, BOTTOM, data))
-					by_y.append((data.aabb.top, TOP, data))
-				by_y.sort()
-			else:
-				by_y = self._by_y
-
-			# Now check the candidates along the y-axis
-			open = set()
-			add_open = open.add
-			discard_open = open.discard
-			self._collision_pairs = set()
-			add_pair = self._collision_pairs.add
-			for _, side, data in by_y:
-				if side is BOTTOM:
-					for open_entity in open:
-						pair = Pair(data.entity, open_entity)
-						if pair in xoverlaps:
-							discard_xoverlap(pair)
-							add_pair(pair)
-							if not xoverlaps:
-								# No more candidates, bail
-								return self._collision_pairs
-					add_open(data.entity)
-				elif side is TOP:
-					discard_open(data.entity)
-		return self._collision_pairs
-	
-	def query_point(self, x_or_point, y=None, from_mask=0xffffffff):
-		"""Hit test at the point specified. 
-
-		:param x_or_point: x coordinate (float) or sequence of (x, y) floats.
-
-		:param y: y coordinate (float) if x is not a sequence
-
-		:param from_mask: Bit mask used to filter query results. This value
-			is bit ANDed with candidate entities' ``collision.into_mask``.
-			If the result is non-zero, then it is considered a hit. By
-			default all entities colliding with the input point are
-			returned.
-
-		:return: A set of entities where the point is inside their bounding
-			boxes as of the last time step.
-		"""
-		if self._by_x is None:
-			# Axis arrays not ready
-			return set()
-		if y is None:
-			x, y = x_or_point
-		else:
-			x = x_or_point
-		LEFT = self.LEFT_ATTR
-		RIGHT = self.RIGHT_ATTR
-		TOP = self.TOP_ATTR
-		BOTTOM = self.BOTTOM_ATTR
-		x_index = bisect_right(self._by_x, [x])
-		x_hits = set()
-		add_x_hit = x_hits.add
-		discard_x_hit = x_hits.discard
-		if x_index <= len(self._by_x) // 2:
-			# closer to the left, scan from left to right
-			while (x == self._by_x[x_index][0] 
-				and self._by_x[x_index][1] is LEFT 
-				and x_index < len(self._by_x)):
-				# Ensure we hit on exact left edge matches
-				x_index += 1
-			for _, side, data in self._by_x[:x_index]:
-				if side is LEFT and from_mask & data.into_mask:
-					add_x_hit(data.entity)
-				else:
-					discard_x_hit(data.entity)
-		else:
-			# closer to the right
-			for _, side, data in reversed(self._by_x[x_index:]):
-				if side is RIGHT and from_mask & data.into_mask:
-					add_x_hit(data.entity)
-				else:
-					discard_x_hit(data.entity)
-		if not x_hits:
-			return x_hits
-
-		y_index = bisect_right(self._by_y, [y])
-		y_hits = set()
-		add_y_hit = y_hits.add
-		discard_y_hit = y_hits.discard
-		if y_index <= len(self._by_y) // 2:
-			# closer to the bottom
-			while (y == self._by_y[y_index][0] 
-				and self._by_y[y_index][1] is BOTTOM 
-				and y_index < len(self._by_y)):
-				# Ensure we hit on exact bottom edge matches
-				y_index += 1
-			for _, side, data in self._by_y[:y_index]:
-				if side is BOTTOM:
-					add_y_hit(data.entity)
-				else:
-					discard_y_hit(data.entity)
-		else:
-			# closer to the top
-			for _, side, data in reversed(self._by_y[y_index:]):
-				if side is TOP:
-					add_y_hit(data.entity)
-				else:
-					discard_y_hit(data.entity)
-		if y_hits:
-			return x_hits & y_hits
-		else:
-			return y_hits
-
-
-class Circular(object):
-	"""Basic narrow-phase collision detector which treats all entities as
-	circles with their radius defined in the collision component.
-
-	:param handlers: A sequence of collision handler functions that are invoked
-		after collision detection.
-	:type handlers: sequence of functions
-	
-	:param collision_component: Name of collision component for this system,
-		defaults to 'collision'. This supplies each entity's collision
-		radius and masks.
-	:type collision_component: str
-
-	:param position_component: Name of position component for this system,
-		defaults to 'position'. This supplies each entity's position.
-	:type position_component: str
-
-	:param update_aabbs: If True (the default), then the entities'
-		`collision.aabb` fields will be updated using their position
-		and collision radius before invoking the broad phase system. 
-		Set this False if another system updates the aabbs.
-	:type update_aabbs: bool
-
-	:param broad_phase: A broad-phase collision system to use as a source
-		for collision pairs. If not specified, a :class:`BroadSweepAndPrune`
-		system will be created automatically.
-	"""
-	world = None
-	"""|World| object this system belongs to"""
-
-	position_component = None
-	"""Name of world's position component used by this system"""
-
-	collision_component = None
-	"""Name of world's collision component used by this system"""
-
-	update_aabbs = True
-	"""Flag to indicate whether the system updates the entities' `collision.aabb`
-	field before invoking the broad phase collision system
-	"""
-	
-	handlers = None
-	"""A sequence of collision handler functions invoke after collision
-	detection
-	"""
-
-	broad_phase = None
-	"""Broad phase collision system used as a source for collision pairs"""
-
-	def __init__(self, handlers=(), position_component='position', 
-		collision_component='collision', update_aabbs=True, broad_phase=None):
-		self.handlers = tuple(handlers)
-		if broad_phase is None:
-			broad_phase = BroadSweepAndPrune(collision_component)
-		self.collision_component = collision_component
-		self.position_component = position_component
-		self.update_aabbs = bool(update_aabbs)
-		self.broad_phase = broad_phase
-		self._collision_pairs = None
-	
-	def set_world(self, world):
-		"""Bind the system to a world"""
-		self.world = world
-		self.broad_phase.set_world(world)
-		for handler in self.handlers:
-			if hasattr(handler, 'set_world'):
-				handler.set_world(world)
-	
-	def step(self, dt):
-		"""Update the collision system for this time step and invoke
-		the handlers
-		"""
-		if self.update_aabbs:
-			for position, collision in self.world.components.join(
-				self.position_component, self.collision_component):
-				aabb = collision.aabb
-				x, y = position.position
-				radius = collision.radius
-				aabb.left = x - radius
-				aabb.right = x + radius
-				aabb.bottom = y - radius
-				aabb.top = y + radius
-		self.broad_phase.step(dt)
-		self._collision_pairs = None
-		for handler in self.handlers:
-			handler(self)
-	
-	@property
-	def collision_pairs(self):
-		"""The set of entity pairs in collision in this timestep"""
-		if self._collision_pairs is None:
-			position = getattr(self.world.components, self.position_component)
-			collision = getattr(self.world.components, self.collision_component)
-			pairs = self._collision_pairs = set()
-			for pair in self.broad_phase.collision_pairs:
-				entity1, entity2 = pair
-				position1 = position[entity1].position
-				position2 = position[entity2].position
-				radius1 = collision[entity1].radius
-				radius2 = collision[entity2].radius
-				separation = position2 - position1
-				if separation.get_length_sqrd() <= (radius1 + radius2)**2:
-					normal = separation.normalized()
-					pair.set_point_normal(
-						normal * radius1 + position1, normal,
-						normal * -radius2 + position2, -normal)
-					pairs.add(pair)
-		return self._collision_pairs
-	
-	def query_point(self, x_or_point, y=None, from_mask=0xffffffff):
-		"""Hit test at the point specified. 
-
-		:param x_or_point: x coordinate (float) or sequence of (x, y) floats.
-
-		:param y: y coordinate (float) if x is not a sequence
-
-		:param from_mask: Bit mask used to filter query results. This value
-			is bit ANDed with candidate entities' ``collision.into_mask``.
-			If the result is non-zero, then it is considered a hit. By
-			default all entities colliding with the input point are
-			returned.
-
-		:return: A set of entities where the point is inside their collision
-			radii as of the last time step.
-
-		"""
-		if y is None:
-			point = Vec2d(x_or_point)
-		else:
-			point = Vec2d(x_or_point, y)
-		hits = set()
-		position = getattr(self.world.components, self.position_component)
-		collision = getattr(self.world.components, self.collision_component)
-		for entity in self.broad_phase.query_point(x_or_point, y, from_mask):
-			separation = point - position[entity].position
-			if separation.get_length_sqrd() <= collision[entity].radius**2:
-				hits.add(entity)
-		return hits
-
-
-def dispatch_events(collision_system):
-	"""Collision handler that dispatches `on_collide()` events to entities
-	marked for collision by the specified collision system. The `on_collide()`
-	event handler methods are defined by the application on the desired entity
-	classes. These methods should have the following signature::
-
-		def on_collide(self, other_entity, collision_point, collision_normal):
-			'''Handle A collision between this entity and `other_entity`
-
-			- other_entity (Entity): The other entity in collision with 
-			  `self`
-
-			- collision_point (Vec2d): The point on this entity (`self`)
-			  where the collision occurred. Note this may be `None` for 
-			  some collision systems that do not report it.
-
-			- collision_normal (Vec2d): The normal vector at the point of
-			  collision. As with `collision_point`, this may be None for
-			  some collision systems.
-			'''
-
-	Note the arguments to `on_collide()` are always passed positionally, so you
-	can use different argument names than above if desired.
-
-	If a pair of entities are in collision, then the event will be dispatched
-	to both objects in arbitrary order if all of their collision masks align.
-	"""
-	collision = getattr(collision_system.world.components, 
-		collision_system.collision_component)
-	for pair in collision_system.collision_pairs:
-		entity1, entity2 = pair
-		if pair.info is not None:
-			args1, args2 = pair.info
-		else:
-			args1 = entity1, None, None
-			args2 = entity2, None, None
-		try:
-			on_collide = entity1.on_collide
-			masks_align = collision[entity2].from_mask & collision[entity1].into_mask
-		except (AttributeError, KeyError):
-			pass
-		else:
-			if masks_align:
-				on_collide(*args2)
-		try:
-			on_collide = entity2.on_collide
-			masks_align = collision[entity1].from_mask & collision[entity2].into_mask
-		except (AttributeError, KeyError):
-			pass
-		else:
-			if masks_align:
-				on_collide(*args1)
-
+#############################################################################
+#
+# Copyright (c) 2010 by Casey Duncan and contributors
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the MIT License
+# A copy of the license should accompany this distribution.
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+#
+#############################################################################
+"""
+**Grease collision detection systems**
+
+Grease uses two-phase broad and narrow collision detection. *Broad-phase*
+collision systems are used to efficiently identify pairs that may be colliding
+without resorting to a brute-force check of all possible pairs. *Narrow-phase*
+collision systems use the pairs generated by the broad-phase and perform more
+precise collision tests to determine if a collision has actually occurred. The
+narrow-phase system also calculates more details about each collision,
+including collision point and normal vector for use in collision response.
+
+A typical collision detection system consists of a narrow-phase system that
+contains a broad-phased system. The narrow-phase system is usually the only
+
+one that the application directly interacts with, though the application is
+free to use the broad-phased system directly if desired. This could be
+useful in cases where speed, rather than precision is paramount.
+
+The narrow-phase system can be assigned handler objects to run after
+collision detection. These can perform tasks like handling collision response
+or dispatching collision events to application handlers.
+
+Note that broad-phase systems can return false positives, though they should
+never return false negatives. Do not assume that all pairs returned by a
+broad-phase system are actually in collision.
+"""
+
+__version__ = '$Id$'
+
+from parpg.bGrease.geometry import Vec2d
+from bisect import bisect_right
+
+
+class Pair(tuple):
+        """Pair of entities in collision. This is an ordered sequence of two
+        entities, that compares and hashes unordered.
+
+        Also stores additional collision point and normal vectors
+        for each entity.
+
+        Sets of ``Pair`` objects are exposed in the ``collision_pairs``
+        attribute of collision systems to indicate the entity pairs in
+        collision.
+        """
+        info = None
+        """A sequence of (entity, collision point, collision normal)
+	for each entity in the pair
+	"""
+
+        def __new__(cls, entity1, entity2, point=None, normal=None):
+                pair = tuple.__new__(cls, (entity1, entity2))
+                return pair
+
+        def __hash__(self):
+                return hash(self[0]) ^ hash(self[1])
+
+        def __eq__(self, other):
+                other = tuple(other)
+                return tuple(self) == other or (self[1], self[0]) == other
+
+        def __repr__(self):
+                return '%s%r' % (self.__class__.__name__, tuple(self))
+
+        def set_point_normal(self, point0, normal0, point1, normal1):
+                """Set the collision point and normal for both entities"""
+                self.info = (
+                        (self[0], point0, normal0),
+                        (self[1], point1, normal1),
+                )
+
+
+class BroadSweepAndPrune(object):
+        """2D Broad-phase sweep and prune bounding box collision detector
+
+        This algorithm is efficient for collision detection between many
+        moving bodies. It has linear algorithmic complexity and takes
+        advantage of temporal coherence between frames. It also does
+        not suffer from bad worst-case performance (like RDC can). 
+        Unlike spacial hashing, it does not need to be optimized for 
+        specific space and body sizes.
+
+        Other algorithms may be more efficient for collision detection with
+        stationary bodies, bodies that are always evenly distributed, or ad-hoc
+        queries.
+
+        :param collision_component: Name of the collision component used by this
+        	system, defaults to 'collision'. This component supplies each
+        	entities' aabb and collision masks.
+        :type collision_component: str
+        """
+        world = None
+        """|World| object this system belongs to"""
+
+        collision_component = None
+        """Name of world's collision component used by this system"""
+
+        LEFT_ATTR = "left"
+        RIGHT_ATTR = "right"
+        TOP_ATTR = "top"
+        BOTTOM_ATTR = "bottom"
+
+        def __init__(self, collision_component='collision'):
+                self.collision_component = collision_component
+                self._by_x = None
+                self._by_y = None
+                self._collision_pairs = None
+
+        def set_world(self, world):
+                """Bind the system to a world"""
+                self.world = world
+
+        def step(self, dt):
+                """Update the system for this time step, updates and sorts the 
+                axis arrays.
+                """
+                component = getattr(self.world.components, self.collision_component)
+                LEFT = self.LEFT_ATTR
+                RIGHT = self.RIGHT_ATTR
+                TOP = self.TOP_ATTR
+                BOTTOM = self.BOTTOM_ATTR
+                if self._by_x is None:
+                        # Build axis lists from scratch
+                        # Note we cache the box positions here
+                        # so that we can perform hit tests efficiently
+                        # it also isolates us from changes made to the 
+                        # box positions after we run
+                        by_x = self._by_x = []
+                        append_x = by_x.append
+                        by_y = self._by_y = []
+                        append_y = by_y.append
+                        for data in component.itervalues():
+                                append_x([data.aabb.left, LEFT, data])
+                                append_x([data.aabb.right, RIGHT, data])
+                                append_y([data.aabb.bottom, BOTTOM, data])
+                                append_y([data.aabb.top, TOP, data])
+                else:
+                        by_x = self._by_x
+                        by_y = self._by_y
+                        removed = []
+                        for entry in by_x:
+                                entry[0] = getattr(entry[2].aabb, entry[1])
+                        for entry in by_y:
+                                entry[0] = getattr(entry[2].aabb, entry[1])
+                        # Removing entities is inefficient, but expected to be rare
+                        if component.deleted_entities:
+                                deleted_entities = component.deleted_entities
+                                deleted_x = []
+                                deleted_y = []
+                                for i, (_, _, data) in enumerate(by_x):
+                                        if data.entity in deleted_entities:
+                                                deleted_x.append(i)
+                                deleted_x.reverse()
+                                for i in deleted_x:
+                                        del by_x[i]
+                                for i, (_, _, data) in enumerate(by_y):
+                                        if data.entity in deleted_entities:
+                                                deleted_y.append(i)
+                                deleted_y.reverse()
+                                for i in deleted_y:
+                                        del by_y[i]
+                        # Tack on new entities
+                        for entity in component.new_entities:
+                                data = component[entity]
+                                by_x.append([data.aabb.left, LEFT, data])
+                                by_x.append([data.aabb.right, RIGHT, data])
+                                by_y.append([data.aabb.bottom, BOTTOM, data])
+                                by_y.append([data.aabb.top, TOP, data])
+
+                # Tim-sort is highly efficient with mostly sorted lists.
+                # Because positions tend to change little each frame
+                # we take advantage of this here. Obviously things are
+                # less efficient with very fast moving, or teleporting entities
+                by_x.sort()
+                by_y.sort()
+                self._collision_pairs = None
+
+        @property
+        def collision_pairs(self):
+                """Set of candidate collision pairs for this timestep"""
+                if self._collision_pairs is None:
+                        if self._by_x is None:
+                                # Axis arrays not ready
+                                return set()
+
+                        LEFT = self.LEFT_ATTR
+                        RIGHT = self.RIGHT_ATTR
+                        TOP = self.TOP_ATTR
+                        BOTTOM = self.BOTTOM_ATTR
+                        # Build candidates overlapping along the x-axis
+                        component = getattr(self.world.components, self.collision_component)
+                        xoverlaps = set()
+                        add_xoverlap = xoverlaps.add
+                        discard_xoverlap = xoverlaps.discard
+                        open = {}
+                        for _, side, data in self._by_x:
+                                if side is LEFT:
+                                        for open_entity, (from_mask, into_mask) in open.iteritems():
+                                                if data.from_mask & into_mask or from_mask & data.into_mask:
+                                                        add_xoverlap(Pair(data.entity, open_entity))
+                                        open[data.entity] = (data.from_mask, data.into_mask)
+                                elif side is RIGHT:
+                                        del open[data.entity]
+
+                        if len(xoverlaps) <= 10 and len(xoverlaps)*4 < len(self._by_y):
+                                # few candidates were found, so just scan the x overlap candidates
+                                # along y. This requires an additional sort, but it should
+                                # be cheaper than scanning everyone and its simpler
+                                # than a separate brute-force check
+                                entities = set([entity for entity, _ in xoverlaps] 
+                                               + [entity for _, entity in xoverlaps])
+                                by_y = []
+                                for entity in entities:
+                                        data = component[entity]
+                                        # We can use tuples here, which are cheaper to create
+                                        by_y.append((data.aabb.bottom, BOTTOM, data))
+                                        by_y.append((data.aabb.top, TOP, data))
+                                by_y.sort()
+                        else:
+                                by_y = self._by_y
+
+                        # Now check the candidates along the y-axis
+                        open = set()
+                        add_open = open.add
+                        discard_open = open.discard
+                        self._collision_pairs = set()
+                        add_pair = self._collision_pairs.add
+                        for _, side, data in by_y:
+                                if side is BOTTOM:
+                                        for open_entity in open:
+                                                pair = Pair(data.entity, open_entity)
+                                                if pair in xoverlaps:
+                                                        discard_xoverlap(pair)
+                                                        add_pair(pair)
+                                                        if not xoverlaps:
+                                                                # No more candidates, bail
+                                                                return self._collision_pairs
+                                        add_open(data.entity)
+                                elif side is TOP:
+                                        discard_open(data.entity)
+                return self._collision_pairs
+
+        def query_point(self, x_or_point, y=None, from_mask=0xffffffff):
+                """Hit test at the point specified. 
+
+                :param x_or_point: x coordinate (float) or sequence of (x, y) floats.
+
+                :param y: y coordinate (float) if x is not a sequence
+
+                :param from_mask: Bit mask used to filter query results. This value
+                	is bit ANDed with candidate entities' ``collision.into_mask``.
+                	If the result is non-zero, then it is considered a hit. By
+                	default all entities colliding with the input point are
+                	returned.
+
+                :return: A set of entities where the point is inside their bounding
+                	boxes as of the last time step.
+                """
+                if self._by_x is None:
+                        # Axis arrays not ready
+                        return set()
+                if y is None:
+                        x, y = x_or_point
+                else:
+                        x = x_or_point
+                LEFT = self.LEFT_ATTR
+                RIGHT = self.RIGHT_ATTR
+                TOP = self.TOP_ATTR
+                BOTTOM = self.BOTTOM_ATTR
+                x_index = bisect_right(self._by_x, [x])
+                x_hits = set()
+                add_x_hit = x_hits.add
+                discard_x_hit = x_hits.discard
+                if x_index <= len(self._by_x) // 2:
+                        # closer to the left, scan from left to right
+                        while (x == self._by_x[x_index][0] 
+                               and self._by_x[x_index][1] is LEFT 
+                               and x_index < len(self._by_x)):
+                                # Ensure we hit on exact left edge matches
+                                x_index += 1
+                        for _, side, data in self._by_x[:x_index]:
+                                if side is LEFT and from_mask & data.into_mask:
+                                        add_x_hit(data.entity)
+                                else:
+                                        discard_x_hit(data.entity)
+                else:
+                        # closer to the right
+                        for _, side, data in reversed(self._by_x[x_index:]):
+                                if side is RIGHT and from_mask & data.into_mask:
+                                        add_x_hit(data.entity)
+                                else:
+                                        discard_x_hit(data.entity)
+                if not x_hits:
+                        return x_hits
+
+                y_index = bisect_right(self._by_y, [y])
+                y_hits = set()
+                add_y_hit = y_hits.add
+                discard_y_hit = y_hits.discard
+                if y_index <= len(self._by_y) // 2:
+                        # closer to the bottom
+                        while (y == self._by_y[y_index][0] 
+                               and self._by_y[y_index][1] is BOTTOM 
+                               and y_index < len(self._by_y)):
+                                # Ensure we hit on exact bottom edge matches
+                                y_index += 1
+                        for _, side, data in self._by_y[:y_index]:
+                                if side is BOTTOM:
+                                        add_y_hit(data.entity)
+                                else:
+                                        discard_y_hit(data.entity)
+                else:
+                        # closer to the top
+                        for _, side, data in reversed(self._by_y[y_index:]):
+                                if side is TOP:
+                                        add_y_hit(data.entity)
+                                else:
+                                        discard_y_hit(data.entity)
+                if y_hits:
+                        return x_hits & y_hits
+                else:
+                        return y_hits
+
+
+class Circular(object):
+        """Basic narrow-phase collision detector which treats all entities as
+        circles with their radius defined in the collision component.
+
+        :param handlers: A sequence of collision handler functions that are invoked
+        	after collision detection.
+        :type handlers: sequence of functions
+
+        :param collision_component: Name of collision component for this system,
+        	defaults to 'collision'. This supplies each entity's collision
+        	radius and masks.
+        :type collision_component: str
+
+        :param position_component: Name of position component for this system,
+        	defaults to 'position'. This supplies each entity's position.
+        :type position_component: str
+
+        :param update_aabbs: If True (the default), then the entities'
+        	`collision.aabb` fields will be updated using their position
+        	and collision radius before invoking the broad phase system. 
+        	Set this False if another system updates the aabbs.
+        :type update_aabbs: bool
+
+        :param broad_phase: A broad-phase collision system to use as a source
+        	for collision pairs. If not specified, a :class:`BroadSweepAndPrune`
+        	system will be created automatically.
+        """
+        world = None
+        """|World| object this system belongs to"""
+
+        position_component = None
+        """Name of world's position component used by this system"""
+
+        collision_component = None
+        """Name of world's collision component used by this system"""
+
+        update_aabbs = True
+        """Flag to indicate whether the system updates the entities' `collision.aabb`
+	field before invoking the broad phase collision system
+	"""
+
+        handlers = None
+        """A sequence of collision handler functions invoke after collision
+	detection
+	"""
+
+        broad_phase = None
+        """Broad phase collision system used as a source for collision pairs"""
+
+        def __init__(self, handlers=(), position_component='position', 
+                     collision_component='collision', update_aabbs=True, broad_phase=None):
+                self.handlers = tuple(handlers)
+                if broad_phase is None:
+                        broad_phase = BroadSweepAndPrune(collision_component)
+                self.collision_component = collision_component
+                self.position_component = position_component
+                self.update_aabbs = bool(update_aabbs)
+                self.broad_phase = broad_phase
+                self._collision_pairs = None
+
+        def set_world(self, world):
+                """Bind the system to a world"""
+                self.world = world
+                self.broad_phase.set_world(world)
+                for handler in self.handlers:
+                        if hasattr(handler, 'set_world'):
+                                handler.set_world(world)
+
+        def step(self, dt):
+                """Update the collision system for this time step and invoke
+                the handlers
+                """
+                if self.update_aabbs:
+                        for position, collision in self.world.components.join(
+                                self.position_component, self.collision_component):
+                                aabb = collision.aabb
+                                x, y = position.position
+                                radius = collision.radius
+                                aabb.left = x - radius
+                                aabb.right = x + radius
+                                aabb.bottom = y - radius
+                                aabb.top = y + radius
+                self.broad_phase.step(dt)
+                self._collision_pairs = None
+                for handler in self.handlers:
+                        handler(self)
+
+        @property
+        def collision_pairs(self):
+                """The set of entity pairs in collision in this timestep"""
+                if self._collision_pairs is None:
+                        position = getattr(self.world.components, self.position_component)
+                        collision = getattr(self.world.components, self.collision_component)
+                        pairs = self._collision_pairs = set()
+                        for pair in self.broad_phase.collision_pairs:
+                                entity1, entity2 = pair
+                                position1 = position[entity1].position
+                                position2 = position[entity2].position
+                                radius1 = collision[entity1].radius
+                                radius2 = collision[entity2].radius
+                                separation = position2 - position1
+                                if separation.get_length_sqrd() <= (radius1 + radius2)**2:
+                                        normal = separation.normalized()
+                                        pair.set_point_normal(
+                                                normal * radius1 + position1, normal,
+                                                normal * -radius2 + position2, -normal)
+                                        pairs.add(pair)
+                return self._collision_pairs
+
+        def query_point(self, x_or_point, y=None, from_mask=0xffffffff):
+                """Hit test at the point specified. 
+
+                :param x_or_point: x coordinate (float) or sequence of (x, y) floats.
+
+                :param y: y coordinate (float) if x is not a sequence
+
+                :param from_mask: Bit mask used to filter query results. This value
+                	is bit ANDed with candidate entities' ``collision.into_mask``.
+                	If the result is non-zero, then it is considered a hit. By
+                	default all entities colliding with the input point are
+                	returned.
+
+                :return: A set of entities where the point is inside their collision
+                	radii as of the last time step.
+
+                """
+                if y is None:
+                        point = Vec2d(x_or_point)
+                else:
+                        point = Vec2d(x_or_point, y)
+                hits = set()
+                position = getattr(self.world.components, self.position_component)
+                collision = getattr(self.world.components, self.collision_component)
+                for entity in self.broad_phase.query_point(x_or_point, y, from_mask):
+                        separation = point - position[entity].position
+                        if separation.get_length_sqrd() <= collision[entity].radius**2:
+                                hits.add(entity)
+                return hits
+
+
+def dispatch_events(collision_system):
+        """Collision handler that dispatches `on_collide()` events to entities
+        marked for collision by the specified collision system. The `on_collide()`
+        event handler methods are defined by the application on the desired entity
+        classes. These methods should have the following signature::
+
+        	def on_collide(self, other_entity, collision_point, collision_normal):
+        		'''Handle A collision between this entity and `other_entity`
+
+        		- other_entity (Entity): The other entity in collision with 
+        		  `self`
+
+        		- collision_point (Vec2d): The point on this entity (`self`)
+        		  where the collision occurred. Note this may be `None` for 
+        		  some collision systems that do not report it.
+
+        		- collision_normal (Vec2d): The normal vector at the point of
+        		  collision. As with `collision_point`, this may be None for
+        		  some collision systems.
+        		'''
+
+        Note the arguments to `on_collide()` are always passed positionally, so you
+        can use different argument names than above if desired.
+
+        If a pair of entities are in collision, then the event will be dispatched
+        to both objects in arbitrary order if all of their collision masks align.
+        """
+        collision = getattr(collision_system.world.components, 
+                            collision_system.collision_component)
+        for pair in collision_system.collision_pairs:
+                entity1, entity2 = pair
+                if pair.info is not None:
+                        args1, args2 = pair.info
+                else:
+                        args1 = entity1, None, None
+                        args2 = entity2, None, None
+                try:
+                        on_collide = entity1.on_collide
+                        masks_align = collision[entity2].from_mask & collision[entity1].into_mask
+                except (AttributeError, KeyError):
+                        pass
+                else:
+                        if masks_align:
+                                on_collide(*args2)
+                try:
+                        on_collide = entity2.on_collide
+                        masks_align = collision[entity1].from_mask & collision[entity2].into_mask
+                except (AttributeError, KeyError):
+                        pass
+                else:
+                        if masks_align:
+                                on_collide(*args1)
--- a/bGrease/component/__init__.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/bGrease/component/__init__.py	Wed Sep 21 16:10:14 2011 +0200
@@ -1,149 +1,148 @@
-#############################################################################
-#
-# Copyright (c) 2010 by Casey Duncan and contributors
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the MIT License
-# A copy of the license should accompany this distribution.
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-#
-#############################################################################
-"""Components store all entity data in a given |World|. You can
-think of components as tables with entities as their primary keys. Like
-database tables, components are defined with a "schema" that specifies
-the data fields. Each field in a component has a name and a type.
-
-Component objects themselves have a dict-like interface with entities
-as keys and data records as values. An application will typically 
-interact with components via entity attributes, entity extents or
-by joining them. For more information see:
-
-- :class:`~grease.entity.Entity` class.
-- :class:`~grease.world.EntityExtent` class.
-- :meth:`~grease.world.ComponentParts.join` method of ComponentParts.
-
-See also :ref:`defining custom components in the tutorial <custom-component-example>`.
-"""
-
-__version__ = '$Id$'
-
-__all__ = ('Component', 'ComponentError', 'Position', 'Transform', 'Movement', 
-	'Shape', 'Renderable', 'Collision')
-
-from bGrease.component.general import Component
-from bGrease.geometry import Vec2d, Vec2dArray, Rect
-from bGrease import color
-
-
-class ComponentError(Exception):
-	"""General component error"""
-
-
-class Position(Component):
-	"""Predefined component that stores position and orientation info for 
-	entities.
-
-	Fields:
-
-	- **position** (Vec2d) -- Position vector
-	- **angle** (float) -- Angle, in degrees
-	"""
-
-	def __init__(self):
-		Component.__init__(self, position=Vec2d, angle=float)
-
-
-class Transform(Component):
-	"""Predefined component that stores offset, shear, 
-	rotation and scale info for entity shapes.
-	
-	Fields:
-
-	- **offset** (Vec2d)
-	- **shear** (Vec2d)
-	- **rotation** (float)
-	- **scale** (float, default 1.0)
-	"""
-
-	def __init__(self):
-		Component.__init__(self, offset=Vec2d, shear=Vec2d, rotation=float, scale=float)
-		self.fields['scale'].default = lambda: 1.0
-
-
-class Movement(Component):
-	"""Predefined component that stores velocity, 
-	acceleration and rotation info for entities.
-	
-	Fields:
-
-	- **velocity** (Vec2d) -- Rate of change of entity position
-	- **accel** (Vec2d) -- Rate of change of entity velocity
-	- **rotation** (Vec2d) -- Rate of change of entity angle, in degrees/time
-	"""
-
-	def __init__(self):
-		Component.__init__(self, velocity=Vec2d, accel=Vec2d, rotation=float)
-
-
-class Shape(Component):
-	"""Predefined component that stores shape vertices for entities
-	
-	- **closed** (bool) -- If the shapes is closed implying an edge between
-	  last and first vertices.
-	- **verts** (Vec2dArray) -- Array of vertex points
-	"""
-
-	def __init__(self):
-		Component.__init__(self, closed=int, verts=Vec2dArray)
-		self.fields['closed'].default = lambda: 1
-
-
-class Renderable(Component):
-	"""Predefined component that identifies entities to be 
-	rendered and provides their depth and color.
-	
-	- **depth** (float) -- Drawing depth, can be used to determine z-order
-		  while rendering.
-	- **color** (color.RGBA) -- Color used for entity. The effect of this
-		  field depends on the renderer.
-	"""
-
-	def __init__(self):
-		Component.__init__(self, depth=float, color=color.RGBA)
-		self.fields['color'].default = lambda: color.RGBA(1,1,1,1)
-
-
-class Collision(Component):
-	"""Predefined component that stores collision masks to determine 
-	which entities can collide.
-
-	Fields:
-
-	- **aabb** (Rect) -- The axis-aligned bounding box for the entity.
-		This is used for broad-phase collision detection.
-
-	- **radius** (float) -- The collision radius of the entity, used for narrow-phase
-		collision detection. The exact meaning of this value depends on the collision
-		system in use.
-	
-	- **from_mask** (int) -- A bitmask that determines what entities this object
-		can collide with.
-
-	- **into_mask** (int) -- A bitmask that determines what entities can collide
-		with this object.
-
-	When considering an entity A for collision with entity B, A's ``from_mask`` is
-	bit ANDed with B's ``into_mask``. If the result is nonzero (meaning 1 or more
-	bits is set the same for each) then the collision test is made. Otherwise,
-	the pair cannot collide. 
-
-	The default value for both of these masks is ``0xffffffff``, which means that
-	all entities will collide with each other by default.
-	"""
-	def __init__(self):
-		Component.__init__(self, aabb=Rect, radius=float, from_mask=int, into_mask=int)
-		self.fields['into_mask'].default = lambda: 0xffffffff
-		self.fields['from_mask'].default = lambda: 0xffffffff
-
+#############################################################################
+#
+# Copyright (c) 2010 by Casey Duncan and contributors
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the MIT License
+# A copy of the license should accompany this distribution.
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+#
+#############################################################################
+"""Components store all entity data in a given |World|. You can
+think of components as tables with entities as their primary keys. Like
+database tables, components are defined with a "schema" that specifies
+the data fields. Each field in a component has a name and a type.
+
+Component objects themselves have a dict-like interface with entities
+as keys and data records as values. An application will typically 
+interact with components via entity attributes, entity extents or
+by joining them. For more information see:
+
+- :class:`~grease.entity.Entity` class.
+- :class:`~grease.world.EntityExtent` class.
+- :meth:`~grease.world.ComponentParts.join` method of ComponentParts.
+
+See also :ref:`defining custom components in the tutorial <custom-component-example>`.
+"""
+
+__version__ = '$Id$'
+
+__all__ = ('Component', 'ComponentError', 'Position', 'Transform', 'Movement', 
+           'Shape', 'Renderable', 'Collision')
+
+from parpg.bGrease.component.general import Component
+from parpg.bGrease.geometry import Vec2d, Vec2dArray, Rect
+from parpg.bGrease import color
+
+
+class ComponentError(Exception):
+        """General component error"""
+
+
+class Position(Component):
+        """Predefined component that stores position and orientation info for 
+        entities.
+
+        Fields:
+
+        - **position** (Vec2d) -- Position vector
+        - **angle** (float) -- Angle, in degrees
+        """
+
+        def __init__(self):
+                Component.__init__(self, position=Vec2d, angle=float)
+
+
+class Transform(Component):
+        """Predefined component that stores offset, shear, 
+        rotation and scale info for entity shapes.
+
+        Fields:
+
+        - **offset** (Vec2d)
+        - **shear** (Vec2d)
+        - **rotation** (float)
+        - **scale** (float, default 1.0)
+        """
+
+        def __init__(self):
+                Component.__init__(self, offset=Vec2d, shear=Vec2d, rotation=float, scale=float)
+                self.fields['scale'].default = lambda: 1.0
+
+
+class Movement(Component):
+        """Predefined component that stores velocity, 
+        acceleration and rotation info for entities.
+
+        Fields:
+
+        - **velocity** (Vec2d) -- Rate of change of entity position
+        - **accel** (Vec2d) -- Rate of change of entity velocity
+        - **rotation** (Vec2d) -- Rate of change of entity angle, in degrees/time
+        """
+
+        def __init__(self):
+                Component.__init__(self, velocity=Vec2d, accel=Vec2d, rotation=float)
+
+
+class Shape(Component):
+        """Predefined component that stores shape vertices for entities
+
+        - **closed** (bool) -- If the shapes is closed implying an edge between
+          last and first vertices.
+        - **verts** (Vec2dArray) -- Array of vertex points
+        """
+
+        def __init__(self):
+                Component.__init__(self, closed=int, verts=Vec2dArray)
+                self.fields['closed'].default = lambda: 1
+
+
+class Renderable(Component):
+        """Predefined component that identifies entities to be 
+        rendered and provides their depth and color.
+
+        - **depth** (float) -- Drawing depth, can be used to determine z-order
+        	  while rendering.
+        - **color** (color.RGBA) -- Color used for entity. The effect of this
+        	  field depends on the renderer.
+        """
+
+        def __init__(self):
+                Component.__init__(self, depth=float, color=color.RGBA)
+                self.fields['color'].default = lambda: color.RGBA(1,1,1,1)
+
+
+class Collision(Component):
+        """Predefined component that stores collision masks to determine 
+        which entities can collide.
+
+        Fields:
+
+        - **aabb** (Rect) -- The axis-aligned bounding box for the entity.
+        	This is used for broad-phase collision detection.
+
+        - **radius** (float) -- The collision radius of the entity, used for narrow-phase
+        	collision detection. The exact meaning of this value depends on the collision
+        	system in use.
+
+        - **from_mask** (int) -- A bitmask that determines what entities this object
+        	can collide with.
+
+        - **into_mask** (int) -- A bitmask that determines what entities can collide
+        	with this object.
+
+        When considering an entity A for collision with entity B, A's ``from_mask`` is
+        bit ANDed with B's ``into_mask``. If the result is nonzero (meaning 1 or more
+        bits is set the same for each) then the collision test is made. Otherwise,
+        the pair cannot collide. 
+
+        The default value for both of these masks is ``0xffffffff``, which means that
+        all entities will collide with each other by default.
+        """
+        def __init__(self):
+                Component.__init__(self, aabb=Rect, radius=float, from_mask=int, into_mask=int)
+                self.fields['into_mask'].default = lambda: 0xffffffff
+                self.fields['from_mask'].default = lambda: 0xffffffff
--- a/bGrease/component/field.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/bGrease/component/field.py	Wed Sep 21 16:10:14 2011 +0200
@@ -1,303 +1,303 @@
-#############################################################################
-#
-# Copyright (c) 2010 by Casey Duncan and contributors
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the MIT License
-# A copy of the license should accompany this distribution.
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-#
-#############################################################################
-
-__version__ = '$Id$'
-
-import operator
-from bGrease.geometry import Vec2d, Vec2dArray, Rect
-from bGrease import color
-
-# Allowed field types -> default values
-types = {int:lambda: 0, 
-         float:lambda: 0.0, 
-         bool:lambda: False,
-         str:lambda:"", 
-         object:lambda:None,
-         Vec2d:lambda: Vec2d(0,0), 
-         Vec2dArray:lambda: Vec2dArray(),
-         color.RGBA: lambda: color.RGBA(0.0, 0.0, 0.0, 0.0),
-         Rect: lambda: Rect(0.0, 0.0, 0.0, 0.0),
-         list: lambda: list(),
-         dict: lambda: dict(),
-         }
-
-class Schema(dict):
-        """Field schema definition for custom components"""
-
-        def __init__(self, **fields):
-                for ftype in fields.values():
-                        assert ftype in types, fname + " has an illegal field type"
-                self.update(fields)
-
-
-class FieldAccessor(object):
-        """Facade for manipulating a field for a set of entities"""
-
-        __field = None
-        __entities = None
-        __attrs = None
-        __getter = None
-        __parent_getters = ()
-
-        def __init__(self, field, entities, attrs=()):
-                self.__field = field
-                self.__entities = entities
-                field_getter = operator.attrgetter(field.name)
-                self.__attrs = attrs
-                if attrs:
-                        getters = [field_getter] + [operator.attrgetter(attr) for attr in attrs]
-                        def get(entity):
-                                value = entity
-                                for getter in getters:
-                                        value = getter(value)
-                                return value
-                        self.__getter = get
-                        self.__parent_getters = getters[:-1]
-                else:
-                        self.__getter = field_getter
-
-        def __getattr__(self, name):
-                """Return a FieldAccessor for the child attribute"""
-                return self.__class__(self.__field, self.__entities, self.__attrs + (name,))
-
-        def __setattr__(self, name, value):
-                if value is self:
-                        return # returned by mutators
-                if hasattr(self.__class__, name):
-                        # Set local attr
-                        self.__dict__[name] = value
-                elif not name.startswith('_'):
-                        getattr(self, name).__set__(value)
-                else:
-                        raise AttributeError("Cannot set field attribute: %s" % name)
-
-        @property
-        def __setter(self):
-                """Return the proper setter function for setting the field value"""
-                if not self.__attrs:
-                        return setattr
-                else:
-                        parent_getters = self.__parent_getters
-                        def setter(data, name, value):
-                                for getter in parent_getters:
-                                        data = getter(data)
-                                setattr(data, name, value)
-                        self.__setter = setter
-                        return setter
-
-        def __set__(self, value):
-                """Set field values en masse"""
-                # Mass set field attr
-                setter = self.__setter
-                component = self.__field.component
-                if self.__attrs:
-                        name = self.__attrs[-1]
-                else:
-                        name = self.__field.name
-                if isinstance(value, FieldAccessor):
-                        # Join set between two entity sets
-                        if not self.__attrs:
-                                cast = self.__field.cast
-                        else: 
-                                cast = lambda x: x
-                        for entity in self.__entities:
-                                try:
-                                        setter(component[entity], name, cast(value[entity]))
-                                except KeyError:
-                                        pass
-                else:
-                        if not self.__attrs:
-                                value = self.__field.cast(value)
-                        for entity in self.__entities:
-                                try:
-                                        setter(component[entity], name, value)
-                                except KeyError:
-                                        pass
-
-        def __getitem__(self, entity):
-                """Return the field value for a single entity (used for joins)"""
-                if entity in self.__entities:
-                        return self.__getter(self.__field.component[entity])
-                raise KeyError(entity)
-
-        def __contains__(self, entity):
-                return entity in self.__entities
-
-        def __repr__(self):
-                return '<%s %s @ %x>' % (
-                        self.__class__.__name__, 
-                        '.'.join((self.__field.name,) + self.__attrs), id(self))
-
-        def __nonzero__(self):
-                return bool(self.__entities)
-
-        def __iter__(self):
-                """Return an iterator of all field values in the set"""
-                component = self.__field.component
-                getter = self.__getter
-                for entity in self.__entities:
-                        try:
-                                data = component[entity]
-                        except KeyError:
-                                continue
-                        yield getter(data)
-
-        ## batch comparison operators ##
-
-        def __match(self, value, op):
-                component = self.__field.component
-                getter = self.__getter
-                matches = set()
-                add = matches.add
-                if isinstance(value, FieldAccessor):
-                        # Join match between entity sets
-                        for entity in self.__entities:
-                                try:
-                                        data = component[entity]
-                                        other = value[entity]
-                                except KeyError:
-                                        continue
-                                if op(getter(data), other):
-                                        add(entity)
-                else:
-                        for entity in self.__entities:
-                                try:
-                                        data = component[entity]
-                                except KeyError:
-                                        continue
-                                if op(getter(data), value):
-                                        add(entity)
-                return matches
-
-        def __eq__(self, value):
-                """Return an entity set of all entities with a matching field value"""
-                return self.__match(value, operator.eq)
-
-        def __ne__(self, value):
-                """Return an entity set of all entities not matching field value"""
-                return self.__match(value, operator.ne)
-
-        def __gt__(self, value):
-                """Return an entity set of all entities with a greater field value"""
-                return self.__match(value, operator.gt)
-
-        def __ge__(self, value):
-                """Return an entity set of all entities with a greater or equal field value"""
-                return self.__match(value, operator.ge)
-
-        def __lt__(self, value):
-                """Return an entity set of all entities with a lesser field value"""
-                return self.__match(value, operator.lt)
-
-        def __le__(self, value):
-                """Return an entity set of all entities with a lesser or equal field value"""
-                return self.__match(value, operator.le)
-
-        def _contains(self, values):
-                """Return an entity set of all entities with a field value contained in values"""
-                return self.__match(values, operator.contains)
-
-        ## Batch in-place mutator methods
-
-        def __mutate(self, value, op):
-                component = self.__field.component
-                if self.__attrs:
-                        name = self.__attrs[-1]
-                else:
-                        name = self.__field.name
-                getter = self.__getter
-                setter = self.__setter
-                if isinstance(value, FieldAccessor):
-                        # Join between entity sets
-                        for entity in self.__entities:
-                                try:
-                                        data = component[entity]
-                                        other = value[entity]
-                                except KeyError:
-                                        continue
-                                setter(data, name, op(getter(data), other))
-                else:
-                        for entity in self.__entities:
-                                try:
-                                        data = component[entity]
-                                except KeyError:
-                                        continue
-                                setter(data, name, op(getter(data), value))
-                return self
-
-        def __iadd__(self, value):
-                return self.__mutate(value, operator.iadd)
-
-        def __isub__(self, value):
-                return self.__mutate(value, operator.isub)
-
-        def __imul__(self, value):
-                return self.__mutate(value, operator.imul)
-
-        def __idiv__(self, value):
-                return self.__mutate(value, operator.idiv)
-
-        def __itruediv__(self, value):
-                return self.__mutate(value, operator.itruediv)
-
-        def __ifloordiv__(self, value):
-                return self.__mutate(value, operator.ifloordiv)
-
-        def __imod__(self, value):
-                return self.__mutate(value, operator.imod)
-
-        def __ipow__(self, value):
-                return self.__mutate(value, operator.ipow)
-
-        def __ilshift__(self, value):
-                return self.__mutate(value, operator.ilshift)
-
-        def __irshift__(self, value):
-                return self.__mutate(value, operator.irshift)
-
-        def __iand__(self, value):
-                return self.__mutate(value, operator.iand)
-
-        def __ior__(self, value):
-                return self.__mutate(value, operator.ior)
-
-        def __ixor__(self, value):
-                return self.__mutate(value, operator.ixor)
-
-
-class Field(object):
-        """Component field metadata and accessor interface"""
-
-        def __init__(self, component, name, type, accessor_factory=FieldAccessor):
-                self.component = component
-                self.name = name
-                self.type = type
-                self.default = types.get(type)
-                self.accessor_factory = accessor_factory
-
-        def cast(self, value):
-                """Cast value to the appropriate type for thi field"""
-                if self.type is not object:
-                        return self.type(value)
-                else:
-                        return value
-
-        def accessor(self, entities=None):
-                """Return the field accessor for the entities in the component,
-                or all entities in the set specified that are also in the component
-                """
-                if entities is None or entities is self.component.entities:
-                        entities = self.component.entities
-                else:
-                        entities = entities & self.component.entities
-                return self.accessor_factory(self, entities)
+#############################################################################
+#
+# Copyright (c) 2010 by Casey Duncan and contributors
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the MIT License
+# A copy of the license should accompany this distribution.
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+#
+#############################################################################
+
+__version__ = '$Id$'
+
+import operator
+from parpg.bGrease.geometry import Vec2d, Vec2dArray, Rect
+from parpg.bGrease import color
+
+# Allowed field types -> default values
+types = {int:lambda: 0, 
+         float:lambda: 0.0, 
+         bool:lambda: False,
+         str:lambda:"", 
+         object:lambda:None,
+         Vec2d:lambda: Vec2d(0,0), 
+         Vec2dArray:lambda: Vec2dArray(),
+         color.RGBA: lambda: color.RGBA(0.0, 0.0, 0.0, 0.0),
+         Rect: lambda: Rect(0.0, 0.0, 0.0, 0.0),
+         list: lambda: list(),
+         dict: lambda: dict(),
+         }
+
+class Schema(dict):
+        """Field schema definition for custom components"""
+
+        def __init__(self, **fields):
+                for ftype in fields.values():
+                        assert ftype in types, fname + " has an illegal field type"
+                self.update(fields)
+
+
+class FieldAccessor(object):
+        """Facade for manipulating a field for a set of entities"""
+
+        __field = None
+        __entities = None
+        __attrs = None
+        __getter = None
+        __parent_getters = ()
+
+        def __init__(self, field, entities, attrs=()):
+                self.__field = field
+                self.__entities = entities
+                field_getter = operator.attrgetter(field.name)
+                self.__attrs = attrs
+                if attrs:
+                        getters = [field_getter] + [operator.attrgetter(attr) for attr in attrs]
+                        def get(entity):
+                                value = entity
+                                for getter in getters:
+                                        value = getter(value)
+                                return value
+                        self.__getter = get
+                        self.__parent_getters = getters[:-1]
+                else:
+                        self.__getter = field_getter
+
+        def __getattr__(self, name):
+                """Return a FieldAccessor for the child attribute"""
+                return self.__class__(self.__field, self.__entities, self.__attrs + (name,))
+
+        def __setattr__(self, name, value):
+                if value is self:
+                        return # returned by mutators
+                if hasattr(self.__class__, name):
+                        # Set local attr
+                        self.__dict__[name] = value
+                elif not name.startswith('_'):
+                        getattr(self, name).__set__(value)
+                else:
+                        raise AttributeError("Cannot set field attribute: %s" % name)
+
+        @property
+        def __setter(self):
+                """Return the proper setter function for setting the field value"""
+                if not self.__attrs:
+                        return setattr
+                else:
+                        parent_getters = self.__parent_getters
+                        def setter(data, name, value):
+                                for getter in parent_getters:
+                                        data = getter(data)
+                                setattr(data, name, value)
+                        self.__setter = setter
+                        return setter
+
+        def __set__(self, value):
+                """Set field values en masse"""
+                # Mass set field attr
+                setter = self.__setter
+                component = self.__field.component
+                if self.__attrs:
+                        name = self.__attrs[-1]
+                else:
+                        name = self.__field.name
+                if isinstance(value, FieldAccessor):
+                        # Join set between two entity sets
+                        if not self.__attrs:
+                                cast = self.__field.cast
+                        else: 
+                                cast = lambda x: x
+                        for entity in self.__entities:
+                                try:
+                                        setter(component[entity], name, cast(value[entity]))
+                                except KeyError:
+                                        pass
+                else:
+                        if not self.__attrs:
+                                value = self.__field.cast(value)
+                        for entity in self.__entities:
+                                try:
+                                        setter(component[entity], name, value)
+                                except KeyError:
+                                        pass
+
+        def __getitem__(self, entity):
+                """Return the field value for a single entity (used for joins)"""
+                if entity in self.__entities:
+                        return self.__getter(self.__field.component[entity])
+                raise KeyError(entity)
+
+        def __contains__(self, entity):
+                return entity in self.__entities
+
+        def __repr__(self):
+                return '<%s %s @ %x>' % (
+                        self.__class__.__name__, 
+                        '.'.join((self.__field.name,) + self.__attrs), id(self))
+
+        def __nonzero__(self):
+                return bool(self.__entities)
+
+        def __iter__(self):
+                """Return an iterator of all field values in the set"""
+                component = self.__field.component
+                getter = self.__getter
+                for entity in self.__entities:
+                        try:
+                                data = component[entity]
+                        except KeyError:
+                                continue
+                        yield getter(data)
+
+        ## batch comparison operators ##
+
+        def __match(self, value, op):
+                component = self.__field.component
+                getter = self.__getter
+                matches = set()
+                add = matches.add
+                if isinstance(value, FieldAccessor):
+                        # Join match between entity sets
+                        for entity in self.__entities:
+                                try:
+                                        data = component[entity]
+                                        other = value[entity]
+                                except KeyError:
+                                        continue
+                                if op(getter(data), other):
+                                        add(entity)
+                else:
+                        for entity in self.__entities:
+                                try:
+                                        data = component[entity]
+                                except KeyError:
+                                        continue
+                                if op(getter(data), value):
+                                        add(entity)
+                return matches
+
+        def __eq__(self, value):
+                """Return an entity set of all entities with a matching field value"""
+                return self.__match(value, operator.eq)
+
+        def __ne__(self, value):
+                """Return an entity set of all entities not matching field value"""
+                return self.__match(value, operator.ne)
+
+        def __gt__(self, value):
+                """Return an entity set of all entities with a greater field value"""
+                return self.__match(value, operator.gt)
+
+        def __ge__(self, value):
+                """Return an entity set of all entities with a greater or equal field value"""
+                return self.__match(value, operator.ge)
+
+        def __lt__(self, value):
+                """Return an entity set of all entities with a lesser field value"""
+                return self.__match(value, operator.lt)
+
+        def __le__(self, value):
+                """Return an entity set of all entities with a lesser or equal field value"""
+                return self.__match(value, operator.le)
+
+        def _contains(self, values):
+                """Return an entity set of all entities with a field value contained in values"""
+                return self.__match(values, operator.contains)
+
+        ## Batch in-place mutator methods
+
+        def __mutate(self, value, op):
+                component = self.__field.component
+                if self.__attrs:
+                        name = self.__attrs[-1]
+                else:
+                        name = self.__field.name
+                getter = self.__getter
+                setter = self.__setter
+                if isinstance(value, FieldAccessor):
+                        # Join between entity sets
+                        for entity in self.__entities:
+                                try:
+                                        data = component[entity]
+                                        other = value[entity]
+                                except KeyError:
+                                        continue
+                                setter(data, name, op(getter(data), other))
+                else:
+                        for entity in self.__entities:
+                                try:
+                                        data = component[entity]
+                                except KeyError:
+                                        continue
+                                setter(data, name, op(getter(data), value))
+                return self
+
+        def __iadd__(self, value):
+                return self.__mutate(value, operator.iadd)
+
+        def __isub__(self, value):
+                return self.__mutate(value, operator.isub)
+
+        def __imul__(self, value):
+                return self.__mutate(value, operator.imul)
+
+        def __idiv__(self, value):
+                return self.__mutate(value, operator.idiv)
+
+        def __itruediv__(self, value):
+                return self.__mutate(value, operator.itruediv)
+
+        def __ifloordiv__(self, value):
+                return self.__mutate(value, operator.ifloordiv)
+
+        def __imod__(self, value):
+                return self.__mutate(value, operator.imod)
+
+        def __ipow__(self, value):
+                return self.__mutate(value, operator.ipow)
+
+        def __ilshift__(self, value):
+                return self.__mutate(value, operator.ilshift)
+
+        def __irshift__(self, value):
+                return self.__mutate(value, operator.irshift)
+
+        def __iand__(self, value):
+                return self.__mutate(value, operator.iand)
+
+        def __ior__(self, value):
+                return self.__mutate(value, operator.ior)
+
+        def __ixor__(self, value):
+                return self.__mutate(value, operator.ixor)
+
+
+class Field(object):
+        """Component field metadata and accessor interface"""
+
+        def __init__(self, component, name, type, accessor_factory=FieldAccessor):
+                self.component = component
+                self.name = name
+                self.type = type
+                self.default = types.get(type)
+                self.accessor_factory = accessor_factory
+
+        def cast(self, value):
+                """Cast value to the appropriate type for thi field"""
+                if self.type is not object:
+                        return self.type(value)
+                else:
+                        return value
+
+        def accessor(self, entities=None):
+                """Return the field accessor for the entities in the component,
+                or all entities in the set specified that are also in the component
+                """
+                if entities is None or entities is self.component.entities:
+                        entities = self.component.entities
+                else:
+                        entities = entities & self.component.entities
+                return self.accessor_factory(self, entities)
--- a/bGrease/component/general.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/bGrease/component/general.py	Wed Sep 21 16:10:14 2011 +0200
@@ -1,143 +1,142 @@
-#############################################################################
-#
-# Copyright (c) 2010 by Casey Duncan and contributors
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the MIT License
-# A copy of the license should accompany this distribution.
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-#
-#############################################################################
-
-__version__ = '$Id$'
-
-from bGrease.component import base
-from bGrease.component import field
-from bGrease.entity import ComponentEntitySet
-
-
-class Component(dict):
-	"""General component with a configurable schema
-
-	The field schema is defined via keyword args where the 
-	arg name is the field name and the value is the type object.
-
-	The following types are supported for fields:
-
-	- :class:`int`
-	- :class:`float`
-	- :class:`bool`
-	- :class:`str`
-	- :class:`object`
-	- |Vec2d|
-	- |Vec2dArray|
-	- |RGBA|
-	- |Rect|
-	"""
-
-	deleted_entities = ()
-	"""List of entities deleted from the component since the last time step"""
-
-	new_entities = ()
-	"""List of entities added to the component since the last time step"""
-
-	def __init__(self, **fields):
-		self.fields = {}
-		for fname, ftype in fields.items():
-			assert ftype in field.types, fname + " has an illegal field type"
-			self.fields[fname] = field.Field(self, fname, ftype)
-		self.entities = ComponentEntitySet(self)
-		self._added = []
-		self._deleted = []
-	
-	def set_world(self, world):
-		self.world = world
-	
-	def step(self, dt):
-		"""Update the component for the next timestep"""
-		delitem = super(Component, self).__delitem__
-		for entity in self._deleted:
-			delitem(entity)
-		self.new_entities = self._added
-		self.deleted_entities = self._deleted
-		self._added = []
-		self._deleted = []
-	
-	def set(self, entity, data=None, **data_kw):
-		"""Set the component data for an entity, adding it to the
-		component if it is not already a member.
-
-		If data is specified, its data for the new entity's fields are
-		copied from its attributes, making it easy to copy another
-		entity's data. Keyword arguments are also matched to fields.
-		If both a data attribute and keyword argument are supplied for
-		a single field, the keyword arg is used.
-		"""
-		if data is not None:
-			for fname, field in self.fields.items():
-				if fname not in data_kw and hasattr(data, fname):
-					data_kw[fname] = getattr(data, fname)
-		data = self[entity] = Data(self.fields, entity, **data_kw)
-		return data
-	
-	def __setitem__(self, entity, data):
-		assert entity.world is self.world, "Entity not in component's world"
-		if entity not in self.entities:
-			self._added.append(entity)
-			self.entities.add(entity)
-		super(Component, self).__setitem__(entity, data)
-	
-	def remove(self, entity):
-		if entity in self.entities:
-			self._deleted.append(entity)
-			self.entities.remove(entity)
-			return True
-		return False
-	
-	__delitem__ = remove
-
-	def __repr__(self):
-		return '<%s %x of %r>' % (
-			self.__class__.__name__, id(self), getattr(self, 'world', None))
-
-
-class Singleton(Component):
-	"""Component that may contain only a single entity"""
-
-	def add(self, entity_id, data=None, **data_kw):
-		if entity_id not in self._data:
-			self.entity_id_set.clear()
-			self._data.clear()
-		Component.add(self, entity_id, data, **data_kw)
-	
-	@property
-	def entity(self):
-		"""Return the entity in the component, or None if empty"""
-		if self._data:
-			return self.manager[self._data.keys()[0]]
-	
-
-class Data(object):
-
-	def __init__(self, fields, entity, **data):
-		self.__dict__['_Data__fields'] = fields
-		self.__dict__['entity'] = entity
-		for field in fields.values():
-			if field.name in data:
-				setattr(self, field.name, data[field.name])
-			else:
-				setattr(self, field.name, field.default())
-	
-	def __setattr__(self, name, value):
-		if name in self.__fields:
-			self.__dict__[name] = self.__fields[name].cast(value)
-		else:
-			raise AttributeError("Invalid data field: " + name)
-	
-	def __repr__(self):
-		return '<%s(%r)>' % (self.__class__.__name__, self.__dict__)
-
-			
-
+#############################################################################
+#
+# Copyright (c) 2010 by Casey Duncan and contributors
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the MIT License
+# A copy of the license should accompany this distribution.
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+#
+#############################################################################
+
+__version__ = '$Id$'
+
+from parpg.bGrease.component import base
+from parpg.bGrease.component import field
+from parpg.bGrease.entity import ComponentEntitySet
+
+
+class Component(dict):
+        """General component with a configurable schema
+
+        The field schema is defined via keyword args where the 
+        arg name is the field name and the value is the type object.
+
+        The following types are supported for fields:
+
+        - :class:`int`
+        - :class:`float`
+        - :class:`bool`
+        - :class:`str`
+        - :class:`object`
+        - |Vec2d|
+        - |Vec2dArray|
+        - |RGBA|
+        - |Rect|
+        """
+
+        deleted_entities = ()
+        """List of entities deleted from the component since the last time step"""
+
+        new_entities = ()
+        """List of entities added to the component since the last time step"""
+
+        def __init__(self, **fields):
+                self.fields = {}
+                for fname, ftype in fields.items():
+                        assert ftype in field.types, fname + " has an illegal field type"
+                        self.fields[fname] = field.Field(self, fname, ftype)
+                self.entities = ComponentEntitySet(self)
+                self._added = []
+                self._deleted = []
+
+        def set_world(self, world):
+                self.world = world
+
+        def step(self, dt):
+                """Update the component for the next timestep"""
+                delitem = super(Component, self).__delitem__
+                for entity in self._deleted:
+                        delitem(entity)
+                self.new_entities = self._added
+                self.deleted_entities = self._deleted
+                self._added = []
+                self._deleted = []
+
+        def set(self, entity, data=None, **data_kw):
+                """Set the component data for an entity, adding it to the
+                component if it is not already a member.
+
+                If data is specified, its data for the new entity's fields are
+                copied from its attributes, making it easy to copy another
+                entity's data. Keyword arguments are also matched to fields.
+                If both a data attribute and keyword argument are supplied for
+                a single field, the keyword arg is used.
+                """
+                if data is not None:
+                        for fname, field in self.fields.items():
+                                if fname not in data_kw and hasattr(data, fname):
+                                        data_kw[fname] = getattr(data, fname)
+                data = self[entity] = Data(self.fields, entity, **data_kw)
+                return data
+
+        def __setitem__(self, entity, data):
+                assert entity.world is self.world, "Entity not in component's world"
+                if entity not in self.entities:
+                        self._added.append(entity)
+                        self.entities.add(entity)
+                super(Component, self).__setitem__(entity, data)
+
+        def remove(self, entity):
+                if entity in self.entities:
+                        self._deleted.append(entity)
+                        self.entities.remove(entity)
+                        return True
+                return False
+
+        __delitem__ = remove
+
+        def __repr__(self):
+                return '<%s %x of %r>' % (
+                        self.__class__.__name__, id(self), getattr(self, 'world', None))
+
+
+class Singleton(Component):
+        """Component that may contain only a single entity"""
+
+        def add(self, entity_id, data=None, **data_kw):
+                if entity_id not in self._data:
+                        self.entity_id_set.clear()
+                        self._data.clear()
+                Component.add(self, entity_id, data, **data_kw)
+
+        @property
+        def entity(self):
+                """Return the entity in the component, or None if empty"""
+                if self._data:
+                        return self.manager[self._data.keys()[0]]
+
+
+class Data(object):
+
+        def __init__(self, fields, entity, **data):
+                self.__dict__['_Data__fields'] = fields
+                self.__dict__['entity'] = entity
+                for field in fields.values():
+                        if field.name in data:
+                                setattr(self, field.name, data[field.name])
+                        else:
+                                setattr(self, field.name, field.default())
+
+        def __setattr__(self, name, value):
+                if name in self.__fields:
+                        self.__dict__[name] = self.__fields[name].cast(value)
+                else:
+                        raise AttributeError("Invalid data field: " + name)
+
+        def __repr__(self):
+                return '<%s(%r)>' % (self.__class__.__name__, self.__dict__)
+
+
--- a/bGrease/controller/__init__.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/bGrease/controller/__init__.py	Wed Sep 21 16:10:14 2011 +0200
@@ -1,4 +1,4 @@
-
-__all__ = ('EulerMovement',)
-
-from bGrease.controller.integrator import EulerMovement
+
+__all__ = ('EulerMovement',)
+
+from parpg.bGrease.controller.integrator import EulerMovement
--- a/bGrease/impl/mode.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/bGrease/impl/mode.py	Wed Sep 21 16:10:14 2011 +0200
@@ -1,203 +1,202 @@
-#############################################################################
-#
-# Copyright (c) 2010 by Casey Duncan and contributors
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the MIT License
-# A copy of the license should accompany this distribution.
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-#
-#############################################################################
-"""
-Modes manage the state and transition between different application modes.
-Typically such modes are presented as different screens that the user can
-navigate between, similar to the way a browser navigates web pages. Individual
-modes may be things like:
-
-- Title screen
-- Options dialog
-- About screen
-- In-progress game
-- Inventory interface
-
-The modal framework provides a simple mechanism to ensure that modes are
-activated and deactivated properly. An activated mode is running and receives
-events. A deactivated mode is paused and does not receive events.
-
-Modes may be managed as a *last-in-first-out* stack, or as a list, or ring
-of modes in sequence, or some combination of all.
-
-For example usage see: :ref:`the mode section of the tutorial <tut-mode-section>`.
-"""
-
-__version__ = '$Id$'
-
-import abc
-import pyglet
-from bGrease.mode import *
-
-class PygletManager(BaseManager):
-	"""Mode manager abstract base class using pyglet.
-	
-	The mode manager keeps a stack of modes where a single mode
-	is active at one time. As modes are pushed on and popped from 
-	the stack, the mode at the top is always active. The current
-	active mode receives events from the manager's event dispatcher.
-	"""
-
-	event_dispatcher = None
-	""":class:`pyglet.event.EventDispatcher` object that the
-	active mode receive events from.
-	"""
-	
-	def activate_mode(self, mode):
-		"""Perform actions to activate a node
-		
-		:param mode: The :class: 'Mode' object to activate
-		"""
-		BaseManager.activate_mode(self, mode)
-		self.event_dispatcher.push_handlers(mode)
-		
-	def deactivate_mode(self, mode):
-		"""Perform actions to deactivate a node
-		
-		:param mode: The :class: 'Mode' object to deactivate
-		"""
-		BaseManager.deactivate_mode(self, mode)
-		self.event_dispatcher.remove_handlers(mode)
-
-class Manager(PygletManager):
-	"""A basic mode manager that wraps a single
-	:class:`pyglet.event.EventDispatcher` object for use by its modes.
-	"""
-
-	def __init__(self, event_dispatcher):
-		self.modes = []
-		self.event_dispatcher = event_dispatcher
-
-
-class ManagerWindow(PygletManager, pyglet.window.Window):
-	"""An integrated mode manager and pyglet window for convenience.
-	The window is the event dispatcher used by modes pushed to
-	this manager.
-
-	Constructor arguments are identical to :class:`pyglet.window.Window`
-	"""
-	
-	def __init__(self, *args, **kw):
-		super(ManagerWindow, self).__init__(*args, **kw)
-		self.modes = []
-		self.event_dispatcher = self
-
-	def on_key_press(self, symbol, modifiers):
-		"""Default :meth:`on_key_press handler`, pops the current mode on ``ESC``"""
-		if symbol == pyglet.window.key.ESCAPE:
-			self.pop_mode()
-
-	def on_last_mode_pop(self, mode):
-		"""Hook executed when the last mode is popped from the manager.
-		When the last mode is popped from a window, an :meth:`on_close` event
-		is dispatched.
-
-		:param mode: The :class:`Mode` object just popped from the manager
-		"""
-		self.dispatch_event('on_close')
-
-
-class Mode(BaseMode):
-	"""Application mode abstract base class using pyglet
-
-	Subclasses must implement the :meth:`step` method
-	
-	:param step_rate: The rate of :meth:`step()` calls per second. 
-
-	:param master_clock: The :class:`pyglet.clock.Clock` interface used
-		as the master clock that ticks the world's clock. This 
-		defaults to the main pyglet clock.
-	"""
-	clock = None
-	"""The :class:`pyglet.clock.Clock` instance used as this mode's clock.
-	You should use this clock to schedule tasks for this mode, so they
-	properly respect when the mode is active or inactive
-
-	Example::
-
-		my_mode.clock.schedule_once(my_cool_function, 4)
-	"""
-
-	def __init__(self, step_rate=60, master_clock=pyglet.clock, 
-		         clock_factory=pyglet.clock.Clock):
-		BaseMode.__init__(self)
-		self.step_rate = step_rate
-		self.time = 0.0
-		self.master_clock = master_clock
-		self.clock = clock_factory(time_function=lambda: self.time)
-		self.clock.schedule_interval(self.step, 1.0 / step_rate)
-	
-	def on_activate(self):
-		"""Being called when the Mode is activated"""
-		self.master_clock.schedule(self.tick)
-	
-	def on_deactivate(self):
-		"""Being called when the Mode is deactivated"""
-		self.master_clock.unschedule(self.tick)
-		
-	def tick(self, dt):
-		"""Tick the mode's clock.
-
-		:param dt: The time delta since the last tick
-		:type dt: float
-		"""
-		self.time += dt
-		self.clock.tick(poll=False)
-	
-	@abc.abstractmethod
-	def step(self, dt):
-		"""Execute a timestep for this mode. Must be defined by subclasses.
-		
-		:param dt: The time delta since the last time step
-		:type dt: float
-		"""
-
-class Multi(BaseMulti, Mode):
-	"""A mode with multiple submodes. One submode is active at one time.
-	Submodes can be switched to directly or switched in sequence. If
-	the Multi is active, then one submode is always active.
-
-	Multis are useful when modes can switch in an order other than
-	a LIFO stack, such as in "hotseat" multiplayer games, a
-	"wizard" style ui, or a sequence of slides.
-
-	Note unlike a normal :class:`Mode`, a :class:`Multi` doesn't have it's own
-	:attr:`clock` and :attr:`step_rate`. The active submode's are used
-	instead.
-	"""
-	
-	def __init__(self, submodes):
-		BaseMulti.__init__(self, submodes)
-		self.time = 0.0
-
-	
-	def _set_active_submode(self, submode):
-		BaseMulti._set_active_submode(self, submode)
-		self.master_clock = submode.master_clock
-		self.clock = submode.clock
-
-	def clear_subnode(self):
-		"""Clear any subnmode data"""
-		BaseMulti.clear_subnode(self)
-		self.master_clock = None
-		self.clock = None
-
-	def tick(self, dt):
-		"""Tick the active submode's clock.
-
-		:param dt: The time delta since the last tick
-		:type dt: float
-		"""
-		self.time += dt
-		if self.active_submode is not None:
-			self.active_submode.clock.tick(poll=False)
-
+#############################################################################
+#
+# Copyright (c) 2010 by Casey Duncan and contributors
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the MIT License
+# A copy of the license should accompany this distribution.
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+#
+#############################################################################
+"""
+Modes manage the state and transition between different application modes.
+Typically such modes are presented as different screens that the user can
+navigate between, similar to the way a browser navigates web pages. Individual
+modes may be things like:
+
+- Title screen
+- Options dialog
+- About screen
+- In-progress game
+- Inventory interface
+
+The modal framework provides a simple mechanism to ensure that modes are
+activated and deactivated properly. An activated mode is running and receives
+events. A deactivated mode is paused and does not receive events.
+
+Modes may be managed as a *last-in-first-out* stack, or as a list, or ring
+of modes in sequence, or some combination of all.
+
+For example usage see: :ref:`the mode section of the tutorial <tut-mode-section>`.
+"""
+
+__version__ = '$Id$'
+
+import abc
+import pyglet
+from parpg.bGrease.mode import *
+
+class PygletManager(BaseManager):
+        """Mode manager abstract base class using pyglet.
+
+        The mode manager keeps a stack of modes where a single mode
+        is active at one time. As modes are pushed on and popped from 
+        the stack, the mode at the top is always active. The current
+        active mode receives events from the manager's event dispatcher.
+        """
+
+        event_dispatcher = None
+        """:class:`pyglet.event.EventDispatcher` object that the
+	active mode receive events from.
+	"""
+
+        def activate_mode(self, mode):
+                """Perform actions to activate a node
+
+                :param mode: The :class: 'Mode' object to activate
+                """
+                BaseManager.activate_mode(self, mode)
+                self.event_dispatcher.push_handlers(mode)
+
+        def deactivate_mode(self, mode):
+                """Perform actions to deactivate a node
+
+                :param mode: The :class: 'Mode' object to deactivate
+                """
+                BaseManager.deactivate_mode(self, mode)
+                self.event_dispatcher.remove_handlers(mode)
+
+class Manager(PygletManager):
+        """A basic mode manager that wraps a single
+        :class:`pyglet.event.EventDispatcher` object for use by its modes.
+        """
+
+        def __init__(self, event_dispatcher):
+                self.modes = []
+                self.event_dispatcher = event_dispatcher
+
+
+class ManagerWindow(PygletManager, pyglet.window.Window):
+        """An integrated mode manager and pyglet window for convenience.
+        The window is the event dispatcher used by modes pushed to
+        this manager.
+
+        Constructor arguments are identical to :class:`pyglet.window.Window`
+        """
+
+        def __init__(self, *args, **kw):
+                super(ManagerWindow, self).__init__(*args, **kw)
+                self.modes = []
+                self.event_dispatcher = self
+
+        def on_key_press(self, symbol, modifiers):
+                """Default :meth:`on_key_press handler`, pops the current mode on ``ESC``"""
+                if symbol == pyglet.window.key.ESCAPE:
+                        self.pop_mode()
+
+        def on_last_mode_pop(self, mode):
+                """Hook executed when the last mode is popped from the manager.
+                When the last mode is popped from a window, an :meth:`on_close` event
+                is dispatched.
+
+                :param mode: The :class:`Mode` object just popped from the manager
+                """
+                self.dispatch_event('on_close')
+
+
+class Mode(BaseMode):
+        """Application mode abstract base class using pyglet
+
+        Subclasses must implement the :meth:`step` method
+
+        :param step_rate: The rate of :meth:`step()` calls per second. 
+
+        :param master_clock: The :class:`pyglet.clock.Clock` interface used
+        	as the master clock that ticks the world's clock. This 
+        	defaults to the main pyglet clock.
+        """
+        clock = None
+        """The :class:`pyglet.clock.Clock` instance used as this mode's clock.
+	You should use this clock to schedule tasks for this mode, so they
+	properly respect when the mode is active or inactive
+
+	Example::
+
+		my_mode.clock.schedule_once(my_cool_function, 4)
+	"""
+
+        def __init__(self, step_rate=60, master_clock=pyglet.clock, 
+                     clock_factory=pyglet.clock.Clock):
+                BaseMode.__init__(self)
+                self.step_rate = step_rate
+                self.time = 0.0
+                self.master_clock = master_clock
+                self.clock = clock_factory(time_function=lambda: self.time)
+                self.clock.schedule_interval(self.step, 1.0 / step_rate)
+
+        def on_activate(self):
+                """Being called when the Mode is activated"""
+                self.master_clock.schedule(self.tick)
+
+        def on_deactivate(self):
+                """Being called when the Mode is deactivated"""
+                self.master_clock.unschedule(self.tick)
+
+        def tick(self, dt):
+                """Tick the mode's clock.
+
+                :param dt: The time delta since the last tick
+                :type dt: float
+                """
+                self.time += dt
+                self.clock.tick(poll=False)
+
+        @abc.abstractmethod
+        def step(self, dt):
+                """Execute a timestep for this mode. Must be defined by subclasses.
+
+                :param dt: The time delta since the last time step
+                :type dt: float
+                """
+
+class Multi(BaseMulti, Mode):
+        """A mode with multiple submodes. One submode is active at one time.
+        Submodes can be switched to directly or switched in sequence. If
+        the Multi is active, then one submode is always active.
+
+        Multis are useful when modes can switch in an order other than
+        a LIFO stack, such as in "hotseat" multiplayer games, a
+        "wizard" style ui, or a sequence of slides.
+
+        Note unlike a normal :class:`Mode`, a :class:`Multi` doesn't have it's own
+        :attr:`clock` and :attr:`step_rate`. The active submode's are used
+        instead.
+        """
+
+        def __init__(self, submodes):
+                BaseMulti.__init__(self, submodes)
+                self.time = 0.0
+
+
+        def _set_active_submode(self, submode):
+                BaseMulti._set_active_submode(self, submode)
+                self.master_clock = submode.master_clock
+                self.clock = submode.clock
+
+        def clear_subnode(self):
+                """Clear any subnmode data"""
+                BaseMulti.clear_subnode(self)
+                self.master_clock = None
+                self.clock = None
+
+        def tick(self, dt):
+                """Tick the active submode's clock.
+
+                :param dt: The time delta since the last tick
+                :type dt: float
+                """
+                self.time += dt
+                if self.active_submode is not None:
+                        self.active_submode.clock.tick(poll=False)
--- a/bGrease/impl/world.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/bGrease/impl/world.py	Wed Sep 21 16:10:14 2011 +0200
@@ -1,129 +1,129 @@
-#############################################################################
-#
-# Copyright (c) 2010 by Casey Duncan and contributors
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the MIT License
-# A copy of the license should accompany this distribution.
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-#
-#############################################################################
-"""Worlds are environments described by a configuration of components, systems and 
-renderers. These parts describe the data, behavioral and presentation aspects
-of the world respectively.
-
-The world environment is the context within which entities exist. A typical
-application consists of one or more worlds containing entities that evolve
-over time and react to internal and external interaction.
-
-See :ref:`an example of world configuration in the tutorial <tut-world-example>`.
-"""
-
-__version__ = '$Id$'
-
-import itertools
-import pyglet
-from pyglet import gl
-from bGrease.world import *
-from bGrease.impl import Mode
-
-class World(Mode, BaseWorld):
-	"""A coordinated collection of components, systems and entities
-	
-	A world is also a mode that may be pushed onto a 
-	:class:`grease.mode.Manager`
-
-	:param step_rate: The rate of :meth:`step()` calls per second. 
-
-	:param master_clock: The :class:`pyglet.clock.Clock` interface used
-		as the master clock that ticks the world's clock. This 
-		defaults to the main pyglet clock.
-	"""
-
-	clock = None
-	""":class:`pyglet.clock` interface for use by constituents
-	of the world for scheduling
-	"""
-
-	time = None
-	"""Current clock time of the world, starts at 0 when the world
-	is instantiated
-	"""
-
-	running = True
-	"""Flag to indicate that the world clock is running, advancing time
-	and stepping the world. Set running to False to pause the world.
-	"""
-
-	def __init__(self, step_rate=60, master_clock=pyglet.clock,
-				 clock_factory=pyglet.clock.Clock):
-		Mode.__init__(self, step_rate, master_clock, clock_factory)
-		BaseWorld.__init__(self)
-	
-	def activate(self, manager):
-		"""Activate the world/mode for the given manager, if the world is already active, 
-		do nothing. This method is typically not used directly, it is called
-		automatically by the mode manager when the world becomes active.
-
-		The systems of the world are pushed onto `manager.event_dispatcher`
-		so they can receive system events.
-
-		:param manager: :class:`mode.BaseManager` instance
-		"""
-		if not self.active:
-			for system in self.systems:
-				manager.event_dispatcher.push_handlers(system)
-		super(World, self).activate(manager)
-	
-	def deactivate(self, manager):
-		"""Deactivate the world/mode, if the world is not active, do nothing.
-		This method is typically not used directly, it is called
-		automatically by the mode manager when the world becomes active.
-
-		Removes the system handlers from the `manager.event_dispatcher`
-
-		:param manager: :class:`mode.BaseManager` instance
-		"""
-		for system in self.systems:
-			manager.event_dispatcher.remove_handlers(system)
-		super(World, self).deactivate(manager)
-
-	def tick(self, dt):
-		"""Tick the mode's clock, but only if the world is currently running
-		
-		:param dt: The time delta since the last tick
-		:type dt: float
-		"""
-		if self.running:
-			super(World, self).tick(dt)
-	
-	def step(self, dt):
-		"""Execute a time step for the world. Updates the world `time`
-		and invokes the world's systems.
-		
-		Note that the specified time delta will be pinned to 10x the
-		configured step rate. For example if the step rate is 60,
-		then dt will be pinned at a maximum of 0.1666. This avoids 
-		pathological behavior when the time between steps goes
-		much longer than expected.
-
-		:param dt: The time delta since the last time step
-		:type dt: float
-		"""
-		dt = min(dt, 10.0 / self.step_rate)
-		for component in self.components:
-			if hasattr(component, "step"):
-				component.step(dt)
-		for system in self.systems:
-			if hasattr(system, "step"):
-				system.step(dt)
-
-	def on_draw(self, gl=pyglet.gl):
-		"""Clear the current OpenGL context, reset the model/view matrix and
-		invoke the `draw()` methods of the renderers in order
-		"""
-		gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
-		gl.glLoadIdentity()
+#############################################################################
+#
+# Copyright (c) 2010 by Casey Duncan and contributors
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the MIT License
+# A copy of the license should accompany this distribution.
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+#
+#############################################################################
+"""Worlds are environments described by a configuration of components, systems and 
+renderers. These parts describe the data, behavioral and presentation aspects
+of the world respectively.
+
+The world environment is the context within which entities exist. A typical
+application consists of one or more worlds containing entities that evolve
+over time and react to internal and external interaction.
+
+See :ref:`an example of world configuration in the tutorial <tut-world-example>`.
+"""
+
+__version__ = '$Id$'
+
+import itertools
+import pyglet
+from pyglet import gl
+from parpg.bGrease.world import *
+from parpg.bGrease.impl import Mode
+
+class World(Mode, BaseWorld):
+	"""A coordinated collection of components, systems and entities
+	
+	A world is also a mode that may be pushed onto a 
+	:class:`grease.mode.Manager`
+
+	:param step_rate: The rate of :meth:`step()` calls per second. 
+
+	:param master_clock: The :class:`pyglet.clock.Clock` interface used
+		as the master clock that ticks the world's clock. This 
+		defaults to the main pyglet clock.
+	"""
+
+	clock = None
+	""":class:`pyglet.clock` interface for use by constituents
+	of the world for scheduling
+	"""
+
+	time = None
+	"""Current clock time of the world, starts at 0 when the world
+	is instantiated
+	"""
+
+	running = True
+	"""Flag to indicate that the world clock is running, advancing time
+	and stepping the world. Set running to False to pause the world.
+	"""
+
+	def __init__(self, step_rate=60, master_clock=pyglet.clock,
+				 clock_factory=pyglet.clock.Clock):
+		Mode.__init__(self, step_rate, master_clock, clock_factory)
+		BaseWorld.__init__(self)
+	
+	def activate(self, manager):
+		"""Activate the world/mode for the given manager, if the world is already active, 
+		do nothing. This method is typically not used directly, it is called
+		automatically by the mode manager when the world becomes active.
+
+		The systems of the world are pushed onto `manager.event_dispatcher`
+		so they can receive system events.
+
+		:param manager: :class:`mode.BaseManager` instance
+		"""
+		if not self.active:
+			for system in self.systems:
+				manager.event_dispatcher.push_handlers(system)
+		super(World, self).activate(manager)
+	
+	def deactivate(self, manager):
+		"""Deactivate the world/mode, if the world is not active, do nothing.
+		This method is typically not used directly, it is called
+		automatically by the mode manager when the world becomes active.
+
+		Removes the system handlers from the `manager.event_dispatcher`
+
+		:param manager: :class:`mode.BaseManager` instance
+		"""
+		for system in self.systems:
+			manager.event_dispatcher.remove_handlers(system)
+		super(World, self).deactivate(manager)
+
+	def tick(self, dt):
+		"""Tick the mode's clock, but only if the world is currently running
+		
+		:param dt: The time delta since the last tick
+		:type dt: float
+		"""
+		if self.running:
+			super(World, self).tick(dt)
+	
+	def step(self, dt):
+		"""Execute a time step for the world. Updates the world `time`
+		and invokes the world's systems.
+		
+		Note that the specified time delta will be pinned to 10x the
+		configured step rate. For example if the step rate is 60,
+		then dt will be pinned at a maximum of 0.1666. This avoids 
+		pathological behavior when the time between steps goes
+		much longer than expected.
+
+		:param dt: The time delta since the last time step
+		:type dt: float
+		"""
+		dt = min(dt, 10.0 / self.step_rate)
+		for component in self.components:
+			if hasattr(component, "step"):
+				component.step(dt)
+		for system in self.systems:
+			if hasattr(system, "step"):
+				system.step(dt)
+
+	def on_draw(self, gl=pyglet.gl):
+		"""Clear the current OpenGL context, reset the model/view matrix and
+		invoke the `draw()` methods of the renderers in order
+		"""
+		gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
+		gl.glLoadIdentity()
 		BaseWorld.draw_renderers(self)
\ No newline at end of file
--- a/bGrease/renderer/__init__.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/bGrease/renderer/__init__.py	Wed Sep 21 16:10:14 2011 +0200
@@ -1,25 +1,25 @@
-#############################################################################
-#
-# Copyright (c) 2010 by Casey Duncan and contributors
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the MIT License
-# A copy of the license should accompany this distribution.
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-#
-#############################################################################
-"""Renderers define world presentation. This module contains the
-built-in renderer classes.
-
-See also:
-
-- :class:`~grease.Renderer` abstract base class.
-- :ref:`Example renderer class in the tutorial <tut-renderer-example>`
-"""
-
-__all__ = ('Vector', 'Camera')
-
-from bGrease.renderer.vector import Vector
-from bGrease.renderer.camera import Camera
+#############################################################################
+#
+# Copyright (c) 2010 by Casey Duncan and contributors
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the MIT License
+# A copy of the license should accompany this distribution.
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+#
+#############################################################################
+"""Renderers define world presentation. This module contains the
+built-in renderer classes.
+
+See also:
+
+- :class:`~grease.Renderer` abstract base class.
+- :ref:`Example renderer class in the tutorial <tut-renderer-example>`
+"""
+
+__all__ = ('Vector', 'Camera')
+
+from parpg.bGrease.renderer.vector import Vector
+from parpg.bGrease.renderer.camera import Camera
--- a/bGrease/renderer/vector.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/bGrease/renderer/vector.py	Wed Sep 21 16:10:14 2011 +0200
@@ -1,166 +1,165 @@
-#############################################################################
-#
-# Copyright (c) 2010 by Casey Duncan and contributors
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the MIT License
-# A copy of the license should accompany this distribution.
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-#
-#############################################################################
-
-__version__ = '$Id$'
-
-__all__ = ('Vector',)
-
-from bGrease.geometry import Vec2d
-import ctypes
-from math import sin, cos, radians
-import pyglet
-
-
-class Vector(object):
-	"""Renders shapes in a classic vector graphics style
-	
-	:param scale: Scaling factor applied to shape vertices when rendered.
-	
-	:param line_width: The line width provided to ``glLineWidth`` before rendering.
-		If not specified or None, ``glLineWidth`` is not called, and the line
-		width used is determined by the OpenGL state at the time of rendering.
-
-	:param anti_alias: If ``True``, OpenGL blending and line smoothing is enabled.
-		This allows for fractional line widths as well. If ``False``, the blending
-		and line smoothing modes are unchanged.
-
-	:param corner_fill: If true (the default), the shape corners will be filled
-		with round points when the ``line_width`` exceeds 2.0. This improves
-		the visual quality of the rendering at larger line widths at some
-		cost to performance. Has no effect if ``line_width`` is not specified.
-
-	:param position_component: Name of :class:`grease.component.Position` 
-		component to use. Shapes rendered are offset by the entity positions.
-
-	:param renderable_component: Name of :class:`grease.component.Renderable` 
-		component to use. This component specifies the entities to be 
-		rendered and their base color.
-
-	:param shape_component: Name of :class:`grease.component.Shape` 
-		component to use. Source of the shape vertices for each entity.
-
-	The entities rendered are taken from the intersection of he position,
-	renderable and shape components each time :meth:`draw` is called.
-	"""
-
-	CORNER_FILL_SCALE = 0.6
-	CORNER_FILL_THRESHOLD = 2.0
-
-	def __init__(self, scale=1.0, line_width=None, anti_alias=True, corner_fill=True,
-		position_component='position', 
-		renderable_component='renderable', 
-		shape_component='shape'):
-		self.scale = float(scale)
-		self.corner_fill = corner_fill
-		self.line_width = line_width
-		self.anti_alias = anti_alias
-		self._max_line_width = None
-		self.position_component = position_component
-		self.renderable_component = renderable_component
-		self.shape_component = shape_component
-	
-	def set_world(self, world):
-		self.world = world
-
-	def _generate_verts(self):
-		"""Generate vertex and index arrays for rendering"""
-		vert_count = sum(len(shape.verts) + 1
-			for shape, ignored, ignored in self.world.components.join(
-				self.shape_component, self.position_component, self.renderable_component))
-		v_array = (CVertColor * vert_count)()
-		if vert_count > 65536:
-			i_array = (ctypes.c_uint * 2 * vert_count)()
-			i_size = pyglet.gl.GL_UNSIGNED_INT
-		else:
-			i_array = (ctypes.c_ushort * (2 * vert_count))()
-			i_size = pyglet.gl.GL_UNSIGNED_SHORT
-		v_index = 0
-		i_index = 0
-		scale = self.scale
-		rot_vec = Vec2d(0, 0)
-		for shape, position, renderable in self.world.components.join(
-			self.shape_component, self.position_component, self.renderable_component):
-			shape_start = v_index
-			angle = radians(-position.angle)
-			rot_vec.x = cos(angle)
-			rot_vec.y = sin(angle)
-			r = int(renderable.color.r * 255)
-			g = int(renderable.color.g * 255)
-			b = int(renderable.color.b * 255)
-			a = int(renderable.color.a * 255)
-			for vert in shape.verts:
-				vert = vert.cpvrotate(rot_vec) * scale + position.position
-				v_array[v_index].vert.x = vert.x
-				v_array[v_index].vert.y = vert.y
-				v_array[v_index].color.r = r
-				v_array[v_index].color.g = g
-				v_array[v_index].color.b = b
-				v_array[v_index].color.a = a
-				if v_index > shape_start:
-					i_array[i_index] = v_index - 1
-					i_index += 1
-					i_array[i_index] = v_index
-					i_index += 1
-				v_index += 1
-			if shape.closed and v_index - shape_start > 2:
-				i_array[i_index] = v_index - 1
-				i_index += 1
-				i_array[i_index] = shape_start
-				i_index += 1
-		return v_array, i_size, i_array, i_index
-
-	def draw(self, gl=pyglet.gl):
-		vertices, index_size, indices, index_count = self._generate_verts()
-		if index_count:
-			if self.anti_alias:
-				gl.glEnable(gl.GL_LINE_SMOOTH)
-				gl.glHint(gl.GL_LINE_SMOOTH_HINT, gl.GL_NICEST)
-				gl.glEnable(gl.GL_BLEND)
-				gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
-			gl.glPushClientAttrib(gl.GL_CLIENT_VERTEX_ARRAY_BIT)
-			gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
-			gl.glEnableClientState(gl.GL_COLOR_ARRAY)
-			gl.glVertexPointer(
-				2, gl.GL_FLOAT, ctypes.sizeof(CVertColor), ctypes.pointer(vertices))
-			gl.glColorPointer(
-				4, gl.GL_UNSIGNED_BYTE, ctypes.sizeof(CVertColor), 
-				ctypes.pointer(vertices[0].color))
-			if self.line_width is not None:
-				gl.glLineWidth(self.line_width)
-				if self._max_line_width is None:
-					range_out = (ctypes.c_float * 2)()
-					gl.glGetFloatv(gl.GL_ALIASED_LINE_WIDTH_RANGE, range_out)
-					self._max_line_width = float(range_out[1]) * self.CORNER_FILL_SCALE
-				if self.corner_fill and self.line_width > self.CORNER_FILL_THRESHOLD:
-					gl.glEnable(gl.GL_POINT_SMOOTH)
-					gl.glPointSize(
-						min(self.line_width * self.CORNER_FILL_SCALE, self._max_line_width))
-					gl.glDrawArrays(gl.GL_POINTS, 0, index_count)
-			gl.glDrawElements(gl.GL_LINES, index_count, index_size, ctypes.pointer(indices))
-			gl.glPopClientAttrib()
-
-
-class CVert(ctypes.Structure):
-	_fields_ = [("x", ctypes.c_float), ("y", ctypes.c_float)]
-
-class CColor(ctypes.Structure):
-	_fields_ = [
-		("r", ctypes.c_ubyte), 
-		("g", ctypes.c_ubyte), 
-		("b", ctypes.c_ubyte), 
-		("a", ctypes.c_ubyte),
-	]
-
-class CVertColor(ctypes.Structure):
-	_fields_ = [("vert", CVert), ("color", CColor)]
-
+#############################################################################
+#
+# Copyright (c) 2010 by Casey Duncan and contributors
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the MIT License
+# A copy of the license should accompany this distribution.
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+#
+#############################################################################
+
+__version__ = '$Id$'
+
+__all__ = ('Vector',)
+
+from parpg.bGrease.geometry import Vec2d
+import ctypes
+from math import sin, cos, radians
+import pyglet
+
+
+class Vector(object):
+        """Renders shapes in a classic vector graphics style
+
+        :param scale: Scaling factor applied to shape vertices when rendered.
+
+        :param line_width: The line width provided to ``glLineWidth`` before rendering.
+        	If not specified or None, ``glLineWidth`` is not called, and the line
+        	width used is determined by the OpenGL state at the time of rendering.
+
+        :param anti_alias: If ``True``, OpenGL blending and line smoothing is enabled.
+        	This allows for fractional line widths as well. If ``False``, the blending
+        	and line smoothing modes are unchanged.
+
+        :param corner_fill: If true (the default), the shape corners will be filled
+        	with round points when the ``line_width`` exceeds 2.0. This improves
+        	the visual quality of the rendering at larger line widths at some
+        	cost to performance. Has no effect if ``line_width`` is not specified.
+
+        :param position_component: Name of :class:`grease.component.Position` 
+        	component to use. Shapes rendered are offset by the entity positions.
+
+        :param renderable_component: Name of :class:`grease.component.Renderable` 
+        	component to use. This component specifies the entities to be 
+        	rendered and their base color.
+
+        :param shape_component: Name of :class:`grease.component.Shape` 
+        	component to use. Source of the shape vertices for each entity.
+
+        The entities rendered are taken from the intersection of he position,
+        renderable and shape components each time :meth:`draw` is called.
+        """
+
+        CORNER_FILL_SCALE = 0.6
+        CORNER_FILL_THRESHOLD = 2.0
+
+        def __init__(self, scale=1.0, line_width=None, anti_alias=True, corner_fill=True,
+                     position_component='position', 
+                     renderable_component='renderable', 
+                     shape_component='shape'):
+                self.scale = float(scale)
+                self.corner_fill = corner_fill
+                self.line_width = line_width
+                self.anti_alias = anti_alias
+                self._max_line_width = None
+                self.position_component = position_component
+                self.renderable_component = renderable_component
+                self.shape_component = shape_component
+
+        def set_world(self, world):
+                self.world = world
+
+        def _generate_verts(self):
+                """Generate vertex and index arrays for rendering"""
+                vert_count = sum(len(shape.verts) + 1
+                                 for shape, ignored, ignored in self.world.components.join(
+                                         self.shape_component, self.position_component, self.renderable_component))
+                v_array = (CVertColor * vert_count)()
+                if vert_count > 65536:
+                        i_array = (ctypes.c_uint * 2 * vert_count)()
+                        i_size = pyglet.gl.GL_UNSIGNED_INT
+                else:
+                        i_array = (ctypes.c_ushort * (2 * vert_count))()
+                        i_size = pyglet.gl.GL_UNSIGNED_SHORT
+                v_index = 0
+                i_index = 0
+                scale = self.scale
+                rot_vec = Vec2d(0, 0)
+                for shape, position, renderable in self.world.components.join(
+                        self.shape_component, self.position_component, self.renderable_component):
+                        shape_start = v_index
+                        angle = radians(-position.angle)
+                        rot_vec.x = cos(angle)
+                        rot_vec.y = sin(angle)
+                        r = int(renderable.color.r * 255)
+                        g = int(renderable.color.g * 255)
+                        b = int(renderable.color.b * 255)
+                        a = int(renderable.color.a * 255)
+                        for vert in shape.verts:
+                                vert = vert.cpvrotate(rot_vec) * scale + position.position
+                                v_array[v_index].vert.x = vert.x
+                                v_array[v_index].vert.y = vert.y
+                                v_array[v_index].color.r = r
+                                v_array[v_index].color.g = g
+                                v_array[v_index].color.b = b
+                                v_array[v_index].color.a = a
+                                if v_index > shape_start:
+                                        i_array[i_index] = v_index - 1
+                                        i_index += 1
+                                        i_array[i_index] = v_index
+                                        i_index += 1
+                                v_index += 1
+                        if shape.closed and v_index - shape_start > 2:
+                                i_array[i_index] = v_index - 1
+                                i_index += 1
+                                i_array[i_index] = shape_start
+                                i_index += 1
+                return v_array, i_size, i_array, i_index
+
+        def draw(self, gl=pyglet.gl):
+                vertices, index_size, indices, index_count = self._generate_verts()
+                if index_count:
+                        if self.anti_alias:
+                                gl.glEnable(gl.GL_LINE_SMOOTH)
+                                gl.glHint(gl.GL_LINE_SMOOTH_HINT, gl.GL_NICEST)
+                                gl.glEnable(gl.GL_BLEND)
+                                gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
+                        gl.glPushClientAttrib(gl.GL_CLIENT_VERTEX_ARRAY_BIT)
+                        gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
+                        gl.glEnableClientState(gl.GL_COLOR_ARRAY)
+                        gl.glVertexPointer(
+                                2, gl.GL_FLOAT, ctypes.sizeof(CVertColor), ctypes.pointer(vertices))
+                        gl.glColorPointer(
+                                4, gl.GL_UNSIGNED_BYTE, ctypes.sizeof(CVertColor), 
+                                ctypes.pointer(vertices[0].color))
+                        if self.line_width is not None:
+                                gl.glLineWidth(self.line_width)
+                                if self._max_line_width is None:
+                                        range_out = (ctypes.c_float * 2)()
+                                        gl.glGetFloatv(gl.GL_ALIASED_LINE_WIDTH_RANGE, range_out)
+                                        self._max_line_width = float(range_out[1]) * self.CORNER_FILL_SCALE
+                                if self.corner_fill and self.line_width > self.CORNER_FILL_THRESHOLD:
+                                        gl.glEnable(gl.GL_POINT_SMOOTH)
+                                        gl.glPointSize(
+                                                min(self.line_width * self.CORNER_FILL_SCALE, self._max_line_width))
+                                        gl.glDrawArrays(gl.GL_POINTS, 0, index_count)
+                        gl.glDrawElements(gl.GL_LINES, index_count, index_size, ctypes.pointer(indices))
+                        gl.glPopClientAttrib()
+
+
+class CVert(ctypes.Structure):
+        _fields_ = [("x", ctypes.c_float), ("y", ctypes.c_float)]
+
+class CColor(ctypes.Structure):
+        _fields_ = [
+                ("r", ctypes.c_ubyte), 
+                ("g", ctypes.c_ubyte), 
+                ("b", ctypes.c_ubyte), 
+                ("a", ctypes.c_ubyte),
+        ]
+
+class CVertColor(ctypes.Structure):
+        _fields_ = [("vert", CVert), ("color", CColor)]
--- a/bGrease/world.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/bGrease/world.py	Wed Sep 21 16:10:14 2011 +0200
@@ -1,302 +1,301 @@
-#############################################################################
-#
-# Copyright (c) 2010 by Casey Duncan and contributors
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the MIT License
-# A copy of the license should accompany this distribution.
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-#
-#############################################################################
-"""Worlds are environments described by a configuration of components, systems and 
-renderers. These parts describe the data, behavioral and presentation aspects
-of the world respectively.
-
-The world environment is the context within which entities exist. A typical
-application consists of one or more worlds containing entities that evolve
-over time and react to internal and external interaction.
-
-See :ref:`an example of world configuration in the tutorial <tut-world-example>`.
-"""
-
-__version__ = '$Id$'
-
-import itertools
-from bGrease import mode
-from bGrease.component import ComponentError
-from bGrease.entity import Entity, ComponentEntitySet
-
-
-class BaseWorld(object):
-	"""A coordinated collection of components, systems and entities
-	
-	A world is also a mode that may be pushed onto a 
-	:class:`grease.mode.Manager`
-	"""
-
-	components = None
-	""":class:`ComponentParts` object containing all world components.
-	:class:`grease.component.Component` objects define and contain all entity data
-	"""
-
-	systems = None
-	""":class:`Parts` object containing all world systems. 
-	:class:`grease.System` objects define world and entity behavior
-	"""
-
-	renderers = None
-	""":class:`Parts` object containing all world renderers. 
-	:class:`grease.Renderer` objects define world presentation
-	"""
-
-	entities = None
-	"""Set of all entities that exist in the world"""
-
-	def __init__(self):
-		self.components = ComponentParts(self)
-		self.systems = Parts(self)
-		self.renderers = Parts(self)
-		self.new_entity_id = itertools.count().next
-		self.new_entity_id() # skip id 0
-		self.entities = WorldEntitySet(self)
-		self._full_extent = EntityExtent(self, self.entities)
-		self._extents = {}
-		self.configure()
-
-	def configure(self):
-		"""Hook to configure the world after construction. This method
-		is called immediately after the world is initialized. Override
-		in a subclass to configure the world's components, systems,
-		and renderers.
-
-		The default implementation does nothing.
-		"""
-	
-	def __getitem__(self, entity_class):
-		"""Return an :class:`EntityExtent` for the given entity class. This extent
-		can be used to access the set of entities of that class in the world
-		or to query these entities via their components. 
-
-		Examples::
-
-			world[MyEntity]
-			world[...]
-
-		:param entity_class: The entity class for the extent.
-
-			May also be a tuple of entity classes, in which case
-			the extent returned contains union of all entities of the classes
-			in the world.
-
-			May also be the special value ellipsis (``...``), which
-			returns an extent containing all entities in the world.  This allows
-			you to conveniently query all entities using ``world[...]``.
-		"""
-		if isinstance(entity_class, tuple):
-			entities = set()
-			for cls in entity_class:
-				if cls in self._extents:
-					entities |= self._extents[cls].entities
-			return EntityExtent(self, entities)
-		elif entity_class is Ellipsis:
-			return self._full_extent
-		try:
-			return self._extents[entity_class]
-		except KeyError:
-			extent = self._extents[entity_class] = EntityExtent(self, set())
-			return extent
-	
-	def draw_renderers(self):
-		"""Draw all renderers"""
-		for renderer in self.renderers:
-			renderer.draw()
-
-class WorldEntitySet(set):
-	"""Entity set for a :class:`World`"""
-
-	def __init__(self, world):
-		self.world = world
-	
-	def add(self, entity):
-		"""Add the entity to the set and all necessary class sets
-		Return the unique entity id for the entity, creating one
-		as needed.
-		"""
-		super(WorldEntitySet, self).add(entity)
-		for cls in entity.__class__.__mro__:
-			if issubclass(cls, Entity):
-				self.world[cls].entities.add(entity)
-
-	def remove(self, entity):
-		"""Remove the entity from the set and, world components,
-		and all necessary class sets
-		"""
-		super(WorldEntitySet, self).remove(entity)
-		for component in self.world.components:
-			try:
-				del component[entity]
-			except KeyError:
-				pass
-		for cls in entity.__class__.__mro__:
-			if issubclass(cls, Entity):
-				self.world[cls].entities.discard(entity)
-	
-	def discard(self, entity):
-		"""Remove the entity from the set if it exists, if not,
-		do nothing
-		"""
-		try:
-			self.remove(entity)
-		except KeyError:
-			pass
-
-
-class EntityExtent(object):
-	"""Encapsulates a set of entities queriable by component. Extents
-	are accessed by using an entity class as a key on the :class:`World`::
-
-		extent = world[MyEntity]
-	"""
-
-	entities = None
-	"""The full set of entities in the extent""" 
-
-	def __init__(self, world, entities):
-		self.__world = world
-		self.entities = entities
-
-	def __getattr__(self, name):
-		"""Return a queriable :class:`ComponentEntitySet` for the named component 
-
-		Example::
-
-			world[MyEntity].movement.velocity > (0, 0)
-
-		Returns a set of entities where the value of the :attr:`velocity` field
-		of the :attr:`movement` component is greater than ``(0, 0)``.
-		"""
-		component = getattr(self.__world.components, name)
-		return ComponentEntitySet(component, self.entities & component.entities)
-
-
-class Parts(object):
-	"""Maps world parts to attributes. The parts are kept in the
-	order they are set. Parts may also be inserted out of order.
-	
-	Used for:
-	
-	- :attr:`World.systems`
-	- :attr:`World.renderers`
-	"""
-
-	_world = None
-	_parts = None
-	_reserved_names = ('entities', 'entity_id', 'world')
-
-	def __init__(self, world):
-		self._world = world
-		self._parts = []
-	
-	def _validate_name(self, name):
-		if (name in self._reserved_names or name.startswith('_') 
-			or hasattr(self.__class__, name)):
-			raise ComponentError('illegal part name: %s' % name)
-		return name
-
-	def __setattr__(self, name, part):
-		if not hasattr(self.__class__, name):
-			self._validate_name(name)
-			if not hasattr(self, name):
-				self._parts.append(part)
-			else:
-				old_part = getattr(self, name)
-				self._parts[self._parts.index(old_part)] = part
-			super(Parts, self).__setattr__(name, part)
-			if hasattr(part, 'set_world'):
-				part.set_world(self._world)
-		elif name.startswith("_"):
-			super(Parts, self).__setattr__(name, part)
-		else:
-			raise AttributeError("%s attribute is read only" % name)
-	
-	def __delattr__(self, name):
-		self._validate_name(name)
-		part = getattr(self, name)
-		self._parts.remove(part)
-		super(Parts, self).__delattr__(name)
-
-	def insert(self, name, part, before=None, index=None):
-		"""Add a part with a particular name at a particular index.
-		If a part by that name already exists, it is replaced.
-			
-		:arg name: The name of the part.
-		:type name: str
-
-		:arg part: The component, system, or renderer part to insert
-	
-		:arg before: A part object or name. If specified, the part is
-			inserted before the specified part in order.
-
-		:arg index: If specified, the part is inserted in the position
-			specified. You cannot specify both before and index.
-		:type index: int
-		"""
-		assert before is not None or index is not None, (
-			"Must specify a value for 'before' or 'index'")
-		assert before is None or index is None, (
-			"Cannot specify both 'before' and 'index' arguments when inserting")
-		self._validate_name(name)
-		if before is not None:
-			if isinstance(before, str):
-				before = getattr(self, before)
-			index = self._parts.index(before)
-		if hasattr(self, name):
-			old_part = getattr(self, name)
-			self._parts.remove(old_part)
-		self._parts.insert(index, part)
-		super(Parts, self).__setattr__(name, part)
-		if hasattr(part, 'set_world'):
-			part.set_world(self._world)
-
-	def __iter__(self):
-		"""Iterate the parts in order"""
-		return iter(tuple(self._parts))
-	
-	def __len__(self):
-		return len(self._parts)
-
-
-class ComponentParts(Parts):
-	"""Maps world components to attributes. The components are kept in the
-	order they are set. Components may also be inserted out of order.
-
-	Used for: :attr:`World.components`
-	"""
-
-	def join(self, *component_names):
-		"""Join and iterate entity data from multiple components together.
-
-		For each entity in all of the components named, yield a tuple containing
-		the entity data from each component specified.
-
-		This is useful in systems that pull data from multiple components.
-		
-		Typical Usage::
-
-			for position, movement in world.components.join("position", "movement"):
-				# Do something with each entity's position and movement data
-		"""
-		if component_names:
-			components = [getattr(self, self._validate_name(name)) 
-				for name in component_names]
-			if len(components) > 1:
-				entities = components[0].entities & components[1].entities
-				for comp in components[2:]:
-					entities &= comp.entities
-			else:
-				entities = components[0].entities
-			for entity in entities:
-				yield tuple(comp[entity] for comp in components)
-
+#############################################################################
+#
+# Copyright (c) 2010 by Casey Duncan and contributors
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the MIT License
+# A copy of the license should accompany this distribution.
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+#
+#############################################################################
+"""Worlds are environments described by a configuration of components, systems and 
+renderers. These parts describe the data, behavioral and presentation aspects
+of the world respectively.
+
+The world environment is the context within which entities exist. A typical
+application consists of one or more worlds containing entities that evolve
+over time and react to internal and external interaction.
+
+See :ref:`an example of world configuration in the tutorial <tut-world-example>`.
+"""
+
+__version__ = '$Id$'
+
+import itertools
+from parpg.bGrease import mode
+from parpg.bGrease.component import ComponentError
+from parpg.bGrease.entity import Entity, ComponentEntitySet
+
+
+class BaseWorld(object):
+        """A coordinated collection of components, systems and entities
+
+        A world is also a mode that may be pushed onto a 
+        :class:`grease.mode.Manager`
+        """
+
+        components = None
+        """:class:`ComponentParts` object containing all world components.
+	:class:`grease.component.Component` objects define and contain all entity data
+	"""
+
+        systems = None
+        """:class:`Parts` object containing all world systems. 
+	:class:`grease.System` objects define world and entity behavior
+	"""
+
+        renderers = None
+        """:class:`Parts` object containing all world renderers. 
+	:class:`grease.Renderer` objects define world presentation
+	"""
+
+        entities = None
+        """Set of all entities that exist in the world"""
+
+        def __init__(self):
+                self.components = ComponentParts(self)
+                self.systems = Parts(self)
+                self.renderers = Parts(self)
+                self.new_entity_id = itertools.count().next
+                self.new_entity_id() # skip id 0
+                self.entities = WorldEntitySet(self)
+                self._full_extent = EntityExtent(self, self.entities)
+                self._extents = {}
+                self.configure()
+
+        def configure(self):
+                """Hook to configure the world after construction. This method
+                is called immediately after the world is initialized. Override
+                in a subclass to configure the world's components, systems,
+                and renderers.
+
+                The default implementation does nothing.
+                """
+
+        def __getitem__(self, entity_class):
+                """Return an :class:`EntityExtent` for the given entity class. This extent
+                can be used to access the set of entities of that class in the world
+                or to query these entities via their components. 
+
+                Examples::
+
+                	world[MyEntity]
+                	world[...]
+
+                :param entity_class: The entity class for the extent.
+
+                	May also be a tuple of entity classes, in which case
+                	the extent returned contains union of all entities of the classes
+                	in the world.
+
+                	May also be the special value ellipsis (``...``), which
+                	returns an extent containing all entities in the world.  This allows
+                	you to conveniently query all entities using ``world[...]``.
+                """
+                if isinstance(entity_class, tuple):
+                        entities = set()
+                        for cls in entity_class:
+                                if cls in self._extents:
+                                        entities |= self._extents[cls].entities
+                        return EntityExtent(self, entities)
+                elif entity_class is Ellipsis:
+                        return self._full_extent
+                try:
+                        return self._extents[entity_class]
+                except KeyError:
+                        extent = self._extents[entity_class] = EntityExtent(self, set())
+                        return extent
+
+        def draw_renderers(self):
+                """Draw all renderers"""
+                for renderer in self.renderers:
+                        renderer.draw()
+
+class WorldEntitySet(set):
+        """Entity set for a :class:`World`"""
+
+        def __init__(self, world):
+                self.world = world
+
+        def add(self, entity):
+                """Add the entity to the set and all necessary class sets
+                Return the unique entity id for the entity, creating one
+                as needed.
+                """
+                super(WorldEntitySet, self).add(entity)
+                for cls in entity.__class__.__mro__:
+                        if issubclass(cls, Entity):
+                                self.world[cls].entities.add(entity)
+
+        def remove(self, entity):
+                """Remove the entity from the set and, world components,
+                and all necessary class sets
+                """
+                super(WorldEntitySet, self).remove(entity)
+                for component in self.world.components:
+                        try:
+                                del component[entity]
+                        except KeyError:
+                                pass
+                for cls in entity.__class__.__mro__:
+                        if issubclass(cls, Entity):
+                                self.world[cls].entities.discard(entity)
+
+        def discard(self, entity):
+                """Remove the entity from the set if it exists, if not,
+                do nothing
+                """
+                try:
+                        self.remove(entity)
+                except KeyError:
+                        pass
+
+
+class EntityExtent(object):
+        """Encapsulates a set of entities queriable by component. Extents
+        are accessed by using an entity class as a key on the :class:`World`::
+
+        	extent = world[MyEntity]
+        """
+
+        entities = None
+        """The full set of entities in the extent""" 
+
+        def __init__(self, world, entities):
+                self.__world = world
+                self.entities = entities
+
+        def __getattr__(self, name):
+                """Return a queriable :class:`ComponentEntitySet` for the named component 
+
+                Example::
+
+                	world[MyEntity].movement.velocity > (0, 0)
+
+                Returns a set of entities where the value of the :attr:`velocity` field
+                of the :attr:`movement` component is greater than ``(0, 0)``.
+                """
+                component = getattr(self.__world.components, name)
+                return ComponentEntitySet(component, self.entities & component.entities)
+
+
+class Parts(object):
+        """Maps world parts to attributes. The parts are kept in the
+        order they are set. Parts may also be inserted out of order.
+
+        Used for:
+
+        - :attr:`World.systems`
+        - :attr:`World.renderers`
+        """
+
+        _world = None
+        _parts = None
+        _reserved_names = ('entities', 'entity_id', 'world')
+
+        def __init__(self, world):
+                self._world = world
+                self._parts = []
+
+        def _validate_name(self, name):
+                if (name in self._reserved_names or name.startswith('_') 
+                    or hasattr(self.__class__, name)):
+                        raise ComponentError('illegal part name: %s' % name)
+                return name
+
+        def __setattr__(self, name, part):
+                if not hasattr(self.__class__, name):
+                        self._validate_name(name)
+                        if not hasattr(self, name):
+                                self._parts.append(part)
+                        else:
+                                old_part = getattr(self, name)
+                                self._parts[self._parts.index(old_part)] = part
+                        super(Parts, self).__setattr__(name, part)
+                        if hasattr(part, 'set_world'):
+                                part.set_world(self._world)
+                elif name.startswith("_"):
+                        super(Parts, self).__setattr__(name, part)
+                else:
+                        raise AttributeError("%s attribute is read only" % name)
+
+        def __delattr__(self, name):
+                self._validate_name(name)
+                part = getattr(self, name)
+                self._parts.remove(part)
+                super(Parts, self).__delattr__(name)
+
+        def insert(self, name, part, before=None, index=None):
+                """Add a part with a particular name at a particular index.
+                If a part by that name already exists, it is replaced.
+
+                :arg name: The name of the part.
+                :type name: str
+
+                :arg part: The component, system, or renderer part to insert
+
+                :arg before: A part object or name. If specified, the part is
+                	inserted before the specified part in order.
+
+                :arg index: If specified, the part is inserted in the position
+                	specified. You cannot specify both before and index.
+                :type index: int
+                """
+                assert before is not None or index is not None, (
+                        "Must specify a value for 'before' or 'index'")
+                assert before is None or index is None, (
+                        "Cannot specify both 'before' and 'index' arguments when inserting")
+                self._validate_name(name)
+                if before is not None:
+                        if isinstance(before, str):
+                                before = getattr(self, before)
+                        index = self._parts.index(before)
+                if hasattr(self, name):
+                        old_part = getattr(self, name)
+                        self._parts.remove(old_part)
+                self._parts.insert(index, part)
+                super(Parts, self).__setattr__(name, part)
+                if hasattr(part, 'set_world'):
+                        part.set_world(self._world)
+
+        def __iter__(self):
+                """Iterate the parts in order"""
+                return iter(tuple(self._parts))
+
+        def __len__(self):
+                return len(self._parts)
+
+
+class ComponentParts(Parts):
+        """Maps world components to attributes. The components are kept in the
+        order they are set. Components may also be inserted out of order.
+
+        Used for: :attr:`World.components`
+        """
+
+        def join(self, *component_names):
+                """Join and iterate entity data from multiple components together.
+
+                For each entity in all of the components named, yield a tuple containing
+                the entity data from each component specified.
+
+                This is useful in systems that pull data from multiple components.
+
+                Typical Usage::
+
+                	for position, movement in world.components.join("position", "movement"):
+                		# Do something with each entity's position and movement data
+                """
+                if component_names:
+                        components = [getattr(self, self._validate_name(name)) 
+                                      for name in component_names]
+                        if len(components) > 1:
+                                entities = components[0].entities & components[1].entities
+                                for comp in components[2:]:
+                                        entities &= comp.entities
+                        else:
+                                entities = components[0].entities
+                        for entity in entities:
+                                yield tuple(comp[entity] for comp in components)
--- a/components/CharacterStatistics.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/components/CharacterStatistics.py	Wed Sep 21 16:10:14 2011 +0200
@@ -11,11 +11,11 @@
 #   You should have received a copy of the GNU General Public License
 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-from bGrease.component import Component
+from parpg.bGrease.component import Component
 
 class CharacterStatistics(Component):
     """Component that defines character statistics."""
-    
+
     def __init__(self):
         """Constructor"""
-        Component.__init__(self, statistics=dict)
+        Component.__init__(self, statistics=dict)
\ No newline at end of file
--- a/components/__init__.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/components/__init__.py	Wed Sep 21 16:10:14 2011 +0200
@@ -1,11 +1,10 @@
-from Behavior import Behavior
-from CharacterStatistics import CharacterStatistics
-from containable import Containable
-from container import Container
-from description import Description
-from dialogue import Dialogue
-from fifeagent import FifeAgent
-from lockable import Lockable
-from usable import Usable
-from change_map import ChangeMap
+from CharacterStatistics import CharacterStatistics
+from containable import Containable
+from container import Container
+from description import Description
+from dialogue import Dialogue
+from fifeagent import FifeAgent
+from lockable import Lockable
+from usable import Usable
+from change_map import ChangeMap
 from equipable import Equipable
\ No newline at end of file
--- a/components/change_map.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/components/change_map.py	Wed Sep 21 16:10:14 2011 +0200
@@ -1,22 +1,22 @@
-#   This program is free software: you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation, either version 3 of the License, or
-#   (at your option) any later version.
-#   
-#   This program is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-#   
-#   You should have received a copy of the GNU General Public License
-#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-from bGrease.component import Component
-from bGrease.geometry import Vec2d
-
-class ChangeMap(Component):
-    """Component that allows an entity to be contained by Container entity."""
-    
-    def __init__(self):
-        """Constructor"""
+#   This program is free software: you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation, either version 3 of the License, or
+#   (at your option) any later version.
+#   
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#   
+#   You should have received a copy of the GNU General Public License
+#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from parpg.bGrease.component import Component
+from parpg.bGrease.geometry import Vec2d
+
+class ChangeMap(Component):
+    """Component that allows an entity to be contained by Container entity."""
+    
+    def __init__(self):
+        """Constructor"""
         Component.__init__(self, target_map=str, target_position=list)
\ No newline at end of file
--- a/components/containable.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/components/containable.py	Wed Sep 21 16:10:14 2011 +0200
@@ -11,7 +11,7 @@
 #   You should have received a copy of the GNU General Public License
 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-from bGrease.component import Component
+from parpg.bGrease.component import Component
 
 class Containable(Component):
     """Component that allows an entity to be contained by Container entity."""
--- a/components/container.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/components/container.py	Wed Sep 21 16:10:14 2011 +0200
@@ -11,7 +11,7 @@
 #   You should have received a copy of the GNU General Public License
 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-from bGrease.component import Component
+from parpg.bGrease.component import Component
 
 class Container(Component):
     """
--- a/components/description.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/components/description.py	Wed Sep 21 16:10:14 2011 +0200
@@ -11,7 +11,7 @@
 #   You should have received a copy of the GNU General Public License
 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-from bGrease.component import Component
+from parpg.bGrease.component import Component
 
 class Description(Component):
     """Component that stores the description of an object"""
--- a/components/dialogue.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/components/dialogue.py	Wed Sep 21 16:10:14 2011 +0200
@@ -11,7 +11,7 @@
 #   You should have received a copy of the GNU General Public License
 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-from bGrease.component import Component
+from parpg.bGrease.component import Component
 
 class Dialogue(Component):
     """Component that stores the dialogue"""
--- a/components/equip.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/components/equip.py	Wed Sep 21 16:10:14 2011 +0200
@@ -1,44 +1,44 @@
-#   This program is free software: you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation, either version 3 of the License, or
-#   (at your option) any later version.
-#   
-#   This program is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-#   
-#   You should have received a copy of the GNU General Public License
-#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-from bGrease.component import Component
-
-class Equip(Component):
-    """
-    Component that stores the equipment (what is being worn/wieled).
-    """
-    
-    def __init__(self):
-        Component.__init__(self, head=object, body=object, leg=object, feet=object, l_arm=object, r_arm=object)
-
-class SlotInvalidError(Exception):
-    """Error that gets raised when the slot is invalid."""
-    
-    def __init__(self, slot):
-        self.slot = slot
-    
-    def __str__(self):
-        return "\"%s\" is not a valid slot." % self.slot
-    
-def equip(wearer, equipable, slot):
-    """Equip the wearer with the given equipable.
-    @returns The equipable that was at the given slot, or None"""
-    if slot in equipable.possible_slots:
-        try:
-            old_item = getattr(wearer, slot)
-            setattr(wearer, slot, equipable)
-            return old_item
-        except AttributeError:
-            raise SlotInvalidError(slot)
-    return None
+#   This program is free software: you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation, either version 3 of the License, or
+#   (at your option) any later version.
+#   
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#   
+#   You should have received a copy of the GNU General Public License
+#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from parpg.bGrease.component import Component
+
+class Equip(Component):
+    """
+    Component that stores the equipment (what is being worn/wieled).
+    """
+    
+    def __init__(self):
+        Component.__init__(self, head=object, body=object, leg=object, feet=object, l_arm=object, r_arm=object)
+
+class SlotInvalidError(Exception):
+    """Error that gets raised when the slot is invalid."""
+    
+    def __init__(self, slot):
+        self.slot = slot
+    
+    def __str__(self):
+        return "\"%s\" is not a valid slot." % self.slot
+    
+def equip(wearer, equipable, slot):
+    """Equip the wearer with the given equipable.
+    @returns The equipable that was at the given slot, or None"""
+    if slot in equipable.possible_slots:
+        try:
+            old_item = getattr(wearer, slot)
+            setattr(wearer, slot, equipable)
+            return old_item
+        except AttributeError:
+            raise SlotInvalidError(slot)
+    return None
     
\ No newline at end of file
--- a/components/equipable.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/components/equipable.py	Wed Sep 21 16:10:14 2011 +0200
@@ -1,22 +1,22 @@
-#   This program is free software: you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation, either version 3 of the License, or
-#   (at your option) any later version.
-#   
-#   This program is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-#   
-#   You should have received a copy of the GNU General Public License
-#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-from bGrease.component import Component
-
-class Equipable(Component):
-    """
-    Component that stores the data for an entity that can be equipped.
-    """
-    
-    def __init__(self):
+#   This program is free software: you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation, either version 3 of the License, or
+#   (at your option) any later version.
+#   
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#   
+#   You should have received a copy of the GNU General Public License
+#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from parpg.bGrease.component import Component
+
+class Equipable(Component):
+    """
+    Component that stores the data for an entity that can be equipped.
+    """
+    
+    def __init__(self):
         Component.__init__(self, possible_slots=list, container=object, in_slot=str)
\ No newline at end of file
--- a/components/fifeagent.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/components/fifeagent.py	Wed Sep 21 16:10:14 2011 +0200
@@ -11,7 +11,7 @@
 #   You should have received a copy of the GNU General Public License
 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-from bGrease.component import Component
+from parpg.bGrease.component import Component
 
 class FifeAgent(Component):
     """Component that stores the values for a fife agent"""
--- a/components/lockable.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/components/lockable.py	Wed Sep 21 16:10:14 2011 +0200
@@ -11,7 +11,7 @@
 #   You should have received a copy of the GNU General Public License
 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-from bGrease.component import Component
+from parpg.bGrease.component import Component
 
 class Lockable(Component):
     """Component that stores the data of a lock"""
--- a/components/usable.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/components/usable.py	Wed Sep 21 16:10:14 2011 +0200
@@ -1,22 +1,22 @@
-#   This program is free software: you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation, either version 3 of the License, or
-#   (at your option) any later version.
-#   
-#   This program is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-#   
-#   You should have received a copy of the GNU General Public License
-#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-from bGrease.component import Component
-
-class Usable(Component):
-    """
-    Component that stores data about the actions that an object can do.
-    """
-    
-    def __init__(self):
+#   This program is free software: you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation, either version 3 of the License, or
+#   (at your option) any later version.
+#   
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#   
+#   You should have received a copy of the GNU General Public License
+#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from parpg.bGrease.component import Component
+
+class Usable(Component):
+    """
+    Component that stores data about the actions that an object can do.
+    """
+    
+    def __init__(self):
         Component.__init__(self, actions=dict)
\ No newline at end of file
--- a/gamemodel.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/gamemodel.py	Wed Sep 21 16:10:14 2011 +0200
@@ -21,7 +21,7 @@
 
 from fife import fife
 from fife.extensions.serializers.xmlobject import XMLObjectLoader 
-from bGrease.geometry import Vec2d
+from parpg.bGrease.geometry import Vec2d
 
 from parpg import vfs
 from gamestate import GameState
--- a/mode.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/mode.py	Wed Sep 21 16:10:14 2011 +0200
@@ -1,21 +1,21 @@
-
-from bGrease.mode import *
-import abc
-
-class FifeManager(BaseManager):
-
-	def __init__(self):
-		self.modes = []
-	
-	def _pump(self):
-		if self.current_mode:
-			self.current_mode.pump(self.current_mode.engine.getTimeManager().getTimeDelta() / 1000.0)
-	
-class FifeMode(BaseMode):
-	
-	def __init__(self):
-		BaseMode.__init__(self)
-	
-	@abc.abstractmethod
-	def pump(self, dt):
-		"""Performs actions every frame"""
\ No newline at end of file
+
+from parpg.bGrease.mode import *
+import abc
+
+class FifeManager(BaseManager):
+
+        def __init__(self):
+                self.modes = []
+
+        def _pump(self):
+                if self.current_mode:
+                        self.current_mode.pump(self.current_mode.engine.getTimeManager().getTimeDelta() / 1000.0)
+
+class FifeMode(BaseMode):
+
+        def __init__(self):
+                BaseMode.__init__(self)
+
+        @abc.abstractmethod
+        def pump(self, dt):
+                """Performs actions every frame"""
\ No newline at end of file
--- a/systems/gamerulessystem.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/systems/gamerulessystem.py	Wed Sep 21 16:10:14 2011 +0200
@@ -11,7 +11,7 @@
 #   You should have received a copy of the GNU General Public License
 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-from bGrease import System
+from parpg.bGrease import System
 
 class GameRulesSystem(System):
     """
--- a/systems/scriptingsystem.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/systems/scriptingsystem.py	Wed Sep 21 16:10:14 2011 +0200
@@ -11,7 +11,7 @@
 #   You should have received a copy of the GNU General Public License
 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-from bGrease import System
+from parpg.bGrease import System
 
 class ScriptingSystem(System):
     """
--- a/world.py	Wed Sep 21 15:43:12 2011 +0200
+++ b/world.py	Wed Sep 21 16:10:14 2011 +0200
@@ -1,32 +1,32 @@
-from bGrease.world import *
-from bGrease.component import Component
-
-from parpg.mode import FifeMode
-from parpg import components
-
-class World(FifeMode, BaseWorld):
-
-    def __init__(self):
-        FifeMode.__init__(self)
-        BaseWorld.__init__(self)
-        
-    def configure(self):
-        """Configure the game world's components, systems and renderers"""
-        self.components.characterstats = components.CharacterStatistics()
-        self.components.containable = components.Containable()
-        self.components.container = components.Container()
-        self.components.description = components.Description()
-        self.components.dialogue = components.Dialogue()
-        self.components.fifeagent = components.FifeAgent()
-        self.components.lockable = components.Lockable()
-        self.components.usable = components.Usable()
-        self.components.change_map = components.ChangeMap()
-        self.components.equipable = components.Equipable()
-    
-    def pump(self, dt):
-        for component in self.components:
-            if hasattr(component, "step"):
-                component.step(dt)
-        for system in self.systems:
-            if hasattr(system, "step"):
+from parpg.bGrease.world import *
+from parpg.bGrease.component import Component
+
+from parpg.mode import FifeMode
+from parpg import components
+
+class World(FifeMode, BaseWorld):
+
+    def __init__(self):
+        FifeMode.__init__(self)
+        BaseWorld.__init__(self)
+        
+    def configure(self):
+        """Configure the game world's components, systems and renderers"""
+        self.components.characterstats = components.CharacterStatistics()
+        self.components.containable = components.Containable()
+        self.components.container = components.Container()
+        self.components.description = components.Description()
+        self.components.dialogue = components.Dialogue()
+        self.components.fifeagent = components.FifeAgent()
+        self.components.lockable = components.Lockable()
+        self.components.usable = components.Usable()
+        self.components.change_map = components.ChangeMap()
+        self.components.equipable = components.Equipable()
+    
+    def pump(self, dt):
+        for component in self.components:
+            if hasattr(component, "step"):
+                component.step(dt)
+        for system in self.systems:
+            if hasattr(system, "step"):
                 system.step(dt)
\ No newline at end of file