Example #1
0
 def create_world(self):
     """Creates the world used by this application"""
     self.world = RPGWorld(self)
     GameVariables.add_callback(self.update_game_variables)
     ScriptingSystem.register_command("set_global_lighting",
                                      self.set_global_lighting,
                                      _SCRIPTING_MODULE)
     ScriptingSystem.register_command("get_global_lighting",
                                      self.get_global_lighting,
                                      _SCRIPTING_MODULE)
     ScriptingSystem.register_command("is_location_in_region",
                                      self.is_location_in_region,
                                      _SCRIPTING_MODULE)
     ScriptingSystem.register_command("is_agent_in_region",
                                      self.is_agent_in_region,
                                      _SCRIPTING_MODULE)
Example #2
0
 def create_world(self):
     """Creates the world used by this application"""
     self.world = RPGWorld(self)
     GameVariables.add_callback(self.update_game_variables)
     ScriptingSystem.register_command("set_global_lighting",
                                      self.set_global_lighting,
                                      _SCRIPTING_MODULE)
     ScriptingSystem.register_command("get_global_lighting",
                                      self.get_global_lighting,
                                      _SCRIPTING_MODULE)
     ScriptingSystem.register_command("is_location_in_region",
                                      self.is_location_in_region,
                                      _SCRIPTING_MODULE)
     ScriptingSystem.register_command("is_agent_in_region",
                                      self.is_agent_in_region,
                                      _SCRIPTING_MODULE)
Example #3
0
class RPGApplication(FifeManager, ApplicationBase):

    """The main application.  It inherits fife.extensions.ApplicationBase.

    Properties:
        name: The name of the Application

        world: The fife_rpg.world.RPGWorld this application uses

        language: The language the application uses

        settings: A fife_settings.Setting instance that stores the settings of
        the application

        maps: A dictionary containing the maps the application has

        current_map: The current active map

        log_manager: The log manager of the application

        engine: A fife.Engine instance
    """

    def __init__(self, TDS):
        """Initialized the application

        Args:
            TDS: A fife_settings.Setting instance
        """
        ApplicationBase.__init__(self, TDS)
        FifeManager.__init__(self)
        self.name = self.settings.get("fife-rpg", "ProjectName")
        if self.name is None:
            raise AttributeError("The application name is not specified in"
                                 "the settings file")
        self._listener = None
        self.world = None
        self._maps = {}
        self._current_map = None
        self._languages = {}
        self._current_language = ""
        self._components = {}
        self._actions = {}
        self._systems = {}
        self._behaviours = {}
        self._map_switched_callbacks = []
        self._map_loaded_callbacks = []
        default_language = self.settings.get("i18n", "DefaultLanguage", "en")
        languages_dir = self.settings.get("i18n", "Directory", "__languages")
        for language in self.settings.get("i18n", "Languages", ("en",)):
            fallback = (language == default_language)
            self._languages[language] = gettext.translation(self.name,
                                                            languages_dir,
                                                            [language],
                                                            fallback=fallback)
        language = self.settings.get("i18n", "Language", default_language)
        self.switch_language(language)

    @property
    def language(self):
        """Returns the current set language"""
        return self._current_language

    @language.setter
    def language(self, language):
        """Sets the current language

        Args:
            language: The language to switch to
        """
        self.switch_language(language)

    @property
    def settings(self):
        """Returns the settings of the application.

        Returns:
            A fife_settings.Setting instance that contains the settings of the
            application.
        """
        return self._setting

    @property
    def log_manager(self):
        """Returns the log manager of the application.

        Returns:
            a fifelog.LogManager instance that contains the log manager of
            the application.
        """
        return self._log

    @property
    def current_map(self):
        """Returns the current active map"""
        return self._current_map

    @property
    def maps(self):
        """Returns a copy of the maps dictionary"""
        return copy(self._maps)

    @property
    def components(self):
        """Returns a copy of the available components"""
        return copy(self._components)

    @property
    def actions(self):
        """Returns a copy of the available actions"""
        return copy(self._actions)

    @property
    def systems(self):
        """Returns a copy of the available systems"""
        return copy(self._systems)

    @property
    def behaviours(self):
        """Returns a copy of the available behaviours"""
        return copy(self._behaviours)

    def switch_language(self, language):
        """Switch to the given language"""
        if language not in self._languages:
            raise KeyError("The language '%s' is not available" % language)
        if not language == self._current_language:
            self._languages[language].install()
            self._current_language = language

    def update_game_variables(self, variables):
        """Called by the game environment when it wants to update its globals

        Args:
            globals: The globals dictionary of the GameEnvironment that is
            filled by the GameScene
        """
        app_module = imp.new_module(_SCRIPTING_MODULE)
        app_module.__dict__["current_map"] = self.current_map
        app_module.__dict__["maps"] = self.maps
        variables[_SCRIPTING_MODULE] = app_module

    def add_map(self, identifier, game_map):
        """Adds a map to the maps dictionary.

        Args:
            identifier: The identifier of the map

            game_map: A Map instance.
        """
        if identifier not in self._maps:
            self._maps[identifier] = game_map
        else:
            raise AlreadyRegisteredError(identifier, "Map")

    def update_agents(self, game_map):
        """Updates the map to be in sync with the entities

        Args:
            game_map: The name of the map, or a Map instance
        """
        if isinstance(game_map, str):
            game_map = self.maps[game_map]
        if isinstance(game_map, str):  # The map is not yet loaded
            return
        object_namespace = self.settings.get("fife-rpg", "ObjectNamespace",
                                             "fife-rpg")
        fife_model = self.engine.getModel()
        game_map.update_entities()
        for entity in game_map.entities:
            agent = getattr(entity, Agent.registered_as)
            namespace = agent.namespace or object_namespace
            map_object = fife_model.getObject(agent.gfx, namespace)
            if not map_object:
                raise RuntimeError("There is no object %s in the namespace %s"
                                   % (agent.gfx, namespace))
            general = getattr(entity, General.registered_as)
            layer = game_map.get_layer(agent.layer)
            fife_instance = layer.getInstance(general.identifier)
            if fife_instance:
                fife_object = fife_instance.getObject()
                if (fife_object.getId() != map_object.getId() or
                        fife_object.getNamespace() !=
                        map_object.getNamespace()):
                    layer.deleteInstance(fife_instance)
                    fife_instance = None
            if not fife_instance:
                position = agent.position
                fife_instance = layer.createInstance(
                    map_object,
                    fife.ExactModelCoordinate(position.x,
                                              position.y,
                                              position.z),
                    general.identifier)
                fife_instance.setRotation(agent.rotation)
                visual = fife.InstanceVisual.create(fife_instance)
                if map_object.getAction('default'):
                    target = fife.Location(game_map.actor_layer)
                    fife_instance.actRepeat('default', target)
                fifeagent = getattr(entity, FifeAgent.registered_as)
                behaviour_class = BehaviourManager.get_behaviour(
                    agent.behaviour_type)
                if behaviour_class is None:
                    raise RuntimeError("There is no registered behaviour %s"
                                       % agent.behaviour_type)
                behaviour = behaviour_class(**agent.behaviour_args)
                behaviour.agent = fife_instance
                fifeagent.behaviour = behaviour
                fifeagent.layer = layer
                fifeagent.instance = fife_instance
                setup_behaviour(fifeagent)
                fifeagent.behaviour.idle()
            else:
                visual = fife_instance.get2dGfxVisual()
            visual.setStackPosition(STACK_POSITION[agent.type])

    def map_loded(self, identifier):
        """Called from Map instances after the map was loaded

        Args:
            identifier: The identifier of the loaded map
        """
        if identifier in self._maps:
            game_map = self.maps[identifier]
            for callback in self._map_loaded_callbacks:
                callback(game_map)
            self.update_agents(game_map)

        else:
            raise LookupError("The map with the identifier '%s' cannot be "
                              "found"
                              % (identifier))

    def switch_map(self, name):
        """Switches to the given map.

        Args:
            name: The name of the map
        """
        old_map = None
        if self._current_map:
            old_map = self._current_map.name
            self._current_map.deactivate()
            self._current_map = None
        if name is None:
            for callback in self._map_switched_callbacks:
                callback(old_map, name)
            return
        if name in self._maps:
            self._current_map = self.maps[name]
            self._current_map.activate()
            for callback in self._map_switched_callbacks:
                callback(old_map, name)
        else:
            raise LookupError("The map with the name '%s' cannot be found"
                              % (name))

    def add_map_switch_callback(self, callback):
        """Adds a callback function which gets called after
        the map switched

        Args:
            callback: The function to add
        """
        if callback not in self._map_switched_callbacks:
            self._map_switched_callbacks.append(callback)

    def remove_map_switch_callback(self, callback):
        """Removes a callback function that got called after the map
        switched.

        Args:
            callback: The function to remove
        """
        if callback in self._map_switched_callbacks:
            index = self._map_switched_callbacks.index(callback)
            del self._map_switched_callbacks[index]

    def add_map_load_callback(self, callback):
        """Adds a callback function which gets called after
        a map was loaded

        Args:
            callback: The function to add
        """
        if callback not in self._map_loaded_callbacks:
            self._map_loaded_callbacks.append(callback)

    def remove_map_load_callback(self, callback):
        """Removes a callback function that got called after a map
        was loaded.

        Args:
            callback: The function to remove
        """
        if callback in self._map_loaded_callbacks:
            index = self._map_loaded_callbacks.index(callback)
            del self._map_loaded_callbacks[index]

    def load_maps(self):
        """Load the names of the available maps from a map file."""
        self._maps = {}
        maps_path = self.settings.get(
            "fife-rpg", "MapsPath", "maps")
        vfs = self.engine.getVFS()
        filename = os.path.join(maps_path, "maps.yaml")
        if not os.path.exists(filename):
            return
        maps_file = vfs.open(filename)
        maps_doc = yaml.load(maps_file)
        maps_path = self.settings.get(
            "fife-rpg", "MapsPath", "maps")
        camera = self.settings.get(
            "fife-rpg", "Camera", "main")

        for name, filename in maps_doc["Maps"].items():
            filepath = os.path.join(maps_path, filename + '.xml')
            identifier = etree.parse(filepath).getroot().attrib["id"]
            regions_filename = ("%s_regions.yaml" %
                                os.path.splitext(filepath)[0])
            regions = {}
            try:
                regions_file = self.engine.getVFS().open(regions_filename)
            except fife.NotFound:
                regions_file = None
            if regions_file is not None:
                regions_data = yaml.load(regions_file)
                if regions_data is not None:
                    for region_name, region_data in (
                            iter(regions_data.items())):
                        region = fife.DoubleRect(x=region_data[0],
                                                 y=region_data[1],
                                                 width=region_data[2],
                                                 height=region_data[3])
                        regions[region_name] = region
            game_map = GameMap(filepath, name, camera, regions, self)
            self.add_map(identifier, game_map)

    def create_world(self):
        """Creates the world used by this application"""
        self.world = RPGWorld(self)
        GameVariables.add_callback(self.update_game_variables)
        ScriptingSystem.register_command("set_global_lighting",
                                         self.set_global_lighting,
                                         _SCRIPTING_MODULE)
        ScriptingSystem.register_command("get_global_lighting",
                                         self.get_global_lighting,
                                         _SCRIPTING_MODULE)
        ScriptingSystem.register_command("is_location_in_region",
                                         self.is_location_in_region,
                                         _SCRIPTING_MODULE)
        ScriptingSystem.register_command("is_agent_in_region",
                                         self.is_agent_in_region,
                                         _SCRIPTING_MODULE)

    def request_quit(self):
        """Sends the quit command to the application's listener.

        We could set self.quitRequested to true also but this is a
        good example on how to build and dispatch a fife.Command.
        """
        cmd = fife.Command()
        cmd.setSource(None)
        cmd.setCommandType(fife.CMD_QUIT_GAME)
        self.engine.getEventManager().dispatchCommand(cmd)

    def screen_coords_to_map_coords(self, click, layer):
        """Converts the screen coordinates to coordinates on the active map

        Args:

           click: Screen coordinates as fife.ScreenPoint or position tuple

           layer: The name of the layer the converted position should be on

        Returns: Converted coordinates as fife.Location
        """
        active_map = self.current_map
        if active_map is None:
            return None
        if not isinstance(click, fife.ScreenPoint):
            click = fife.ScreenPoint(click[0], click[1])
        coord = active_map.camera.toMapCoordinates(click, False)
        coord.z = 0
        location = fife.Location(active_map.get_layer(layer))
        location.setMapCoordinates(coord)
        return location

    def load_components(self, filename=None):
        """Load the component definitions from a file

        Args:
            filename: The path to the components file. If this is set to None
            the ComponentsFile or CombinedFile setting will be used.
        """
        if filename is None:
            filename = self.settings.get("fife-rpg", "ComponentsFile",
                                         "components.yaml")
            filename = self.settings.get("fife-rpg", "CombinedFile",
                                         filename)
        self._components = {}
        components_file = self.engine.getVFS().open(filename)
        for name, path in yaml.load(components_file)["Components"].items():
            self._components[name] = path

    def get_component_data(self, component_name):
        """Returns the class and module of the given component

        Args:

            component_name: The name of the component
        """
        component_path = self._components[component_name]
        module = __import__(component_path, fromlist=[component_path])
        component = getattr(module, component_name)
        return component, module

    def register_component(self, component_name, registered_name=None,
                           register_checkers=True,
                           register_script_commands=True):
        """Calls the components register method.

        Args:
            component_name: Name of the component

            registered_name: Name under which the component should be
            registered

            register_checkers: If True a "register_checkers" function will be
            searched in the module and called

            register_script_commands: If True a "register_script_commands"
            functions will be searched in the module and called
        """
        component, module = self.get_component_data(component_name)
        if registered_name is not None:
            component.register(registered_name)
        else:
            component.register()
        if register_checkers and hasattr(module, "register_checkers"):
            module.register_checkers()
        if register_script_commands and hasattr(module,
                                                "register_script_commands"):
            module.register_script_commands(component.registered_as)

    def register_components(self, component_list=None, register_checkers=True,
                            register_script_commands=True):
        """Calls the register method of the components in the component list

        Args:
            component_list: A list of components if an item is not a string
            it will be interpreted as a tuple or list with the second item
            as the name to use when registering. If this is None the Components
            settings will be used.

            register_checkers: If True a "register_checkers" function will be
            search in the module and called

            register_script_commands: If True a "register_script_commands"
            functions will be searched in the module and called
        """
        if component_list is None:
            component_list = self.settings.get("fife-rpg", "Components")

        if component_list is None:
            raise ValueError("No component list supplied and no"
                             " \"Components\" Setting found")

        for component in component_list:
            if not isinstance(component, basestring):
                self.register_component(
                    *component,
                    register_checkers=register_checkers,
                    register_script_commands=register_script_commands)
            else:
                self.register_component(
                    component,
                    register_checkers=register_checkers,
                    register_script_commands=register_script_commands)

    def load_actions(self, filename=None):
        """Load the action definitions from a file

        Args:
            filename: The path to the actions file. If this is set to None the
            ActionsFile or CombinedFile setting will be used.
        """
        if filename is None:
            filename = self.settings.get("fife-rpg", "ActionsFile",
                                         "actions.yaml")
            filename = self.settings.get("fife-rpg", "CombinedFile",
                                         filename)
        self._actions = {}
        actions_file = self.engine.getVFS().open(filename)
        file_data = yaml.load(actions_file)
        for name, path in file_data["Actions"].items():
            self._actions[name] = path

    def get_action_data(self, action_name):
        """Returns the class and module of the givenaction

        Args:

            action_name: The name of the action
        """
        action_path = self._actions[action_name]
        module = __import__(action_path, fromlist=[action_path])
        action = getattr(module, action_name)
        return action, module

    def register_action(self, action_name, registered_name=None):
        """Calls the actions register method.

        Args:
            action_name: Name of the action

            registered_name: Name under which the action should be registered
        """
        action = self.get_action_data(action_name)[0]
        if registered_name is not None:
            action.register(registered_name)
        else:
            action.register()

    def register_actions(self, action_list=None):
        """Calls the register method of the actions in the action list

        Args:
            action_list: A list of actions if an item is not a string
            it will be interpreted as a tuple or list with the second item
            as the name to use when registering. If this is None the Actions
            settings will be used.
        """
        if action_list is None:
            action_list = self.settings.get("fife-rpg", "Actions")

        if action_list is None:
            raise ValueError("No action list supplied and no \"Actions\" "
                             "Setting found")

        for action in action_list:
            if not isinstance(action, basestring):
                self.register_action(*action)
            else:
                self.register_action(action)

    def load_systems(self, filename=None):
        """Load the system definitions from a file

        Args:
            filename: The path to the systems file. If this is set to None the
            SystemsFile or CombinedFile setting will be used.
        """
        if filename is None:
            filename = self.settings.get("fife-rpg", "SystemsFile",
                                         "systems.yaml")
            filename = self.settings.get("fife-rpg", "CombinedFile",
                                         filename)
        self._systems = {}
        systems_file = self.engine.getVFS().open(filename)
        for name, path in yaml.load(systems_file)["Systems"].items():
            self._systems[name] = path

    def get_system_data(self, system_name):
        """Returns the class and module of the given system

        Args:

            system_name: The name of the system
        """
        system_path = self._systems[system_name]
        module = __import__(system_path, fromlist=[system_path])
        system = getattr(module, system_name)
        return system, module

    def register_system(self, system_name, registered_name=None):
        """Calls the systems register method.

        Args:
            system_name: Name of the system

            registered_name: Name under which the system should be registered
        """
        system = self.get_system_data(system_name)[0]
        if registered_name is not None:
            system.register(registered_name)
        else:
            system.register()

    def register_systems(self, system_list=None):
        """Calls the register method of the systems in the system list

        Args:
            system_list: A list of systems if an item is not a string
            it will be interpreted as a tuple or list with the second item
            as the name to use when registering. If this is None the Systems
            settings will be used.
        """
        if system_list is None:
            system_list = self.settings.get("fife-rpg", "Systems")

        if system_list is None:
            raise ValueError("No system list supplied and no \"Systems\" "
                             "Setting found")

        for system in system_list:
            if not isinstance(system, basestring):
                self.register_system(*system)
            else:
                self.register_system(system)

    def load_behaviours(self, filename=None):
        """Load the behaviour definitions from a file

        Args:
            filename: The path to the behaviours file. If this is set to None
            the BehavioursFile or CombinedFile setting will be used.
        """
        if filename is None:
            filename = self.settings.get("fife-rpg", "BehavioursFile",
                                         "behaviours.yaml")
            filename = self.settings.get("fife-rpg", "CombinedFile",
                                         filename)
        self._behaviours = {}
        behaviours_file = self.engine.getVFS().open(filename)
        for name, path in yaml.load(behaviours_file)["Behaviours"].items():
            self._behaviours[name] = path

    def get_behaviour_data(self, behaviour_name):
        """Returns the class and module of the given behaviour

        Args:

            behaviour_name: The name of the behaviour
        """
        behaviour_path = self._behaviours[behaviour_name]
        module = __import__(behaviour_path, fromlist=[behaviour_path])
        behaviour = getattr(module, behaviour_name)
        return behaviour, module

    def register_behaviour(self, behaviour_name, registered_name=None):
        """Calls the behaviours register method.

        Args:
            behaviour_name: Name of the behaviour

            registered_name: Name under which the behaviour should be
            registered
        """
        behaviour = self.get_behaviour_data(behaviour_name)[0]
        if registered_name is not None:
            behaviour.register(registered_name)
        else:
            behaviour.register()

    def register_behaviours(self, behaviour_list=None):
        """Calls the register method of the behaviours in the behaviour list

        Args:
            behaviour_list: A list of behaviours if an item is not a string
            it will be interpreted as a tuple or list with the second item
            as the name to use when registering. If this is None the Behaviours
            settings will be used.
        """
        if behaviour_list is None:
            behaviour_list = self.settings.get("fife-rpg", "Behaviours")

        if behaviour_list is None:
            raise ValueError("No behaviour list supplied and no"
                             " \"Behaviours\" Setting found")

        for behaviour in behaviour_list:
            if not isinstance(behaviour, basestring):
                self.register_behaviour(*behaviour)
            else:
                self.register_behaviour(behaviour)

    def load_combined(self, filepath=None):
        """Loads components, actions, systems and behaviours.

        Args:
            filepath: The path to the file. If set to None either the
            CominedFile Setting or the specific setting for the module will be
            used.
        """
        self.load_actions(filepath)
        self.load_behaviours(filepath)
        self.load_components(filepath)
        self.load_systems(filepath)

    def is_location_in_region(self, map_name, location, region_name):
        """Checks whether the location is in the region of the map

        Args:
            map_name: Name of the map. If None the current map will be used

            region_name: Name of the region

            location: A list or tuple containing the location
        """
        game_map = (self.maps[map_name]
                    if map_name is not None
                    else self.current_map)
        return game_map.is_in_region(location, region_name)

    def is_agent_in_region(self, map_name, agent_name, region_name):
        """Checks whether the agent is in the region of the map

        Args:
            map_name: Name of the map. If None the current map will be used

            region_name: Name of the region

            agent_name: Name of the agent
        """
        entity = self.world.get_entity(agent_name)
        agent = getattr(entity, Agent.registered_as)
        location = agent.position
        return self.is_location_in_region(map_name, location, region_name)

    def execute_console_command(self, command):
        """Executes a console command

        Args:
            command: The command string to execute

        Returns: The result of the command
        """
        return self._listener.onConsoleCommand(command)

    def check_agent_changes(self):
        """Checks all agents for changes"""
        extent = getattr(self.world[...], Agent.registered_as)
        extent = extent.map == self.current_map.name
        new_test = True
        for entity in extent:
            if not getattr(entity, FifeAgent.registered_as):
                new_test = False
        for agent, fifeagent in self.world.components.join(
                Agent.registered_as,
                FifeAgent.registered_as):
            map_test = agent.map == self.current_map.name

            fife_object = fifeagent.instance.getObject()
            gfx_test = (fife_object.getNamespace() == agent.namespace and
                        fife_object.getId() == agent.gfx)
            if map_test and gfx_test and new_test:
                continue
            agent.map = agent.new_map or agent.map
            agent.layer = agent.new_layer or agent.layer
            agent.position = agent.new_position or agent.position
            agent.rotation = agent.new_rotation or agent.rotation
            agent.new_map = None
            agent.new_layer = None
            agent.new_position = None
            agent.new_rotation = None

        self.update_agents(self.current_map)

    def set_global_lighting(self, red, green, blue):
        """Sets the color of the current maps lighting

        Args:
            red: The red value of the light as a float between 0.0 and 1.0

            green: The green value of the light as a float between 0.0 and 1.0

            blue: The blue value of the light as a float between 0.0 and 1.0
        """
        if self.current_map:
            self.current_map.camera.setLightingColor(red, green, blue)

    def get_global_lighting(self):
        """Returns the values of the current maps lighting"""
        if self.current_map:
            self.current_map.camera.getLightingColor()
        return (1.0, 1.0, 1.0)

    def step(self, time_delta):
        """Performs actions every frame.

        Args:
            time_delta: Time elapsed since last call to pump
        """
        if self.current_map:
            self.check_agent_changes()
            self.current_map.update_entities_fife()
            self.current_map.update_entities()
            self.current_map.update_entitities_agent()
        if self.world:
            self.world.step(time_delta)
        FifeManager.step(self, time_delta)
Example #4
0
class RPGApplication(FifeManager, ApplicationBase):
    """The main application.  It inherits fife.extensions.ApplicationBase.

    Properties:
        name: The name of the Application

        world: The fife_rpg.world.RPGWorld this application uses

        language: The language the application uses

        settings: A fife_settings.Setting instance that stores the settings of
        the application

        maps: A dictionary containing the maps the application has

        current_map: The current active map

        log_manager: The log manager of the application

        engine: A fife.Engine instance
    """
    def __init__(self, TDS):
        """Initialized the application

        Args:
            TDS: A fife_settings.Setting instance
        """
        ApplicationBase.__init__(self, TDS)
        FifeManager.__init__(self)
        self.name = self.settings.get("fife-rpg", "ProjectName")
        if self.name is None:
            raise AttributeError("The application name is not specified in"
                                 "the settings file")
        self._listener = None
        self.world = None
        self._maps = {}
        self._current_map = None
        self._languages = {}
        self._current_language = ""
        self._components = {}
        self._actions = {}
        self._systems = {}
        self._behaviours = {}
        self._map_switched_callbacks = []
        self._map_loaded_callbacks = []
        default_language = self.settings.get("i18n", "DefaultLanguage", "en")
        languages_dir = self.settings.get("i18n", "Directory", "__languages")
        for language in self.settings.get("i18n", "Languages", ("en", )):
            fallback = (language == default_language)
            self._languages[language] = gettext.translation(self.name,
                                                            languages_dir,
                                                            [language],
                                                            fallback=fallback)
        language = self.settings.get("i18n", "Language", default_language)
        self.switch_language(language)

    @property
    def language(self):
        """Returns the current set language"""
        return self._current_language

    @language.setter
    def language(self, language):
        """Sets the current language

        Args:
            language: The language to switch to
        """
        self.switch_language(language)

    @property
    def settings(self):
        """Returns the settings of the application.

        Returns:
            A fife_settings.Setting instance that contains the settings of the
            application.
        """
        return self._setting

    @property
    def log_manager(self):
        """Returns the log manager of the application.

        Returns:
            a fifelog.LogManager instance that contains the log manager of
            the application.
        """
        return self._log

    @property
    def current_map(self):
        """Returns the current active map"""
        return self._current_map

    @property
    def maps(self):
        """Returns a copy of the maps dictionary"""
        return copy(self._maps)

    @property
    def components(self):
        """Returns a copy of the available components"""
        return copy(self._components)

    @property
    def actions(self):
        """Returns a copy of the available actions"""
        return copy(self._actions)

    @property
    def systems(self):
        """Returns a copy of the available systems"""
        return copy(self._systems)

    @property
    def behaviours(self):
        """Returns a copy of the available behaviours"""
        return copy(self._behaviours)

    def switch_language(self, language):
        """Switch to the given language"""
        if language not in self._languages:
            raise KeyError("The language '%s' is not available" % language)
        if not language == self._current_language:
            self._languages[language].install()
            self._current_language = language

    def update_game_variables(self, variables):
        """Called by the game environment when it wants to update its globals

        Args:
            globals: The globals dictionary of the GameEnvironment that is
            filled by the GameScene
        """
        app_module = imp.new_module(_SCRIPTING_MODULE)
        app_module.__dict__["current_map"] = self.current_map
        app_module.__dict__["maps"] = self.maps
        variables[_SCRIPTING_MODULE] = app_module

    def add_map(self, identifier, game_map):
        """Adds a map to the maps dictionary.

        Args:
            identifier: The identifier of the map

            game_map: A Map instance.
        """
        if identifier not in self._maps:
            self._maps[identifier] = game_map
        else:
            raise AlreadyRegisteredError(identifier, "Map")

    def update_agents(self, game_map):
        """Updates the map to be in sync with the entities

        Args:
            game_map: The name of the map, or a Map instance
        """
        if isinstance(game_map, str):
            game_map = self.maps[game_map]
        if isinstance(game_map, str):  # The map is not yet loaded
            return
        object_namespace = self.settings.get("fife-rpg", "ObjectNamespace",
                                             "fife-rpg")
        fife_model = self.engine.getModel()
        game_map.update_entities()
        for entity in game_map.entities:
            agent = getattr(entity, Agent.registered_as)
            namespace = agent.namespace or object_namespace
            map_object = fife_model.getObject(agent.gfx, namespace)
            if not map_object:
                raise RuntimeError(
                    "There is no object %s in the namespace %s" %
                    (agent.gfx, namespace))
            general = getattr(entity, General.registered_as)
            layer = game_map.get_layer(agent.layer)
            fife_instance = layer.getInstance(general.identifier)
            if fife_instance:
                fife_object = fife_instance.getObject()
                if (fife_object.getId() != map_object.getId()
                        or fife_object.getNamespace() !=
                        map_object.getNamespace()):
                    layer.deleteInstance(fife_instance)
                    fife_instance = None
            if not fife_instance:
                position = agent.position
                fife_instance = layer.createInstance(
                    map_object,
                    fife.ExactModelCoordinate(position.x, position.y,
                                              position.z), general.identifier)
                fife_instance.setRotation(agent.rotation)
                visual = fife.InstanceVisual.create(fife_instance)
                if map_object.getAction('default'):
                    target = fife.Location(game_map.actor_layer)
                    fife_instance.actRepeat('default', target)
                fifeagent = getattr(entity, FifeAgent.registered_as)
                behaviour_class = BehaviourManager.get_behaviour(
                    agent.behaviour_type)
                if behaviour_class is None:
                    raise RuntimeError("There is no registered behaviour %s" %
                                       agent.behaviour_type)
                behaviour = behaviour_class(**agent.behaviour_args)
                behaviour.agent = fife_instance
                fifeagent.behaviour = behaviour
                fifeagent.layer = layer
                fifeagent.instance = fife_instance
                setup_behaviour(fifeagent)
                fifeagent.behaviour.idle()
            else:
                visual = fife_instance.get2dGfxVisual()
            visual.setStackPosition(STACK_POSITION[agent.type])

    def map_loded(self, identifier):
        """Called from Map instances after the map was loaded

        Args:
            identifier: The identifier of the loaded map
        """
        if identifier in self._maps:
            game_map = self.maps[identifier]
            for callback in self._map_loaded_callbacks:
                callback(game_map)
            self.update_agents(game_map)

        else:
            raise LookupError("The map with the identifier '%s' cannot be "
                              "found" % (identifier))

    def switch_map(self, name):
        """Switches to the given map.

        Args:
            name: The name of the map
        """
        old_map = None
        if self._current_map:
            old_map = self._current_map.name
            self._current_map.deactivate()
            self._current_map = None
        if name is None:
            for callback in self._map_switched_callbacks:
                callback(old_map, name)
            return
        if name in self._maps:
            self._current_map = self.maps[name]
            self._current_map.activate()
            for callback in self._map_switched_callbacks:
                callback(old_map, name)
        else:
            raise LookupError("The map with the name '%s' cannot be found" %
                              (name))

    def add_map_switch_callback(self, callback):
        """Adds a callback function which gets called after
        the map switched

        Args:
            callback: The function to add
        """
        if callback not in self._map_switched_callbacks:
            self._map_switched_callbacks.append(callback)

    def remove_map_switch_callback(self, callback):
        """Removes a callback function that got called after the map
        switched.

        Args:
            callback: The function to remove
        """
        if callback in self._map_switched_callbacks:
            index = self._map_switched_callbacks.index(callback)
            del self._map_switched_callbacks[index]

    def add_map_load_callback(self, callback):
        """Adds a callback function which gets called after
        a map was loaded

        Args:
            callback: The function to add
        """
        if callback not in self._map_loaded_callbacks:
            self._map_loaded_callbacks.append(callback)

    def remove_map_load_callback(self, callback):
        """Removes a callback function that got called after a map
        was loaded.

        Args:
            callback: The function to remove
        """
        if callback in self._map_loaded_callbacks:
            index = self._map_loaded_callbacks.index(callback)
            del self._map_loaded_callbacks[index]

    def load_maps(self):
        """Load the names of the available maps from a map file."""
        self._maps = {}
        maps_path = self.settings.get("fife-rpg", "MapsPath", "maps")
        vfs = self.engine.getVFS()
        filename = os.path.join(maps_path, "maps.yaml")
        if not os.path.exists(filename):
            return
        maps_file = vfs.open(filename)
        maps_doc = yaml.load(maps_file)
        maps_path = self.settings.get("fife-rpg", "MapsPath", "maps")
        camera = self.settings.get("fife-rpg", "Camera", "main")

        for name, filename in maps_doc["Maps"].items():
            filepath = os.path.join(maps_path, filename + '.xml')
            identifier = etree.parse(filepath).getroot().attrib["id"]
            regions_filename = ("%s_regions.yaml" %
                                os.path.splitext(filepath)[0])
            regions = {}
            try:
                regions_file = self.engine.getVFS().open(regions_filename)
            except fife.NotFound:
                regions_file = None
            if regions_file is not None:
                regions_data = yaml.load(regions_file)
                if regions_data is not None:
                    for region_name, region_data in (iter(
                            regions_data.items())):
                        region = fife.DoubleRect(x=region_data[0],
                                                 y=region_data[1],
                                                 width=region_data[2],
                                                 height=region_data[3])
                        regions[region_name] = region
            game_map = GameMap(filepath, name, camera, regions, self)
            self.add_map(identifier, game_map)

    def create_world(self):
        """Creates the world used by this application"""
        self.world = RPGWorld(self)
        GameVariables.add_callback(self.update_game_variables)
        ScriptingSystem.register_command("set_global_lighting",
                                         self.set_global_lighting,
                                         _SCRIPTING_MODULE)
        ScriptingSystem.register_command("get_global_lighting",
                                         self.get_global_lighting,
                                         _SCRIPTING_MODULE)
        ScriptingSystem.register_command("is_location_in_region",
                                         self.is_location_in_region,
                                         _SCRIPTING_MODULE)
        ScriptingSystem.register_command("is_agent_in_region",
                                         self.is_agent_in_region,
                                         _SCRIPTING_MODULE)

    def request_quit(self):
        """Sends the quit command to the application's listener.

        We could set self.quitRequested to true also but this is a
        good example on how to build and dispatch a fife.Command.
        """
        cmd = fife.Command()
        cmd.setSource(None)
        cmd.setCommandType(fife.CMD_QUIT_GAME)
        self.engine.getEventManager().dispatchCommand(cmd)

    def screen_coords_to_map_coords(self, click, layer):
        """Converts the screen coordinates to coordinates on the active map

        Args:

           click: Screen coordinates as fife.ScreenPoint or position tuple

           layer: The name of the layer the converted position should be on

        Returns: Converted coordinates as fife.Location
        """
        active_map = self.current_map
        if active_map is None:
            return None
        if not isinstance(click, fife.ScreenPoint):
            click = fife.ScreenPoint(click[0], click[1])
        coord = active_map.camera.toMapCoordinates(click, False)
        coord.z = 0
        location = fife.Location(active_map.get_layer(layer))
        location.setMapCoordinates(coord)
        return location

    def load_components(self, filename=None):
        """Load the component definitions from a file

        Args:
            filename: The path to the components file. If this is set to None
            the ComponentsFile or CombinedFile setting will be used.
        """
        if filename is None:
            filename = self.settings.get("fife-rpg", "ComponentsFile",
                                         "components.yaml")
            filename = self.settings.get("fife-rpg", "CombinedFile", filename)
        self._components = {}
        components_file = self.engine.getVFS().open(filename)
        for name, path in yaml.load(components_file)["Components"].items():
            self._components[name] = path

    def get_component_data(self, component_name):
        """Returns the class and module of the given component

        Args:

            component_name: The name of the component
        """
        component_path = self._components[component_name]
        module = __import__(component_path, fromlist=[component_path])
        component = getattr(module, component_name)
        return component, module

    def register_component(self,
                           component_name,
                           registered_name=None,
                           register_checkers=True,
                           register_script_commands=True):
        """Calls the components register method.

        Args:
            component_name: Name of the component

            registered_name: Name under which the component should be
            registered

            register_checkers: If True a "register_checkers" function will be
            searched in the module and called

            register_script_commands: If True a "register_script_commands"
            functions will be searched in the module and called
        """
        component, module = self.get_component_data(component_name)
        if registered_name is not None:
            component.register(registered_name)
        else:
            component.register()
        if register_checkers and hasattr(module, "register_checkers"):
            module.register_checkers()
        if register_script_commands and hasattr(module,
                                                "register_script_commands"):
            module.register_script_commands(component.registered_as)

    def register_components(self,
                            component_list=None,
                            register_checkers=True,
                            register_script_commands=True):
        """Calls the register method of the components in the component list

        Args:
            component_list: A list of components if an item is not a string
            it will be interpreted as a tuple or list with the second item
            as the name to use when registering. If this is None the Components
            settings will be used.

            register_checkers: If True a "register_checkers" function will be
            search in the module and called

            register_script_commands: If True a "register_script_commands"
            functions will be searched in the module and called
        """
        if component_list is None:
            component_list = self.settings.get("fife-rpg", "Components")

        if component_list is None:
            raise ValueError("No component list supplied and no"
                             " \"Components\" Setting found")

        for component in component_list:
            if not isinstance(component, basestring):
                self.register_component(
                    *component,
                    register_checkers=register_checkers,
                    register_script_commands=register_script_commands)
            else:
                self.register_component(
                    component,
                    register_checkers=register_checkers,
                    register_script_commands=register_script_commands)

    def load_actions(self, filename=None):
        """Load the action definitions from a file

        Args:
            filename: The path to the actions file. If this is set to None the
            ActionsFile or CombinedFile setting will be used.
        """
        if filename is None:
            filename = self.settings.get("fife-rpg", "ActionsFile",
                                         "actions.yaml")
            filename = self.settings.get("fife-rpg", "CombinedFile", filename)
        self._actions = {}
        actions_file = self.engine.getVFS().open(filename)
        file_data = yaml.load(actions_file)
        for name, path in file_data["Actions"].items():
            self._actions[name] = path

    def get_action_data(self, action_name):
        """Returns the class and module of the givenaction

        Args:

            action_name: The name of the action
        """
        action_path = self._actions[action_name]
        module = __import__(action_path, fromlist=[action_path])
        action = getattr(module, action_name)
        return action, module

    def register_action(self, action_name, registered_name=None):
        """Calls the actions register method.

        Args:
            action_name: Name of the action

            registered_name: Name under which the action should be registered
        """
        action = self.get_action_data(action_name)[0]
        if registered_name is not None:
            action.register(registered_name)
        else:
            action.register()

    def register_actions(self, action_list=None):
        """Calls the register method of the actions in the action list

        Args:
            action_list: A list of actions if an item is not a string
            it will be interpreted as a tuple or list with the second item
            as the name to use when registering. If this is None the Actions
            settings will be used.
        """
        if action_list is None:
            action_list = self.settings.get("fife-rpg", "Actions")

        if action_list is None:
            raise ValueError("No action list supplied and no \"Actions\" "
                             "Setting found")

        for action in action_list:
            if not isinstance(action, basestring):
                self.register_action(*action)
            else:
                self.register_action(action)

    def load_systems(self, filename=None):
        """Load the system definitions from a file

        Args:
            filename: The path to the systems file. If this is set to None the
            SystemsFile or CombinedFile setting will be used.
        """
        if filename is None:
            filename = self.settings.get("fife-rpg", "SystemsFile",
                                         "systems.yaml")
            filename = self.settings.get("fife-rpg", "CombinedFile", filename)
        self._systems = {}
        systems_file = self.engine.getVFS().open(filename)
        for name, path in yaml.load(systems_file)["Systems"].items():
            self._systems[name] = path

    def get_system_data(self, system_name):
        """Returns the class and module of the given system

        Args:

            system_name: The name of the system
        """
        system_path = self._systems[system_name]
        module = __import__(system_path, fromlist=[system_path])
        system = getattr(module, system_name)
        return system, module

    def register_system(self, system_name, registered_name=None):
        """Calls the systems register method.

        Args:
            system_name: Name of the system

            registered_name: Name under which the system should be registered
        """
        system = self.get_system_data(system_name)[0]
        if registered_name is not None:
            system.register(registered_name)
        else:
            system.register()

    def register_systems(self, system_list=None):
        """Calls the register method of the systems in the system list

        Args:
            system_list: A list of systems if an item is not a string
            it will be interpreted as a tuple or list with the second item
            as the name to use when registering. If this is None the Systems
            settings will be used.
        """
        if system_list is None:
            system_list = self.settings.get("fife-rpg", "Systems")

        if system_list is None:
            raise ValueError("No system list supplied and no \"Systems\" "
                             "Setting found")

        for system in system_list:
            if not isinstance(system, basestring):
                self.register_system(*system)
            else:
                self.register_system(system)

    def load_behaviours(self, filename=None):
        """Load the behaviour definitions from a file

        Args:
            filename: The path to the behaviours file. If this is set to None
            the BehavioursFile or CombinedFile setting will be used.
        """
        if filename is None:
            filename = self.settings.get("fife-rpg", "BehavioursFile",
                                         "behaviours.yaml")
            filename = self.settings.get("fife-rpg", "CombinedFile", filename)
        self._behaviours = {}
        behaviours_file = self.engine.getVFS().open(filename)
        for name, path in yaml.load(behaviours_file)["Behaviours"].items():
            self._behaviours[name] = path

    def get_behaviour_data(self, behaviour_name):
        """Returns the class and module of the given behaviour

        Args:

            behaviour_name: The name of the behaviour
        """
        behaviour_path = self._behaviours[behaviour_name]
        module = __import__(behaviour_path, fromlist=[behaviour_path])
        behaviour = getattr(module, behaviour_name)
        return behaviour, module

    def register_behaviour(self, behaviour_name, registered_name=None):
        """Calls the behaviours register method.

        Args:
            behaviour_name: Name of the behaviour

            registered_name: Name under which the behaviour should be
            registered
        """
        behaviour = self.get_behaviour_data(behaviour_name)[0]
        if registered_name is not None:
            behaviour.register(registered_name)
        else:
            behaviour.register()

    def register_behaviours(self, behaviour_list=None):
        """Calls the register method of the behaviours in the behaviour list

        Args:
            behaviour_list: A list of behaviours if an item is not a string
            it will be interpreted as a tuple or list with the second item
            as the name to use when registering. If this is None the Behaviours
            settings will be used.
        """
        if behaviour_list is None:
            behaviour_list = self.settings.get("fife-rpg", "Behaviours")

        if behaviour_list is None:
            raise ValueError("No behaviour list supplied and no"
                             " \"Behaviours\" Setting found")

        for behaviour in behaviour_list:
            if not isinstance(behaviour, basestring):
                self.register_behaviour(*behaviour)
            else:
                self.register_behaviour(behaviour)

    def load_combined(self, filepath=None):
        """Loads components, actions, systems and behaviours.

        Args:
            filepath: The path to the file. If set to None either the
            CominedFile Setting or the specific setting for the module will be
            used.
        """
        self.load_actions(filepath)
        self.load_behaviours(filepath)
        self.load_components(filepath)
        self.load_systems(filepath)

    def is_location_in_region(self, map_name, location, region_name):
        """Checks whether the location is in the region of the map

        Args:
            map_name: Name of the map. If None the current map will be used

            region_name: Name of the region

            location: A list or tuple containing the location
        """
        game_map = (self.maps[map_name]
                    if map_name is not None else self.current_map)
        return game_map.is_in_region(location, region_name)

    def is_agent_in_region(self, map_name, agent_name, region_name):
        """Checks whether the agent is in the region of the map

        Args:
            map_name: Name of the map. If None the current map will be used

            region_name: Name of the region

            agent_name: Name of the agent
        """
        entity = self.world.get_entity(agent_name)
        agent = getattr(entity, Agent.registered_as)
        location = agent.position
        return self.is_location_in_region(map_name, location, region_name)

    def execute_console_command(self, command):
        """Executes a console command

        Args:
            command: The command string to execute

        Returns: The result of the command
        """
        return self._listener.onConsoleCommand(command)

    def check_agent_changes(self):
        """Checks all agents for changes"""
        extent = getattr(self.world[...], Agent.registered_as)
        extent = extent.map == self.current_map.name
        new_test = True
        for entity in extent:
            if not getattr(entity, FifeAgent.registered_as):
                new_test = False
        for agent, fifeagent in self.world.components.join(
                Agent.registered_as, FifeAgent.registered_as):
            map_test = agent.map == self.current_map.name

            fife_object = fifeagent.instance.getObject()
            gfx_test = (fife_object.getNamespace() == agent.namespace
                        and fife_object.getId() == agent.gfx)
            if map_test and gfx_test and new_test:
                continue
            agent.map = agent.new_map or agent.map
            agent.layer = agent.new_layer or agent.layer
            agent.position = agent.new_position or agent.position
            agent.rotation = agent.new_rotation or agent.rotation
            agent.new_map = None
            agent.new_layer = None
            agent.new_position = None
            agent.new_rotation = None

        self.update_agents(self.current_map)

    def set_global_lighting(self, red, green, blue):
        """Sets the color of the current maps lighting

        Args:
            red: The red value of the light as a float between 0.0 and 1.0

            green: The green value of the light as a float between 0.0 and 1.0

            blue: The blue value of the light as a float between 0.0 and 1.0
        """
        if self.current_map:
            self.current_map.camera.setLightingColor(red, green, blue)

    def get_global_lighting(self):
        """Returns the values of the current maps lighting"""
        if self.current_map:
            self.current_map.camera.getLightingColor()
        return (1.0, 1.0, 1.0)

    def step(self, time_delta):
        """Performs actions every frame.

        Args:
            time_delta: Time elapsed since last call to pump
        """
        if self.current_map:
            self.check_agent_changes()
            self.current_map.update_entities_fife()
            self.current_map.update_entities()
            self.current_map.update_entitities_agent()
        if self.world:
            self.world.step(time_delta)
        FifeManager.step(self, time_delta)