changeset 86:a9cc5559ec2a

Move the identifier field from the FifeAgent component to the new General component. Added General Entity.
author KarstenBock@gmx.net
date Sat, 24 Sep 2011 15:48:24 +0200
parents 04af237dde10
children aed2e094e0c7
files bGrease/entity.py behaviours/base.py components/__init__.py components/fifeagent.py components/general.py entities/__init__.py entities/general.py gamemodel.py gamescenecontroller.py objects/action.py world.py
diffstat 11 files changed, 402 insertions(+), 357 deletions(-) [+]
line wrap: on
line diff
--- a/bGrease/entity.py	Fri Sep 23 15:09:02 2011 +0200
+++ b/bGrease/entity.py	Sat Sep 24 15:48:24 2011 +0200
@@ -1,212 +1,212 @@
-#############################################################################
-#
-# 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 entities are useful as actionable, interactive
-game elements that are often visible to the player.
-
-You might use entities to represent:
-
-- Characters
-- Bullets
-- Particles
-- Pick-ups
-- Space Ships
-- Weapons
-- Trees
-- Planets
-- Explosions
-
-See :ref:`an example entity class in the tutorial <tut-entity-example>`.
-"""
-
-__version__ = '$Id$'
-
-__all__ = ('Entity', 'EntityComponentAccessor', 'ComponentEntitySet')
-
-
-class EntityMeta(type):
-	"""The entity metaclass enforces fixed slots of `entity_id` and `world`
-	for all subclasses. This prevents accidental use of other entity instance 
-	attributes, which may not be saved. 
-	
-	Class attributes are not affected by this restriction, but subclasses
-	should be careful not to cause name collisions with world components,
-	which are exposed as entity attributes. Using a naming convention for
-	class attributes, such as UPPER_CASE_WITH_UNDERSCORES is recommended to
-	avoid name clashes.
-
-	Note as a result of this, entity subclasses are not allowed to define
-	`__slots__`, and doing so will cause a `TypeError` to be raised.
-	"""
-
-	def __new__(cls, name, bases, clsdict):
-		if '__slots__' in clsdict:
-			raise TypeError('__slots__ may not be defined in Entity subclasses')
-		clsdict['__slots__'] = ('world', 'entity_id')
-		return type.__new__(cls, name, bases, clsdict)
-
-
-class Entity(object):
-	"""Base class for grease entities.
-	
-	Entity objects themselves are merely identifiers within a :class:`grease.world.World`.
-	They also provide a facade for convenient entity-wise access of component
-	data. However, they do not contain any data themselves other than an
-	entity id.
-
-	Entities must be instantiated in the context of a world. To instantiate an
-	entity, you must pass the world as the first argument to the constructor.
-	Subclasses that implement the :meth:`__init__()` method, must accept the world
-	as their first argument (after ``self``). Other constructor arguments can be
-	specified arbitarily by the subclass.
-	"""
-	__metaclass__ = EntityMeta
-
-	def __new__(cls, world, *args, **kw):
-		"""Create a new entity and add it to the world"""
-		entity = object.__new__(cls)
-		entity.world = world
-		entity.entity_id = world.new_entity_id()
-		world.entities.add(entity)
-		return entity
-	
-	def __getattr__(self, name):
-		"""Return an :class:`EntityComponentAccessor` for this entity
-		for the component named.
-
-		Example::
-
-			my_entity.movement
-		"""
-		component = getattr(self.world.components, name)
-		return EntityComponentAccessor(component, self)
-	
-	def __setattr__(self, name, value):
-		"""Set the entity data in the named component for this entity.
-		This sets the values of the component fields to the values of
-		the matching attributes of the value provided. This value must
-		have attributes for each of the component fields.
-
-		This allows you to easily copy component data from one entity
-		to another.
-
-		Example::
-
-			my_entity.position = other_entity.position
-		"""
-		if name in self.__class__.__slots__:
-			super(Entity, self).__setattr__(name, value)
-		else:
-			component = getattr(self.world.components, name)
-			component.set(self, value)
-	
-	def __delattr__(self, name):
-		"""Remove this entity and its data from the component.
-		
-		Example::
-		
-			del my_entity.renderable
-		"""
-		component = getattr(self.world.components, name)
-		del component[self]
-	
-	def __hash__(self):
-		return self.entity_id
-	
-	def __eq__(self, other):
-		return self.world is other.world and self.entity_id == other.entity_id
-
-	def __repr__(self):
-		return "<%s id: %s of %s %x>" % (
-			self.__class__.__name__, self.entity_id,
-			self.world.__class__.__name__, id(self.world))
-
-	def delete(self):
-		"""Delete the entity from its world. This removes all of its
-		component data. If then entity has already been deleted, 
-		this call does nothing.
-		"""
-		self.world.entities.discard(self)
-
-	@property
-	def exists(self):
-		"""True if the entity still exists in the world"""
-		return self in self.world.entities
-
-
-class EntityComponentAccessor(object):
-	"""A facade for accessing specific component data for a single entity.
-	The implementation is lazy and does not actually access the component
-	data until needed. If an attribute is set for a component that the 
-	entity is not yet a member of, it is automatically added to the
-	component first.
-
-	:param component: The :class:`grease.Component` being accessed
-	:param entity: The :class:`Entity` being accessed
-	"""
-	
-	# beware, name mangling ahead. We want to avoid clashing with any
-	# user-configured component field names
-	__data = None
-
-	def __init__(self, component, entity):
-		clsname = self.__class__.__name__
-		self.__dict__['_%s__component' % clsname] = component
-		self.__dict__['_%s__entity' % clsname] = entity
-	
-	def __nonzero__(self):
-		"""The accessor is True if the entity is in the component,
-		False if not, for convenient membership tests
-		"""
-		return self.__entity in self.__component
-	
-	def __getattr__(self, name):
-		"""Return the data for the specified field of the entity's component"""
-		if self.__data is None:
-			try:
-				data = self.__component[self.__entity]
-			except KeyError:
-				raise AttributeError(name)
-			clsname = self.__class__.__name__
-			self.__dict__['_%s__data' % clsname] = data
-		return getattr(self.__data, name)
-	
-	def __setattr__(self, name, value):
-		"""Set the data for the specified field of the entity's component"""
-		if self.__data is None:
-			clsname = self.__class__.__name__
-			if self.__entity in self.__component:
-				self.__dict__['_%s__data' % clsname] = self.__component[self.__entity]
-			else:
-				self.__dict__['_%s__data' % clsname] = self.__component.set(self.__entity)
-		setattr(self.__data, name, value)
-
-
-class ComponentEntitySet(set):
-	"""Set of entities in a component, can be queried by component fields"""
-
-	_component = None
-
-	def __init__(self, component, entities=()):
-		self.__dict__['_component'] = component
-		super(ComponentEntitySet, self).__init__(entities)
-	
-	def __getattr__(self, name):
-		if self._component is not None and name in self._component.fields:
-			return self._component.fields[name].accessor(self)
-		raise AttributeError(name)
-	
-	def __setattr__(self, name, value):
-		if self._component is not None and name in self._component.fields:
-			self._component.fields[name].accessor(self).__set__(value)
-		raise AttributeError(name)
-
+#############################################################################
+#
+# 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 entities are useful as actionable, interactive
+game elements that are often visible to the player.
+
+You might use entities to represent:
+
+- Characters
+- Bullets
+- Particles
+- Pick-ups
+- Space Ships
+- Weapons
+- Trees
+- Planets
+- Explosions
+
+See :ref:`an example entity class in the tutorial <tut-entity-example>`.
+"""
+
+__version__ = '$Id$'
+
+__all__ = ('Entity', 'EntityComponentAccessor', 'ComponentEntitySet')
+
+
+class EntityMeta(type):
+	"""The entity metaclass enforces fixed slots of `entity_id` and `world`
+	for all subclasses. This prevents accidental use of other entity instance 
+	attributes, which may not be saved. 
+	
+	Class attributes are not affected by this restriction, but subclasses
+	should be careful not to cause name collisions with world components,
+	which are exposed as entity attributes. Using a naming convention for
+	class attributes, such as UPPER_CASE_WITH_UNDERSCORES is recommended to
+	avoid name clashes.
+
+	Note as a result of this, entity subclasses are not allowed to define
+	`__slots__`, and doing so will cause a `TypeError` to be raised.
+	"""
+
+	def __new__(cls, name, bases, clsdict):
+		if '__slots__' in clsdict:
+			raise TypeError('__slots__ may not be defined in Entity subclasses')
+		clsdict['__slots__'] = ('world', 'entity_id')
+		return type.__new__(cls, name, bases, clsdict)
+
+
+class Entity(object):
+	"""Base class for grease entities.
+	
+	Entity objects themselves are merely identifiers within a :class:`grease.world.World`.
+	They also provide a facade for convenient entity-wise access of component
+	data. However, they do not contain any data themselves other than an
+	entity id.
+
+	Entities must be instantiated in the context of a world. To instantiate an
+	entity, you must pass the world as the first argument to the constructor.
+	Subclasses that implement the :meth:`__init__()` method, must accept the world
+	as their first argument (after ``self``). Other constructor arguments can be
+	specified arbitarily by the subclass.
+	"""
+	__metaclass__ = EntityMeta
+
+	def __new__(cls, world, *args, **kw):
+		"""Create a new entity and add it to the world"""
+		entity = object.__new__(cls)
+		entity.world = world
+		entity.entity_id = world.new_entity_id()
+		world.entities.add(entity)
+		return entity
+	
+	def __getattr__(self, name):
+		"""Return an :class:`EntityComponentAccessor` for this entity
+		for the component named.
+
+		Example::
+
+			my_entity.movement
+		"""
+		component = getattr(self.world.components, name)
+		return EntityComponentAccessor(component, self)
+	
+	def __setattr__(self, name, value):
+		"""Set the entity data in the named component for this entity.
+		This sets the values of the component fields to the values of
+		the matching attributes of the value provided. This value must
+		have attributes for each of the component fields.
+
+		This allows you to easily copy component data from one entity
+		to another.
+
+		Example::
+
+			my_entity.position = other_entity.position
+		"""
+		if name in self.__class__.__slots__:
+			super(Entity, self).__setattr__(name, value)
+		else:
+			component = getattr(self.world.components, name)
+			component.set(self, value)
+	
+	def __delattr__(self, name):
+		"""Remove this entity and its data from the component.
+		
+		Example::
+		
+			del my_entity.renderable
+		"""
+		component = getattr(self.world.components, name)
+		del component[self]
+	
+	def __hash__(self):
+		return self.entity_id
+	
+	def __eq__(self, other):
+		return self.world is other.world and self.entity_id == other.entity_id
+
+	def __repr__(self):
+		return "<%s id: %s of %s %x>" % (
+			self.__class__.__name__, self.entity_id,
+			self.world.__class__.__name__, id(self.world))
+
+	def delete(self):
+		"""Delete the entity from its world. This removes all of its
+		component data. If then entity has already been deleted, 
+		this call does nothing.
+		"""
+		self.world.entities.discard(self)
+
+	@property
+	def exists(self):
+		"""True if the entity still exists in the world"""
+		return self in self.world.entities
+
+
+class EntityComponentAccessor(object):
+	"""A facade for accessing specific component data for a single entity.
+	The implementation is lazy and does not actually access the component
+	data until needed. If an attribute is set for a component that the 
+	entity is not yet a member of, it is automatically added to the
+	component first.
+
+	:param component: The :class:`grease.Component` being accessed
+	:param entity: The :class:`Entity` being accessed
+	"""
+	
+	# beware, name mangling ahead. We want to avoid clashing with any
+	# user-configured component field names
+	__data = None
+
+	def __init__(self, component, entity):
+		clsname = self.__class__.__name__
+		self.__dict__['_%s__component' % clsname] = component
+		self.__dict__['_%s__entity' % clsname] = entity
+	
+	def __nonzero__(self):
+		"""The accessor is True if the entity is in the component,
+		False if not, for convenient membership tests
+		"""
+		return self.__entity in self.__component
+	
+	def __getattr__(self, name):
+		"""Return the data for the specified field of the entity's component"""
+		if self.__data is None:
+			try:
+				data = self.__component[self.__entity]
+			except KeyError:
+				raise AttributeError(name)
+			clsname = self.__class__.__name__
+			self.__dict__['_%s__data' % clsname] = data
+		return getattr(self.__data, name)
+	
+	def __setattr__(self, name, value):
+		"""Set the data for the specified field of the entity's component"""
+		if self.__data is None:
+			clsname = self.__class__.__name__
+			if self.__entity in self.__component:
+				self.__dict__['_%s__data' % clsname] = self.__component[self.__entity]
+			else:
+				self.__dict__['_%s__data' % clsname] = self.__component.set(self.__entity)
+		setattr(self.__data, name, value)
+
+
+class ComponentEntitySet(set):
+	"""Set of entities in a component, can be queried by component fields"""
+
+	_component = None
+
+	def __init__(self, component, entities=()):
+		self.__dict__['_component'] = component
+		super(ComponentEntitySet, self).__init__(entities)
+	
+	def __getattr__(self, name):
+		if self._component is not None and name in self._component.fields:
+			return self._component.fields[name].accessor(self)
+		raise AttributeError(name)
+	
+	def __setattr__(self, name, value):
+		if self._component is not None and name in self._component.fields:
+			self._component.fields[name].accessor(self).__set__(value)
+		raise AttributeError(name)
+
--- a/behaviours/base.py	Fri Sep 23 15:09:02 2011 +0200
+++ b/behaviours/base.py	Sat Sep 24 15:48:24 2011 +0200
@@ -1,91 +1,91 @@
-#   This file is part of PARPG.
-
-#   PARPG 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.
-
-#   PARPG 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 PARPG.  If not, see <http://www.gnu.org/licenses/>.
-
-from fife import fife
-
-_AGENT_STATE_NONE, _AGENT_STATE_IDLE, _AGENT_STATE_APPROACH, _AGENT_STATE_RUN, _AGENT_STATE_WANDER, _AGENT_STATE_TALK = xrange(6)
-
-class BaseBehaviour (fife.InstanceActionListener):
-    """Fife agent listener"""
-    def __init__(self):
-        fife.InstanceActionListener.__init__(self)
-        self.agent = None
-        self.state = None
-    
-    def attachToLayer(self, agent_ID, layer):
-        """Attaches to a certain layer
-           @type agent_ID: String
-           @param agent_ID: ID of the layer to attach to.
-           @type layer: Fife layer
-           @param layer: Layer of the agent to attach the behaviour to
-           @return: None"""
-        self.agent = layer.getInstance(agent_ID)
-        self.agent.addActionListener(self)
-        self.state = _AGENT_STATE_NONE
-        
-    def getX(self):
-        """Get the NPC's x position on the map.
-           @rtype: integer"
-           @return: the x coordinate of the NPC's location"""
-        return self.agent.getLocation().getLayerCoordinates().x
-
-    def getY(self):
-        """Get the NPC's y position on the map.
-           @rtype: integer
-           @return: the y coordinate of the NPC's location"""
-        return self.agent.getLocation().getLayerCoordinates().y
-        
-    def onNewMap(self, layer):
-        """Sets the agent onto the new layer."""
-        if self.agent is not None:
-            self.agent.removeActionListener(self)
-            
-        self.agent = layer.getInstance(self.parent.fifeagent.identifier)
-        self.agent.addActionListener(self)
-        self.state = _AGENT_STATE_NONE
-    
-    def idle(self):
-        """@return: None"""
-        self.state = _AGENT_STATE_IDLE
-        
-    def onInstanceActionFinished(self, instance, action):
-        """@type instance: ???
-           @param instance: ???
-           @type action: ???
-           @param action: ???
-           @return: None"""
-        # First we reset the next behavior 
-        act = self.nextAction
-        self.nextAction = None 
-        self.idle()
-        
-        if act:
-            act.execute()
-          
-            
-    def getLocation(self):
-        """Get the agents position as a fife.Location object. 
-           @rtype: fife.Location
-           @return: the location of the agent"""
-        return self.agent.getLocation()
-    
-        
-    def talk(self, pc):
-        """Makes the agent ready to talk to the PC
-           @return: None"""
-        self.state = _AGENT_STATE_TALK
-        self.pc = pc.behaviour.agent
-        self.idle()
+#   This file is part of PARPG.
+
+#   PARPG 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.
+
+#   PARPG 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 PARPG.  If not, see <http://www.gnu.org/licenses/>.
+
+from fife import fife
+
+_AGENT_STATE_NONE, _AGENT_STATE_IDLE, _AGENT_STATE_APPROACH, _AGENT_STATE_RUN, _AGENT_STATE_WANDER, _AGENT_STATE_TALK = xrange(6)
+
+class BaseBehaviour (fife.InstanceActionListener):
+    """Fife agent listener"""
+    def __init__(self):
+        fife.InstanceActionListener.__init__(self)
+        self.agent = None
+        self.state = None
+    
+    def attachToLayer(self, agent_ID, layer):
+        """Attaches to a certain layer
+           @type agent_ID: String
+           @param agent_ID: ID of the layer to attach to.
+           @type layer: Fife layer
+           @param layer: Layer of the agent to attach the behaviour to
+           @return: None"""
+        self.agent = layer.getInstance(agent_ID)
+        self.agent.addActionListener(self)
+        self.state = _AGENT_STATE_NONE
+        
+    def getX(self):
+        """Get the NPC's x position on the map.
+           @rtype: integer"
+           @return: the x coordinate of the NPC's location"""
+        return self.agent.getLocation().getLayerCoordinates().x
+
+    def getY(self):
+        """Get the NPC's y position on the map.
+           @rtype: integer
+           @return: the y coordinate of the NPC's location"""
+        return self.agent.getLocation().getLayerCoordinates().y
+        
+    def onNewMap(self, layer):
+        """Sets the agent onto the new layer."""
+        if self.agent is not None:
+            self.agent.removeActionListener(self)
+            
+        self.agent = layer.getInstance(self.parent.general.identifier)
+        self.agent.addActionListener(self)
+        self.state = _AGENT_STATE_NONE
+    
+    def idle(self):
+        """@return: None"""
+        self.state = _AGENT_STATE_IDLE
+        
+    def onInstanceActionFinished(self, instance, action):
+        """@type instance: ???
+           @param instance: ???
+           @type action: ???
+           @param action: ???
+           @return: None"""
+        # First we reset the next behavior 
+        act = self.nextAction
+        self.nextAction = None 
+        self.idle()
+        
+        if act:
+            act.execute()
+          
+            
+    def getLocation(self):
+        """Get the agents position as a fife.Location object. 
+           @rtype: fife.Location
+           @return: the location of the agent"""
+        return self.agent.getLocation()
+    
+        
+    def talk(self, pc):
+        """Makes the agent ready to talk to the PC
+           @return: None"""
+        self.state = _AGENT_STATE_TALK
+        self.pc = pc.behaviour.agent
+        self.idle()
         
\ No newline at end of file
--- a/components/__init__.py	Fri Sep 23 15:09:02 2011 +0200
+++ b/components/__init__.py	Sat Sep 24 15:48:24 2011 +0200
@@ -8,4 +8,5 @@
 from usable import Usable
 from change_map import ChangeMap
 from equipable import Equipable
-from equip import Equip
\ No newline at end of file
+from equip import Equip
+from general import General
\ No newline at end of file
--- a/components/fifeagent.py	Fri Sep 23 15:09:02 2011 +0200
+++ b/components/fifeagent.py	Sat Sep 24 15:48:24 2011 +0200
@@ -18,10 +18,10 @@
     
     def __init__(self):
         """Constructor"""
-        Component.__init__(self, identifier=str, layer=object, behaviour=object, gfx=str)
+        Component.__init__(self, layer=object, behaviour=object, gfx=str)
 
         
 def setup_behaviour(agent):
     """Attach the behaviour to the layer"""
     if agent.behaviour:   
-        agent.behaviour.attachToLayer(agent.identifier, agent.layer)
\ No newline at end of file
+        agent.behaviour.attachToLayer(agent.entity.getID(), agent.layer)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/general.py	Sat Sep 24 15:48:24 2011 +0200
@@ -0,0 +1,21 @@
+#   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 General(Component):
+    """Component that stores the general values of an parpg entity"""
+    
+    def __init__(self):
+        """Constructor"""
+        Component.__init__(self, identifier=str)
\ No newline at end of file
--- a/entities/__init__.py	Fri Sep 23 15:09:02 2011 +0200
+++ b/entities/__init__.py	Sat Sep 24 15:48:24 2011 +0200
@@ -1,40 +1,40 @@
-#   This file is part of PARPG.
-
-#   PARPG 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.
-
-#   PARPG 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 PARPG.  If not, see <http://www.gnu.org/licenses/>.
-
-import sys
-
-from parpg.bGrease import Entity
-
-def createEntity(info, world, extra = None):
-    """Called when we need to get an actual object.
-       @type info: dict
-       @param info: stores information about the object we want to create
-       @type extra: dict
-       @param extra: stores additionally required attributes
-       @return: the object"""
-    # First, we try to get the world, which every game_obj needs.
-    extra = extra or {}
-
-    # add the extra info
-    for key, val in extra.items():
-        info[key].update(val)
-
-    # this is for testing purposes
-    new_ent = Entity(world)
-    for component, data in info.items():
-        comp_obj = getattr(new_ent, component)
-        for key, value in data.items():
-            setattr(comp_obj, key, value)
-    return new_ent
+#   This file is part of PARPG.
+
+#   PARPG 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.
+
+#   PARPG 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 PARPG.  If not, see <http://www.gnu.org/licenses/>.
+
+import sys
+
+from general import General
+
+def createEntity(info, identifier, world, extra = None):
+    """Called when we need to get an actual object.
+       @type info: dict
+       @param info: stores information about the object we want to create
+       @type extra: dict
+       @param extra: stores additionally required attributes
+       @return: the object"""
+    # First, we try to get the world, which every game_obj needs.
+    extra = extra or {}
+
+    # add the extra info
+    for key, val in extra.items():
+        info[key].update(val)
+
+    # this is for testing purposes
+    new_ent = General(world, identifier)
+    for component, data in info.items():
+        comp_obj = getattr(new_ent, component)
+        for key, value in data.items():
+            setattr(comp_obj, key, value)
+    return new_ent
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/entities/general.py	Sat Sep 24 15:48:24 2011 +0200
@@ -0,0 +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 parpg.bGrease import Entity
+
+class General(Entity):
+    
+    def __init__(self, world, identifier):
+        self.general.identifier = identifier
+        
+    def getID(self):
+        return self.general.identifier
\ No newline at end of file
--- a/gamemodel.py	Fri Sep 23 15:09:02 2011 +0200
+++ b/gamemodel.py	Sat Sep 24 15:48:24 2011 +0200
@@ -437,7 +437,6 @@
             inst.act('default', target, True)        
 
             
-        entity_data["fifeagent"]["identifier"] = inst_id
         if entity_data["fifeagent"].has_key("behaviour"):
             entity_data["fifeagent"]["behaviour"] = getattr(behaviours, entity_data["fifeagent"]["behaviour"])()
         else:
@@ -446,7 +445,7 @@
             entity_data["dialogue"] = {}
             entity_data["dialogue"]["dialogue"] = self.dialogues[inst_id]           
                        
-        obj = self.createMapObject(self.active_map.agent_layer, entity_data, world)
+        obj = self.createMapObject(self.active_map.agent_layer, entity_data, inst_id, world)
 
         if agent.has_key("Inventory"):
             inv = agent["Inventory"]
@@ -477,9 +476,10 @@
                     raise Exception("Item %s is not containable or equipable." % item_type)
 
     def create_item(self, item_data, world, item_type, data):
-        item = createEntity(item_data, world, None)
+        identifier = self.createUniqueID(data["ID"])
+        item = createEntity(item_data, identifier, world, None)
         item.containable.item_type = item_type
-        self.game_state.addObject(self.createUniqueID(data["ID"]), None, item)
+        self.game_state.addObject(identifier, None, item)
         return item
 
     def placeAgents(self, world):
@@ -544,7 +544,7 @@
         self.active_map.makeActive()
         self.game_state.current_map_name = map_name
 
-    def createMapObject (self, layer, attributes, world):
+    def createMapObject (self, layer, attributes, inst_id, world):
         """Create an object and add it to the current map.
            @type layer: fife.Layer
            @param layer: FIFE layer object exists in
@@ -559,7 +559,7 @@
             extra['fifeagent'] = {}
             extra['fifeagent']['layer'] = layer
         
-        obj = createEntity(attributes, world, extra)
+        obj = createEntity(attributes, inst_id, world, extra)
         if obj:
             self.addObject(layer, obj)
         return obj
@@ -590,11 +590,11 @@
            @type instance: fife.Instance
            @param instance: FIFE instance of object
            @return: None"""
-        ref = self.game_state.getObjectById(obj.fifeagent.identifier,
+        ref = self.game_state.getObjectById(obj.general.identifier,
                                             self.game_state.current_map_name) 
         if ref is None:
             # no, add it to the game state
-            self.game_state.addObject(obj.fifeagent.identifier, self.game_state.current_map_name, obj)
+            self.game_state.addObject(obj.general.identifier, self.game_state.current_map_name, obj)
         else:
             # yes, use the current game state data
             obj.fifeagent.pos.X = ref.X
@@ -625,7 +625,7 @@
            @return: Status of result (True/False)"""
         for game_object in \
            self.game_state.getObjectsFromMap(self.game_state.current_map_name):
-            if (game_object.fifeagent.identifier == ident):
+            if (game_object.general.identifier == ident):
                 # we found a match
                 return game_object
         # no match
--- a/gamescenecontroller.py	Fri Sep 23 15:09:02 2011 +0200
+++ b/gamescenecontroller.py	Sat Sep 24 15:48:24 2011 +0200
@@ -409,7 +409,7 @@
         # TODO: work more on this when we get NPCData and HeroData straightened
         # out
         npc = self.model.game_state.getObjectById(
-            npc_info.fifeagent.identifier, 
+            npc_info.general.identifier, 
             self.model.game_state.current_map_name
         )
         npc_pos = npc.fifeagent.behaviour.getLocation().getLayerCoordinates()
@@ -430,7 +430,7 @@
                                       self.model.game_state.current_map_name)
         obj_pos = obj.fifeagent.behaviour.getLocation().getLayerCoordinates()
         player = self.model.game_state.getObjectById("PlayerCharacter")
-        is_player = obj.fifeagent.identifier == player.fifeagent.identifier
+        is_player = obj.general.identifier == player.general.identifier
         
         
         #TODO: Check all actions to be compatible with the grease components
--- a/objects/action.py	Fri Sep 23 15:09:02 2011 +0200
+++ b/objects/action.py	Sat Sep 24 15:48:24 2011 +0200
@@ -383,7 +383,7 @@
     def execute(self):
         real_item = self.item.containable
         player = self.model.game_state.getObjectById("PlayerCharacter")
-        self.model.moveObject(self.item.fifeagent.identifier, None)
+        self.model.moveObject(self.item.general.identifier, None)
         container.put_item(player.container, real_item)
         super(PickUpAction, self).execute()
 
--- a/world.py	Fri Sep 23 15:09:02 2011 +0200
+++ b/world.py	Sat Sep 24 15:48:24 2011 +0200
@@ -12,6 +12,7 @@
         
     def configure(self):
         """Configure the game world's components, systems and renderers"""
+        self.components.general = components.General()
         self.components.characterstats = components.CharacterStatistics()
         self.components.containable = components.Containable()
         self.components.container = components.Container()