Index: branches/network/src/defs/class_id.h
===================================================================
--- branches/network/src/defs/class_id.h	(revision 8036)
+++ branches/network/src/defs/class_id.h	(revision 8067)
@@ -190,4 +190,5 @@
   CL_HOVER                      =    0x0000035e,
   CL_TURBINE_HOVER              =    0x0000035f,
+  CL_SPECTATOR                  =    0x00000360,
 
   // Powerups
Index: branches/network/src/lib/network/message_manager.cc
===================================================================
--- branches/network/src/lib/network/message_manager.cc	(revision 8036)
+++ branches/network/src/lib/network/message_manager.cc	(revision 8067)
@@ -309,5 +309,6 @@
   {
     if ( 
-         recieverType == RT_ALL ||
+         recieverType == RT_ALL_ME ||
+         recieverType == RT_ALL_NOT_ME ||
          recieverType == RT_USER && it->first == reciever ||
          recieverType == RT_NOT_USER && it->first != reciever
@@ -324,7 +325,10 @@
       
       it->second.messages.push_back( msg );
-    }
-  }
-}
-
-
+      
+      if ( recieverType == RT_ALL_ME )
+        incomingMessabeBuffer.push_back( msg );
+    }
+  }
+}
+
+
Index: branches/network/src/lib/network/message_manager.h
===================================================================
--- branches/network/src/lib/network/message_manager.h	(revision 8036)
+++ branches/network/src/lib/network/message_manager.h	(revision 8067)
@@ -36,7 +36,8 @@
 enum RecieverType
 {
-  RT_ALL = 1,   //!< message is sent to all users
-  RT_USER,      //!< message is only sent to reciever
-  RT_NOT_USER   //!< message is sent to all but reciever
+  RT_ALL_NOT_ME = 1,   //!< message is sent to all users
+  RT_ALL_ME,           //!< message is sent to all users
+  RT_USER,             //!< message is only sent to reciever
+  RT_NOT_USER          //!< message is sent to all but reciever
 };
 
Index: branches/network/src/lib/network/network_game_manager.cc
===================================================================
--- branches/network/src/lib/network/network_game_manager.cc	(revision 8036)
+++ branches/network/src/lib/network/network_game_manager.cc	(revision 8067)
@@ -59,4 +59,7 @@
   
   MessageManager::getInstance()->registerMessageHandler( MSGID_DELETESYNCHRONIZEABLE, delSynchronizeableHandler, NULL );
+  
+  this->gameState = 0;
+  registerVar( new SynchronizeableInt( &gameState, &gameState, "gameState" ) );
 }
 
@@ -118,4 +121,6 @@
 bool NetworkGameManager::signalLeftPlayer(int userID)
 {
+  delete PlayerStats::getStats( userID )->getPlayable();
+  delete PlayerStats::getStats( userID );
 }
 
@@ -166,4 +171,9 @@
 void NetworkGameManager::removeSynchronizeable( int uniqueId )
 {
+  byte buf[INTSIZE];
+  
+  assert( Converter::intToByteArray( uniqueId, buf, INTSIZE ) == INTSIZE );
+  
+  MessageManager::getInstance()->sendMessage( MSGID_DELETESYNCHRONIZEABLE, buf, INTSIZE, RT_ALL_NOT_ME, 0, MP_HIGHBANDWIDTH );
 }
 
@@ -172,2 +182,3 @@
 
 
+
Index: branches/network/src/lib/network/network_game_manager.h
===================================================================
--- branches/network/src/lib/network/network_game_manager.h	(revision 8036)
+++ branches/network/src/lib/network/network_game_manager.h	(revision 8067)
@@ -47,5 +47,5 @@
   public:
     virtual ~NetworkGameManager();
-
+    
     static NetworkGameManager* NetworkGameManager::getInstance()
     { if (!NetworkGameManager::singletonRef) NetworkGameManager::singletonRef = new NetworkGameManager(); return NetworkGameManager::singletonRef; }
@@ -57,4 +57,6 @@
     void removeSynchronizeable( int uniqueId );
 
+    inline void setGameState( int gameState ){ this->gameState = gameState; }
+    inline int getGameState(){ return this->gameState; }
 
   private:
@@ -64,4 +66,6 @@
 
     static NetworkGameManager*    singletonRef;
+    
+    int                           gameState;
 };
 
Index: branches/network/src/lib/network/player_stats.cc
===================================================================
--- branches/network/src/lib/network/player_stats.cc	(revision 8036)
+++ branches/network/src/lib/network/player_stats.cc	(revision 8067)
@@ -48,5 +48,6 @@
 
   this->userId = 0;
-  this->teamId = 0;
+  this->teamId = TEAM_NOTEAM;
+  this->preferedTeamId = TEAM_NOTEAM;
   this->score = 0;
   this->playableClassId = 0;
@@ -54,5 +55,6 @@
   
   userId_handle = registerVarId( new SynchronizeableInt( &userId, &userId, "userId" ) );
-  groupId_handle = registerVarId( new SynchronizeableInt( &teamId, &teamId, "teamId" ) );
+  teamId_handle = registerVarId( new SynchronizeableInt( &teamId, &teamId, "teamId" ) );
+  preferedTeamId_handle = registerVarId( new SynchronizeableInt( &preferedTeamId, &preferedTeamId, "preferedUserId" ) );
   score_handle = registerVarId( new SynchronizeableInt( &score, &score, "score" ) );
   playableClassId_handle = registerVarId( new SynchronizeableInt( &playableClassId, &playableClassId, "playableClassId") );
Index: branches/network/src/lib/network/player_stats.h
===================================================================
--- branches/network/src/lib/network/player_stats.h	(revision 8036)
+++ branches/network/src/lib/network/player_stats.h	(revision 8067)
@@ -12,4 +12,11 @@
 #include <string>
 #include <list>
+
+enum
+{
+  TEAM_NOTEAM = -3,
+  TEAM_RANDOM = -2,
+  TEAM_SPECTATOR = -1
+};
 
 //! A class for storing player information
@@ -31,4 +38,7 @@
     inline void setTeamId( int teamId ){ this->teamId = teamId; }
     
+    inline int getPreferedTeamId(){ return preferedTeamId; }
+    inline void setPreferedTeamId( int preferedTeamId ){ this->preferedTeamId = preferedTeamId; }
+    
     inline int getScore(){ return score; }
     inline void setScore( int score ){ this->score = score; }
@@ -48,4 +58,5 @@
     int userId;                //!< userId
     int teamId;                //!< teamId
+    int preferedTeamId;        //!< preferedTeamId
 
     int score;                 //!< users score points
@@ -58,5 +69,6 @@
     // handles for SynchronizeableVars
     int userId_handle;
-    int groupId_handle;
+    int teamId_handle;
+    int preferedTeamId_handle;
     int score_handle;
     int playableClassId_handle;
Index: branches/network/src/lib/network/synchronizeable.cc
===================================================================
--- branches/network/src/lib/network/synchronizeable.cc	(revision 8036)
+++ branches/network/src/lib/network/synchronizeable.cc	(revision 8067)
@@ -21,4 +21,5 @@
 #include "netdefs.h"
 #include "network_log.h"
+#include "network_game_manager.h"
 
 #include "state.h"
@@ -68,4 +69,7 @@
   if ( this->networkStream )
     this->networkStream->disconnectSynchronizeable(*this);
+  
+  if ( this->isServer() && this->beSynchronized() && this->getUniqueID() > 0 )
+    NetworkGameManager::getInstance()->removeSynchronizeable( this->getUniqueID() );
 }
 
Index: branches/network/src/util/multiplayer_team_deathmatch.cc
===================================================================
--- branches/network/src/util/multiplayer_team_deathmatch.cc	(revision 8036)
+++ branches/network/src/util/multiplayer_team_deathmatch.cc	(revision 8067)
@@ -15,4 +15,6 @@
 #define DEBUG_MODULE_GAME_RULES
 
+#include <map>
+
 #include "multiplayer_team_deathmatch.h"
 
@@ -34,4 +36,6 @@
 #include "space_ships/space_ship.h"
 
+#include "network_game_manager.h"
+
 
 using namespace std;
@@ -52,4 +56,7 @@
   this->deathTimeout = 10.0f;     // 5 seconds
   this->timeout = 0.0f;
+  this->numTeams = 2;
+  this->currentGameState = GAMESTATE_PRE_GAME;
+  this->gameStateTimer = 10.0f;
 
   this->deathScreen = new ImagePlane();
@@ -87,4 +94,7 @@
   LoadParam(root, "death-screen-image", this, MultiplayerTeamDeathmatch, setDeathScreen)
       .describe("sets the death screen image");
+  
+  LoadParam(root, "num-teams", this, MultiplayerTeamDeathmatch, setNumTeams)
+      .describe("sets number of teams");
 
 }
@@ -128,4 +138,22 @@
 void MultiplayerTeamDeathmatch::tick(float dt)
 {
+  if ( !SharedNetworkData::getInstance()->isGameServer() )
+    return;
+  
+  gameStateTimer -= dt;
+  PRINTF(0)("TICK %f\n", gameStateTimer);
+  
+  if ( currentGameState != GAMESTATE_GAME && gameStateTimer < 0 )
+    nextGameState();
+  
+  this->currentGameState = NetworkGameManager::getInstance()->getGameState();
+  
+  if ( currentGameState == GAMESTATE_GAME )
+  {
+    handleTeamChanges();
+  }
+  
+  this->calculateTeamScore();
+  
   this->checkGameRules();
 
@@ -164,95 +192,180 @@
 void MultiplayerTeamDeathmatch::checkGameRules()
 {
-
-  Vector big_left(-201, 0, 0);
-  float rBig = 176.0f;
-  Vector big_right(177, 0, 0);
-  Vector small_left(10, 0, 0);
-  Vector small_middle(0, 0, 0);
-  Vector small_right(-10, 0, 0);
-  float rSmall = 90.0f;
-
-
+  if ( !SharedNetworkData::getInstance()->isGameServer() )
+    return;
+  
   // check for max killing count
-  if( this->teamAKills >= this->maxKills)
-  {
-    // team A winns
-  }
-  else if( this->teamBKills >= this->maxKills)
-  {
-    // team B winns
-  }
-
-
-  if ( SharedNetworkData::getInstance()->isGameServer() )
-  {
-    float offsetx = 500.0f;
-    float offsety = 323.0f;
-    float offsetz = 200.0f;
-
-    offsetz += 10;
-
-    Terrain * terrain = dynamic_cast<Terrain*>(*(ClassList::getList( CL_TERRAIN )->begin()));
-    const std::list<BaseObject*> * list = ClassList::getList( CL_SPACE_SHIP );
-    for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++)
-    {
-      SpaceShip * ss = dynamic_cast<SpaceShip*>(*it);
-      float terrx = ss->getAbsCoor().x + offsetx;
-      float terry = ss->getAbsCoor().z + offsetz;
-      float terrz = ss->getAbsCoor().y + offsety;
-      if ( terrz < terrain->getHeight( terrx, terry ) && ss->getAbsCoor().x > -1000 )
+  for ( int i = 0; i<numTeams; i++ )
+  {
+    if ( teamScore[i] >= maxKills )
+    {
+      //team i wins
+      //TODO
+    }
+  }
+}
+
+/**
+ * find group for new player
+ * @return group id
+ */
+int MultiplayerTeamDeathmatch::getTeamForNewUser( )
+{
+  return TEAM_NOTEAM;
+}
+
+ClassID MultiplayerTeamDeathmatch::getPlayableClassId( int team )
+{
+  return CL_SPECTATOR;
+}
+
+std::string MultiplayerTeamDeathmatch::getPlayableModelFileName( int team, ClassID classId )
+{
+  return "";
+}
+
+/**
+ * calculate team score
+ */
+void MultiplayerTeamDeathmatch::calculateTeamScore( )
+{
+  teamScore.clear();
+  
+  for ( int i = 0; i<numTeams; i++ )
+    teamScore[i] = 0;
+  
+    
+  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
+  
+  if ( !list )
+    return;
+  
+  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
+  {
+    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
+
+    if ( stats.getTeamId() >= 0 )
+    {
+      teamScore[stats.getTeamId()] += stats.getScore();
+    }
+  }
+}
+
+/**
+ * get team for player who choose to join random team
+ * @return smallest team
+ */
+int MultiplayerTeamDeathmatch::getRandomTeam( )
+{
+  std::map<int,int> playersInTeam;
+  
+  for ( int i = 0; i<numTeams; i++ )
+    playersInTeam[i] = 0;
+  
+  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
+  
+  if ( !list )
+    return 0;
+  
+  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
+  {
+    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
+
+    if ( stats.getTeamId() >= 0 )
+    {
+      playersInTeam[stats.getTeamId()]++;
+    }
+  }
+  
+  
+  int minPlayers = 0xFFFF;
+  int minTeam = -1;
+  
+  for ( int i = 0; i<numTeams; i++ )
+  {
+    if ( playersInTeam[i] < minPlayers )
+    {
+      minTeam = i;
+      minPlayers = playersInTeam[i];
+    }
+  }
+  
+  assert( minTeam != -1 );
+  
+  return minTeam;
+}
+
+void MultiplayerTeamDeathmatch::nextGameState( )
+{
+  if ( currentGameState == GAMESTATE_PRE_GAME )
+  {
+    NetworkGameManager::getInstance()->setGameState( GAMESTATE_GAME );
+    
+    return;
+  }
+  
+  if ( currentGameState == GAMESTATE_GAME )
+  {
+    NetworkGameManager::getInstance()->setGameState( GAMESTATE_POST_GAME );
+    
+    return;
+  }
+  
+  if ( currentGameState == GAMESTATE_POST_GAME )
+  {
+    //TODO end game
+    
+    return;
+  }
+}
+
+void MultiplayerTeamDeathmatch::handleTeamChanges( )
+{
+  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
+  
+  if ( !list )
+    return;
+  
+  //first server players with choices
+  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
+  {
+    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
+
+    if ( stats.getTeamId() != stats.getPreferedTeamId() )
+    {
+      if ( stats.getPreferedTeamId() == TEAM_SPECTATOR || ( stats.getPreferedTeamId() <= 0 && stats.getPreferedTeamId() < numTeams ) )
       {
-        //TODO handle this
+        teamChange( stats.getUserId() );
       }
-
-
-      float dist = (dynamic_cast<Playable*>(*it)->getAbsCoor() - big_left).len();
-      if( (dynamic_cast<Playable*>(*it)->getAbsCoor() - big_left).len() > rBig &&
-           (dynamic_cast<Playable*>(*it)->getAbsCoor() - big_right).len() > rBig &&
-           (dynamic_cast<Playable*>(*it)->getAbsCoor() - small_left).len() > rSmall &&
-           (dynamic_cast<Playable*>(*it)->getAbsCoor() - small_middle).len() > rSmall &&
-           (dynamic_cast<Playable*>(*it)->getAbsCoor() - small_right).len() > rSmall
-           && ss->getAbsCoor().x > -1000)
+    }
+  }
+  
+  //now serve player who want join a random team
+  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
+  {
+    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
+
+    if ( stats.getTeamId() != stats.getPreferedTeamId() )
+    {
+      if ( stats.getPreferedTeamId() == TEAM_RANDOM )
       {
-        PRINTF(0)("KILLLLLLLL\n");
-
-        if((*it)->isA(CL_SPACE_SHIP))
-        {
-          //TODO handle this
-        }
+        stats.setPreferedTeamId( getTeamForNewUser() );
+        teamChange( stats.getUserId() );
       }
     }
   }
-
-
-#if 0
-  std::list<BaseObject*>::const_iterator it;
-  const std::list<BaseObject*>* list = ClassList::getList(CL_PLAYABLE);
-
-  if( SharedNetworkData::getInstance()->isGameServer())
-  {
-    for(it = list->begin(); it != list->end(); it++)
-    {
-      float dist = (dynamic_cast<Playable*>(*it)->getAbsCoor() - big_left).len();
-      if( (dynamic_cast<Playable*>(*it)->getAbsCoor() - big_left).len() > rBig &&
-           (dynamic_cast<Playable*>(*it)->getAbsCoor() - big_right).len() > rBig &&
-           (dynamic_cast<Playable*>(*it)->getAbsCoor() - small_left).len() > rSmall &&
-           (dynamic_cast<Playable*>(*it)->getAbsCoor() - small_middle).len() > rSmall &&
-           (dynamic_cast<Playable*>(*it)->getAbsCoor() - small_right).len() > rSmall)
-      {
-        PRINTF(0)("KILLLLLLLL\n");
-
-        if((*it)->isA(CL_SPACE_SHIP))
-          dynamic_cast<SpaceShip*>(*it)->doCollideNetwork(116369220.33434f);
-      }
-    }
-  }
-#endif
-
-}
-
-
-
-
-
-
+}
+
+void MultiplayerTeamDeathmatch::teamChange( int userId )
+{
+  assert( PlayerStats::getStats( userId ) );
+  PlayerStats & stats = *(PlayerStats::getStats( userId ));
+  
+  assert(false);
+}
+
+
+
+
+
+
Index: branches/network/src/util/multiplayer_team_deathmatch.h
===================================================================
--- branches/network/src/util/multiplayer_team_deathmatch.h	(revision 8036)
+++ branches/network/src/util/multiplayer_team_deathmatch.h	(revision 8067)
@@ -18,4 +18,11 @@
 class ImagePlane;
 
+enum
+{
+  GAMESTATE_PRE_GAME = 0,
+  GAMESTATE_GAME,
+  GAMESTATE_POST_GAME
+};
+
 
 class MultiplayerTeamDeathmatch : public NetworkGameRules
@@ -28,4 +35,7 @@
     virtual void loadParams(const TiXmlElement* root);
 
+    virtual int getTeamForNewUser();
+    virtual ClassID getPlayableClassId( int team );
+    virtual std::string getPlayableModelFileName( int team, ClassID classId );
 
     virtual void onPlayerSpawn();
@@ -39,4 +49,9 @@
     inline void setMaxKills(int kills) { this->maxKills = kills; }
     void setDeathScreen(const std::string& imageName);
+    
+    inline void setNumTeams( int numTeams ){ this->numTeams = numTeams; }
+    inline int getNumTeams(){ return this->numTeams; }
+    
+    int getRandomTeam();
 
   protected:
@@ -49,8 +64,17 @@
     int                maxKills;                   //!< max kills for winning condition
 
-    int                teamAKills;                 //!< kills of team A
-    int                teamBKills;                 //!< kills of team B
+    int                numTeams;                   //!< number of teams
 
-    ImagePlane*         deathScreen;                //!< the death screen
+    std::map<int,int>  teamScore;                  //!< team score
+
+    ImagePlane*        deathScreen;                //!< the death screen
+
+    int                currentGameState;           //!< game state
+    float              gameStateTimer;             //!< if less than 0 -> change game state
+
+    void calculateTeamScore();
+    void nextGameState();
+    void handleTeamChanges();
+    void teamChange( int userId );
 };
 
Index: branches/network/src/util/network_game_rules.h
===================================================================
--- branches/network/src/util/network_game_rules.h	(revision 8036)
+++ branches/network/src/util/network_game_rules.h	(revision 8067)
@@ -20,9 +20,9 @@
     virtual ~NetworkGameRules();
     
-    int getTeamForNewUser();
-    ClassID getPlayableClassId( int team );
-    std::string getPlayableModelFileName( int team, ClassID classId );
+    virtual int getTeamForNewUser();
+    virtual ClassID getPlayableClassId( int team );
+    virtual std::string getPlayableModelFileName( int team, ClassID classId );
     
-    PlayerStats * getNewPlayerStats( int userId ){ return new PlayerStats( userId ); }
+    virtual PlayerStats * getNewPlayerStats( int userId ){ return new PlayerStats( userId ); }
 
 
Index: branches/network/src/util/signal_handler.cc
===================================================================
--- branches/network/src/util/signal_handler.cc	(revision 8036)
+++ branches/network/src/util/signal_handler.cc	(revision 8067)
@@ -105,5 +105,5 @@
     {
       dup2( fd[0], STDIN_FILENO );
-      snprintf( command, 255, "gdb -p %d %s 1>" GDB_BT_FILE " 2>&1", pid, getInstance()->appName.c_str() );
+      snprintf( command, 255, "gdb -p %d %s 1>>" GDB_BT_FILE " 2>&1", pid, getInstance()->appName.c_str() );
     }
     else
Index: branches/network/src/world_entities/WorldEntities.am
===================================================================
--- branches/network/src/world_entities/WorldEntities.am	(revision 8036)
+++ branches/network/src/world_entities/WorldEntities.am	(revision 8067)
@@ -39,4 +39,5 @@
                 world_entities/space_ships/turbine_hover.cc \
                 world_entities/creatures/md2_creature.cc \
+                world_entities/spectator.cc \
                 \
                 \
@@ -90,4 +91,5 @@
                 space_ships/turbine_hover.h \
                 creatures/md2_creature.h \
+                spectator.h \
                 \
                 environments/water.h \
Index: branches/network/src/world_entities/spectator.cc
===================================================================
--- branches/network/src/world_entities/spectator.cc	(revision 8067)
+++ branches/network/src/world_entities/spectator.cc	(revision 8067)
@@ -0,0 +1,134 @@
+/*
+   orxonox - the future of 3D-vertical-scrollers
+
+   Copyright (C) 2004 orx
+
+   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, or (at your option)
+   any later version.
+
+### File Specific:
+   main-programmer: Christoph Renner
+   co-programmer: ...
+
+*/
+
+#include "spectator.h"
+
+#include "src/lib/util/loading/factory.h"
+#include "key_mapper.h"
+
+
+CREATE_FACTORY(Spectator, CL_SPECTATOR);
+
+
+/**
+ * constructor
+ */
+Spectator::Spectator( const TiXmlElement * root )
+{
+  this->setClassID(CL_SPECTATOR, "Spectator");
+  
+  bool                  bLeft;
+  bool                  bRight;
+  bool                  bForward;
+  bool                  bBackward;
+    
+  float                 xMouse;             //!< mouse moved in x-Direction
+  float                 yMouse;             //!< mouse moved in y-Direction
+
+  this->bLeft = false;
+  this->bRight = false;
+  this->bForward = false;
+  this->bBackward = false;
+  this->xMouse = 0.0f;
+  this->yMouse = 0.0f;
+    
+  registerEvent(KeyMapper::PEV_FORWARD);
+  registerEvent(KeyMapper::PEV_BACKWARD);
+  registerEvent(KeyMapper::PEV_LEFT);
+  registerEvent(KeyMapper::PEV_RIGHT);
+  registerEvent(KeyMapper::PEV_FIRE1);
+  registerEvent(EV_MOUSE_MOTION);
+  
+  registerVar( new SynchronizeableBool( &bLeft, &bLeft, "bLeft", PERMISSION_OWNER ) );
+  registerVar( new SynchronizeableBool( &bRight, &bRight, "bRight", PERMISSION_OWNER ) );
+  registerVar( new SynchronizeableBool( &bForward, &bForward, "bForward", PERMISSION_OWNER ) );
+  registerVar( new SynchronizeableBool( &bBackward, &bBackward, "bBackward", PERMISSION_OWNER ) );
+  registerVar( new SynchronizeableQuaternion( &mouseDir, &mouseDir, "mouseDir", PERMISSION_OWNER ) );
+}
+
+/**
+ * destructor
+ */
+Spectator::~Spectator( )
+{
+  this->setPlayer(NULL);
+}
+
+void Spectator::setPlayDirection( const Quaternion & rot, float speed )
+{
+  this->mouseDir =  rot;
+  this->rotY = Quaternion( rot.getHeading(), Vector( 0, 1, 0) );
+  this->rotAxis = Quaternion( rot.getAttitude(), Vector( 0, 0, 1 ) );
+}
+
+void Spectator::enter( )
+{
+  this->attachCamera();
+}
+
+void Spectator::leave( )
+{
+  this->detachCamera();
+}
+
+/**
+ * collision handling
+ * @param entity other entity
+ * @param location 
+ * @todo dont allow spectator to go through walls
+ */
+void Spectator::collidesWith( WorldEntity * entity, const Vector & location )
+{
+}
+
+void Spectator::tick( float time )
+{
+  Playable::tick( time );
+  
+  if( ( xMouse != 0 || yMouse != 0 ) && this->getOwner() == this->getHostID() )
+  {
+    xMouse *= time / 10;
+    yMouse *= time / 10;
+    
+    this->rotY *= Quaternion(-M_PI/4.0*this->xMouse, Vector(0,1,0));
+    this->rotAxis *= Quaternion(-M_PI/4.0*this->yMouse, Vector(0,0,1) );
+
+    this->mouseDir = rotY * rotAxis;
+    //this->mouseDir *= Quaternion(-M_PI/4.0*this->yMouse, Vector(0,0,1));
+    xMouse = yMouse = 0;
+  }
+  
+  this->setAbsDir( this->mouseDir );
+}
+
+void Spectator::process( const Event & event )
+{
+  Playable::process(event);
+
+  if( event.type == KeyMapper::PEV_LEFT)
+    this->bLeft = event.bPressed;
+  else if( event.type == KeyMapper::PEV_RIGHT)
+    this->bRight = event.bPressed;
+  else if( event.type == KeyMapper::PEV_FORWARD)
+    this->bForward = event.bPressed; //this->shiftCoor(0,.1,0);
+  else if( event.type == KeyMapper::PEV_BACKWARD)
+    this->bBackward = event.bPressed; //this->shiftCoor(0,-.1,0);
+  else if( event.type == EV_MOUSE_MOTION)
+  {
+    this->xMouse += event.xRel;
+    this->yMouse += event.yRel;
+  }
+}
Index: branches/network/src/world_entities/spectator.h
===================================================================
--- branches/network/src/world_entities/spectator.h	(revision 8067)
+++ branches/network/src/world_entities/spectator.h	(revision 8067)
@@ -0,0 +1,41 @@
+/*!
+ * @file cpectator.h
+ * Implements a playable for lazy people
+ */
+
+#ifndef _SPECTATOR_H
+#define _SPECTATOR_H
+
+#include "playable.h"
+
+class Spectator : public Playable
+{
+  public:
+    Spectator( const TiXmlElement* root = NULL );
+    virtual ~Spectator();
+    
+    virtual void setPlayDirection(const Quaternion& rot, float speed = 0.0f);
+
+    virtual void enter();
+    virtual void leave();
+    
+    virtual void collidesWith(WorldEntity* entity, const Vector& location);
+    virtual void tick(float time);
+
+    virtual void process(const Event &event);
+    
+  private:
+    bool                  bLeft;
+    bool                  bRight;
+    bool                  bForward;
+    bool                  bBackward;
+    
+    float                 xMouse;             //!< mouse moved in x-Direction
+    float                 yMouse;             //!< mouse moved in y-Direction
+    Quaternion            mouseDir;           //!< the direction where the player wants to fly
+
+    Quaternion            rotY;
+    Quaternion            rotAxis;
+};
+
+#endif
