Index: /trunk/src/lib/math/quaternion.h
===================================================================
--- /trunk/src/lib/math/quaternion.h	(revision 8801)
+++ /trunk/src/lib/math/quaternion.h	(revision 8802)
@@ -50,4 +50,6 @@
   /** @param q: the Quaternion to compare with this one. @returns true if the Quaternions are the same, false otherwise */
   inline bool operator== (const Quaternion& q) const { return (unlikely(this->v==q.v&&this->w==q.w))?true:false; };
+  /** @param q: the Quaternion to compare with this one. @returns true if the Quaternions are the same, false otherwise */
+  inline bool operator!= (const Quaternion& q) const { return (unlikely(this->v!=q.v&&this->w!=q.w))?true:false; };
   /** @param f: a real value @return a Quaternion containing the quotient */
   inline Quaternion operator/ (const float& f) const { return (unlikely(f==0.0)) ? Quaternion() : Quaternion(this->v/f, this->w/f); };
Index: /trunk/src/lib/network/netdefs.h
===================================================================
--- /trunk/src/lib/network/netdefs.h	(revision 8801)
+++ /trunk/src/lib/network/netdefs.h	(revision 8802)
@@ -19,5 +19,5 @@
 #define MAX_CONNECTIONS 1000
 
-#define NETWORK_FREQUENCY 33
+#define NETWORK_FREQUENCY 66
 
 
Index: /trunk/src/lib/network/udp_server_socket.cc
===================================================================
--- /trunk/src/lib/network/udp_server_socket.cc	(revision 8801)
+++ /trunk/src/lib/network/udp_server_socket.cc	(revision 8802)
@@ -147,7 +147,4 @@
     res.length = packetBuffer[userId].front().length;
     packetBuffer[userId].pop_front();
-
-    if ( res.length == 0 )
-      res.length = -1;
   }
 
@@ -173,5 +170,5 @@
  * @param ip users host / port
  */
-void UdpServerSocket::initUser( int userId, IPaddress ip )
+void UdpServerSocket::initUser( int userId, IPaddress ip, byte randomByte )
 {
   int channel = SDLNet_UDP_Bind( socket, userId, &ip );
@@ -192,5 +189,6 @@
     userList.resize( userId + 1 );
 
-  userList[ userId ] = ip;
+  userList[ userId ].addr = ip;
+  userList[ userId ].randomByte = randomByte;
 }
 
@@ -206,6 +204,6 @@
     return;
 
-  userList[userId].host = 0;
-  userList[userId].port = 0;
+  userList[userId].addr.host = 0;
+  userList[userId].addr.port = 0;
 
   SDLNet_UDP_Unbind( socket, userId );
@@ -234,5 +232,5 @@
     return false;
   }
-
+  
   return true;
 }
@@ -251,11 +249,13 @@
     bool isNewConnection = false;
 
+    if ( packet->len <= 0 )
+      continue; 
+        
     for ( userId =0; userId < (int)userList.size(); userId++ )
-      if ( userList[userId].host == packet->address.host && userList[userId].port == packet->address.port )
+      if ( userList[userId].addr.host == packet->address.host && userList[userId].addr.port == packet->address.port && userList[userId].randomByte == ( packet->data[0] & 0xFC ) )
         break;
 
     if ( userId >= (int)userList.size() )
     {
-
       newConn++;
       isNewConnection = true;
@@ -268,9 +268,9 @@
 
       for ( userId =0; userId < (int)userList.size(); userId++ )
-        if ( userList[userId].host == 0 && userList[userId].port == 0 )
+        if ( userList[userId].addr.host == 0 && userList[userId].addr.port == 0 )
           break;
 
-      initUser( userId, packet->address );
-      UdpSocket * sock = new UdpSocket( this, packet->address, userId );
+      initUser( userId, packet->address, packet->data[0] & 0xFC );
+      UdpSocket * sock = new UdpSocket( this, packet->address, userId, packet->data[0] & 0xFC );
       newSocketList.push_back( sock );
       PRINTF(0)("NEW CONNECTION %x\n", packet->address.host );
@@ -292,5 +292,4 @@
     memcpy( networkPacket.data, packet->data, packet->len );
     packetBuffer[userId].push_back( networkPacket );
-
   }
 
Index: /trunk/src/lib/network/udp_server_socket.h
===================================================================
--- /trunk/src/lib/network/udp_server_socket.h	(revision 8801)
+++ /trunk/src/lib/network/udp_server_socket.h	(revision 8802)
@@ -33,5 +33,11 @@
 typedef std::vector<NetworkPacketList> PacketBuffer;
 
-typedef std::vector<IPaddress> UserList;
+struct UserInfo
+{
+  IPaddress addr;
+  byte randomByte;
+};
+
+typedef std::vector<UserInfo> UserList;
 
 typedef std::list<UdpSocket*> UdpSocketList;
@@ -57,5 +63,5 @@
     bool sendPacket( NetworkPacket networkPacket, int userId );
     int getPacketCount( int childId );
-    void initUser( int childId, IPaddress ip );
+    void initUser( int childId, IPaddress ip, byte randomByte );
     
   private:
Index: /trunk/src/lib/network/udp_socket.cc
===================================================================
--- /trunk/src/lib/network/udp_socket.cc	(revision 8801)
+++ /trunk/src/lib/network/udp_socket.cc	(revision 8802)
@@ -25,4 +25,5 @@
   this->socket = NULL;
   this->packet = NULL;
+  this->randomByte = 0;
 }
 
@@ -70,9 +71,10 @@
  * @param userId userid used by serverSocket
  */
-UdpSocket::UdpSocket( UdpServerSocket * serverSocket, IPaddress ip, int userId )
+UdpSocket::UdpSocket( UdpServerSocket * serverSocket, IPaddress ip, int userId, byte randomByte )
 {
   this->init();
   this->serverSocket = serverSocket;
   this->userId = userId;
+  this->randomByte = randomByte;
 }
 
@@ -104,4 +106,6 @@
 
   IPaddress ip;
+  
+  this->randomByte = generateNewRandomByte();
 
   PRINTF(0)("connect to server %s on port %d\n", host.c_str(), port);
@@ -137,5 +141,6 @@
 {
   PRINTF(0)("disconnect\n");
-  writePacket( NULL, 0 );
+  byte cmd = this->randomByte | UDPCMD_DISCONNECT;
+  writeRawPacket( &cmd, 1 );
   SDLNet_UDP_Unbind( socket, -1 );
   SDLNet_UDP_Close( socket );
@@ -152,4 +157,91 @@
 bool UdpSocket::writePacket( byte * data, int length )
 {
+  byte * buf = new byte[length+1];
+  if ( length > 0 )
+    memcpy( buf+1, data, length );
+  buf[0] = this->randomByte;
+  return writeRawPacket( buf, length+1 );
+}
+
+/**
+ * recieve one packet from another host
+ * @param data pointer to buffer to copy data into
+ * @param maxLength maximal length of buffer
+ * @return less than 0 on error, number bytes read else
+ */
+int UdpSocket::readPacket( byte * data, int maxLength )
+{
+  assert( maxLength <= UDP_PACKET_SIZE );
+
+  if ( serverSocket )
+  {
+    NetworkPacket networkPacket = serverSocket->getPacket( this->userId );
+
+    byte udpCmd = 0;
+    
+    if ( networkPacket.length > 0 )
+    {
+      assert( maxLength > networkPacket.length );
+
+      memcpy( data, networkPacket.data+1, networkPacket.length-1 );
+      udpCmd = networkPacket.data[0];
+    }
+    else
+      return 0;
+      
+    if ( !checkRandomByte( networkPacket.data[0] ) )
+      return 0;
+
+    if ( networkPacket.data )
+    {
+      free( networkPacket.data );
+      networkPacket.data = NULL;
+    }
+    
+    if ( !checkUdpCmd( udpCmd ) )
+      return 0;
+
+    return networkPacket.length-1;
+  }
+  else
+  {
+    int numrecv = SDLNet_UDP_Recv( socket, packet);
+    
+    byte udpCmd = 0;
+
+    if ( numrecv > 0)
+    {
+      assert( packet->len <= maxLength );
+
+      if ( packet->len > 0 )
+        memcpy( data, packet->data+1, packet->len-1 );
+      else
+        return 0;
+            
+      if ( !checkRandomByte( packet->data[0] ) )
+        return 0;
+              
+      if ( !checkUdpCmd( udpCmd ) )
+        return 0;
+
+      return packet->len-1;
+    }
+    else if ( numrecv < 0 )
+    {
+      PRINTF(1)("SDLNet_UDP_Recv: %s\n", SDLNet_GetError());
+      bOk = false;
+      return -1;
+    }
+    else
+    {
+      return 0;
+    }
+  }
+
+  return 0;
+}
+
+bool UdpSocket::writeRawPacket( byte * data, int length )
+{
   if ( serverSocket )
   {
@@ -183,70 +275,48 @@
 }
 
-/**
- * recieve one packet from another host
- * @param data pointer to buffer to copy data into
- * @param maxLength maximal length of buffer
- * @return less than 0 on error, number bytes read else
- */
-int UdpSocket::readPacket( byte * data, int maxLength )
-{
-  assert( maxLength <= UDP_PACKET_SIZE );
-
-  if ( serverSocket )
-  {
-    NetworkPacket networkPacket = serverSocket->getPacket( this->userId );
-
-    if ( networkPacket.length == -1 )
-    {
-      this->disconnectServer();
-      return 0;
-    }
-
-    if ( networkPacket.length > 0 )
-    {
-      assert( maxLength > networkPacket.length );
-
-      memcpy( data, networkPacket.data, networkPacket.length );
-    }
-
-    if ( networkPacket.data )
-    {
-      free( networkPacket.data );
-      networkPacket.data = NULL;
-    }
-
-    return networkPacket.length;
+bool UdpSocket::checkUdpCmd( byte udpCmd )
+{
+  if ( udpCmd & UDPCMD_DISCONNECT )
+  {
+    this->disconnectServer();
+    PRINTF(0)("received disconnect byte\n");
+    return false;
+  }
+  
+  if ( !this->serverSocket && ( udpCmd & UDPCMD_INVALIDRNDBYTE ) )
+  {
+    PRINTF(0)("received invlid random number byte\n");
+    byte cmd = this->randomByte | UDPCMD_DISCONNECT;
+    writeRawPacket( &cmd, 1 );
+    this->randomByte = generateNewRandomByte();
+    return false;
+  }
+  
+  return true;
+}
+
+byte UdpSocket::generateNewRandomByte( )
+{
+  srand( SDL_GetTicks() );
+  byte res = ( rand() & 0xFC );
+  
+  PRINTF(0)("generated random byte: %x\n", res);
+  
+  return res;
+}
+
+bool UdpSocket::checkRandomByte( byte rndByte )
+{
+  if ( ( rndByte & 0xFC ) == this->randomByte )
+  {
+    return true;
   }
   else
   {
-    int numrecv = SDLNet_UDP_Recv( socket, packet);
-    if ( numrecv > 0)
-    {
-      assert( packet->len <= maxLength );
-
-      if ( packet->len == 0 )
-      {
-        this->disconnectServer();
-        return 0;
-      }
-
-      memcpy( data, packet->data, packet->len );
-      return packet->len;
-    }
-    else if ( numrecv < 0 )
-    {
-      PRINTF(1)("SDLNet_UDP_Recv: %s\n", SDLNet_GetError());
-      bOk = false;
-      return -1;
-    }
-    else
-    {
-      return 0;
-    }
-  }
-
-  return 0;
-}
-
-
-
+    PRINTF(2)("wrong random byte: %x\n", ( rndByte & 0xFC ));
+    return false;
+  }
+}
+
+
+
Index: /trunk/src/lib/network/udp_socket.h
===================================================================
--- /trunk/src/lib/network/udp_socket.h	(revision 8801)
+++ /trunk/src/lib/network/udp_socket.h	(revision 8802)
@@ -16,9 +16,15 @@
 class UdpServerSocket;
 
+enum
+{
+  UDPCMD_DISCONNECT = 1,
+  UDPCMD_INVALIDRNDBYTE = 2
+};
+
 class UdpSocket : public NetworkSocket
 {
   public:
     UdpSocket();
-    UdpSocket( UdpServerSocket * serverSocket, IPaddress ip, int userId );
+    UdpSocket( UdpServerSocket * serverSocket, IPaddress ip, int userId, byte randomByte );
     UdpSocket( std::string host, int port );
     virtual ~UdpSocket();
@@ -28,5 +34,5 @@
     virtual void disconnectServer();
 
-    virtual bool writePacket(byte * data, int length);
+    virtual bool writePacket(byte * data, int length );
 
     virtual int readPacket(byte * data, int maxLength);
@@ -39,4 +45,11 @@
     UDPpacket *       packet;
     
+    byte              randomByte;     //!< contains random bytes & 0xFC
+    
+    bool writeRawPacket( byte * data, int length );
+    bool checkUdpCmd( byte udpCmd );
+    bool checkRandomByte( byte rndByte );
+    byte generateNewRandomByte();
+    
     void init();
 
Index: /trunk/src/util/game_rules.cc
===================================================================
--- /trunk/src/util/game_rules.cc	(revision 8801)
+++ /trunk/src/util/game_rules.cc	(revision 8802)
@@ -21,4 +21,6 @@
 
 #include "util/mission_goal.h"
+
+#include "shared_network_data.h"
 
 #include "debug.h"
@@ -86,4 +88,6 @@
 void GameRules::registerKill(const Kill& kill)
 {
+  if ( !SharedNetworkData::getInstance()->isGameServer() )
+    return;
   PRINTF(0)("Received Event: Kill\n");
   this->killList.push_back(kill);
Index: /trunk/src/util/game_rules.h
===================================================================
--- /trunk/src/util/game_rules.h	(revision 8801)
+++ /trunk/src/util/game_rules.h	(revision 8802)
@@ -35,8 +35,8 @@
     /** adding a kill event to the kill list @param kill the kill object containing all infos */
     void registerKill(const Kill& kill);
+    virtual void registerSpawn( WorldEntity * we ){}
 
     virtual void onPlayerSpawn() {}
     virtual void onPlayerDeath() {}
-
 
     virtual void tick(float dt) = 0;
Index: /trunk/src/util/multiplayer_team_deathmatch.cc
===================================================================
--- /trunk/src/util/multiplayer_team_deathmatch.cc	(revision 8801)
+++ /trunk/src/util/multiplayer_team_deathmatch.cc	(revision 8802)
@@ -45,4 +45,6 @@
 
 #include "shell_command.h"
+
+#include "spawning_point.h"
 
 
@@ -70,9 +72,6 @@
 
   this->box = NULL;
-
-  this->deathScreen = new ImagePlane();
-  this->deathScreen->setSize(State::getResX()/4.0, State::getResY()/4.0);
-  this->deathScreen->setAbsCoor2D(State::getResX()/2.0f, State::getResY()/2.0f);
-  this->deathScreen->setVisibility(false);
+  this->table = NULL;
+  this->statsBox = NULL;
 
   this->localPlayer = State::getPlayer();
@@ -83,5 +82,8 @@
   subscribeEvent( ES_GAME, SDLK_o );
   subscribeEvent( ES_GAME, SDLK_TAB );
-
+  subscribeEvent( ES_GAME, SDLK_F1 );
+  subscribeEvent( ES_MENU, SDLK_F1 );
+  subscribeEvent( ES_MENU, KeyMapper::PEV_FIRE1 );
+  
   this->notifier = new OrxGui::GLGuiNotifier();
   this->notifier->show();
@@ -99,10 +101,10 @@
 MultiplayerTeamDeathmatch::~MultiplayerTeamDeathmatch()
 {
-  if( this->deathScreen)
-    delete this->deathScreen;
-
   unsubscribeEvent( ES_GAME, SDLK_o );
   unsubscribeEvent( ES_GAME, SDLK_TAB );
-
+  unsubscribeEvent( ES_GAME, SDLK_F1 );
+  unsubscribeEvent( ES_MENU, SDLK_F1 );
+  unsubscribeEvent( ES_MENU, KeyMapper::PEV_FIRE1 );
+  
   if ( this->notifier )
   {
@@ -130,7 +132,4 @@
       .describe("sets the maximal kills for winning condition");
 
-  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");
@@ -139,35 +138,4 @@
 
 
-
-void MultiplayerTeamDeathmatch::setDeathScreen(const std::string& imageName)
-{
-  if( this->deathScreen)
-    this->deathScreen->setTexture(imageName);
-}
-
-
-
-/**
- * called when the player enters the game
- * @param player the spawned player
- */
-void MultiplayerTeamDeathmatch::onPlayerSpawn()
-{
-  this->bLocalPlayerDead = false;
-  this->deathScreen->setVisibility(false);
-}
-
-
-/**
- * when the player is killed
- * @param player the killed player
- */
-void MultiplayerTeamDeathmatch::onPlayerDeath()
-{
-  this->bLocalPlayerDead = true;
-  this->deathScreen->setVisibility(true);
-}
-
-
 /**
  * time tick
@@ -176,4 +144,5 @@
 void MultiplayerTeamDeathmatch::tick(float dt)
 {
+  tickStatsTable();
   //on client side hostId is -1 until hanshake finished
   if ( SharedNetworkData::getInstance()->getHostID() < 0 )
@@ -250,5 +219,16 @@
   if ( !SharedNetworkData::getInstance()->isGameServer() )
     return;
-
+    
+  //handle kills
+  for ( std::vector<Kill>::iterator it = this->killList.begin(); it != this->killList.end();  )
+  {
+    std::vector<Kill>::iterator delit = it;
+    
+    onKill( it->getKiller()->getOwner(), it->getVictim()->getOwner() );
+    
+    it++;
+    killList.erase( delit );
+  }
+  
   gameStateTimer -= dt;
   //PRINTF(0)("TICK %f\n", gameStateTimer);
@@ -310,6 +290,5 @@
     if ( teamScore[i] >= maxKills )
     {
-      //team i wins
-      //TODO
+      nextGameState();
     }
   }
@@ -435,5 +414,6 @@
   if ( currentGameState == GAMESTATE_POST_GAME )
   {
-    //TODO end game
+    State::getCurrentStoryEntity()->stop();
+    this->bShowTeamChange = false;
 
     return;
@@ -563,4 +543,16 @@
     if ( event.bPressed )
       this->bShowTeamChange = true;
+  } else if ( event.type == SDLK_F1 )
+  {
+    if ( !this->statsBox && event.bPressed )
+    {
+      PRINTF(0)("show stats\n");
+      this->showStats();
+    }
+    if ( this->statsBox && !this->bLocalPlayerDead && event.bPressed && this->table->rowCount() != 0 && this->table->columnCount() != 0 )
+    {
+      PRINTF(0)("hide stats\n");
+      this->hideStats();
+    }
   }
   else if ( event.type == SDLK_TAB )
@@ -576,4 +568,8 @@
     }
   }
+  else if ( this->bLocalPlayerDead && statsBox && event.type == KeyMapper::PEV_FIRE1 )
+  {
+    this->hideStats();
+  }
 }
 
@@ -623,5 +619,158 @@
 }
 
-
-
-
+/**
+ * show table with frags
+ */
+void MultiplayerTeamDeathmatch::showStats( )
+{
+  EventHandler::getInstance()->pushState( ES_MENU );
+  statsBox = new OrxGui::GLGuiBox();
+  statsBox->setAbsCoor2D( 300, 100 );
+  
+  this->table = new OrxGui::GLGuiTable(0,0);
+
+  statsBox->pack( this->table );
+
+  statsBox->showAll();
+}
+
+/**
+ * hide table with frags
+ */
+void MultiplayerTeamDeathmatch::hideStats( )
+{
+    if ( statsBox )
+    {
+      delete statsBox;
+      statsBox = NULL;
+    }
+      
+    EventHandler::getInstance()->popState();
+}
+
+/**
+ * fill stats table with values
+ */
+void MultiplayerTeamDeathmatch::tickStatsTable( )
+{
+  if ( !this->statsBox )
+    return;
+
+  std::vector<std::string> headers;
+  headers.push_back("Red Team");
+  headers.push_back("");
+  headers.push_back("");
+  headers.push_back("Blue Team");
+  headers.push_back("");
+  this->table->setHeader(headers);
+  
+  std::map<int,std::string> fragsTeam0;
+  std::map<int,std::string> fragsTeam1;
+  
+  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 || stats.getTeamId() == 1 )
+    {
+      if ( stats.getTeamId() == 0 )
+        fragsTeam0[stats.getScore()] = stats.getNickName();
+      else
+        fragsTeam1[stats.getScore()] = stats.getNickName();
+    }
+  }
+  
+  char st[10];
+  int i = 0;
+  
+  
+  i = 2;
+  for ( std::map<int,std::string>::const_iterator it = fragsTeam0.begin(); it != fragsTeam0.end(); it++ )
+  {
+    this->table->setEntry( 0, i, it->second );
+    snprintf( st, 10, "%d", it->first );
+    this->table->setEntry( 1, i, st );
+    this->table->setEntry( 2, i, "" );
+    i++;
+  }
+  
+  i = 2;
+  for ( std::map<int,std::string>::const_iterator it = fragsTeam1.begin(); it != fragsTeam1.end(); it++ )
+  {
+    this->table->setEntry( 3, i, it->second );
+    snprintf( st, 10, "%d", it->first );
+    this->table->setEntry( 4, i, st );
+    i++;
+  }
+}
+
+/**
+ * this function is called when a player kills another one or himself
+ * @param killedUserId 
+ * @param userId 
+ */
+void MultiplayerTeamDeathmatch::onKill( int killedUserId, int userId )
+{
+  assert( PlayerStats::getStats( killedUserId ) );
+  assert( PlayerStats::getStats( userId ) );
+  
+  PlayerStats & killedStats = *PlayerStats::getStats( killedUserId );
+  PlayerStats & stats = *PlayerStats::getStats( userId );
+  
+  if ( killedUserId != userId )
+    stats.setScore( stats.getScore() + 1 );
+  else
+    stats.setScore( stats.getScore() - 1 );
+  
+  if ( killedUserId == SharedNetworkData::getInstance()->getHostID() )
+  {
+    this->bLocalPlayerDead = true;
+    this->showStats();
+  }
+  
+  const std::list<BaseObject*> * list = ClassList::getList( CL_SPAWNING_POINT );
+  
+  assert( list );
+  
+  std::vector<SpawningPoint*> spList;
+  
+  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
+  {
+    SpawningPoint * sp = dynamic_cast<SpawningPoint*>(*it);
+    
+    if ( sp->getTeamId() < 0 || sp->getTeamId() == killedStats.getTeamId() )
+      spList.push_back( sp );
+  }
+ 
+  int n = spList.size()*rand();
+  
+  spList[n]->pushEntity( killedStats.getPlayable(), 3 );
+}
+
+/**
+ * this function is called on player respawn
+ * @param userId 
+ */
+void MultiplayerTeamDeathmatch::onRespawn( int userId )
+{
+  if ( userId == SharedNetworkData::getInstance()->getHostID() )
+  {
+    this->bLocalPlayerDead = false;
+    this->hideStats();
+  }
+}
+
+/**
+ * this function is called on player respawn
+ * @param we 
+ */
+void MultiplayerTeamDeathmatch::registerSpawn( WorldEntity * we )
+{
+  onRespawn( we->getOwner() );
+}
+
Index: /trunk/src/util/multiplayer_team_deathmatch.h
===================================================================
--- /trunk/src/util/multiplayer_team_deathmatch.h	(revision 8801)
+++ /trunk/src/util/multiplayer_team_deathmatch.h	(revision 8802)
@@ -41,7 +41,5 @@
     virtual std::string getPlayableModelFileName( int userId, int team, ClassID classId );
 
-    virtual void onPlayerSpawn();
-    virtual void onPlayerDeath();
-
+    virtual void registerSpawn( WorldEntity * we );
 
     virtual void tick(float dt);
@@ -50,5 +48,4 @@
     inline void setDeathPenaltyTimeout(float time) { this->deathTimeout = time; }
     inline void setMaxKills(int kills) { this->maxKills = kills; }
-    void setDeathScreen(const std::string& imageName);
     
     inline void setNumTeams( int numTeams ){ this->numTeams = numTeams; }
@@ -58,4 +55,7 @@
     
     virtual void process(const Event &event);
+    
+    void onKill( int killedUserId, int userId );
+    void onRespawn( int userId );
     
     virtual void handleChatMessage( int userId, const std::string & message, int messageType );
@@ -73,6 +73,4 @@
 
     std::map<int,int>  teamScore;                  //!< team score
-
-    ImagePlane*        deathScreen;                //!< the death screen
 
     int                currentGameState;           //!< game state
@@ -100,4 +98,11 @@
     
     void onInputEnter( const std::string & text );
+    
+    OrxGui::GLGuiBox* statsBox;
+    OrxGui::GLGuiTable* table;
+    void tickStatsTable();
+    
+    void showStats();
+    void hideStats();
 };
 
Index: /trunk/src/world_entities/npcs/generic_npc.cc
===================================================================
--- /trunk/src/world_entities/npcs/generic_npc.cc	(revision 8801)
+++ /trunk/src/world_entities/npcs/generic_npc.cc	(revision 8802)
@@ -30,4 +30,6 @@
 #include "generic_npc.h"
 
+#include "animation/animation3d.h"
+
 using namespace std;
 
@@ -55,5 +57,8 @@
  */
 GenericNPC::~GenericNPC ()
-{}
+{
+  if( this->currentAnim != NULL)
+    delete this->currentAnim;
+}
 
 
@@ -138,6 +143,44 @@
 float GenericNPC::walkTo(float x, float y, float z, float qu, float qx, float qy, float qz)
 {
-
-  return true;
+  Vector destCoor = Vector(x, y, z);
+  Quaternion destDir = Quaternion(Vector(qx, qy, qz), qu);
+
+  // check if this is the current goal
+  if( this->destCoor != destCoor && this->destDir != destDir)
+  {
+    this->destCoor = Vector(x, y, 0.0f);
+    this->destDir = Quaternion(Vector(qx, qy, qz), qu);
+
+    float time = 5.0f;
+
+    if( this->currentAnim != NULL)
+      delete this->currentAnim;
+
+    this->currentAnim = new Animation3D(this);
+    this->currentAnim->addKeyFrame(this->getAbsCoor(), this->getAbsDir(), 0.0f);
+    this->currentAnim->addKeyFrame(this->destCoor, this->destDir, time);
+  }
+
+  // calculate the distance
+  Vector distance = this->getAbsCoor() - this->destCoor;
+  return distance.len();
+}
+
+
+
+/**
+ * walk to a specific place with direction
+ *
+ * @param x: x coordinate to go to
+ * @param y: y coordinate to go to
+ * @param qu: angle to rotate
+ * @param qx: x coordinate of rotation vector
+ * @param qy: y coordinate of rotation vector
+ * @param qz: z coordinate of rotation vector
+ *
+ */
+float GenericNPC::walkTo(float x, float y, float qu, float qx, float qy, float qz)
+{
+  return this->walkTo(x, y, 0.0f, qu, qx, qy, qz);
 }
 
Index: /trunk/src/world_entities/npcs/generic_npc.h
===================================================================
--- /trunk/src/world_entities/npcs/generic_npc.h	(revision 8801)
+++ /trunk/src/world_entities/npcs/generic_npc.h	(revision 8802)
@@ -22,4 +22,5 @@
 
 class TiXmlElement;
+class Animation3D;
 
 
@@ -71,4 +72,6 @@
    Vector                                  destCoor;
    Quaternion                              destDir;
+
+   Animation3D*                            currentAnim;
 };
 
Index: /trunk/src/world_entities/spawning_point.cc
===================================================================
--- /trunk/src/world_entities/spawning_point.cc	(revision 8801)
+++ /trunk/src/world_entities/spawning_point.cc	(revision 8802)
@@ -24,5 +24,6 @@
 #include "compiler.h"
 
-#include <map>
+#include "state.h"
+#include "game_rules.h"
 
 
@@ -59,4 +60,6 @@
 {
   this->setClassID(CL_SPAWNING_POINT, "SpawningPoint");
+  
+  this->teamId = -1;
 }
 
@@ -81,4 +84,8 @@
   LoadParam(root, "delay", this, SpawningPoint, setSpawningDelay)
       .describe("sets the delay of the spawning point");
+      
+  /* load teamId */
+  LoadParam(root, "teamId", this, SpawningPoint, setTeamId)
+      .describe("sets teamId");
 
 
@@ -101,5 +108,10 @@
 void SpawningPoint::pushEntity(WorldEntity* entity, float delay)
 {
-  this->queue[entity] = this->localTimer + delay;
+  QueueEntry qe;
+  qe.entity = entity;
+  qe.list = entity->getOMListNumber();
+  qe.respawnTime = this->localTimer + delay;
+  
+  queue.push_back( qe );
 }
 
@@ -113,7 +125,8 @@
 
 
-  //BaseObject* spawningEntity = Factory::fabricate(this->classID);
-  //   if( likely(this->world != NULL))
-  //     this->world->spawn(dynamic_cast<WorldEntity*>(spawningEntity));
+  entity->setAbsCoor( this->getAbsCoor() );
+  entity->setAbsDir( this->getAbsDir() );
+  
+  //TODO set camera (not smooth)
 }
 
@@ -129,13 +142,29 @@
   this->localTimer += dt;
 
-  std::map<WorldEntity*, float>::iterator it = this->queue.begin();
-  for( ; it != this->queue.end(); it++)
+  std::list<QueueEntry>::iterator it = this->queue.begin();
+  for( ; it != this->queue.end(); )
   {
-    //
-    if( it->second <= this->localTimer)
+    
+    if( it->respawnTime <= this->localTimer)
     {
       //spawn the player
-      this->spawn(it->first);
+      this->spawn(it->entity);
+      
+      it->entity->toList( it->list );
+      
+      if ( State::getGameRules() )
+      {
+        (State::getGameRules())->registerSpawn( it->entity );
+      }
+      
+      std::list<QueueEntry>::iterator delit = it;
+      it++;
+      
+      queue.erase( delit );
+      
+      continue;
     }
+    
+    it++;
   }
 
Index: /trunk/src/world_entities/spawning_point.h
===================================================================
--- /trunk/src/world_entities/spawning_point.h	(revision 8801)
+++ /trunk/src/world_entities/spawning_point.h	(revision 8802)
@@ -8,11 +8,17 @@
 #define _SPAWNING_POINT
 
-#include "world_entity.h"
+#include "playable.h"
 
-#include <map>
+#include <list>
 
 class World;
 class TiXmlElement;
 
+struct QueueEntry
+{
+  float respawnTime;
+  WorldEntity * entity;
+  OM_LIST list;
+};
 
 //!< used to indicate what type of objects are spawned by this spawning point
@@ -50,4 +56,7 @@
     /** sets the spawning point mode @param mode: the mode */
     void SpawningPoint::setSpawningMode(int mode) { this->mode = (SpawningPointMode)mode; }
+    
+    inline int getTeamId(){ return this->teamId; }
+    inline void setTeamId( int teamId ){ this->teamId = teamId; }
 
     void pushEntity(WorldEntity* entity, float delay = 0);
@@ -72,7 +81,8 @@
     float                           localTimer;                     //!< the local timer
     float                           seed;                           //!< the random seed of the position
+    int                             teamId;                         //!< only spawn players of this team
     ClassID                         classid;                        //!< the classid of the entity to spawn
     SpawningPointMode               mode;                           //!< the mode of the spawning point
-    std::map<WorldEntity*, float>   queue;                          //!< queue of waiting WorldEntities to be spawned
+    std::list<QueueEntry>           queue;                          //!< queue of waiting WorldEntities to be spawned
     bool                            bSpawning;                      //!< flag to indicate if this spawning point is active or not
 };
