Index: /code/trunk/data/levels/portals.oxw
===================================================================
--- /code/trunk/data/levels/portals.oxw	(revision 8457)
+++ /code/trunk/data/levels/portals.oxw	(revision 8457)
@@ -0,0 +1,111 @@
+ 
+<LevelInfo
+ name = "Portals"
+ description = "Level for testing portals"
+ tags = "tutorial"
+/>
+
+<?lua
+  include("HUDTemplates3.oxo")
+  include("stats.oxo")
+  include("templates/spaceshipAssff.oxt")
+  include("templates/pickupRepresentationTemplates.oxt")
+  include("templates/lodInformation.oxt")
+?>
+
+<Level
+ name         = "Presentation"
+ description  = "A simple testlevel"
+>
+  <templates>
+    <Template link=lodtemplate_default />
+  </templates>
+
+  <Scene
+   ambientlight = "0.5, 0.5, 0.5"
+   skybox       = "Orxonox/skypanoramagen1"
+  >
+
+    <Template name=PortalDefault>
+        <PortalEndPoint>
+            <attached>
+                <Billboard material="Portals/Default" />
+            </attached>
+        </PortalEndPoint>
+    </Template>
+
+    <PortalEndPoint position="0,0,0" id="1" distance="40" target="MobileEntity" design="PortalDefault"/>
+    <PortalEndPoint position="-100,0,0" id="2" distance="40" target="MobileEntity" design="PortalDefault"/>
+    <PortalLink fromID="1" toID="2" />
+    <PortalLink fromID="2" toID="1" />
+
+    <!--PickupSpawner position="-200,0,0" triggerDistance="10" respawnTime="10" maxSpawnedItems="10">
+      <pickup>
+        <DronePickup template=dronepickup />
+      </pickup>
+    </PickupSpawner-->
+
+    <Light type=directional position="0,0,0" direction="0.253, 0.593, -0.765" diffuse="1.0, 0.9, 0.9, 1.0" specular="1.0, 0.9, 0.9, 1.0" />
+
+    <SpawnPoint position="200,0,0" lookat="0,0,0" spawnclass=SpaceShip pawndesign=spaceshipassff />
+
+    <GlobalShader compositor="Bloom" visible=false>
+      <events>
+        <visibility>
+          <DistanceTrigger position="0,0,0" distance=30 target="Spectator" switch=true />
+        </visibility>
+      </events>
+    </GlobalShader>
+
+
+<!--
+    <Model position="0,0,0" scale=8 mesh="ast1.mesh" />
+    <StaticEntity position="0,0,0" collisionType=static>
+      <collisionShapes>
+        <SphereCollisionShape radius="20" />
+      </collisionShapes>
+    </StaticEntity>
+-->
+
+
+<!--
+    <?lua
+      for i = 1, 70, 1 do
+    ?>
+      <MovableEntity position="<?lua print(math.random() * 6000 - 3000)?>, <?lua print(math.random() * 6000 - 3000) ?>, <?lua print(math.random() * 1000 + 3000) ?>" rotationaxis="<?lua print(math.random()) ?>, <?lua print(math.random()) ?>, <?lua print(math.random()) ?>" rotationrate="<?lua print(math.random() * 30 + 5) ?>">
+        <attached>
+          <Model scale="<?lua print(math.random() * 30 + 10) ?>" mesh="ast<?lua print( math.mod(i,6) + 1) ?>.mesh" shadow=false />
+        </attached>
+      </MovableEntity>
+      <MovableEntity position="<?lua print(math.random() * 6000 - 3000)?>, <?lua print(math.random() * 6000 - 3000) ?>, <?lua print(math.random() * -1000 - 3000) ?>" rotationaxis="<?lua print(math.random()) ?>, <?lua print(math.random()) ?>, <?lua print(math.random()) ?>" rotationrate="<?lua print(math.random() * 30 + 5) ?>">
+        <attached>
+          <Model scale="<?lua print(math.random() * 30 + 10) ?>" mesh="ast<?lua print( math.mod(i,6) + 1) ?>.mesh" shadow=false />
+        </attached>
+      </MovableEntity>
+
+      <MovableEntity position="<?lua print(math.random() * 6000 - 3000)?>, <?lua print(math.random() * 1000 + 3000) ?>, <?lua print(math.random() * 6000 - 3000) ?>" rotationaxis="<?lua print(math.random()) ?>, <?lua print(math.random()) ?>, <?lua print(math.random()) ?>" rotationrate="<?lua print(math.random() * 30 + 5) ?>">
+        <attached>
+          <Model scale="<?lua print(math.random() * 30 + 10) ?>" mesh="ast<?lua print( math.mod(i,6) + 1) ?>.mesh" shadow=false />
+        </attached>
+      </MovableEntity>
+      <MovableEntity position="<?lua print(math.random() * 6000 - 3000)?>, <?lua print(math.random() * -1000 - 3000) ?>, <?lua print(math.random() * 6000 - 3000) ?>" rotationaxis="<?lua print(math.random()) ?>, <?lua print(math.random()) ?>, <?lua print(math.random()) ?>" rotationrate="<?lua print(math.random() * 30 + 5) ?>">
+        <attached>
+          <Model scale="<?lua print(math.random() * 30 + 10) ?>" mesh="ast<?lua print( math.mod(i,6) + 1) ?>.mesh" shadow=false />
+        </attached>
+      </MovableEntity>
+
+      <MovableEntity position="<?lua print(math.random() * 1000 + 3000)?>, <?lua print(math.random() * 6000 - 3000) ?>, <?lua print(math.random() * 6000 - 3000) ?>" rotationaxis="<?lua print(math.random()) ?>, <?lua print(math.random()) ?>, <?lua print(math.random()) ?>" rotationrate="<?lua print(math.random() * 30 + 5) ?>">
+        <attached>
+          <Model scale="<?lua print(math.random() * 30 + 10) ?>" mesh="ast<?lua print( math.mod(i,6) + 1) ?>.mesh" shadow=false />
+        </attached>
+      </MovableEntity>
+      <MovableEntity position="<?lua print(math.random() * -1000 - 3000)?>, <?lua print(math.random() * 6000 - 3000) ?>, <?lua print(math.random() * 6000 - 3000) ?>" rotationaxis="<?lua print(math.random()) ?>, <?lua print(math.random()) ?>, <?lua print(math.random()) ?>" rotationrate="<?lua print(math.random() * 30 + 5) ?>">
+        <attached>
+          <Model scale="<?lua print(math.random() * 30 + 10) ?>" mesh="ast<?lua print( math.mod(i,6) + 1) ?>.mesh" shadow=false />
+        </attached>
+      </MovableEntity>
+    <?lua end ?>
+-->
+
+  </Scene>
+</Level>
Index: /code/trunk/src/modules/CMakeLists.txt
===================================================================
--- /code/trunk/src/modules/CMakeLists.txt	(revision 8456)
+++ /code/trunk/src/modules/CMakeLists.txt	(revision 8457)
@@ -32,4 +32,5 @@
 ADD_SUBDIRECTORY(pickup)
 ADD_SUBDIRECTORY(pong)
+ADD_SUBDIRECTORY(portals)
 ADD_SUBDIRECTORY(questsystem)
 ADD_SUBDIRECTORY(weapons)
Index: /code/trunk/src/modules/objects/triggers/MultiTrigger.h
===================================================================
--- /code/trunk/src/modules/objects/triggers/MultiTrigger.h	(revision 8456)
+++ /code/trunk/src/modules/objects/triggers/MultiTrigger.h	(revision 8457)
@@ -146,4 +146,6 @@
             inline bool isTarget(BaseObject* target)
                 { if(target == NULL) return true; else return targetMask_.isIncluded(target->getIdentifier()); }
+                
+            void addTarget(const std::string& targets); //!< Add some target to the MultiTrigger.
 
         protected:
@@ -158,6 +160,5 @@
             void broadcast(bool status); //!< Helper method. Broadcasts an Event for every object that is a target.
 
-            void addTarget(const std::string& targets); //!< Add some target to the MultiTrigger.
-            void removeTarget(const std::string& targets); //!< Remove some target from the MultiTrigger.
+            void removeTarget(const std::string& target); //!< Remove some target from the MultiTrigger.
 
             /**
Index: /code/trunk/src/modules/portals/CMakeLists.txt
===================================================================
--- /code/trunk/src/modules/portals/CMakeLists.txt	(revision 8457)
+++ /code/trunk/src/modules/portals/CMakeLists.txt	(revision 8457)
@@ -0,0 +1,16 @@
+SET_SOURCE_FILES(PORTALS_SRC_FILES
+  PortalEndPoint.cc
+  PortalLink.cc
+)
+
+ORXONOX_ADD_LIBRARY(portals
+  MODULE
+  FIND_HEADER_FILES
+  TOLUA_FILES
+  PCH_FILE
+    PortalsPrecompiledHeaders.h
+  LINK_LIBRARIES
+    orxonox
+    objects
+  SOURCE_FILES ${PORTALS_SRC_FILES}
+)
Index: /code/trunk/src/modules/portals/PortalEndPoint.cc
===================================================================
--- /code/trunk/src/modules/portals/PortalEndPoint.cc	(revision 8457)
+++ /code/trunk/src/modules/portals/PortalEndPoint.cc	(revision 8457)
@@ -0,0 +1,98 @@
+#include "PortalEndPoint.h"
+#include "core/XMLPort.h"
+#include "objects/triggers/MultiTriggerContainer.h"
+#include "portals/PortalLink.h"
+#include "worldentities/MobileEntity.h"
+
+
+namespace orxonox
+{
+    CreateFactory(PortalEndPoint);
+    
+    /*static*/ const std::string PortalEndPoint::EVENTFUNCTIONNAME = "execute";
+
+    std::map<unsigned int, PortalEndPoint *> PortalEndPoint::idMap_s;
+
+    PortalEndPoint::PortalEndPoint(BaseObject* creator) : StaticEntity(creator), id_(0), trigger_(new DistanceMultiTrigger(this))
+    {
+        RegisterObject(PortalEndPoint);
+        this->trigger_->setName("portal");
+        this->attach(trigger_);
+    }
+    
+    PortalEndPoint::~PortalEndPoint()
+    {
+    
+    }
+
+    void PortalEndPoint::XMLPort(Element& xmlelement, XMLPort::Mode mode)
+    {
+        SUPER(PortalEndPoint, XMLPort, xmlelement, mode);
+        
+        XMLPortParam(PortalEndPoint, "id", setID, getID, xmlelement, mode);
+        XMLPortParam(PortalEndPoint, "design", setTemplate, getTemplate, xmlelement, mode);
+        XMLPortParamExtern(PortalEndPoint, DistanceMultiTrigger, this->trigger_, "distance", setDistance, getDistance, xmlelement, mode);
+        XMLPortParamLoadOnly(PortalEndPoint, "target", setTarget, xmlelement, mode).defaultValues("Pawn");
+        
+        // Add the DistanceMultiTrigger as event source.
+        this->addEventSource(this->trigger_, EVENTFUNCTIONNAME);
+        
+        if(mode == XMLPort::LoadObject)
+        {
+            PortalEndPoint::idMap_s[this->id_] = this;
+        }
+    }
+
+    void PortalEndPoint::XMLEventPort(Element& xmlelement, XMLPort::Mode mode)
+    {
+        SUPER(PortalEndPoint, XMLEventPort, xmlelement, mode);
+        
+        XMLPortEventSink(PortalEndPoint, BaseObject, EVENTFUNCTIONNAME, execute, xmlelement, mode);
+    }
+
+    bool PortalEndPoint::execute(bool bTriggered, BaseObject* trigger)
+    {
+        if(!this->isActive())
+            return true;
+        
+        MultiTriggerContainer * cont = orxonox_cast<MultiTriggerContainer *>(trigger);
+        if(cont == 0)
+            return true;
+        
+        DistanceMultiTrigger * originatingTrigger = orxonox_cast<DistanceMultiTrigger *>(cont->getOriginator());
+        if(originatingTrigger == 0)
+        {
+            COUT(1) << "originator no DistanceMultiTrigger\n" << std::endl;
+            return true;
+        }
+        
+        MobileEntity * entity = orxonox_cast<MobileEntity *>(cont->getData());
+        if(entity == 0)
+            return true;
+        
+        if(bTriggered)
+        {
+            if(this->recentlyJumpedOut_.find(entity) == this->recentlyJumpedOut_.end())  // only enter the portal if not just jumped out of it
+            {
+                PortalLink::use(entity, this);
+            }
+        }
+        else
+        {
+            this->recentlyJumpedOut_.erase(entity);
+        }
+        
+        return true;
+    }
+
+    void PortalEndPoint::jumpOut(MobileEntity* entity)
+    {
+        this->recentlyJumpedOut_.insert(entity);
+        
+        entity->setPosition(this->getWorldPosition());
+        entity->rotate(this->getWorldOrientation());
+        entity->setVelocity(this->getWorldOrientation() * entity->getVelocity());
+        entity->setVelocity(entity->getVelocity() * 1.5);
+    }
+
+}
Index: /code/trunk/src/modules/portals/PortalEndPoint.h
===================================================================
--- /code/trunk/src/modules/portals/PortalEndPoint.h	(revision 8457)
+++ /code/trunk/src/modules/portals/PortalEndPoint.h	(revision 8457)
@@ -0,0 +1,78 @@
+#ifndef _PortalEndPoint_H__
+#define _PortalEndPoint_H__
+
+#include "portals/PortalsPrereqs.h"
+
+#include <set>
+#include <string>
+#include <map>
+
+#include "worldentities/StaticEntity.h"
+#include "graphics/Billboard.h"
+#include "objects/triggers/DistanceMultiTrigger.h"
+#include "core/EventIncludes.h"
+
+namespace orxonox
+{
+    class _PortalsExport PortalEndPoint : public StaticEntity
+    {
+        public:
+            PortalEndPoint(BaseObject* creator);
+            virtual ~PortalEndPoint();
+            virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
+            inline void setTarget(const std::string & target)                 //!< add types which are allowed to activate the PortalEndPoint
+            {
+                this->trigger_->addTarget(target);
+            }
+            
+            void XMLEventPort(Element& xmlelement, XMLPort::Mode mode);
+            static std::map<unsigned int, PortalEndPoint *> idMap_s; //!< Maps the id of each PortalEndPoint to a pointer to that PortalEndPoint
+            inline void setID(unsigned int id)
+            {
+                this->id_ = id;
+            }
+            
+            inline unsigned int getID() const
+            {
+                return this->id_;
+            }
+            
+            /// \brief Set templateName_ (the name of the design Template) and add that Template to this Object
+            inline void setTemplate(const std::string & name)
+            {
+                this->templateName_ = name;
+                this->addTemplate(name);
+            }
+
+            /// \brief Get the name of the attached design template
+            inline const std::string & getTemplate()
+            {
+                return this->templateName_;
+            }
+
+            /*! \brief This function is called each time the DistanceMultiTrigger of this PortalEndPoint changed
+             * \param bTriggered true if the trigger was triggered on, false if the trigger has switched to off
+             * \param trigger the MultiTriggerContainer containing the triggering BaseObject (and trigger_ the portal's MultiDistanceTrigger which we already know)
+             * 
+             * if bTriggered is \c true the triggering entity enters this portal (if it is an entrance)
+             * otherwise the triggering entity is removed from the set of entities who recently jumped out of this portal */
+            bool execute(bool bTriggered, BaseObject* trigger);
+
+            /*! \brief Let an Entity jump out of this portal no matter where it was before
+             * \param entity The Entity which should jump out of this portal */
+            void jumpOut(MobileEntity * entity);
+        protected:
+            
+        private:
+            static const std::string EVENTFUNCTIONNAME; //!< = "execute"
+            
+            unsigned int id_;            //!< the hopefully (depends on the writer of the levelfile) unique id, which is used to establish links between PortalEndPoints
+            DistanceMultiTrigger * trigger_;      //!< the DistanceMultiTrigger which notices near entities of the defined type
+            std::string templateName_;            //!< The name of the design template used for this endpoint
+
+            std::set<MobileEntity *> recentlyJumpedOut_; //!< Entities which recently jumped out of this EndPoint, hence they shouldn't be pulled in again if the endpoint is the beginning of a link
+    };
+
+}
+
+#endif /* _Portals_H__ */
Index: /code/trunk/src/modules/portals/PortalLink.cc
===================================================================
--- /code/trunk/src/modules/portals/PortalLink.cc	(revision 8457)
+++ /code/trunk/src/modules/portals/PortalLink.cc	(revision 8457)
@@ -0,0 +1,52 @@
+#include "PortalLink.h"
+#include "core/XMLPort.h"
+#include "objects/triggers/MultiTriggerContainer.h"
+#include "worldentities/MobileEntity.h"
+
+namespace orxonox
+{
+    CreateFactory(PortalLink);
+
+    std::map<PortalEndPoint *, PortalEndPoint *> PortalLink::links_s;
+    
+    PortalLink::PortalLink(BaseObject* creator) : BaseObject(creator), fromID_(0), toID_(0), from_(0), to_(0)
+    {
+        RegisterObject(PortalLink);
+    }
+    
+    PortalLink::~PortalLink()
+    {
+    }
+    
+    void PortalLink::XMLPort(Element& xmlelement, XMLPort::Mode mode)
+    {
+        SUPER(PortalLink, XMLPort, xmlelement, mode);
+        XMLPortParam(PortalLink, "fromID", setFromID, getFromID, xmlelement, mode);
+        XMLPortParam(PortalLink, "toID", setToID, getToID, xmlelement, mode);
+
+        if(mode == XMLPort::LoadObject)
+        {
+            PortalEndPoint * from = PortalEndPoint::idMap_s[this->fromID_];
+            PortalEndPoint * to   = PortalEndPoint::idMap_s[this->toID_];
+            PortalLink::links_s[from] = to;
+        }
+    }
+
+    void PortalLink::use(MobileEntity* entity, PortalEndPoint * entrance)
+    {
+        if(entrance == 0)
+        {
+            // TODO COUT
+            return;
+        }
+        
+        std::map<PortalEndPoint *, PortalEndPoint *>::iterator endpoint = PortalLink::links_s.find(entrance);
+        
+        if(endpoint == PortalLink::links_s.end())  // entrance has no corresponding exit
+            return;
+        
+        endpoint->second->jumpOut(entity);
+    }
+
+
+}
Index: /code/trunk/src/modules/portals/PortalLink.h
===================================================================
--- /code/trunk/src/modules/portals/PortalLink.h	(revision 8457)
+++ /code/trunk/src/modules/portals/PortalLink.h	(revision 8457)
@@ -0,0 +1,50 @@
+#ifndef _PortalLink_H__
+#define _PortalLink_H__
+
+#include "portals/PortalsPrereqs.h"
+#include "tools/interfaces/Tickable.h"
+#include "core/BaseObject.h"
+#include "PortalEndPoint.h"
+#include "objects/eventsystem/EventListener.h"
+
+#include <map>
+
+namespace orxonox
+{
+    class _PortalsExport PortalLink : public BaseObject
+    {
+        public:
+            PortalLink(BaseObject* creator);
+            virtual ~PortalLink();
+            virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
+            inline void setFromID(unsigned int from)    //!< set the ID of the PortalEndPoint which should act as the entrance of this link
+            {
+                this->fromID_ = from;
+            }
+            inline unsigned int getFromID(unsigned int) const
+            {
+                return this->fromID_;
+            }
+            inline void setToID(unsigned int to)     //!< set the ID of the PortalEndPoint which should act as the exit of this link
+            {
+                this->toID_ = to;
+            }
+            inline unsigned int getToID(unsigned int) const
+            {
+                return this->toID_;
+            }
+            static void use(MobileEntity * entity, PortalEndPoint * entrance);   //
+        protected:
+        private:
+            static std::map<PortalEndPoint *, PortalEndPoint *> links_s;
+            unsigned int fromID_;
+            unsigned int toID_;
+            PortalEndPoint* from_;
+            PortalEndPoint* to_;
+            float activationRadius_;
+            bool isNowPortable(WorldEntity * ent);
+    };
+
+}
+
+#endif /* _Portals_H__ */
Index: /code/trunk/src/modules/portals/PortalsPrecompiledHeaders.h
===================================================================
--- /code/trunk/src/modules/portals/PortalsPrecompiledHeaders.h	(revision 8457)
+++ /code/trunk/src/modules/portals/PortalsPrecompiledHeaders.h	(revision 8457)
@@ -0,0 +1,53 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   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 2
+ *   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, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Reto Grieder
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+/**
+@file
+@brief
+*/
+
+#include "OrxonoxConfig.h"
+
+///////////////////////////////////////////
+/////          Stable Headers         /////
+///////////////////////////////////////////
+
+#include <LinearMath/btTransform.h>
+
+///////////////////////////////////////////
+/////       All Rebuild Headers       /////
+///////////////////////////////////////////
+
+#include "core/BaseObject.h"
+#include "core/CoreIncludes.h"
+#include "core/XMLPort.h"
+
+
+// Just in case some header included windows.h
+#undef min
+#undef max
Index: /code/trunk/src/modules/portals/PortalsPrereqs.h
===================================================================
--- /code/trunk/src/modules/portals/PortalsPrereqs.h	(revision 8457)
+++ /code/trunk/src/modules/portals/PortalsPrereqs.h	(revision 8457)
@@ -0,0 +1,73 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   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 2
+ *   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, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Damian 'Mozork' Frick
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+/**
+@file
+@brief
+    Shared library macros, enums, constants and forward declarations for the questsystem module
+*/
+
+#ifndef _PortalsPrereqs_H__
+#define _PortalsPrereqs_H__
+
+#include "OrxonoxConfig.h"
+#include "OrxonoxPrereqs.h"
+
+//-----------------------------------------------------------------------
+// Shared library settings
+//-----------------------------------------------------------------------
+
+#if defined(ORXONOX_PLATFORM_WINDOWS) && !defined(Portals_STATIC_BUILD)
+#  ifdef Portals_SHARED_BUILD
+#    define _PortalsExport __declspec(dllexport)
+#  else
+#    if defined( __MINGW32__ )
+#      define _PortalsExport
+#    else
+#      define _PortalsExport __declspec(dllimport)
+#    endif
+#  endif
+#elif defined ( ORXONOX_GCC_VISIBILITY )
+#  define _PortalsExport  __attribute__ ((visibility("default")))
+#else
+#  define _PortalsExport
+#endif
+
+//-----------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------
+
+namespace orxonox
+{
+
+    class PortalEndPoint;
+    class PortalLink;
+
+}
+
+#endif /* _PortalsPrereqs_H__ */
