diff -Naur teeworlds-0.4.2-src/src/engine/e_if_server.h racemodspam/src/engine/e_if_server.h
--- teeworlds-0.4.2-src/src/engine/e_if_server.h	2008-04-05 15:13:02.000000000 +0200
+++ racemodspam/src/engine/e_if_server.h	2008-08-07 17:53:52.000000000 +0200
@@ -106,7 +106,9 @@
 		<other_func>
 */
 void server_kick(int client_id, const char *reason);
-
+void server_ban(int client_id, int time, char *ban_message);
+void server_ban_saved(int time, char *ban_message);
+void server_save_ip(int client_id);
 /*
 	Function: server_tick
 		TODO
diff -Naur teeworlds-0.4.2-src/src/engine/server/es_server.c racemodspam/src/engine/server/es_server.c
--- teeworlds-0.4.2-src/src/engine/server/es_server.c	2008-04-05 15:13:02.000000000 +0200
+++ racemodspam/src/engine/server/es_server.c	2008-09-17 16:16:56.000000000 +0200
@@ -2,6 +2,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <ctype.h>
 
 #include <engine/e_system.h>
 #include <engine/e_config.h>
@@ -38,6 +39,10 @@
 static int current_map_crc;
 static unsigned char *current_map_data = 0;
 static int current_map_size = 0;
+int *banlist;
+int *bantime;
+int bans=0;
+int saved_ip=0;
 
 void *snap_new_item(int type, int id, int size)
 {
@@ -69,20 +74,20 @@
 	SRVCLIENT_STATE_CONNECTING,
 	SRVCLIENT_STATE_READY,
 	SRVCLIENT_STATE_INGAME,
-	
+
 	SRVCLIENT_SNAPRATE_INIT=0,
 	SRVCLIENT_SNAPRATE_FULL,
 	SRVCLIENT_SNAPRATE_RECOVER
 };
 
-typedef struct 
+typedef struct
 {
 	int data[MAX_INPUT_SIZE];
 	int pred_tick; /* tick that the client predicted for the input */
 	int game_tick; /* the tick that was chosen for the input */
 	int64 timeleft; /* how much time in ms there were left before this should be applied */
 } CLIENT_INPUT;
-	
+
 /* */
 typedef struct
 {
@@ -90,14 +95,14 @@
 	int state;
 	int latency;
 	int snap_rate;
-	
+
 	int last_acked_snapshot;
 	SNAPSTORAGE snapshots;
-	
+
 	CLIENT_INPUT latestinput;
 	CLIENT_INPUT inputs[200]; /* TODO: handle input better */
 	int current_input;
-	
+
 	char name[MAX_NAME_LENGTH];
 	char clan[MAX_CLANNAME_LENGTH];
 	int score;
@@ -107,6 +112,22 @@
 static CLIENT clients[MAX_CLIENTS];
 NETSERVER *net;
 
+struct blacklist
+{
+	char *name;
+	struct blacklist *next;
+};
+static struct blacklist *start, *end;
+
+static void str_lower(char *str)
+{
+	int i = 0;
+	for(;str[i];i++)
+	{
+		str[i] = tolower(str[i]);
+	}
+}
+
 static void snap_init_id()
 {
 	int i;
@@ -115,31 +136,31 @@
 		snap_ids[i].next = i+1;
 		snap_ids[i].state = 0;
 	}
-		
+
 	snap_ids[MAX_IDS-1].next = -1;
 	snap_first_free_id = 0;
 	snap_first_timed_id = -1;
 	snap_last_timed_id = -1;
 	snap_id_usage = 0;
 	snap_id_inusage = 0;
-	
+
 	snap_id_inited = 1;
 }
 
 static void snap_remove_first_timeout()
 {
 	int next_timed = snap_ids[snap_first_timed_id].next;
-	
+
 	/* add it to the free list */
 	snap_ids[snap_first_timed_id].next = snap_first_free_id;
 	snap_ids[snap_first_timed_id].state = 0;
 	snap_first_free_id = snap_first_timed_id;
-	
+
 	/* remove it from the timed list */
 	snap_first_timed_id = next_timed;
 	if(snap_first_timed_id == -1)
 		snap_last_timed_id = -1;
-		
+
 	snap_id_usage--;
 }
 
@@ -148,12 +169,12 @@
 	int id;
 	int64 now = time_get();
 	dbg_assert(snap_id_inited == 1, "requesting id too soon");
-	
-	
+
+
 	/* process timed ids */
 	while(snap_first_timed_id != -1 && snap_ids[snap_first_timed_id].timeout < now)
 		snap_remove_first_timeout();
-	
+
 	id = snap_first_free_id;
 	dbg_assert(id != -1, "id error");
 	snap_first_free_id = snap_ids[snap_first_free_id].next;
@@ -178,7 +199,7 @@
 	snap_ids[id].state = 2;
 	snap_ids[id].timeout = time_get()+time_freq()*5;
 	snap_ids[id].next = -1;
-	
+
 	if(snap_last_timed_id != -1)
 	{
 		snap_ids[snap_last_timed_id].next = id;
@@ -222,10 +243,32 @@
 void server_setclientname(int client_id, const char *name)
 {
 	char nametry[MAX_NAME_LENGTH];
+	char name_lower[MAX_NAME_LENGTH];
 	int i;
+	struct blacklist *act;
+	act = start;
 	if(client_id < 0 || client_id > MAX_CLIENTS || clients[client_id].state < SRVCLIENT_STATE_READY)
 		return;
-		
+	if(!strcmp("", name))
+	{
+		server_kick(client_id, "This name is not allowed here!");
+	}
+	if(config.sv_name_blacklist)
+	{
+		strcpy(name_lower, name);
+		str_lower(name_lower);
+		while(1)
+		{
+			if(strstr(name_lower, (*act).name) != NULL)
+			{
+				server_ban(client_id, 30, "Forbidden name");
+				return;
+			}
+			if(act == end)
+				break;
+			act = (*act).next;
+		}
+	}
 	str_copy(nametry, name, MAX_NAME_LENGTH);
 	if(server_try_setclientname(client_id, nametry))
 	{
@@ -260,11 +303,80 @@
 {
 	if(client_id < 0 || client_id > MAX_CLIENTS)
 		return;
-		
+
 	if(clients[client_id].state != SRVCLIENT_STATE_EMPTY)
 		netserver_drop(net, client_id, reason);
 }
 
+void server_save_ip(int client_id)
+{
+	if(clients[client_id].state != SRVCLIENT_STATE_EMPTY)
+	{
+		NETADDR4 addr;
+		netserver_client_addr(net, client_id, &addr);
+		saved_ip = (addr.ip[0]<<24)+(addr.ip[1]<<16)+(addr.ip[2]<<8)+addr.ip[3];
+	}
+	else
+		saved_ip = 0;
+}
+
+void server_ban_saved(int time, char *ban_message)
+{
+	int i;
+	NETADDR4 addr;
+	char reason[256];
+	bans++;
+	if (bans==1) {banlist=malloc(sizeof(long));bantime=malloc(sizeof(long));}
+	else {banlist=realloc(banlist,sizeof(long)*bans);bantime=realloc(bantime,sizeof(long)*bans);}
+	banlist[bans-1]=saved_ip;
+	if(time > 0)bantime[bans-1]=server_tick()+server_tickspeed()*time *60;
+	else bantime[bans-1]=0;
+
+	if(time > 0)str_format(reason, sizeof(reason), "Banned by console for %d minutes",time);
+	else str_format(reason, sizeof(reason), "Banned by console permanently.");
+	for(i = 0; i < MAX_CLIENTS; i++)
+	{
+		if(clients[i].state != SRVCLIENT_STATE_EMPTY)
+		{
+			netserver_client_addr(net, i, &addr);
+			if(saved_ip == (addr.ip[0]<<24)+(addr.ip[1]<<16)+(addr.ip[2]<<8)+addr.ip[3])
+			{
+				if(strlen(ban_message) > 0)
+					server_kick(i, ban_message);
+				else
+					server_kick(i, reason);
+			}
+		}
+	}
+}
+
+void server_ban(int client_id, int time, char *ban_message) {
+        NETADDR4 addr;
+        int clientip;
+	char reason[256];
+	if (clients[client_id].authed != 1)
+	{
+		netserver_client_addr(net, client_id, &addr);
+
+		clientip=(addr.ip[0]<<24)+(addr.ip[1]<<16)+(addr.ip[2]<<8)+addr.ip[3];
+		dbg_msg("server", "the ip %d.%d.%d.%d is now banned",addr.ip[0],addr.ip[1],addr.ip[2],addr.ip[3]);
+
+		bans++;
+		if (bans==1) {banlist=malloc(sizeof(long));bantime=malloc(sizeof(long));}
+		else {banlist=realloc(banlist,sizeof(long)*bans);bantime=realloc(bantime,sizeof(long)*bans);}
+		banlist[bans-1]=clientip;
+		if(time > 0)bantime[bans-1]=server_tick()+server_tickspeed()*time *60;
+		else bantime[bans-1]=0;
+
+		if(time > 0)str_format(reason, sizeof(reason), "Banned by console for %d minutes",time);
+		else str_format(reason, sizeof(reason), "Banned by console permanently.");
+		if(strlen(ban_message) > 0)
+			server_kick(client_id, ban_message);
+		else
+			server_kick(client_id, reason);
+	}
+}
+
 int server_tick()
 {
 	return current_tick;
@@ -317,16 +429,16 @@
 	NETPACKET packet;
 	if(!info)
 		return -1;
-		
+
 	mem_zero(&packet, sizeof(NETPACKET));
-	
+
 	packet.client_id = client_id;
 	packet.data = info->data;
 	packet.data_size = info->size;
 
-	if(info->flags&MSGFLAG_VITAL)	
+	if(info->flags&MSGFLAG_VITAL)
 		packet.flags = PACKETFLAG_VITAL;
-			
+
 	if(client_id == -1)
 	{
 		/* broadcast */
@@ -346,7 +458,7 @@
 static void server_do_snap()
 {
 	int i, k;
-	
+
 	{
 		static PERFORMACE_INFO scope = {"presnap", 0};
 		perf_start(&scope);
@@ -359,15 +471,15 @@
 		/* client must be ingame to recive snapshots */
 		if(clients[i].state != SRVCLIENT_STATE_INGAME)
 			continue;
-			
+
 		/* this client is trying to recover, don't spam snapshots */
 		if(clients[i].snap_rate == SRVCLIENT_SNAPRATE_RECOVER && (server_tick()%50) != 0)
 			continue;
-			
+
 		/* this client is trying to recover, don't spam snapshots */
 		if(clients[i].snap_rate == SRVCLIENT_SNAPRATE_INIT && (server_tick()%10) != 0)
 			continue;
-			
+
 		{
 			char data[MAX_SNAPSHOT_SIZE];
 			char deltadata[MAX_SNAPSHOT_SIZE];
@@ -400,14 +512,14 @@
 			/* remove old snapshos */
 			/* keep 1 seconds worth of snapshots */
 			snapstorage_purge_until(&clients[i].snapshots, current_tick-SERVER_TICK_SPEED);
-			
+
 			/* save it the snapshot */
 			snapstorage_add(&clients[i].snapshots, current_tick, time_get(), snapshot_size, data, 0);
-			
+
 			/* find snapshot that we can preform delta against */
 			emptysnap.data_size = 0;
 			emptysnap.num_items = 0;
-			
+
 			{
 				deltashot_size = snapstorage_get(&clients[i].snapshots, clients[i].last_acked_snapshot, 0, &deltashot, 0);
 				if(deltashot_size >= 0)
@@ -419,7 +531,7 @@
 						clients[i].snap_rate = SRVCLIENT_SNAPRATE_RECOVER;
 				}
 			}
-			
+
 			for(k = 0; k < 200; k++) /* TODO: do this better */
 			{
 				if(clients[i].inputs[k].game_tick == current_tick)
@@ -429,7 +541,7 @@
 					break;
 				}
 			}
-			
+
 			/* create delta */
 			{
 				static PERFORMACE_INFO scope = {"delta", 0};
@@ -438,7 +550,7 @@
 				perf_end();
 			}
 
-			
+
 			if(deltasize)
 			{
 				/* compress it */
@@ -449,17 +561,17 @@
 				int numpackets;
 				int n, left;
 
-				{				
+				{
 					static PERFORMACE_INFO scope = {"compress", 0};
 					perf_start(&scope);
-					
+
 					{
 						static PERFORMACE_INFO scope = {"int", 0};
 						perf_start(&scope);
 						intsize = intpack_compress(deltadata, deltasize, intdata);
 						perf_end();
 					}
-					
+
 					{
 						static PERFORMACE_INFO scope = {"zero", 0};
 						perf_start(&scope);
@@ -468,12 +580,12 @@
 					}
 					perf_end();
 				}
-				
+
 
 				numpackets = (snapshot_size+max_size-1)/max_size;
-				
-				
-				
+
+
+
 				for(n = 0, left = snapshot_size; left; n++)
 				{
 					int chunk = left < max_size ? left : max_size;
@@ -483,18 +595,18 @@
 						msg_pack_start_system(NETMSG_SNAPSINGLE, 0);
 					else
 						msg_pack_start_system(NETMSG_SNAP, 0);
-						
+
 					msg_pack_int(current_tick);
 					msg_pack_int(current_tick-delta_tick); /* compressed with */
 					msg_pack_int(input_predtick);
 					msg_pack_int((timeleft*1000)/time_freq());
-					
+
 					if(numpackets != 1)
 					{
 						msg_pack_int(numpackets);
 						msg_pack_int(n);
 					}
-					
+
 					msg_pack_int(crc);
 					msg_pack_int(chunk);
 					msg_pack_raw(&compdata[n*max_size], chunk);
@@ -512,7 +624,7 @@
 				msg_pack_end();
 				server_send_msg(i);
 			}
-			
+
 			perf_end();
 		}
 	}
@@ -527,7 +639,7 @@
 	clients[cid].state = SRVCLIENT_STATE_CONNECTING;
 	clients[cid].name[0] = 0;
 	clients[cid].clan[0] = 0;
-	
+
 	/* reset input */
 	for(i = 0; i < 200; i++)
 	{
@@ -535,9 +647,9 @@
 		clients[cid].inputs[i].pred_tick = -1;
 	}
 	clients[cid].current_input = 0;
-	
+
 	mem_zero(&clients[cid].latestinput, sizeof(clients[cid].latestinput));
-	
+
 	snapstorage_purge_all(&clients[cid].snapshots);
 	clients[cid].last_acked_snapshot = -1;
 	clients[cid].snap_rate = SRVCLIENT_SNAPRATE_INIT;
@@ -584,16 +696,16 @@
 {
 	static volatile int reentry_guard = 0;
 	int i;
-	
+
 	if(reentry_guard) return;
 	reentry_guard++;
-	
+
 	for(i = 0; i < MAX_CLIENTS; i++)
 	{
 		if(clients[i].state != SRVCLIENT_STATE_EMPTY && clients[i].authed)
 			server_send_rcon_line(i, line);
 	}
-	
+
 	reentry_guard--;
 }
 
@@ -602,6 +714,9 @@
 	int cid = packet->client_id;
 	int sys;
 	int msg = msg_unpack_start(packet->data, packet->data_size, &sys);
+	int i;
+	int clientip;
+	NETADDR4 addr;
 	if(sys)
 	{
 		/* system message */
@@ -610,7 +725,7 @@
 			char version[64];
 			const char *password;
 			str_copy(version, msg_unpack_string(), 64);
-			if(strcmp(version, mods_net_version()) != 0)
+			if(strcmp(version, "0.4 1bd7780b0f76307c") != 0)
 			{
 				/* OH FUCK! wrong version, drop him */
 				char reason[256];
@@ -618,18 +733,32 @@
 				netserver_drop(net, cid, reason);
 				return;
 			}
-			
+
 			str_copy(clients[cid].name, msg_unpack_string(), MAX_NAME_LENGTH);
 			str_copy(clients[cid].clan, msg_unpack_string(), MAX_CLANNAME_LENGTH);
 			password = msg_unpack_string();
-			
+
 			if(config.password[0] != 0 && strcmp(config.password, password) != 0)
 			{
 				/* wrong password */
 				netserver_drop(net, cid, "wrong password");
 				return;
 			}
-			
+			if(cid >= (config.sv_max_clients-config.sv_reserved_slots) && config.sv_reserved_slots_pass[0] != 0 && strcmp(config.sv_reserved_slots_pass, password) != 0)
+			{
+				/* wrong password */
+				netserver_drop(net, cid, "Dropped due reserved slot");
+				return;
+			}
+
+			netserver_client_addr(net, cid, &addr);
+			clientip=(addr.ip[0]<<24)+(addr.ip[1]<<16)+(addr.ip[2]<<8)+addr.ip[3];
+			for (i=0; i<bans; i++) {
+				if (banlist[i]==clientip) {
+					dbg_msg("server", "a banned player (ip=%d.%d.%d.%d) is trying to enter",addr.ip[0],addr.ip[1],addr.ip[2],addr.ip[3]);
+					netserver_drop(net, cid, "You are banned");
+				}
+			}
 			server_send_map(cid);
 		}
 		else if(msg == NETMSG_REQUEST_MAP_DATA)
@@ -638,7 +767,7 @@
 			int chunk_size = 1024-128;
 			int offset = chunk * chunk_size;
 			int last = 0;
-			
+
 			if(offset+chunk_size >= current_map_size)
 			{
 				chunk_size = current_map_size-offset;
@@ -646,7 +775,7 @@
 					chunk_size = 0;
 				last = 1;
 			}
-			
+
 			msg_pack_start_system(NETMSG_MAP_DATA, MSGFLAG_VITAL);
 			msg_pack_int(last);
 			msg_pack_int(current_map_size);
@@ -654,7 +783,7 @@
 			msg_pack_raw(&current_map_data[offset], chunk_size);
 			msg_pack_end();
 			server_send_msg(cid);
-			
+
 			if(config.debug)
 				dbg_msg("server", "sending chunk %d with size %d", chunk, chunk_size);
 		}
@@ -685,41 +814,41 @@
 			clients[cid].last_acked_snapshot = msg_unpack_int();
 			tick = msg_unpack_int();
 			size = msg_unpack_int();
-			
+
 			/* check for errors */
 			if(msg_unpack_error() || size/4 > MAX_INPUT_SIZE)
 				return;
-			
+
 			if(clients[cid].last_acked_snapshot > 0)
 				clients[cid].snap_rate = SRVCLIENT_SNAPRATE_FULL;
-				
+
 			if(snapstorage_get(&clients[cid].snapshots, clients[cid].last_acked_snapshot, &tagtime, 0, 0) >= 0)
 				clients[cid].latency = (int)(((time_get()-tagtime)*1000)/time_freq());
 
 			input = &clients[cid].inputs[clients[cid].current_input];
 			input->timeleft = server_tick_start_time(tick)-time_get();
 			input->pred_tick = tick;
-			
+
 			if(tick <= server_tick())
 				tick = server_tick()+1;
 
 			input->game_tick = tick;
-			
+
 			for(i = 0; i < size/4; i++)
 				input->data[i] = msg_unpack_int();
-			
+
 			mem_copy(clients[cid].latestinput.data, input->data, MAX_INPUT_SIZE*sizeof(int));
-			
+
 			clients[cid].current_input++;
 			clients[cid].current_input %= 200;
-		
+
 			/* call the mod with the fresh input data */
 			mods_client_direct_input(cid, clients[cid].latestinput.data);
 		}
 		else if(msg == NETMSG_RCON_CMD)
 		{
 			const char *cmd = msg_unpack_string();
-			
+
 			if(msg_unpack_error() == 0 && clients[cid].authed)
 			{
 				dbg_msg("server", "cid=%d rcon='%s'", cid, cmd);
@@ -731,7 +860,7 @@
 			const char *pw;
 			msg_unpack_string(); /* login name, not used */
 			pw = msg_unpack_string();
-			
+
 			if(msg_unpack_error() == 0)
 			{
 				if(config.sv_rcon_password[0] == 0)
@@ -744,7 +873,7 @@
 					msg_pack_int(1);
 					msg_pack_end();
 					server_send_msg(cid);
-					
+
 					clients[cid].authed = 1;
 					server_send_rcon_line(cid, "Authentication successful. Remote console access granted.");
 					dbg_msg("server", "cid=%d authed", cid);
@@ -779,7 +908,7 @@
 	PACKER p;
 	char buf[128];
 
-	/* count the players */	
+	/* count the players */
 	int c = 0;
 	int i;
 	for(i = 0; i < MAX_CLIENTS; i++)
@@ -787,7 +916,7 @@
 		if(clients[i].state != SRVCLIENT_STATE_EMPTY)
 			c++;
 	}
-	
+
 	packer_reset(&p);
 	if(lan)
 		packer_add_raw(&p, SERVERBROWSE_INFO_LAN, sizeof(SERVERBROWSE_INFO_LAN));
@@ -811,7 +940,7 @@
 	/* progression */
 	str_format(buf, sizeof(buf), "%d", browseinfo_progression);
 	packer_add_string(&p, buf, 4);
-	
+
 	str_format(buf, sizeof(buf), "%d", c); packer_add_string(&p, buf, 3);  /* num players */
 	str_format(buf, sizeof(buf), "%d", netserver_max_clients(net)); packer_add_string(&p, buf, 3); /* max players */
 
@@ -823,8 +952,8 @@
 			str_format(buf, sizeof(buf), "%d", clients[i].score); packer_add_string(&p, buf, 6);  /* player score */
 		}
 	}
-	
-	
+
+
 	packet.client_id = -1;
 	packet.address = *addr;
 	packet.flags = PACKETFLAG_CONNLESS;
@@ -841,7 +970,7 @@
 	NETPACKET packet;
 
 	netserver_update(net);
-	
+
 	/* process packets */
 	while(netserver_recv(net, &packet))
 	{
@@ -875,17 +1004,17 @@
 	df = datafile_load(buf);
 	if(!df)
 		return 0;
-	
+
 	/* reinit snapshot ids */
 	snap_timeout_ids();
-	
+
 	/* get the crc of the map */
 	current_map_crc = datafile_crc(buf);
 	dbg_msg("server", "%s crc is %08x", buf, current_map_crc);
-		
+
 	str_copy(current_map, mapname, sizeof(current_map));
 	map_set(df);
-	
+
 	/* load compelate map into memory for download */
 	{
 		IOHANDLE file = io_open(buf, IOFLAG_READ);
@@ -905,7 +1034,7 @@
 
 	net_init();
 	snap_init_id();
-	
+
 	/* */
 	console_register_print_callback(server_send_rcon_line_authed);
 
@@ -915,7 +1044,7 @@
 		dbg_msg("server", "failed to load map. mapname='%s'", config.sv_map);
 		return -1;
 	}
-	
+
 	/* start server */
 	if(config.sv_bindaddr[0] && net_host_lookup(config.sv_bindaddr, config.sv_port, &bindaddr) == 0)
 	{
@@ -926,18 +1055,49 @@
 		mem_zero(&bindaddr, sizeof(bindaddr));
 		bindaddr.port = config.sv_port;
 	}
-	
+	if(config.sv_name_blacklist)
+	{
+
+		FILE *name_file = fopen("name_blacklist", "r");
+		if(name_file != NULL)
+		{
+			char tmp_names[MAX_NAME_LENGTH];
+			if(fgets(tmp_names, MAX_NAME_LENGTH, name_file) != NULL)
+			{
+				tmp_names[strlen(tmp_names)-1] = 0;
+				start = malloc(sizeof(struct blacklist));
+				end = start;
+				(*start).name = malloc(MAX_NAME_LENGTH);
+				strcpy((*start).name, tmp_names);
+				str_lower((*start).name);
+			}
+			while(fgets(tmp_names, MAX_NAME_LENGTH, name_file) != NULL)
+			{
+				tmp_names[strlen(tmp_names)-1] = 0;
+				(*end).next = malloc(sizeof(struct blacklist));
+				end = (*end).next;
+				(*end).name = malloc(MAX_NAME_LENGTH);
+				strcpy((*end).name, tmp_names);
+				str_lower((*end).name);
+			}
+			fclose(name_file);
+		}
+		else
+		{
+			config.sv_name_blacklist = 0;
+		}
+	}
 	net = netserver_open(bindaddr, config.sv_max_clients, 0);
 	if(!net)
 	{
 		dbg_msg("server", "couldn't open socket. port might already be in use");
 		return -1;
 	}
-	
+
 	netserver_set_callbacks(net, new_client_callback, del_client_callback, 0);
-	
+
 	dbg_msg("server", "server name is '%s'", config.sv_name);
-	
+
 	mods_init();
 	dbg_msg("server", "version %s", mods_net_version());
 
@@ -945,10 +1105,10 @@
 	{
 		int64 reporttime = time_get();
 		int reportinterval = 3;
-	
+
 		lastheartbeat = 0;
 		game_start_time = time_get();
-	
+
 		if(config.debug)
 			dbg_msg("server", "baseline memory usage %dk", mem_allocated()/1024);
 
@@ -957,34 +1117,34 @@
 			static PERFORMACE_INFO rootscope = {"root", 0};
 			int64 t = time_get();
 			int new_ticks = 0;
-			
+
 			perf_start(&rootscope);
-			
+
 			/* load new map TODO: don't poll this */
 			if(strcmp(config.sv_map, current_map) != 0 || config.sv_map_reload)
 			{
 				config.sv_map_reload = 0;
-				
+
 				/* load map */
 				if(server_load_map(config.sv_map))
 				{
 					int c;
-					
+
 					/* new map loaded */
 					mods_shutdown();
-					
+
 					for(c = 0; c < MAX_CLIENTS; c++)
 					{
 						if(clients[c].state == SRVCLIENT_STATE_EMPTY)
 							continue;
-						
+
 						server_send_map(c);
 						clients[c].state = SRVCLIENT_STATE_CONNECTING;
 						clients[c].last_acked_snapshot = -1;
 						clients[c].snap_rate = SRVCLIENT_SNAPRATE_RECOVER;
 						snapstorage_purge_all(&clients[c].snapshots);
 					}
-					
+
 					game_start_time = time_get();
 					current_tick = 0;
 					mods_init();
@@ -995,19 +1155,19 @@
 					config_set_sv_map(&config, current_map);
 				}
 			}
-			
+
 			while(t > server_tick_start_time(current_tick+1))
 			{
 				current_tick++;
 				new_ticks++;
-				
+
 				/* apply new input */
 				{
 					static PERFORMACE_INFO scope = {"input", 0};
 					int c, i;
-					
+
 					perf_start(&scope);
-					
+
 					for(c = 0; c < MAX_CLIENTS; c++)
 					{
 						if(clients[c].state == SRVCLIENT_STATE_EMPTY)
@@ -1021,10 +1181,10 @@
 							}
 						}
 					}
-					
+
 					perf_end();
 				}
-				
+
 				/* progress game */
 				{
 					static PERFORMACE_INFO scope = {"tick", 0};
@@ -1033,7 +1193,7 @@
 					perf_end();
 				}
 			}
-			
+
 			/* snap game */
 			if(new_ticks)
 			{
@@ -1044,11 +1204,27 @@
 					server_do_snap();
 					perf_end();
 				}
+				if (bans>0) {
+					int i=0,j=0;
+					for (i=0; i<bans; i++) {
+						if(bantime[i] != 0 && server_tick()-bantime[i] > server_tickspeed())
+						{
+							dbg_msg("server","the IP=%d:%d:%d:%d is no longer banned",i,((banlist[i]>>24)&0xFF),((banlist[i]>>16)&0xFF),((banlist[i]>>8)&0xFF),(banlist[i]&0xFF));
+							for (j=i; j<bans; j++) {
+								banlist[j]=banlist[j+1];
+								bantime[j]=bantime[j+1];
+							}
+							bans--;
+							realloc(banlist,sizeof(long)*bans);
+							realloc(bantime,sizeof(long)*bans);
+						}
+					}
+				}
 			}
-			
+
 			/* master server stuff */
 			register_update();
-	
+
 
 			{
 				static PERFORMACE_INFO scope = {"net", 0};
@@ -1058,7 +1234,7 @@
 			}
 
 			perf_end();
-	
+
 			if(reporttime < time_get())
 			{
 				if(config.debug)
@@ -1066,22 +1242,22 @@
 					static NETSTATS prev_stats;
 					NETSTATS stats;
 					netserver_stats(net, &stats);
-					
+
 					perf_next();
-					
+
 					if(config.dbg_pref)
 						perf_dump(&rootscope);
 
 					dbg_msg("server", "send=%8d recv=%8d",
 						(stats.send_bytes - prev_stats.send_bytes)/reportinterval,
 						(stats.recv_bytes - prev_stats.recv_bytes)/reportinterval);
-						
+
 					prev_stats = stats;
 				}
-	
+
 				reporttime += time_freq()*reportinterval;
 			}
-			
+
 			/* wait for incomming data */
 			net_socket_read_wait(netserver_socket(net), 5);
 		}
@@ -1100,6 +1276,56 @@
 	server_kick(console_arg_int(result, 0), "kicked by console");
 }
 
+static void con_ban(void *result, void *user_data) {
+        NETADDR4 addr;
+        int clientip;
+	char reason[256];
+        netserver_client_addr(net, console_arg_int(result, 0), &addr);
+
+        clientip=(addr.ip[0]<<24)+(addr.ip[1]<<16)+(addr.ip[2]<<8)+addr.ip[3];
+        dbg_msg("server", "the ip %d.%d.%d.%d is now banned",addr.ip[0],addr.ip[1],addr.ip[2],addr.ip[3]);
+
+        bans++;
+        if (bans==1) {banlist=malloc(sizeof(long));bantime=malloc(sizeof(long));}
+        else {banlist=realloc(banlist,sizeof(long)*bans);bantime=realloc(bantime,sizeof(long)*bans);}
+        banlist[bans-1]=clientip;
+	if(console_arg_int(result, 1) > 0)bantime[bans-1]=server_tick()+server_tickspeed()*console_arg_int(result, 1)*60;
+	else bantime[bans-1]=0;
+
+	if(console_arg_int(result, 1) > 0)str_format(reason, sizeof(reason), "Banned by console for %d minutes",console_arg_int(result, 1));
+	else str_format(reason, sizeof(reason), "Banned by console permanently.");
+	server_kick(console_arg_int(result, 0), reason);
+}
+
+static void con_banlist(void *result, void *user_data) {
+        int i;
+        if (bans>0) {
+                for (i=0; i<bans; i++) {
+                        dbg_msg("server","banid=%d, IP=%d:%d:%d:%d, time:%d min",i,((banlist[i]>>24)&0xFF),((banlist[i]>>16)&0xFF),((banlist[i]>>8)&0xFF),(banlist[i]&0xFF),(bantime[i]-server_tick())/(server_tickspeed()*60));
+                }
+        } else {
+                dbg_msg("server","there is no ban");
+        }
+}
+
+static void con_unban(void *result, void *user_data) {
+        int i=0;
+        int d=console_arg_int(result, 0);
+
+        if (d<0 || d>=bans) dbg_msg("server","no such banid: %d, type banlist to see banids",d);
+        else
+	{
+		dbg_msg("server","the IP=%d:%d:%d:%d is no longer banned",d,((banlist[d]>>24)&0xFF),((banlist[d]>>16)&0xFF),((banlist[d]>>8)&0xFF),(banlist[d]&0xFF));
+                for (i=d; i<bans; i++) {
+                        banlist[i]=banlist[i+1];
+			bantime[i]=bantime[i+1];
+                }
+                bans--;
+                realloc(banlist,sizeof(long)*bans);
+		realloc(bantime,sizeof(long)*bans);
+	}
+}
+
 static void con_status(void *result, void *user_data)
 {
 	int i;
@@ -1122,11 +1348,37 @@
 	/*server_kick(console_arg_int(result, 0), "kicked by console");*/
 }
 
+static void con_add_name_blacklist(void *result, void *user_data)
+{
+	FILE *names_blacklist = fopen("name_blacklist", "a");
+	if(!config.sv_name_blacklist)
+	{
+		fclose(names_blacklist);
+		return;
+	}
+	(*end).next = malloc(sizeof(struct blacklist));
+	end = (*end).next;
+	(*end).name = malloc(100);
+
+	strcpy((*end).name, console_arg_string(result, 0));
+	str_lower((*end).name);
+	if(names_blacklist != NULL)
+	{
+		fputs((*end).name, names_blacklist);
+		fputs("\n", names_blacklist);
+		fclose(names_blacklist);
+	}
+}
+
 static void server_register_commands()
 {
 	MACRO_REGISTER_COMMAND("kick", "i", con_kick, 0);
 	MACRO_REGISTER_COMMAND("status", "", con_status, 0);
 	MACRO_REGISTER_COMMAND("shutdown", "", con_shutdown, 0);
+	MACRO_REGISTER_COMMAND("ban", "ii", con_ban, 0);
+	MACRO_REGISTER_COMMAND("banlist", "", con_banlist, 0);
+	MACRO_REGISTER_COMMAND("unban", "i", con_unban, 0);
+	MACRO_REGISTER_COMMAND("add_blacklist", "s", con_add_name_blacklist, 0);
 }
 
 int main(int argc, char **argv)
@@ -1146,14 +1398,14 @@
 	/* init the engine */
 	dbg_msg("server", "starting...");
 	engine_init("Teeworlds");
-	
+
 	/* register all console commands */
 	server_register_commands();
 	mods_console_init();
-	
+
 	/* parse the command line arguments */
 	engine_parse_arguments(argc, argv);
-	
+
 	/* run the server */
 	server_run();
 	return 0;
diff -Naur teeworlds-0.4.2-src/src/game/g_collision.cpp racemodspam/src/game/g_collision.cpp
--- teeworlds-0.4.2-src/src/game/g_collision.cpp	2008-04-05 15:13:02.000000000 +0200
+++ racemodspam/src/game/g_collision.cpp	2008-08-02 08:08:48.000000000 +0200
@@ -8,8 +8,10 @@
 #include <game/g_layers.h>
 
 static TILE *tiles;
+static int *dest[10];
 static int width = 0;
 static int height = 0;
+static int len[10];
 
 int col_width() { return width; }
 int col_height() { return height; }
@@ -19,6 +21,25 @@
 	width = layers_game_layer()->width;
 	height = layers_game_layer()->height;
 	tiles = (TILE *)map_get_data(layers_game_layer()->data);
+	mem_zero(&len, sizeof(len));
+	for(int i=width*height-1;i>=0;i--) {
+		if(tiles[i].index==TILE_AIR) {
+			len[0]++;
+		} else if((tiles[i].index&1)!=0 && tiles[i].index>2 && tiles[i].index<21) {
+			len[tiles[i].index>>1]++;
+		}
+	}
+	for(int i=0;i<10;i++) {
+		dest[i] = new int[len[i]];
+		len[i] = 0;
+	}
+	for(int i=width*height-1;i>=0;i--) {
+		if(tiles[i].index==TILE_AIR) {
+			dest[0][len[0]++] = i;
+		} else if((tiles[i].index&1)!=0 && tiles[i].index>2 && tiles[i].index<21) {
+			dest[tiles[i].index>>1][len[tiles[i].index>>1]++] = i;
+		}
+	}
 	return 1;
 }
 
@@ -30,12 +51,87 @@
 	if(nx < 0 || nx >= width || ny >= height)
 		return 1;
 	
-	if(y < 0)
-		return 0; // up == sky == free
+	if(y<0) {
+		return(tiles[nx].index==TILE_SOLID);
+	}
 	
 	return tiles[ny*width+nx].index == TILE_SOLID;
 }
 
+int col_is_damage(int x, int y)
+{
+	int nx = x/32;
+	int ny = y/32;
+	if(y<0 || nx < 0 || nx >= width || ny >= height)
+		return 0;
+	
+	return tiles[ny*width+nx].index == TILE_DAMAGE;
+}
+
+int col_is_nohook(int x, int y)
+{
+	int nx = x/32;
+	int ny = y/32;
+	if(nx < 0 || nx >= width || ny >= height)
+		return 0;
+
+	if(y<0) {
+		return(tiles[nx].index==TILE_NOHOOK);
+	}
+	
+	return tiles[ny*width+nx].index == TILE_NOHOOK;
+}
+
+int col_is_teleport(int x, int y)
+{
+	int nx = x/32;
+	int ny = y/32;
+	if(y < 0 || nx < 0 || nx >= width || ny >= height)
+		return 0;
+
+	int z = tiles[ny*width+nx].index-1;
+	if(z>2 && z<21 && (z&1)!=0) {
+		return(z>>1);
+	}
+	return(0);
+}
+
+int col_is_begin(int x, int y)
+{
+	int nx = x/32;
+	int ny = y/32;
+	if(y<0 || nx < 0 || nx >= width || ny >= height)
+		return 0;
+	
+	return tiles[ny*width+nx].index == TILE_BEGIN;
+}
+int col_is_end(int x, int y)
+{
+	int nx = x/32;
+	int ny = y/32;
+	if(y<0 || nx < 0 || nx >= width || ny >= height)
+		return 0;
+	
+	return tiles[ny*width+nx].index == TILE_END;
+}
+vec2 teleport(int a) {
+	if(len[a]>0) {
+		int r = rand()%len[a];
+		int x = (dest[a][r]%width)<<5;
+		int y = (dest[a][r]/width)<<5;
+		return(vec2((float)x+16.0,(float)y+16.0));
+	} else {
+		return(vec2(0,0));
+	}
+}
+
+vec2 rand_point() {
+	int p = rand()%len[0];
+	int x = (dest[0][p]%width)<<5;
+	int y = (dest[0][p]/width)<<5;
+	return(vec2((float)x+16.0,(float)y+16.0));
+}
+
 // TODO: rewrite this smarter!
 bool col_intersect_line(vec2 pos0, vec2 pos1, vec2 *out)
 {
@@ -57,6 +153,21 @@
 	return false;
 }
 
+bool col_intersect_nohook(vec2 pos0, vec2 pos1)
+{
+	float d = distance(pos0, pos1);
+	
+	for(float f = 0; f < d; f++)
+	{
+		float a = f/d;
+		vec2 pos = mix(pos0, pos1, a);
+		if(col_is_nohook((int)pos.x, (int)pos.y)) {
+			return true;
+		}
+	}
+	return false;
+}
+
 /*
 	Simple collision rutines!
 */
diff -Naur teeworlds-0.4.2-src/src/game/g_collision.h racemodspam/src/game/g_collision.h
--- teeworlds-0.4.2-src/src/game/g_collision.h	2008-04-05 15:13:02.000000000 +0200
+++ racemodspam/src/game/g_collision.h	2008-08-02 08:08:48.000000000 +0200
@@ -7,8 +7,16 @@
 
 int col_init();
 int col_is_solid(int x, int y);
+int col_is_damage(int x, int y);
+int col_is_nohook(int x, int y);
+int col_is_teleport(int x, int y);
+int col_is_begin(int x, int y);
+int col_is_end(int x, int y);
 int col_width();
+vec2 teleport(int z);
 int col_height();
+vec2 rand_point();
 bool col_intersect_line(vec2 pos0, vec2 pos1, vec2 *out);
+bool col_intersect_nohook(vec2 pos0, vec2 pos1);
 
 #endif
diff -Naur teeworlds-0.4.2-src/src/game/g_game.cpp racemodspam/src/game/g_game.cpp
--- teeworlds-0.4.2-src/src/game/g_game.cpp	2008-04-05 15:13:02.000000000 +0200
+++ racemodspam/src/game/g_game.cpp	2008-08-22 21:38:24.000000000 +0200
@@ -1,6 +1,7 @@
 /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
 #include <string.h>
 #include "g_game.h"
+#include <engine/e_config.h>
 
 const char *tuning_params::names[] =
 {
@@ -271,6 +272,8 @@
 				going_to_hit_ground = true;
 
 			// Check against other players first
+			if(!config.sv_player_nohook)
+			{
 			for(int i = 0; i < MAX_CLIENTS; i++)
 			{
 				player_core *p = world->players[i];
@@ -286,7 +289,7 @@
 					break;
 				}
 			}
-			
+			}
 			if(hook_state == HOOK_FLYING)
 			{
 				// check against ground
@@ -377,7 +380,7 @@
 			// handle player <-> player collision
 			float d = distance(pos, p->pos);
 			vec2 dir = normalize(pos - p->pos);
-			if(d < phys_size*1.25f && d > 1.0f)
+			if(config.sv_player_collide && d < phys_size*1.25f && d > 1.0f)
 			{
 				float a = (phys_size*1.45f - d);
 				
diff -Naur teeworlds-0.4.2-src/src/game/g_game.h racemodspam/src/game/g_game.h
--- teeworlds-0.4.2-src/src/game/g_game.h	2008-04-05 15:13:02.000000000 +0200
+++ racemodspam/src/game/g_game.h	2008-09-17 16:35:30.000000000 +0200
@@ -20,11 +20,11 @@
 	}
 
 	static const char *names[];
-	
+
 	#define MACRO_TUNING_PARAM(name,value) tune_param name;
 	#include "g_tuning.h"
 	#undef MACRO_TUNING_PARAM
-	
+
 	static int num() { return sizeof(tuning_params)/sizeof(int); }
 	bool set(int index, float value);
 	bool set(const char *name, float value);
@@ -100,7 +100,7 @@
 	HOOK_RETRACT_END=3,
 	HOOK_FLYING,
 	HOOK_GRABBED,
-	
+
 	COREEVENT_GROUND_JUMP=0x01,
 	COREEVENT_AIR_JUMP=0x02,
 	COREEVENT_HOOK_LAUNCH=0x04,
@@ -116,7 +116,7 @@
 	{
 		mem_zero(players, sizeof(players));
 	}
-	
+
 	tuning_params tuning;
 	class player_core *players[MAX_CLIENTS];
 };
@@ -125,25 +125,26 @@
 {
 public:
 	world_core *world;
-	
+
 	vec2 pos;
 	vec2 vel;
-	
+
 	vec2 hook_pos;
 	vec2 hook_dir;
+	vec2 old_vel;
 	int hook_tick;
 	int hook_state;
 	int hooked_player;
-	
+
 	int jumped;
 	NETOBJ_PLAYER_INPUT input;
-	
+
 	int triggered_events;
-	
+
 	void reset();
 	void tick();
 	void move();
-	
+
 	void read(const NETOBJ_PLAYER_CORE *obj_core);
 	void write(NETOBJ_PLAYER_CORE *obj_core);
 	void quantize();
diff -Naur teeworlds-0.4.2-src/src/game/g_mapitems.h racemodspam/src/game/g_mapitems.h
--- teeworlds-0.4.2-src/src/game/g_mapitems.h	2008-04-05 15:13:02.000000000 +0200
+++ racemodspam/src/game/g_mapitems.h	2008-08-02 08:08:48.000000000 +0200
@@ -43,8 +43,28 @@
 	
 	TILE_AIR=0,
 	TILE_SOLID,
+	TILE_DAMAGE,
+	TILE_D1,
+	TILE_T1,
+	TILE_D2,
+	TILE_T2,
+	TILE_D3,
+	TILE_T3,
+	TILE_D4,
+	TILE_T4,
+	TILE_D5,
+	TILE_T5,
+	TILE_D6,
+	TILE_T6,
+	TILE_D7,
+	TILE_T7,
+	TILE_D8,
+	TILE_T8,
+	TILE_D9,
+	TILE_T9,
 	TILE_NOHOOK,
-	
+	TILE_BEGIN,
+	TILE_END,
 	TILEFLAG_VFLIP=1,
 	TILEFLAG_HFLIP=2,
 	TILEFLAG_OPAQUE=4,
diff -Naur teeworlds-0.4.2-src/src/game/g_variables.h racemodspam/src/game/g_variables.h
--- teeworlds-0.4.2-src/src/game/g_variables.h	2008-04-05 15:13:02.000000000 +0200
+++ racemodspam/src/game/g_variables.h	2008-09-17 17:03:11.000000000 +0200
@@ -57,3 +57,65 @@
 MACRO_CONFIG_INT(sv_spamprotection, 1, 0, 1)
 
 MACRO_CONFIG_INT(sv_spectator_slots, 0, 0, 12)
+
+MACRO_CONFIG_INT(sv_player_nohook, 0, 0, 1)
+MACRO_CONFIG_INT(sv_player_collide, 1, 0, 1)
+MACRO_CONFIG_INT(sv_ko_mode, 0, 0, 1)
+MACRO_CONFIG_INT(sv_teamchanges, 0, 0, 100)
+MACRO_CONFIG_INT(sv_time_blocked, 180, 1, 1000)
+MACRO_CONFIG_INT(sv_teamchangeskick, 0, 0, 100)
+MACRO_CONFIG_INT(sv_teamchangesban, 0, 0, 100)
+MACRO_CONFIG_INT(sv_messagesnum, 0, 0, 100)
+MACRO_CONFIG_INT(sv_same_messages, 0, 0, 100)
+MACRO_CONFIG_INT(sv_time_muted, 180, 1, 1000)
+MACRO_CONFIG_INT(sv_messageskick, 0, 0, 100)
+MACRO_CONFIG_INT(sv_messagesban, 0, 0, 100)
+MACRO_CONFIG_STR(sv_startmessage, 1000, "")
+MACRO_CONFIG_STR(sv_endroundmessage, 1000, "")
+MACRO_CONFIG_INT(sv_handle_mapvotes, 0, 0, 1)
+MACRO_CONFIG_INT(sv_kick_teamkiller, 0, 0, 100)
+MACRO_CONFIG_INT(sv_name_blacklist, 0, 0, 1)
+MACRO_CONFIG_INT(sv_reserved_slots, 0, 0, 12)
+MACRO_CONFIG_STR(sv_reserved_slots_pass, 32, "")
+MACRO_CONFIG_INT(sv_allow_votes, 1, 0, 1)
+MACRO_CONFIG_INT(sv_all_vote, 0, 0, 1)
+MACRO_CONFIG_INT(sv_votetime, 60, 0, 500)
+MACRO_CONFIG_INT(sv_ban_time, 10, 0, 1000)
+MACRO_CONFIG_INT(sv_regen, 0, 0, 0)
+MACRO_CONFIG_INT(sv_teleport, 0, 0, 1)
+MACRO_CONFIG_INT(sv_strip, 0, 0, 1)
+MACRO_CONFIG_INT(sv_infinite_ammo, 0, 0, 1)
+MACRO_CONFIG_STR(sv_start, 18, "1 1 0 0 0 0")
+MACRO_CONFIG_INT(sv_race_mod, 0, 0, 1)
+MACRO_CONFIG_INT(sv_teleport_grenade, 0, 0, 1)
+MACRO_CONFIG_INT(sv_teleport_kill, 0, 0, 1)
+MACRO_CONFIG_INT(sv_suicide_killer, 0, 0, 1)
+MACRO_CONFIG_INT(sv_rocket_jump_damage, 1, 0, 1)
+MACRO_CONFIG_INT(sv_powerup_respawn, 1, 0, 10)
+MACRO_CONFIG_STR(sv_rank_site, 32, "none")
+MACRO_CONFIG_INT(sv_team_balance, 0, 0, 100)
+MACRO_CONFIG_INT(sv_allow_next_map, 0, 0, 1)
+MACRO_CONFIG_INT(sv_allow_timelimit, 0, 0, 1)
+MACRO_CONFIG_INT(sv_allow_scorelimit, 0, 0, 1)
+MACRO_CONFIG_INT(sv_ban_teamkiller, 0, 0, 100)
+MACRO_CONFIG_INT(sv_vote_pause, 0, 0, 1000)
+MACRO_CONFIG_INT(sv_silent_mode, 0, 0, 1)
+MACRO_CONFIG_INT(sv_balance_warning, 0, 0, 1000)
+
+MACRO_CONFIG_INT(sv_start_health, 10, 0, 10)
+MACRO_CONFIG_INT(sv_start_armor, 0, 0, 10)
+MACRO_CONFIG_INT(sv_spawn_powerups, 1, 0, 1)
+MACRO_CONFIG_INT(sv_ninja_mod, 0, 0, 1)
+MACRO_CONFIG_INT(sv_infinite_jumping, 0, 0, 1)
+
+MACRO_CONFIG_INT(sv_gun_startvelocity, 0, 0, 100000)
+MACRO_CONFIG_INT(sv_shotgun_startvelocity, 0, 0, 100000)
+MACRO_CONFIG_INT(sv_grenadelauncher_startvelocity, 0, 0, 100000)
+MACRO_CONFIG_INT(sv_gun_bulletdimension, 0, 0, 1000)
+MACRO_CONFIG_INT(sv_shotgun_bulletdimension, 0, 0, 1000)
+MACRO_CONFIG_INT(sv_grenade_bulletdimension, 0, 0, 1000)
+MACRO_CONFIG_INT(sv_activate_stopdamage, 0, 0, 1000)
+MACRO_CONFIG_INT(sv_stopdamage, 0, 0, 1000)
+MACRO_CONFIG_INT(sv_correct_selfdamage, 0, 0, 1)
+
+MACRO_CONFIG_INT(sv_scoreboard, 10, 0, 1000)
diff -Naur teeworlds-0.4.2-src/src/game/server/gs_common.h racemodspam/src/game/server/gs_common.h
--- teeworlds-0.4.2-src/src/game/server/gs_common.h	2008-04-05 15:13:02.000000000 +0200
+++ racemodspam/src/game/server/gs_common.h	2008-09-17 20:29:49.000000000 +0200
@@ -15,7 +15,7 @@
 //
 class event_handler
 {
-	static const int MAX_EVENTS = 128;
+	static const int MAX_EVENTS = 256;
 	static const int MAX_DATASIZE = 128*64;
 
 	int types[MAX_EVENTS];  // TODO: remove some of these arrays
@@ -23,7 +23,7 @@
 	int sizes[MAX_EVENTS];
 	int client_masks[MAX_EVENTS];
 	char data[MAX_DATASIZE];
-	
+
 	int current_offset;
 	int num_events;
 public:
@@ -42,7 +42,7 @@
 	friend class game_world;
 	friend class player;
 	entity *prev_entity;
-	entity *next_entity;
+
 
 	entity *prev_type_entity;
 	entity *next_type_entity;
@@ -53,28 +53,28 @@
 	unsigned flags;
 	int objtype;
 	vec2 pos;
-
+	entity *next_entity;
 	enum
 	{
 		FLAG_DESTROY=0x00000001,
 		FLAG_PHYSICS=0x00000002,
 	};
-	
+
 	entity(int objtype);
 	virtual ~entity();
-	
+
 	virtual void reset() {}
 	virtual void post_reset() {}
-	
+
 	void set_flag(unsigned flag) { flags |= flag; }
 	void clear_flag(unsigned flag) { flags &= ~flag; }
 
 	virtual void destroy() { delete this; }
 	virtual void tick() {}
 	virtual void tick_defered() {}
-		
+
 	virtual void snap(int snapping_client) {}
-		
+
 	virtual bool take_damage(vec2 force, int dmg, int from, int weapon) { return true; }
 };
 
@@ -94,9 +94,9 @@
 	entity *first_entity_types[NUM_ENT_TYPES];
 	bool paused;
 	bool reset_requested;
-	
+
 	world_core core;
-	
+
 	game_world();
 	~game_world();
 	int find_entities(vec2 pos, float radius, entity **ents, int max);
@@ -105,7 +105,7 @@
 	void insert_entity(entity *ent);
 	void destroy_entity(entity *ent);
 	void remove_entity(entity *ent);
-	
+
 	//
 	void snap(int snapping_client);
 	void tick();
@@ -120,42 +120,44 @@
 protected:
 	void cyclemap();
 	void resetgame();
-	
+
 	int round_start_tick;
 	int game_over_tick;
 	int sudden_death;
-	
+
 	int teamscore[2];
-	
+
 	int warmup;
 	int round_count;
-	
+
 	bool is_teamplay;
-	
+
 public:
 	int gametype;
+	int next_players[MAX_CLIENTS];
+	bool queue_initiated;
 	gameobject();
 
 	void do_team_score_wincheck();
 	void do_player_score_wincheck();
-	
+
 	void do_warmup(int seconds);
-	
+
 	void startround();
 	void endround();
-	
+
 	bool is_friendly_fire(int cid1, int cid2);
-	
+
 	virtual bool on_entity(int index, vec2 pos);
-	
+
 	virtual void post_reset();
 	virtual void tick();
-	
+
 	virtual void on_player_spawn(class player *p) {}
 	virtual int on_player_death(class player *victim, class player *killer, int weapon);
-	
+
 	virtual void on_player_info_change(class player *p);
-	
+
 	virtual void snap(int snapping_client);
 	virtual int get_auto_team(int notthisid);
 	virtual bool can_join_team(int team, int notthisid);
@@ -170,12 +172,12 @@
 {
 public:
 	static const int phys_size = 14;
-	
+
 	int type;
 	int subtype; // weapon type for instance?
 	int spawntick;
 	powerup(int _type, int _subtype = 0);
-	
+
 	virtual void reset();
 	virtual void tick();
 	virtual void snap(int snapping_client);
@@ -189,7 +191,7 @@
 	{
 		PROJECTILE_FLAGS_EXPLODE = 1 << 0,
 	};
-	
+
 	vec2 direction;
 	entity *powner; // this is nasty, could be removed when client quits
 	int lifespan;
@@ -202,13 +204,13 @@
 	int bounce;
 	float force;
 	int start_tick;
-	
+	float dimension;
 	projectile(int type, int owner, vec2 pos, vec2 vel, int span, entity* powner,
 		int damage, int flags, float force, int sound_impact, int weapon);
 
 	vec2 get_pos(float time);
 	void fill_info(NETOBJ_PROJECTILE *proj);
-
+	void proceed_bulletcollision(vec2 curpos);
 	virtual void reset();
 	virtual void tick();
 	virtual void snap(int snapping_client);
@@ -222,14 +224,14 @@
 	int bounces;
 	int eval_tick;
 	player *owner;
-	
+
 	bool hit_player(vec2 from, vec2 to);
 	void do_bounce();
-	
+
 public:
-	
+
 	laser(vec2 pos, vec2 direction, float start_energy, player *owner);
-	
+
 	virtual void reset();
 	virtual void tick();
 	virtual void snap(int snapping_client);
@@ -239,6 +241,7 @@
 class player : public entity
 {
 public:
+	bool played;
 	static const int phys_size = 28;
 
 	// weapon info
@@ -251,21 +254,21 @@
 		int ammocost;
 		bool got;
 	} weapons[NUM_WEAPONS];
-	
+
 	int active_weapon;
 	int last_weapon;
 	int queued_weapon;
-	
+
 	int reload_timer;
 	int attack_tick;
-	
+
 	int damage_taken;
 
 	int emote_type;
 	int emote_stop;
 
 	int last_action; // last tick that the player took any action ie some input
-	
+
 	//
 	int client_id;
 	char skin_name[64];
@@ -277,12 +280,16 @@
 	NETOBJ_PLAYER_INPUT latest_previnput;
 	NETOBJ_PLAYER_INPUT latest_input;
 
-	// input	
+	// input
 	NETOBJ_PLAYER_INPUT previnput;
 	NETOBJ_PLAYER_INPUT input;
 	int num_inputs;
 	int jumped;
-	
+
+	int starttime;
+	int ended;
+	int started;
+	int refreshtime;
 	int damage_taken_tick;
 
 	int health;
@@ -299,14 +306,18 @@
 
 	//
 	int score;
+	int lastplayer;
+	int lastplayertime;
+	int lastvote;
+	int votedfor;
 	int team;
 	int player_state; // if the client is chatting, accessing a menu or so
-	
+
 	bool spawning;
 	bool dead;
 	int die_tick;
 	vec2 die_pos;
-	
+
 	// latency calculations
 	int latency_accum;
 	int latency_accum_min;
@@ -315,9 +326,9 @@
 	int latency_min;
 	int latency_max;
 
-	// the player core for the physics	
+	// the player core for the physics
 	player_core core;
-	
+
 	//
 	int64 last_chat;
 
@@ -326,32 +337,36 @@
 	void init();
 	virtual void reset();
 	virtual void destroy();
-		
+
 	void try_respawn();
 	void respawn();
-	
+
 	void set_team(int team);
-	
+
 	bool is_grounded();
-	
+
 	void set_weapon(int w);
-	
+
 	void handle_weaponswitch();
 	void do_weaponswitch();
-	
+
 	int handle_weapons();
 	int handle_ninja();
-	
+
 	void on_direct_input(NETOBJ_PLAYER_INPUT *input);
 	void fire_weapon();
 
 	virtual void tick();
 	virtual void tick_defered();
-	
+
 	void die(int killer, int weapon);
-	
+
 	virtual bool take_damage(vec2 force, int dmg, int from, int weapon);
 	virtual void snap(int snaping_client);
+
+	int last_message_tick; unsigned char message_num; bool muted;
+	bool teamchanging; unsigned char team_changes; int last_team_set; int teamkills;
+	bool voted;
 };
 
 extern player *players;
diff -Naur teeworlds-0.4.2-src/src/game/server/gs_game.cpp racemodspam/src/game/server/gs_game.cpp
--- teeworlds-0.4.2-src/src/game/server/gs_game.cpp	2008-04-05 15:13:02.000000000 +0200
+++ racemodspam/src/game/server/gs_game.cpp	2008-09-17 20:29:44.000000000 +0200
@@ -5,6 +5,7 @@
 #include <game/g_mapitems.h>
 #include "gs_common.h"
 
+
 gameobject::gameobject()
 : entity(NETOBJTYPE_GAME)
 {
@@ -24,7 +25,8 @@
 		gametype = GAMETYPE_DM;
 		dbg_msg("game", "-- Death Match --");
 	}
-		
+	for(int n = 0; n < MAX_CLIENTS; n++)
+		next_players[n] = -1;
 	//
 	do_warmup(config.sv_warmup);
 	game_over_tick = -1;
@@ -33,7 +35,7 @@
 	round_count = 0;
 	is_teamplay = false;
 	teamscore[0] = 0;
-	teamscore[1] = 0;	
+	teamscore[1] = 0;
 }
 
 // UGLY!!!!
@@ -44,7 +46,7 @@
 {
 	int type = -1;
 	int subtype = 0;
-	
+
 	if(index == ENTITY_SPAWN)
 		spawn_points[0][num_spawn_points[0]++] = pos;
 	else if(index == ENTITY_SPAWN_RED)
@@ -75,7 +77,7 @@
 		type = POWERUP_NINJA;
 		subtype = WEAPON_NINJA;
 	}
-	
+
 	if(type != -1)
 	{
 		powerup *ppower = new powerup(type, subtype);
@@ -90,7 +92,15 @@
 {
 	if(warmup) // game can't end when we are running warmup
 		return;
-		
+	if(strlen(config.sv_endroundmessage) > 0)
+	{
+		NETMSG_SV_CHAT msg;
+		msg.team = 0;
+		msg.cid = -1;
+		msg.message = config.sv_endroundmessage;
+		msg.pack(MSGFLAG_VITAL);
+		server_send_msg(-1);
+	}
 	world->paused = true;
 	game_over_tick = server_tick();
 	sudden_death = 0;
@@ -106,7 +116,7 @@
 void gameobject::startround()
 {
 	resetgame();
-	
+
 	round_start_tick = server_tick();
 	sudden_death = 0;
 	game_over_tick = -1;
@@ -123,11 +133,11 @@
 
 	if(round_count < config.sv_rounds_per_map-1)
 		return;
-		
+
 	// handle maprotation
 	const char *map_rotation = config.sv_maprotation;
 	const char *current_map = config.sv_map;
-	
+
 	int current_map_len = strlen(current_map);
 	const char *next_map = map_rotation;
 	while(*next_map)
@@ -135,25 +145,25 @@
 		int wordlen = 0;
 		while(next_map[wordlen] && !is_separator(next_map[wordlen]))
 			wordlen++;
-		
+
 		if(wordlen == current_map_len && strncmp(next_map, current_map, current_map_len) == 0)
 		{
 			// map found
 			next_map += current_map_len;
 			while(*next_map && is_separator(*next_map))
 				next_map++;
-				
+
 			break;
 		}
-		
+
 		next_map++;
 	}
-	
+
 	// restart rotation
 	if(next_map[0] == 0)
 		next_map = map_rotation;
 
-	// cut out the next map	
+	// cut out the next map
 	char buf[512];
 	for(int i = 0; i < 512; i++)
 	{
@@ -164,12 +174,12 @@
 			break;
 		}
 	}
-	
+
 	// skip spaces
 	int i = 0;
 	while(is_separator(buf[i]))
 		i++;
-	
+
 	dbg_msg("game", "rotating map to %s", &buf[i]);
 	str_copy(config.sv_map, &buf[i], sizeof(config.sv_map));
 }
@@ -182,7 +192,7 @@
 			players[i].respawn();
 	}
 }
-	
+
 void gameobject::on_player_info_change(class player *p)
 {
 	const int team_colors[2] = {65387, 10223467};
@@ -201,7 +211,7 @@
 int gameobject::on_player_death(class player *victim, class player *killer, int weapon)
 {
 	// do scoreing
-	if(!killer)
+	if(!killer || weapon == -1)
 		return 0;
 	if(killer == victim)
 		victim->score--; // suicide
@@ -224,13 +234,13 @@
 {
 	if(cid1 == cid2)
 		return false;
-	
+
 	if(is_teamplay)
 	{
 		if(players[cid1].team == players[cid2].team)
 			return true;
 	}
-	
+
 	return false;
 }
 
@@ -243,18 +253,105 @@
 		if(!warmup)
 			startround();
 	}
-	
+
 	if(game_over_tick != -1)
 	{
 		// game over.. wait for restart
-		if(server_tick() > game_over_tick+server_tickspeed()*10)
+		if(server_tick() > game_over_tick+server_tickspeed()*config.sv_scoreboard)
 		{
+			if((gametype == GAMETYPE_TDM || gametype == GAMETYPE_CTF) && config.sv_ko_mode)
+			{
+				int team0 = -1;
+				int team1 = -1;
+				int next = next_players[0];
+				for(int i = 0; i < MAX_CLIENTS; i++)
+				{
+					if(players[i].client_id != -1)
+					{
+						if(players[i].team == 0)
+							team0 = i;
+						if(players[i].team == 1)
+							team1 = i;
+					}
+				}
+				if(teamscore[0] > teamscore[1] || (team0 != -1 && team1 == -1))
+				{
+					if(next > -1)
+					{
+						if(team1 != -1)
+						{
+							players[team1].set_team(-1);
+							players[team1].played = true;
+						}
+						players[next].set_team(1);
+					}
+					else
+					{
+						char note[64];
+						strcpy(note, server_clientname(team0));
+						strcat(note, " is the best player on this server");
+						NETMSG_SV_BROADCAST msg;
+						msg.message = note;
+						msg.pack(MSGFLAG_VITAL);
+						server_send_msg(-1);
+						for(int i = 0; i < MAX_CLIENTS; i++)
+						{
+							if(players[i].client_id != -1)
+							{
+								players[i].played = false;
+							}
+						}
+						cyclemap();
+						startround();
+						return;
+					}
+				}
+				else
+				{
+					if(next > -1)
+					{
+						if(team0 != -1)
+						{
+							players[team0].set_team(-1);
+							players[team0].played = true;
+						}
+						players[next].set_team(0);
+					}
+					else
+					{
+						char note[64];
+						strcpy(note, server_clientname(team1));
+						strcat(note, " is the best player on this server");
+						NETMSG_SV_BROADCAST msg;
+						msg.message = note;
+						msg.pack(MSGFLAG_VITAL);
+						server_send_msg(-1);
+						for(int i = 0; i < MAX_CLIENTS; i++)
+						{
+							if(players[i].client_id != -1)
+							{
+								players[i].played = false;
+							}
+						}
+						cyclemap();
+						startround();
+						return;
+					}
+				}
+				for(int i = 1; i < MAX_CLIENTS; i++)
+				{
+						next_players[i-1] = next_players[i];
+				}
+				next_players[MAX_CLIENTS - 1] = -1;
+				startround();
+				return;
+			}
 			cyclemap();
 			startround();
 		}
 	}
-	
-	
+
+
 	// update browse info
 	int prog = -1;
 	if(config.sv_timelimit > 0)
@@ -279,7 +376,7 @@
 
 	if(warmup)
 		prog = -1;
-		
+
 	server_setbrowseinfo(gametype, prog);
 }
 
@@ -289,14 +386,14 @@
 	game->paused = world->paused;
 	game->game_over = game_over_tick==-1?0:1;
 	game->sudden_death = sudden_death;
-	
+
 	game->score_limit = config.sv_scorelimit;
 	game->time_limit = config.sv_timelimit;
 	game->round_start_tick = round_start_tick;
 	game->gametype = gametype;
-	
+
 	game->warmup = warmup;
-	
+
 	game->teamscore_red = teamscore[0];
 	game->teamscore_blue = teamscore[1];
 }
@@ -316,7 +413,7 @@
 	int team = 0;
 	if(is_teamplay)
 		team = numplayers[0] > numplayers[1] ? 1 : 0;
-		
+
 	if(can_join_team(team, notthisid))
 		return team;
 	return -1;
@@ -334,7 +431,7 @@
 				numplayers[players[i].team]++;
 		}
 	}
-	
+
 	return (numplayers[0] + numplayers[1]) < config.sv_max_clients-config.sv_spectator_slots;
 }
 
@@ -358,7 +455,7 @@
 					topscore_count++;
 			}
 		}
-		
+
 		// check score win condition
 		if((config.sv_scorelimit > 0 && topscore >= config.sv_scorelimit) ||
 			(config.sv_timelimit > 0 && (server_tick()-round_start_tick) >= config.sv_timelimit*server_tickspeed()*60))
diff -Naur teeworlds-0.4.2-src/src/game/server/gs_game_ctf.cpp racemodspam/src/game/server/gs_game_ctf.cpp
--- teeworlds-0.4.2-src/src/game/server/gs_game_ctf.cpp	2008-04-05 15:13:02.000000000 +0200
+++ racemodspam/src/game/server/gs_game_ctf.cpp	2008-08-02 08:08:48.000000000 +0200
@@ -1,6 +1,7 @@
 /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
 #include <engine/e_server_interface.h>
 #include <game/g_mapitems.h>
+#include <engine/e_config.h>
 #include "gs_common.h"
 #include "gs_game_ctf.h"
 
@@ -86,7 +87,7 @@
 				{
 					// CAPTURE! \o/
 					teamscore[fi^1] += 100;
-					f->carrying_player->score += 5;
+					if(!config.sv_race_mod)f->carrying_player->score += 5;
 
 					dbg_msg("game", "flag_capture player='%d:%s'", f->carrying_player->client_id, server_clientname(f->carrying_player->client_id));
 
@@ -110,7 +111,7 @@
 					if(!f->at_stand)
 					{
 						player *p = close_players[i];
-						p->score += 1;
+						if(!config.sv_race_mod)p->score += 1;
 
 						dbg_msg("game", "flag_return player='%d:%s'", p->client_id, server_clientname(p->client_id));
 
@@ -125,7 +126,7 @@
 						teamscore[fi^1]++;
 					f->at_stand = 0;
 					f->carrying_player = close_players[i];
-					f->carrying_player->score += 1;
+					if(!config.sv_race_mod)f->carrying_player->score += 1;
 
 					dbg_msg("game", "flag_grab player='%d:%s'", f->carrying_player->client_id, server_clientname(f->carrying_player->client_id));
 					
@@ -145,7 +146,7 @@
 			
 			if(!f->carrying_player && !f->at_stand)
 			{
-				if(server_tick() > f->drop_tick + server_tickspeed()*30)
+				if(server_tick() > f->drop_tick + server_tickspeed()*30 || col_is_damage(f->pos.x, f->pos.y))
 				{
 					create_sound_global(SOUND_CTF_RETURN);
 					f->reset();
diff -Naur teeworlds-0.4.2-src/src/game/server/gs_server.cpp racemodspam/src/game/server/gs_server.cpp
--- teeworlds-0.4.2-src/src/game/server/gs_server.cpp	2008-04-05 15:13:02.000000000 +0200
+++ racemodspam/src/game/server/gs_server.cpp	2008-09-17 20:29:51.000000000 +0200
@@ -2,6 +2,12 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <cstdlib>
+#include <string>
+#include <sstream>
+#include <fstream>
+#include <list>
+#include <iterator>
 #include <engine/e_config.h>
 #include <engine/e_server_interface.h>
 #include <game/g_version.h>
@@ -24,10 +30,91 @@
 void create_playerspawn(vec2 p);
 void create_death(vec2 p, int who);
 void create_sound(vec2 pos, int sound, int mask=-1);
+void auto_balancing();
 class player *intersect_player(vec2 pos0, vec2 pos1, float radius, vec2 &new_pos, class entity *notthis = 0);
 class player *closest_player(vec2 pos, float radius, entity *notthis);
-
+int timer_vote=-1;bool vote_called=false;int votetime=-1;char votetype[32];static int votedtokick=-1;
 game_world *world;
+int regn = 0,tele=0,strip=0;
+int start[6];char vote_message[300];
+class player_score {
+        public:
+                std::string my_name;
+                float my_score;
+
+                player_score(std::string n_name,float n_score) {
+                        this->my_name=n_name;
+                        this->my_score=n_score;
+                }
+                void setScore(float n_score) {
+                        this->my_score=n_score;
+                }
+                std::string name() {
+                        return this->my_name;
+                }
+                float score() {
+                        return this->my_score;
+                }
+                bool operator==(const player_score& other) {
+                        return (this->my_score==other.my_score);
+                }
+                bool operator<(const player_score& other) {
+                        return (this->my_score<other.my_score);
+                }
+};
+
+std::list<player_score> top5;
+
+std::string top5_recordfile() {
+        std::ostringstream oss;
+        oss << config.sv_map << "_record.dtb";
+        return oss.str();
+}
+
+void top5_save() {
+        std::fstream f;
+        f.open(top5_recordfile().c_str(),std::ios::out);
+        if (f.fail()==false) {
+                for (std::list<player_score>::iterator i=top5.begin(); i!=top5.end(); i++) {
+                        f << i->name() << std::endl << i->score() << std::endl;
+                }
+        }
+        f.close();
+}
+
+void top5_load() {
+        std::fstream f;
+        f.open(top5_recordfile().c_str(),std::ios::in);
+        top5.clear();
+        while (!f.eof() && !f.fail()) {
+                std::string tmpname;
+                float tmpscore;
+                std::getline(f, tmpname);
+                if (!f.eof() && tmpname!="") {
+                        f >> tmpscore;
+                        top5.push_back(*new player_score(tmpname,tmpscore));
+                }
+        }
+        f.close();
+}
+
+void top5_parsePlayer(std::string nom,float score) {
+
+        for (std::list<player_score>::iterator i=top5.begin(); i!=top5.end(); i++) {
+                if (i->name() == nom) {
+                        if (i->score() > score)
+                                i->setScore(score);
+                        top5.sort();
+			top5_save();
+                        return;
+                }
+        }
+        player_score nscore(nom,score);
+        top5.push_back(nscore);
+
+        top5.sort();
+	top5_save();
+}
 
 enum
 {
@@ -36,13 +123,146 @@
 	CHAT_RED=0,
 	CHAT_BLUE=1
 };
+static void send_display(char *message, int to)
+{
+	if(to == -1)
+	{
+		dbg_msg("chat", "*** %s", message);
+	}
+	NETMSG_SV_BROADCAST msg;
+	msg.message = message;
+	msg.pack(MSGFLAG_VITAL);
+	server_send_msg(to);
+}
+
+void send_message(char *message, int to)
+{
+	if(to == -1)
+	{
+		dbg_msg("chat", "*** %s", message);
+		if(config.sv_silent_mode)
+			return;
+	}
+	NETMSG_SV_CHAT msg;
+	msg.team = 0;
+	msg.cid = -1;
+	msg.message = message;
+	msg.pack(MSGFLAG_VITAL);
+	server_send_msg(to);
+}
+
+int get_team(int teamm)
+{
+	int i=0;
+	int result = 0;
+	for(;i<MAX_CLIENTS;i++)
+	{
+		if(players[i].client_id != -1 && players[i].team == teamm)
+		{
+			result++;
+		}
+	}
+	return result;
+}
 
 static void send_chat(int cid, int team, const char *text)
 {
+	static char lastmessages[MAX_CLIENTS][768];
+	static short int same_messages[MAX_CLIENTS];
+	player *tmp = get_player(cid);
+
+	if(config.sv_handle_mapvotes && (strcmp("/++",text) == 0 || strcmp("/--", text) == 0))
+	{
+		if(tmp->voted)
+		{
+			send_display("You already voted, ignoring vote", cid);
+		}
+		else
+		{
+			tmp->voted = true;
+			dbg_msg("game", "map-voting %s", text);
+			send_display("You voted for the map, thank you", cid);
+		}
+		return;
+	}
+
+	if(config.sv_messagesnum && cid > -1 && cid < MAX_CLIENTS)
+	{
+
+
+		if(tmp->muted)
+		{
+			if(tmp->last_message_tick + config.sv_time_muted*SERVER_TICK_SPEED > server_tick())
+			{
+				tmp->message_num++;
+				char buf[128];
+				sprintf(buf, "You can speak in %i seconds", (config.sv_time_muted * server_tickspeed() + tmp->last_message_tick - server_tick())/server_tickspeed());
+				send_display(buf, cid);
+				if(config.sv_messageskick && tmp->message_num > config.sv_messageskick)
+				{
+					char kicking[127];
+					sprintf(kicking, "%s was kicked because of spamming.", server_clientname(cid));
+					send_message(kicking, -1);
+					if(config.sv_messagesban)
+					{
+						char ban_message[255];
+						sprintf(ban_message, "You were banned for %i minutes because of spamming", config.sv_messagesban);
+						server_ban(cid, config.sv_teamchangesban, ban_message);
+					}
+					else
+						server_kick(cid,"You were kicked because of spamming");
+				}
+				return;
+			}
+			else
+			{
+				tmp->muted = false;
+				tmp->message_num = 0;
+				tmp->last_message_tick = server_tick();
+			}
+		}
+		else
+		{
+			if(tmp->last_message_tick + 30*SERVER_TICK_SPEED > server_tick())
+			{
+				tmp->message_num++;
+				if(config.sv_same_messages && strcmp(lastmessages[cid], text) == 0)
+				{
+					same_messages[cid]++;
+				}
+				else
+				{
+					strncpy(lastmessages[cid], text, 768);
+					same_messages[cid] = 0;
+				}
+				if(tmp->message_num >= config.sv_messagesnum || (config.sv_same_messages && config.sv_same_messages <= same_messages[cid]))
+				{
+					tmp->muted = true;same_messages[cid] = 0;
+					tmp->message_num = 0;
+					char muting[127];
+					sprintf(muting, "%s was muted for %d seconds because of spamming.", server_clientname(cid), config.sv_time_muted);
+					send_message(muting, -1);
+					sprintf(muting, "You are muted for %d seconds\nbecause of spamming", config.sv_time_muted);
+					send_display(muting, cid);
+					return;
+				}
+
+			}
+			else
+			{
+				tmp->last_message_tick = server_tick();
+				tmp->message_num = 0;
+			}
+		}
+	}
 	if(cid >= 0 && cid < MAX_CLIENTS)
 		dbg_msg("chat", "%d:%d:%s: %s", cid, team, server_clientname(cid), text);
 	else
+	{
 		dbg_msg("chat", "*** %s", text);
+		if(config.sv_silent_mode)
+			return;
+	}
 
 	if(team == CHAT_ALL)
 	{
@@ -80,7 +300,7 @@
 	msg.color_body = players[who].color_body;
 	msg.color_feet =players[who].color_feet;
 	msg.pack(MSGFLAG_VITAL);
-	
+
 	server_send_msg(to_who);
 }
 
@@ -120,6 +340,82 @@
 	server_send_msg(cid);
 }
 
+void resultvote()
+{
+	int players_serv=0,total=0,voteur=0;
+	for (int i=0; i < MAX_CLIENTS;i++)
+	{
+		if(players[i].client_id !=-1)
+		{
+			if(players[i].votedfor != -1)
+			{total+=players[i].votedfor;voteur++;}
+			players_serv++;
+		}
+	}
+	char buf[256];
+	str_format(buf, sizeof(buf), "YES: %d | NO: %d (Time remaining : %d secondes)",total,voteur-total,votetime - (server_tick()-timer_vote)/(server_tickspeed()));
+	send_chat(-1,CHAT_ALL,buf);
+	if (voteur==players_serv || (server_tick()-timer_vote  > server_tickspeed()*votetime && timer_vote != -1))
+	{
+		vote_called=false;
+		int result=1;
+		char message[256];
+		if((total > voteur / 2 && !config.sv_all_vote) || (total > players_serv / 2 && config.sv_all_vote))str_format(message, sizeof(message), "Vote passed");
+		else {str_format(message, sizeof(message), "Vote failed");result=0;}
+		send_display(message, -1);
+		if(!strcmp(votetype,"kick") && votedtokick != -1)
+		{
+			if(result)
+			{
+				sprintf(message,"You are kicked by vote for %i minutes (YES: %d | NO: %d)", config.sv_ban_time,total,voteur-total);
+				server_ban_saved(config.sv_ban_time, message);
+			}
+			str_format(votetype, sizeof(votetype), "null");
+			votedtokick = -1;
+		}
+		else if(!strcmp(votetype,"next_map"))
+		{
+			if(result)
+			{
+				gameobj->endround();
+			}
+			str_format(votetype, sizeof(votetype), "null");
+			votedtokick = -1;
+		}
+		else if(!strcmp(votetype,"timelimit"))
+		{
+			if(result)
+			{
+				if(votedtokick == -1)
+					config.sv_timelimit = 0;
+				else
+					config.sv_timelimit = votedtokick;
+			}
+			str_format(votetype, sizeof(votetype), "null");
+			votedtokick = -1;
+		}
+		else if(!strcmp(votetype,"scorelimit"))
+		{
+			if(result)
+			{
+				if(votedtokick == -1)
+					config.sv_scorelimit = 0;
+				else
+					config.sv_scorelimit = votedtokick;
+			}
+			str_format(votetype, sizeof(votetype), "null");
+			votedtokick = -1;
+		}
+		for (int i=0; i < MAX_CLIENTS;i++)
+		{
+			if(players[i].client_id !=-1)
+			{
+				players[i].votedfor=-1;
+			}
+		}
+	}
+}
+
 //////////////////////////////////////////////////
 // Event handler
 //////////////////////////////////////////////////
@@ -352,9 +648,10 @@
 {
 	if(reset_requested)
 		reset();
-
 	if(!paused)
 	{
+		auto_balancing();
+		if(timer_vote != -1 && server_tick()-timer_vote  > server_tickspeed()*votetime && vote_called)resultvote();
 		/*
 		static PERFORMACE_INFO scopes[OBJTYPE_FLAG+1] =
 		{
@@ -377,10 +674,10 @@
 			{"powerup", 0},
 			{"flag", 0}
 		};
-				
+
 		static PERFORMACE_INFO tick_scope = {"tick", 0};
 		perf_start(&tick_scope);*/
-		
+
 		// update all objects
 		for(entity *ent = first_entity; ent; ent = ent->next_entity)
 		{
@@ -390,7 +687,7 @@
 			/*if(ent->objtype >= 0 && ent->objtype < OBJTYPE_FLAG)
 				perf_end();*/
 		}
-		
+
 		/*
 		perf_end();
 
@@ -455,6 +752,18 @@
 	this->weapon = weapon;
 	this->bounce = 0;
 	this->start_tick = server_tick();
+	switch(weapon)
+	{
+		case WEAPON_GUN:
+			dimension = (float)config.sv_gun_bulletdimension/10;
+			break;
+		case WEAPON_SHOTGUN:
+			dimension = (float)config.sv_shotgun_bulletdimension/10;
+			break;
+		case WEAPON_GRENADE:
+			dimension = (float)config.sv_grenade_bulletdimension/10;
+			break;
+	}
 	world->insert_entity(this);
 }
 
@@ -482,38 +791,85 @@
 		curvature = tuning.gun_curvature;
 		speed = tuning.gun_speed;
 	}
-	
+
 	return calc_pos(pos, direction, curvature, speed, time);
 }
 
+void projectile::proceed_bulletcollision(vec2 curpos)
+{
+	projectile *check = (projectile*)world->first_entity;
+	bool collide = false;
+
+	while(check)
+	{
+		vec2 otherpos = check->get_pos((server_tick()-check->start_tick)/(float)server_tickspeed());
+		if(check->objtype == NETOBJTYPE_PROJECTILE && check != this &&
+				((curpos.x - dimension < otherpos.x + check->dimension && curpos.x + dimension > otherpos.x + check->dimension)
+						|| (curpos.x + dimension > otherpos.x - dimension && curpos.x - dimension < otherpos.x - dimension))
+				&& ((curpos.y - dimension < otherpos.y + check->dimension && curpos.y + dimension > otherpos.y + check->dimension)
+						||(curpos.y + dimension > otherpos.y - dimension && curpos.y - dimension < otherpos.y - dimension)))
+		{
+			collide = true;
+			if (check->lifespan >= 0 || check->weapon == WEAPON_GRENADE)
+				create_sound(otherpos, sound_impact);
+			if (check->flags & check->PROJECTILE_FLAGS_EXPLODE)
+				create_explosion(otherpos, check->owner, check->weapon, false);
+			world->destroy_entity(check);
+		}
+		check = (projectile*)check->next_entity;
+	}
+	if(collide)
+	{
+		if (lifespan >= 0 || weapon == WEAPON_GRENADE)
+			create_sound(curpos, sound_impact);
+		if (flags & PROJECTILE_FLAGS_EXPLODE)
+			create_explosion(curpos, owner, weapon, false);
+		world->destroy_entity(this);
+	}
+}
 
 void projectile::tick()
 {
-	
+
 	float pt = (server_tick()-start_tick-1)/(float)server_tickspeed();
 	float ct = (server_tick()-start_tick)/(float)server_tickspeed();
 	vec2 prevpos = get_pos(pt);
 	vec2 curpos = get_pos(ct);
 
 	lifespan--;
-	
+
 	int collide = col_intersect_line(prevpos, curpos, &curpos);
 	//int collide = col_check_point((int)curpos.x, (int)curpos.y);
-	
-	entity *targetplayer = (entity*)intersect_player(prevpos, curpos, 6.0f, curpos, powner);
-	if(targetplayer || collide || lifespan < 0)
+
+	entity *targetplayer;
+	if(config.sv_correct_selfdamage && ct > 0.06)
+	{
+		targetplayer = (entity*)intersect_player(prevpos, curpos, 6.0f, curpos, NULL);
+	}
+	else
+	{
+		targetplayer = (entity*)intersect_player(prevpos, curpos, 6.0f, curpos, powner);
+	}
+	if((!config.sv_race_mod && targetplayer) || collide || lifespan < 0)
 	{
 		if (lifespan >= 0 || weapon == WEAPON_GRENADE)
 			create_sound(curpos, sound_impact);
 
 		if (flags & PROJECTILE_FLAGS_EXPLODE)
 			create_explosion(curpos, owner, weapon, false);
-		else if (targetplayer)
+		else if (targetplayer && !config.sv_race_mod)
 		{
 			targetplayer->take_damage(direction * max(0.001f, force), damage, owner, weapon);
 		}
 
 		world->destroy_entity(this);
+		return;
+	}
+	proceed_bulletcollision(curpos);
+	int z = col_is_teleport((int)curpos.x,curpos.y);
+	if(tele && z && config.sv_teleport_grenade && weapon == WEAPON_GRENADE) {
+		pos = teleport(z);
+		start_tick=server_tick();
 	}
 }
 
@@ -530,7 +886,7 @@
 void projectile::snap(int snapping_client)
 {
 	float ct = (server_tick()-start_tick)/(float)server_tickspeed();
-	
+
 	if(distance(players[snapping_client].pos, get_pos(ct)) > 1000.0f)
 		return;
 
@@ -551,7 +907,7 @@
 	dir = direction;
 	bounces = 0;
 	do_bounce();
-	
+
 	world->insert_entity(this);
 }
 
@@ -565,7 +921,7 @@
 
 	this->from = from;
 	pos = at;
-	energy = -1;		
+	energy = -1;
 	hit->take_damage(vec2(0,0), tuning.laser_damage, owner->client_id, WEAPON_RIFLE);
 	return true;
 }
@@ -573,16 +929,16 @@
 void laser::do_bounce()
 {
 	eval_tick = server_tick();
-	
+
 	if(energy < 0)
 	{
 		//dbg_msg("laser", "%d removed", server_tick());
 		world->destroy_entity(this);
 		return;
 	}
-	
+
 	vec2 to = pos + dir*energy;
-	
+
 	if(col_intersect_line(pos, to, &to))
 	{
 		if(!hit_player(pos, to))
@@ -592,17 +948,17 @@
 			pos = to - dir*2;
 			vec2 temp_pos = pos;
 			vec2 temp_dir = dir*4.0f;
-			
+
 			move_point(&temp_pos, &temp_dir, 1.0f, 0);
 			pos = temp_pos;
 			dir = normalize(temp_dir);
-			
+
 			energy -= distance(from, pos) + tuning.laser_bounce_cost;
 			bounces++;
-			
+
 			if(bounces > tuning.laser_bounce_num)
 				energy = -1;
-				
+
 			create_sound(pos, SOUND_RIFLE_BOUNCE);
 		}
 	}
@@ -615,10 +971,10 @@
 			energy = -1;
 		}
 	}
-		
+
 	//dbg_msg("laser", "%d done %f %f %f %f", server_tick(), from.x, from.y, pos.x, pos.y);
 }
-	
+
 void laser::reset()
 {
 	world->destroy_entity(this);
@@ -659,6 +1015,10 @@
 
 void player::init()
 {
+	voted = false;
+	teamchanging = false; team_changes = 0; last_team_set = server_tick();
+	last_message_tick = server_tick(); message_num = 0; muted = false;
+
 	proximity_radius = phys_size;
 	client_id = -1;
 	team = -1; // -1 == spectator
@@ -677,12 +1037,13 @@
 {
 	pos = vec2(0.0f, 0.0f);
 	core.reset();
-	
+
 	emote_type = 0;
 	emote_stop = -1;
-	
+
 	//direction = vec2(0.0f, 1.0f);
-	score = 0;
+	if(config.sv_race_mod)score = -9999;
+	else score=0;
 	dead = true;
 	clear_flag(entity::FLAG_PHYSICS);
 	spawning = false;
@@ -703,7 +1064,7 @@
 	attack_tick = 0;
 
 	mem_zero(&ninja, sizeof(ninja));
-	
+
 	active_weapon = WEAPON_GUN;
 	last_weapon = WEAPON_HAMMER;
 	queued_weapon = -1;
@@ -715,13 +1076,13 @@
 {
 	if(w == active_weapon)
 		return;
-		
+
 	last_weapon = active_weapon;
 	queued_weapon = -1;
 	active_weapon = w;
 	if(active_weapon < 0 || active_weapon >= NUM_WEAPONS)
 		active_weapon = 0;
-		
+
 	create_sound(pos, SOUND_WEAPON_SWITCH);
 }
 
@@ -744,26 +1105,239 @@
 		else if(team == 1)
 			return "blue team";
 	}
-	
+
 	return "spectators";
 }
 
+void auto_balancing()
+{
+	static int last_warning_tick = 0;
+	static int start_unbalance = 0;
+	if((config.sv_team_balance || config.sv_balance_warning) && gameobj->gametype != GAMETYPE_DM)
+	{
+		int team0 = get_team(0);
+		int team1 = get_team(1);
+		if(!start_unbalance)
+			start_unbalance = server_tick();
+		if((config.sv_team_balance && (team0-team1 > config.sv_team_balance || team1-team0 > config.sv_team_balance)) || (!config.sv_team_balance && config.sv_balance_warning && (team0-team1 > config.sv_balance_warning || team1-team0 > config.sv_balance_warning)))
+		{
+			if(((config.sv_balance_warning && config.sv_team_balance && start_unbalance + config.sv_balance_warning*server_tickspeed() > server_tick()) || !config.sv_team_balance) && last_warning_tick + 20*server_tickspeed() < server_tick())
+			{
+				send_display("Teams are not balanced", -1);
+				last_warning_tick = server_tick();
+			}
+			else if((config.sv_team_balance && config.sv_balance_warning && start_unbalance + config.sv_balance_warning*server_tickspeed() < server_tick()) || !config.sv_balance_warning)
+			{
+				send_display("Auto balancing teams...", -1);
+				while(team0-team1 > config.sv_team_balance)
+				{
+					int i = rand() % MAX_CLIENTS;
+					int steps = rand() % MAX_CLIENTS;
+					int now = 0;
+					while(1)
+					{
+						if(players[i].team == 0 && steps == now++)
+						{
+							int tmp_points = players[i].score;
+							players[i].team_changes--;
+							send_display("You have been assigned to the blue team", i);
+							players[i].set_team(1);
+							team0--;
+							players[i].score = tmp_points;
+							break;
+						}
+						if(++i == MAX_CLIENTS)
+						{
+							i = 0;
+						}
+					}
+				}
+				while(team1-team0 > config.sv_team_balance)
+				{
+					int i = rand() % MAX_CLIENTS;
+					int steps = rand() % MAX_CLIENTS;
+					int now = 0;
+					while(1)
+					{
+						if(players[i].team == 1 && steps == now++)
+						{
+							int tmp_points = players[i].score;
+							players[i].team_changes--;
+							send_display("You have been assigned to the red team", i);
+							players[i].set_team(0);
+							team1--;
+							players[i].score = tmp_points;
+							break;
+						}
+						if(++i == MAX_CLIENTS)
+						{
+							i = 0;
+						}
+					}
+				}
+			}
+		}
+		else
+		{
+			start_unbalance = 0;
+			last_warning_tick = 0;
+		}
+	}
+}
+
 void player::set_team(int new_team)
 {
+	if((gameobj->gametype == GAMETYPE_TDM || gameobj->gametype == GAMETYPE_CTF) && config.sv_ko_mode)
+	{
+		if(team == 1 || team == 0)
+		{
+			if(new_team == 1 || new_team == 0)
+				return;
+			if(new_team == -1)
+				gameobj->endround();
+		}
+		else
+		{
+			int playing = get_team(0) + get_team(1);
+			if(playing == 1 && gameobj->next_players[0] == -1)
+			{
+				gameobj->next_players[0] = client_id;
+				gameobj->endround();
+				return;
+			}
+			else if(playing > 1 || (playing == 1 && gameobj->next_players[0] != -1 && gameobj->next_players[0] != client_id))
+			{
+				if(played == true)
+				{
+					send_display("You already played in this tournament,\nplease wait for the next tournament", client_id);
+					return;
+				}
+				for(int i = 0; i < MAX_CLIENTS; i++)
+				{
+					if(gameobj->next_players[i] == client_id)
+					{
+						char pos_msg[128];
+						sprintf(pos_msg, "You are on position %i", i+1);
+						return;
+					}
+					if(gameobj->next_players[i] == -1)
+					{
+						gameobj->next_players[i] = client_id;
+						char pos_msg[128];
+						sprintf(pos_msg, "You are on position %i", i+1);
+						send_display(pos_msg, client_id);
+						return;
+					}
+				}
+			}
+		}
+	}
+	else
+	{
+		if(config.sv_teamchanges)
+		{
+			if(teamchanging)
+			{
+				if(last_team_set + config.sv_time_blocked*SERVER_TICK_SPEED > server_tick())
+				{
+					team_changes++;
+					char buf[128];
+					sprintf(buf, "You can change team in %i seconds", (config.sv_time_blocked * server_tickspeed() + last_team_set - server_tick())/server_tickspeed());
+					send_display(buf, client_id);
+					if(config.sv_teamchangeskick && team_changes > config.sv_teamchangeskick)
+					{
+
+						char kicking[127];
+						sprintf(kicking, "%s was kicked because of fast teamchanging.", server_clientname(client_id));
+						send_message(kicking, -1);
+						if(config.sv_teamchangesban)
+						{
+							char ban_message[255];
+							sprintf(ban_message, "You were banned for %i minutes because of fast teamchanging", config.sv_teamchangesban);
+							server_ban(client_id, config.sv_teamchangesban, ban_message);
+						}
+						else
+							server_kick(client_id,"You were kicked because of fast teamchanging");
+					}
+					return;
+				}
+				else
+				{
+					teamchanging = false;
+					team_changes = 0;
+					last_team_set = server_tick();
+				}
+			}
+			else
+			{
+				if(last_team_set + 30*SERVER_TICK_SPEED > server_tick())
+				{
+					team_changes++;
+					if(config.sv_teamchanges && team_changes >= config.sv_teamchanges)
+					{
+						teamchanging = true;
+						team_changes = 0;
+						char blocking[127];
+						sprintf(blocking, "%s can't change team for %d seconds", server_clientname(client_id), config.sv_time_blocked);
+						send_message(blocking, -1);
+						sprintf(blocking, "You can't change team for %d seconds", config.sv_time_blocked);
+						send_display(blocking, client_id);
+						return;
+					}
+
+				}
+				else
+				{
+					last_team_set = server_tick();
+					team_changes = 0;
+				}
+			}
+		}
+		if(config.sv_team_balance && !config.sv_balance_warning && gameobj->gametype != GAMETYPE_DM)
+		{
+			int team0 = get_team(0);
+			int team1 = get_team(1);
+			if(team == -1)
+			{
+				if(new_team == 1 && team1-team0 + 1 > config.sv_team_balance)
+				{
+					send_display("You can't join blue because of team-balance", client_id);
+					new_team = 0;
+				}
+				else if(new_team == 0 && team0-team1 + 1 > config.sv_team_balance)
+				{
+					send_display("You can't join red because of team-balance", client_id);
+					new_team = 1;
+				}
+			}
+			else if(new_team == 1 && team1-team0 + 2 > config.sv_team_balance)
+			{
+				send_display("You can't join blue because of team-balance", client_id);
+				return;
+			}
+			else if(new_team == 0 && team0-team1 + 2 > config.sv_team_balance)
+			{
+				send_display("You can't join red because of team-balance", client_id);
+				return;
+			}
+		}
+	}
+	teamkills = 0;
 	// clamp the team
 	new_team = gameobj->clampteam(new_team);
 	if(team == new_team)
 		return;
-		
+
 	char buf[512];
 	str_format(buf, sizeof(buf), "%s joined the %s", server_clientname(client_id), get_team_name(new_team));
-	send_chat(-1, CHAT_ALL, buf); 
-	
+	send_chat(-1, CHAT_ALL, buf);
+
 	die(client_id, -1);
 	team = new_team;
-	score = 0;
+	started=0;
+	if(!config.sv_race_mod)score=0;
 	dbg_msg("game", "team_join player='%d:%s' team=%d", client_id, server_clientname(client_id), team);
-	
+
 	gameobj->on_player_info_change(&players[client_id]);
 
 	// send all info to this client
@@ -786,7 +1360,7 @@
 		die_pos = vec2(0,0);
 		pos = vec2(100,100);
 	}
-		
+
 	vec2 pos;
 	bool got;
 	int friendly_team;
@@ -797,35 +1371,35 @@
 static float evaluate_spawn(spawneval *eval, vec2 pos)
 {
 	float score = 0.0f;
-	
+
 	for(int c = 0; c < MAX_CLIENTS; c++)
 	{
 		if(players[c].client_id == -1)
 			continue;
-			
+
 		// don't count dead people
 		if(!(players[c].flags&entity::FLAG_PHYSICS))
 			continue;
-		
+
 		// team mates are not as dangerous as enemies
 		float scoremod = 1.0f;
 		if(eval->friendly_team != -1 && players[c].team == eval->friendly_team)
 			scoremod = 0.5f;
-			
+
 		float d = distance(pos, players[c].pos);
 		if(d == 0)
 			score += 1000000000.0f;
 		else
 			score += 1.0f/d;
 	}
-	
+
 	// weight in the die posititon
 	float d = distance(pos, eval->die_pos);
 	if(d == 0)
 		score += 1000000000.0f;
 	else
 		score += 1.0f/d;
-	
+
 	return score;
 }
 
@@ -856,17 +1430,17 @@
 void player::try_respawn()
 {
 	vec2 spawnpos = vec2(100.0f, -60.0f);
-	
+
 	// get spawn point
 	spawneval eval;
 	eval.die_pos = die_pos;
-	
+
 	eval.pos = vec2(100, 100);
-	
+
 	if(gameobj->gametype == GAMETYPE_CTF)
 	{
 		eval.friendly_team = team;
-		
+
 		// try first try own team spawn, then normal spawn and then enemy
 		evaluate_spawn_type(&eval, 1+(team&1));
 		if(!eval.got)
@@ -880,12 +1454,12 @@
 	{
 		if(gameobj->gametype == GAMETYPE_TDM)
 			eval.friendly_team = team;
-			
+
 		evaluate_spawn_type(&eval, 0);
 		evaluate_spawn_type(&eval, 1);
 		evaluate_spawn_type(&eval, 2);
 	}
-	
+
 	spawnpos = eval.pos;
 
 	// check if the position is occupado
@@ -897,7 +1471,7 @@
 		if(ents[i] != this)
 			return;
 	}
-	
+
 	spawning = false;
 	pos = spawnpos;
 
@@ -905,12 +1479,12 @@
 	core.vel = vec2(0,0);
 	core.hooked_player = -1;
 
-	health = 10;
-	armor = 0;
+	health = config.sv_start_health;
+	armor = config.sv_start_armor;
 	jumped = 0;
-	
+
 	mem_zero(&ninja, sizeof(ninja));
-	
+
 	dead = false;
 	set_flag(entity::FLAG_PHYSICS);
 	player_state = PLAYERSTATE_PLAYING;
@@ -921,17 +1495,41 @@
 
 	// init weapons
 	mem_zero(&weapons, sizeof(weapons));
-	weapons[WEAPON_HAMMER].got = true;
-	weapons[WEAPON_HAMMER].ammo = -1;
-	weapons[WEAPON_GUN].got = true;
-	weapons[WEAPON_GUN].ammo = data->weapons[WEAPON_GUN].maxammo;
+	bool activated = false;
+	for(int i=0;i<NUM_WEAPONS;i++) {
+		if(start[i]) {
+			weapons[i].got = true;
+			if (i == 0)weapons[i].ammo = -1;
+			else
+			{
+				weapons[i].ammo = data->weapons[i].maxammo;
+				if(i == 6)
+				{
+					ninja.activationtick = server_tick();
+					//handle_ninja();
+					last_weapon = 0;
+				}
+
+			}
+			if(!activated)
+			{
+				active_weapon = i;
+				last_weapon = i;
+				queued_weapon = i;
+				activated = true;
+			}
+		} else {
+			weapons[i].got = false;
+			weapons[i].ammo = 0;
+		}
+	}
 
 	/*weapons[WEAPON_RIFLE].got = true;
 	weapons[WEAPON_RIFLE].ammo = -1;*/
-	
-	active_weapon = WEAPON_GUN;
-	last_weapon = WEAPON_HAMMER;
-	queued_weapon = 0;
+
+	//active_weapon = WEAPON_GUN;
+	//last_weapon = WEAPON_HAMMER;
+
 
 	reload_timer = 0;
 
@@ -940,6 +1538,8 @@
 	create_playerspawn(pos);
 
 	gameobj->on_player_spawn(this);
+	lastplayer=-1;
+	lastplayertime=-1;
 }
 
 bool player::is_grounded()
@@ -966,7 +1566,7 @@
 		set_weapon(active_weapon);
 		return 0;
 	}
-	
+
 	// force ninja weapon
 	set_weapon(WEAPON_NINJA);
 
@@ -978,7 +1578,7 @@
 		ninja.activationdir = direction;
 		ninja.currentmovetime = data->weapons[WEAPON_NINJA].movetime * server_tickspeed() / 1000;
 		ninja.currentcooldown = data->weapons[WEAPON_NINJA].firedelay * server_tickspeed() / 1000 + server_tick();
-		
+
 		// reset hit objects
 		numobjectshit = 0;
 
@@ -1058,7 +1658,7 @@
 {
 	if(reload_timer != 0) // make sure we have reloaded
 		return;
-		
+
 	if(queued_weapon == -1) // check for a queued weapon
 		return;
 
@@ -1074,7 +1674,7 @@
 	int wanted_weapon = active_weapon;
 	if(queued_weapon != -1)
 		wanted_weapon = queued_weapon;
-	
+
 	// select weapon
 	int next = count_input(latest_previnput.next_weapon, latest_input.next_weapon).presses;
 	int prev = count_input(latest_previnput.prev_weapon, latest_input.prev_weapon).presses;
@@ -1106,7 +1706,7 @@
 	// check for insane values
 	if(wanted_weapon >= 0 && wanted_weapon < NUM_WEAPONS && wanted_weapon != active_weapon && weapons[wanted_weapon].got)
 		queued_weapon = wanted_weapon;
-	
+
 	do_weaponswitch();
 }
 
@@ -1114,11 +1714,11 @@
 {
 	if(reload_timer != 0 || active_weapon == WEAPON_NINJA)
 		return;
-		
+
 	do_weaponswitch();
-	
+
 	vec2 direction = normalize(vec2(latest_input.target_x, latest_input.target_y));
-	
+
 	bool fullauto = false;
 	if(active_weapon == WEAPON_GRENADE || active_weapon == WEAPON_SHOTGUN || active_weapon == WEAPON_RIFLE)
 		fullauto = true;
@@ -1130,16 +1730,16 @@
 	if(fullauto && (latest_input.fire&1) && weapons[active_weapon].ammo) will_fire = true;
 	if(!will_fire)
 		return;
-		
+
 	// check for ammo
 	if(!weapons[active_weapon].ammo)
 	{
 		create_sound(pos, SOUND_WEAPON_NOAMMO);
 		return;
 	}
-	
+
 	vec2 projectile_startpos = pos+direction*phys_size*0.75f;
-	
+
 	switch(active_weapon)
 	{
 		case WEAPON_HAMMER:
@@ -1147,17 +1747,18 @@
 			// reset objects hit
 			numobjectshit = 0;
 			create_sound(pos, SOUND_HAMMER_FIRE);
-			
+
 			int type = NETOBJTYPE_PLAYER_CHARACTER;
+			int num = -1;
 			entity *ents[64];
-			int num = world->find_entities(pos+direction*phys_size*0.75f, phys_size*0.5f, ents, 64, &type, 1);			
+			if(!config.sv_race_mod)num = world->find_entities(pos+direction*phys_size*0.75f, phys_size*0.5f, ents, 64, &type, 1);
 
 			for (int i = 0; i < num; i++)
 			{
 				player *target = (player*)ents[i];
 				if (target == this)
 					continue;
-					
+
 				// hit a player, give him damage and stuffs...
 				vec2 fdir = normalize(ents[i]->pos - pos);
 
@@ -1169,14 +1770,16 @@
 					dir = normalize(target->pos - pos);
 				else
 					dir = vec2(0,-1);
-					
+
 				target->core.vel += normalize(dir + vec2(0,-1.1f)) * 10.0f;
 			}
-			
+
 		} break;
 
 		case WEAPON_GUN:
 		{
+			direction.x += core.vel.x*((float)config.sv_gun_startvelocity/10000);
+			direction.y += core.vel.y*((float)config.sv_gun_startvelocity/10000);
 			projectile *proj = new projectile(WEAPON_GUN,
 				client_id,
 				projectile_startpos,
@@ -1184,28 +1787,30 @@
 				(int)(server_tickspeed()*tuning.gun_lifetime),
 				this,
 				1, 0, 0, -1, WEAPON_GUN);
-				
+
 			// pack the projectile and send it to the client directly
 			NETOBJ_PROJECTILE p;
 			proj->fill_info(&p);
-			
+
 			msg_pack_start(NETMSGTYPE_SV_EXTRA_PROJECTILE, 0);
 			msg_pack_int(1);
 			for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++)
 				msg_pack_int(((int *)&p)[i]);
 			msg_pack_end();
 			server_send_msg(client_id);
-							
+
 			create_sound(pos, SOUND_GUN_FIRE);
 		} break;
-		
+
 		case WEAPON_SHOTGUN:
 		{
+			direction.x += core.vel.x*((float)config.sv_shotgun_startvelocity/10000);
+			direction.y += core.vel.y*((float)config.sv_shotgun_startvelocity/10000);
 			int shotspread = 2;
 
 			msg_pack_start(NETMSGTYPE_SV_EXTRA_PROJECTILE, 0);
 			msg_pack_int(shotspread*2+1);
-			
+
 			for(int i = -shotspread; i <= shotspread; i++)
 			{
 				float spreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f};
@@ -1220,23 +1825,25 @@
 					(int)(server_tickspeed()*tuning.shotgun_lifetime),
 					this,
 					1, 0, 0, -1, WEAPON_SHOTGUN);
-					
+
 				// pack the projectile and send it to the client directly
 				NETOBJ_PROJECTILE p;
 				proj->fill_info(&p);
-				
+
 				for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++)
 					msg_pack_int(((int *)&p)[i]);
 			}
 
 			msg_pack_end();
-			server_send_msg(client_id);					
-			
+			server_send_msg(client_id);
+
 			create_sound(pos, SOUND_SHOTGUN_FIRE);
 		} break;
 
 		case WEAPON_GRENADE:
 		{
+			direction.x += core.vel.x*((float)config.sv_grenadelauncher_startvelocity/10000);
+			direction.y += core.vel.y*((float)config.sv_grenadelauncher_startvelocity/10000);
 			projectile *proj = new projectile(WEAPON_GRENADE,
 				client_id,
 				projectile_startpos,
@@ -1248,7 +1855,7 @@
 			// pack the projectile and send it to the client directly
 			NETOBJ_PROJECTILE p;
 			proj->fill_info(&p);
-			
+
 			msg_pack_start(NETMSGTYPE_SV_EXTRA_PROJECTILE, 0);
 			msg_pack_int(1);
 			for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++)
@@ -1258,16 +1865,16 @@
 
 			create_sound(pos, SOUND_GRENADE_FIRE);
 		} break;
-		
+
 		case WEAPON_RIFLE:
 		{
 			new laser(pos, direction, tuning.laser_reach, this);
 			create_sound(pos, SOUND_RIFLE_FIRE);
 		} break;
-		
+
 	}
 
-	if(weapons[active_weapon].ammo > 0) // -1 == unlimited
+	if(weapons[active_weapon].ammo > 0 && !config.sv_infinite_ammo) // -1 == unlimited
 		weapons[active_weapon].ammo--;
 	attack_tick = server_tick();
 	reload_timer = data->weapons[active_weapon].firedelay * server_tickspeed() / 1000;
@@ -1295,7 +1902,7 @@
 		reload_timer--;
 		return 0;
 	}
-	
+
 	if (active_weapon == WEAPON_NINJA)
 	{
 		// don't update other weapons while ninja is active
@@ -1326,7 +1933,7 @@
 			weapons[active_weapon].ammoregenstart = -1;
 		}
 	}
-	
+
 	return 0;
 }
 
@@ -1344,7 +1951,10 @@
 void player::tick()
 {
 	server_setclientscore(client_id, score);
-
+	if(config.sv_ninja_mod)
+	{
+		ninja.activationtick = server_tick();
+	}
 	// grab latest input
 	/*
 	{
@@ -1356,7 +1966,8 @@
 			mem_copy(&latest_input, input, sizeof(latest_input));
 		}
 	}*/
-	
+	if(config.sv_infinite_jumping)
+		core.jumped = 0;
 	// check if we have enough input
 	// this is to prevent initial weird clicks
 	if(num_inputs < 2)
@@ -1364,7 +1975,7 @@
 		latest_previnput = latest_input;
 		previnput = input;
 	}
-	
+
 	// do latency stuff
 	{
 		CLIENT_INFO info;
@@ -1422,10 +2033,99 @@
 	//core.jumped = jumped;
 	core.input = input;
 	core.tick();
+	if(config.sv_activate_stopdamage)
+	{
+		if(fabs(core.old_vel.x - core.vel.x) > config.sv_activate_stopdamage)
+		{
+			take_damage(vec2(0,0), (int)((fabs(core.old_vel.x - core.vel.x) - config.sv_activate_stopdamage)/(float)10*config.sv_stopdamage), client_id, WEAPON_HAMMER);
+		}
+		if(fabs(core.old_vel.y - core.vel.y) > config.sv_activate_stopdamage)
+		{
+			take_damage(vec2(0,0), (int)((fabs(core.old_vel.y - core.vel.y) - config.sv_activate_stopdamage)/(float)10*config.sv_stopdamage), client_id, WEAPON_HAMMER);
+		}
+		core.old_vel = core.vel;
+	}
+	if (players[client_id].started && server_tick()-players[client_id].refreshtime > server_tickspeed() && config.sv_race_mod)
+		{
+		char buf[128];
+		int time=(server_tick()-players[client_id].starttime)/server_tickspeed();
+		sprintf(buf,"Current time: %d min %d seconde",time/60,(time%60));
+		send_broadcast(buf, client_id);
+		players[client_id].refreshtime=server_tick();
+	}
 
 	// handle weapons
 	handle_weapons();
-
+	if(regn && (server_tick()%regn)==0) {
+		if(health<10) {
+			health++;
+		} else if(armor<10) {
+			armor++;
+		}
+	}
+	if(col_is_damage((int)core.pos.x,core.pos.y)) {
+		if(lastplayer != -1 && config.sv_suicide_killer && server_tick()-lastplayertime < server_tickspeed()*2){die(lastplayer,-1);if(players[lastplayer].team == team) players[lastplayer].score--; else players[lastplayer].score++;}
+		else die(client_id,-1);
+	}
+	else if(col_is_begin((int)core.pos.x,core.pos.y)) {
+		players[client_id].starttime=server_tick();
+		players[client_id].ended=0;
+		players[client_id].started=1;
+		players[client_id].refreshtime=server_tick();
+	}
+	else if(col_is_end((int)core.pos.x,core.pos.y) && !players[client_id].ended && players[client_id].started) {
+		float time=((float)(server_tick()-players[client_id].starttime))/((float) server_tickspeed());
+		char buf[128];
+		sprintf(buf,"%s finished in: %d min %d seconde",server_clientname(client_id),(int) time/60,((int)time%60));
+		send_chat(-1,CHAT_ALL, buf);
+		int ttime = 0 - (int) time;
+		players[client_id].ended=1;
+		players[client_id].started=0;
+		if (players[client_id].score < ttime)players[client_id].score=ttime;
+		top5_parsePlayer(server_clientname(client_id),(float) time);
+	}
+	int z = col_is_teleport((int)core.pos.x,core.pos.y);
+	if(tele && z) {
+		core.hooked_player = -1;
+		core.hook_state = HOOK_RETRACTED;
+		core.triggered_events |= COREEVENT_HOOK_RETRACT;
+		core.hook_state = HOOK_RETRACTED;
+		core.pos = teleport(z);
+		core.hook_pos = core.pos;
+		player* cplayer = closest_player(core.pos, 20.0f, this);
+		if(cplayer && cplayer->client_id != -1 && config.sv_teleport_kill){
+			cplayer->die(client_id,-1);
+		dbg_msg("Rajh","%s sest teleporter sur : %s",server_clientname(client_id),server_clientname(cplayer->client_id));}
+		if(strip) {
+			active_weapon = WEAPON_HAMMER;
+			last_weapon = WEAPON_HAMMER;
+			if(z&1) {
+				weapons[0].got = true;
+				for(int i=1;i<5;i++) {
+					weapons[i].got = false;
+				}
+			} else {
+				for(int i=0;i<NUM_WEAPONS;i++) {
+					if(start[i]) {
+						weapons[i].got = true;
+						weapons[i].ammo = data->weapons[i].maxammo;
+					} else {
+						weapons[i].got = false;
+						weapons[i].ammo = 0;
+					}
+				}
+			}
+		}
+	}
+	if((core.hook_state==HOOK_FLYING || core.hook_state==HOOK_GRABBED) && col_intersect_nohook(core.pos,core.hook_pos)) {
+		core.hooked_player = -1;
+		core.hook_state = HOOK_RETRACTED;
+		core.triggered_events |= COREEVENT_HOOK_RETRACT;
+		core.hook_state = HOOK_RETRACTED;
+		core.hook_pos = core.pos;
+		core.hook_tick = 0;
+	}
+	if (core.hooked_player != -1){players[core.hooked_player].lastplayer=client_id;players[core.hooked_player].lastplayertime=server_tick();}
 	player_state = input.player_state;
 
 	// Previnput
@@ -1440,16 +2140,16 @@
 		vec2 start_pos = core.pos;
 		vec2 start_vel = core.vel;
 		bool stuck_before = test_box(core.pos, vec2(28.0f, 28.0f));
-		
+
 		core.move();
 		bool stuck_after_move = test_box(core.pos, vec2(28.0f, 28.0f));
 		core.quantize();
 		bool stuck_after_quant = test_box(core.pos, vec2(28.0f, 28.0f));
 		pos = core.pos;
-		
+
 		if(!stuck_before && (stuck_after_move || stuck_after_quant))
 		{
-			dbg_msg("player", "STUCK!!! %d %d %d %f %f %f %f %x %x %x %x", 
+			dbg_msg("player", "STUCK!!! %d %d %d %f %f %f %f %x %x %x %x",
 				stuck_before,
 				stuck_after_move,
 				stuck_after_quant,
@@ -1461,7 +2161,7 @@
 
 		int events = core.triggered_events;
 		int mask = cmask_all_except_one(client_id);
-		
+
 		if(events&COREEVENT_GROUND_JUMP) create_sound(pos, SOUND_PLAYER_JUMP, mask);
 		if(events&COREEVENT_AIR_JUMP)
 		{
@@ -1473,14 +2173,14 @@
 				c->y = (int)pos.y;
 			}
 		}
-		
+
 		//if(events&COREEVENT_HOOK_LAUNCH) snd_play_random(CHN_WORLD, SOUND_HOOK_LOOP, 1.0f, pos);
 		if(events&COREEVENT_HOOK_ATTACH_PLAYER) create_sound(pos, SOUND_HOOK_ATTACH_PLAYER, cmask_all());
 		if(events&COREEVENT_HOOK_ATTACH_GROUND) create_sound(pos, SOUND_HOOK_ATTACH_GROUND, mask);
 		//if(events&COREEVENT_HOOK_RETRACT) snd_play_random(CHN_WORLD, SOUND_PLAYER_JUMP, 1.0f, pos);
-		
+
 	}
-	
+
 	if(team == -1)
 	{
 		pos.x = input.target_x;
@@ -1517,19 +2217,31 @@
 	die_tick = server_tick();
 	clear_flag(FLAG_PHYSICS);
 	create_death(pos, client_id);
+	if(((weapon == -1 && client_id == killer) || (killer != client_id && players[killer].team != team)) && players[killer].teamkills > 0)
+		players[killer].teamkills --;
+	if(config.sv_kick_teamkiller && ((killer == client_id && weapon != -1) || players[killer].team == team) && players[killer].teamkills++ >= config.sv_kick_teamkiller)
+	{
+		char kickmessage[256];
+		sprintf(kickmessage, "%s was kicked because of teamkilling/selfkillng.", server_clientname(killer));
+		send_message(kickmessage, -1);
+		if(config.sv_ban_teamkiller)
+			server_ban(killer, config.sv_ban_teamkiller, "You were banned because of teamkilling/selfkilling");
+		else
+			server_kick(killer, "You were kicked because of teamkilling/selfkilling");
+	}
 }
 
 bool player::take_damage(vec2 force, int dmg, int from, int weapon)
 {
-	core.vel += force;
-	
+	if(!config.sv_race_mod || (config.sv_race_mod && from == client_id))core.vel += force;
+
 	if(gameobj->is_friendly_fire(client_id, from) && !config.sv_teamdamage)
 		return false;
 
 	// player only inflicts half damage on self
-	if(from == client_id)
+	if(!config.sv_correct_selfdamage && from == client_id)
 		dmg = max(1, dmg/2);
-
+	if(from == client_id && !config.sv_rocket_jump_damage)dmg=0;
 	// CTF and TDM (TODO: check for FF)
 	//if (gameobj->gametype != GAMETYPE_DM && from >= 0 && players[from].team == team)
 		//return false;
@@ -1557,7 +2269,7 @@
 				health--;
 				dmg--;
 			}
-			
+
 			if(dmg > armor)
 			{
 				dmg -= armor;
@@ -1569,8 +2281,10 @@
 				dmg = 0;
 			}
 		}
-		
+
 		health -= dmg;
+		lastplayer=from;
+		lastplayertime=server_tick();
 	}
 
 	damage_taken_tick = server_tick();
@@ -1649,7 +2363,7 @@
 		character->ammocount = 0;
 		character->health = 0;
 		character->armor = 0;
-		
+
 		character->weapon = active_weapon;
 		character->attacktick = attack_tick;
 
@@ -1689,11 +2403,13 @@
 	type = _type;
 	subtype = _subtype;
 	proximity_radius = phys_size;
+	if(config.sv_spawn_powerups)
+	{
+		reset();
 
-	reset();
-
-	// TODO: should this be done here?
-	world->insert_entity(this);
+		// TODO: should this be done here?
+		world->insert_entity(this);
+	}
 }
 
 void powerup::reset()
@@ -1795,7 +2511,7 @@
 
 				pplayer->emote_type = EMOTE_ANGRY;
 				pplayer->emote_stop = server_tick() + 1200 * server_tickspeed() / 1000;
-				
+
 				break;
 			}
 		default:
@@ -1806,7 +2522,7 @@
 		{
 			dbg_msg("game", "pickup player='%d:%s' item=%d/%d",
 				pplayer->client_id, server_clientname(pplayer->client_id), type, subtype);
-			spawntick = server_tick() + server_tickspeed() * respawntime;
+			spawntick = server_tick() + server_tickspeed() * respawntime * config.sv_powerup_respawn;
 		}
 	}
 }
@@ -1950,12 +2666,12 @@
 	float closest_len = distance(pos0, pos1) * 100.0f;
 	vec2 line_dir = normalize(pos1-pos0);
 	player *closest = 0;
-		
+
 	for(int i = 0; i < MAX_CLIENTS; i++)
 	{
-		if(players[i].client_id < 0 || (entity *)&players[i] == notthis)
+		if(players[i].client_id < 0 || (notthis != NULL && (entity *)&players[i] == notthis))
 			continue;
-			
+
 		if(!(players[i].flags&entity::FLAG_PHYSICS))
 			continue;
 
@@ -1971,7 +2687,7 @@
 			}
 		}
 	}
-	
+
 	return closest;
 }
 
@@ -1981,12 +2697,12 @@
 	// Find other players
 	float closest_range = radius*2;
 	player *closest = 0;
-		
+
 	for(int i = 0; i < MAX_CLIENTS; i++)
 	{
 		if(players[i].client_id < 0 || (entity *)&players[i] == notthis)
 			continue;
-			
+
 		if(!(players[i].flags&entity::FLAG_PHYSICS))
 			continue;
 
@@ -2000,7 +2716,7 @@
 			}
 		}
 	}
-	
+
 	return closest;
 }
 
@@ -2012,6 +2728,35 @@
 
 	if(world->paused) // make sure that the game object always updates
 		gameobj->tick();
+	if(config.sv_regen>=0) {
+		char buf[128];
+		regn = config.sv_regen;
+		if(regn>0) {
+			sprintf(buf,"Tee's regenerate health at %.2f health/sec",50.0/(float)regn);
+		} else {
+			sprintf(buf,"Tee's no longer regenerate health.");
+		}
+		send_chat(-1,-2,buf);
+		config.sv_regen = -1;}
+	else if(config.sv_teleport) {
+		tele = tele?0:1;
+		char buf[128];
+		tele?sprintf(buf,"Teleport tiles will teleport tee's."):sprintf(buf,"Teleport tiles will no longer teleport tee's.");
+		send_chat(-1,-2,buf);
+		config.sv_teleport = 0;}
+	else if(config.sv_strip) {
+		strip = strip?0:1;
+		char buf[128];
+		strip?sprintf(buf,"Tee's will have weapons removed on teleport."):sprintf(buf,"Tee's will not lose weapons on teleport.");
+		send_chat(-1,-2,buf);
+		config.sv_strip = 0;
+	}
+	 else if(config.sv_start[0]!=0) {
+		sscanf(config.sv_start,"%d %d %d %d %d %d",&(start[0]),&(start[1]),&(start[2]),&(start[3]),&start[4],&start[5]);
+		char buf[128];
+		sprintf(buf,"%s%s%s%s%s%senabled on spawn!",start[0]?"Hammer ":"",start[1]?"Pistol ":"",start[2]?"Shotgun ":"",start[3]?"Grenade ":"",start[4]?"Rifle ":"",start[5]?"Ninja ":"");
+		send_chat(-1,-2,buf);
+		config.sv_start[0] = 0;}
 }
 
 void mods_snap(int client_id)
@@ -2024,7 +2769,7 @@
 {
 	if(!world->paused)
 		players[client_id].on_direct_input((NETOBJ_PLAYER_INPUT *)input);
-	
+
 	/*
 	if(i->fire)
 	{
@@ -2044,7 +2789,7 @@
 		//players[client_id].previnput = players[client_id].input;
 		players[client_id].input = *(NETOBJ_PLAYER_INPUT*)input;
 		players[client_id].num_inputs++;
-		
+
 		if(players[client_id].input.target_x == 0 && players[client_id].input.target_y == 0)
 			players[client_id].input.target_y = -1;
 	}
@@ -2057,19 +2802,67 @@
 	players[client_id].respawn();
 	dbg_msg("game", "join player='%d:%s'", client_id, server_clientname(client_id));
 
-
+	if(config.sv_race_mod)players[client_id].score=-9999;
+	else players[client_id].score=0;
+	players[client_id].started=0;
+	players[client_id].votedfor=-1;
+	players[client_id].teamkills = 0;
+	players[client_id].voted = false;
 	char buf[512];
+	players[client_id].played = false;
 	str_format(buf, sizeof(buf), "%s entered and joined the %s", server_clientname(client_id), get_team_name(players[client_id].team));
-	send_chat(-1, CHAT_ALL, buf); 
-
+	send_chat(-1, CHAT_ALL, buf);
+	if(strlen(config.sv_startmessage) > 0)
+	{
+		NETMSG_SV_CHAT msg;
+		msg.team = 0;
+		msg.cid = -1;
+		msg.message = config.sv_startmessage;
+		msg.pack(MSGFLAG_VITAL);
+		server_send_msg(client_id);
+	}
 	dbg_msg("game", "team_join player='%d:%s' team=%d", client_id, server_clientname(client_id), players[client_id].team);
 }
 
+void top5_draw(int id) {
+        int pos=1;
+	char buf[512];
+        send_chat(-1,CHAT_ALL,"----------- Top 5 -----------");
+        for (std::list<player_score>::iterator i=top5.begin(); i!=top5.end() && pos<=5; i++) {
+                std::ostringstream oss;
+                oss << pos << ". " << i->name() << " Time:" << (int)(i->score())/60 << " minutes " << i->score()-((int)i->score()/60)*60 <<" secondes.";
+                send_chat(-1, CHAT_ALL, oss.str().c_str());
+                pos++;
+        }
+	str_format(buf, sizeof(buf), "-----------------------------(%s)",server_clientname(id));
+	send_chat(-1, CHAT_ALL, buf);
+}
+
+void rank_draw(int id) {
+        int pos=1;;
+	float found=-1;
+	char buf[512];
+        for (std::list<player_score>::iterator i=top5.begin(); i!=top5.end(); i++) {
+		if(!strcmp(i->name().c_str(),server_clientname(id))){found=i->score();break;}
+                pos++;
+        }
+	if(found != -1){
+	str_format(buf, sizeof(buf), "%s Rank: %d Time:%d minutes %f secondes",server_clientname(id),pos,(int)found/60,found-((int)found/60)*60,config.sv_rank_site);
+	send_chat(-1, CHAT_ALL, buf);
+	str_format(buf, sizeof(buf), "See all rank at %s",config.sv_rank_site);
+	send_chat(-1, CHAT_ALL, buf);
+	}
+	else{
+	str_format(buf, sizeof(buf), "%s is not ranked",server_clientname(id));
+	send_chat(-1, CHAT_ALL, buf);
+	}
+}
+
 void mods_connected(int client_id)
 {
 	players[client_id].init();
 	players[client_id].client_id = client_id;
-	
+
 	// Check which team the player should be on
 	if(config.sv_tournament_mode)
 		players[client_id].team = -1;
@@ -2085,16 +2878,37 @@
 
 void mods_client_drop(int client_id)
 {
+	if((gameobj->gametype == GAMETYPE_TDM || gameobj->gametype == GAMETYPE_CTF) && config.sv_ko_mode && players[client_id].team != -1)
+	{
+		gameobj->endround();
+		bool in_it = false;
+		for(int i = 0; i < MAX_CLIENTS; i++)
+		{
+			if(in_it)
+			{
+				gameobj->next_players[i-1] = gameobj->next_players[i];
+			}
+			if(gameobj->next_players[i] == client_id)
+			{
+				in_it = true;
+			}
+		}
+		if(in_it)
+		{
+			gameobj->next_players[MAX_CLIENTS - 1] = -1;
+		}
+	}
 	char buf[512];
 	str_format(buf, sizeof(buf),  "%s has left the game", server_clientname(client_id));
 	send_chat(-1, CHAT_ALL, buf);
-
 	dbg_msg("game", "leave player='%d:%s'", client_id, server_clientname(client_id));
 
 	gameobj->on_player_death(&players[client_id], 0, -1);
 	world->remove_entity(&players[client_id]);
 	world->core.players[client_id] = 0x0;
+
 	players[client_id].client_id = -1;
+
 }
 
 void mods_message(int msgtype, int client_id)
@@ -2105,7 +2919,7 @@
 		dbg_msg("server", "dropped weird message '%s' (%d), failed on '%s'", netmsg_get_name(msgtype), msgtype, netmsg_failed_on());
 		return;
 	}
-	
+
 	if(msgtype == NETMSGTYPE_CL_SAY)
 	{
 		NETMSG_CL_SAY *msg = (NETMSG_CL_SAY *)rawmsg;
@@ -2114,15 +2928,244 @@
 			team = players[client_id].team;
 		else
 			team = CHAT_ALL;
-		
+
 		if(config.sv_spamprotection && players[client_id].last_chat+time_freq() > time_get())
 		{
 			// consider this as spam
 		}
 		else
 		{
-			players[client_id].last_chat = time_get();
-			send_chat(client_id, team, msg->message);
+			if(!strcasecmp(msg->message, ".info"))
+			{
+				char commands[768]="Mod from scosu (http://scosu.de). Available commands:\n";
+				if(config.sv_handle_mapvotes)
+				{
+					strcat(commands, "Positive map-voting: /++\n");
+					strcat(commands, "Negative map-voting: /--\n");
+				}
+				strcat(commands, "Current vote: /currentvote\n");
+				strcat(commands, "List of player-ids: /players\n");
+				if(config.sv_allow_votes)
+				{
+					strcat(commands, "Kick player by name: /kick <player name>\n");
+					strcat(commands, "Kick player by id: /kick_id <player id>\n");
+				}
+				if(config.sv_allow_next_map)
+				{
+					strcat(commands, "Start vote for change to next map: /next_map\n");
+				}
+				if(config.sv_allow_timelimit)
+				{
+					strcat(commands, "Start vote for set timelimit: /timelimit <new limit(-1 disable)>\n");
+				}
+				if(config.sv_allow_scorelimit)
+				{
+					strcat(commands, "Start vote for set scorelimit: /scorelimit <new limit(-1 disable)>\n");
+				}
+				send_message(commands, client_id);
+				//players[client_id].last_chat = time_get()+time_freq()*10;
+			}
+			else if (!strncasecmp(msg->message, "/kick ",6) && !vote_called && config.sv_allow_votes)
+			{
+				if(config.sv_vote_pause && players[client_id].lastvote != 0 && (server_tick() - players[client_id].lastvote)/server_tickspeed() < config.sv_vote_pause)
+				{
+					char novote[90];
+					sprintf(novote, "You can start votings in %i seconds", config.sv_vote_pause-(server_tick() - players[client_id].lastvote)/server_tickspeed());
+					send_display(novote, client_id);
+					return;
+				}
+				int playersnumber=0;
+				int playerstokick=-1;
+				char message[256];
+				for (int i=0; i < MAX_CLIENTS;i++)
+				{
+					if(players[i].client_id !=-1)
+					{
+						str_format(message, sizeof(message), "/kick ");
+						strcat(message,server_clientname(i));
+						if(!strncmp(msg->message, message,9))
+						{
+							playersnumber++;
+							playerstokick=i;
+						}
+					}
+				}
+				if(playersnumber == 1 && playerstokick != -1)
+				{
+					votetime = config.sv_votetime;
+					str_format(votetype, sizeof(votetype), "kick");
+					votedtokick=playerstokick;
+					str_format(vote_message, sizeof(vote_message), "Vote for: kick %s\nsay \"/yes\" or \"/no\" (%s)", server_clientname(playerstokick),server_clientname(client_id));
+					send_display(vote_message,-1);
+					vote_called=true;
+					timer_vote = server_tick();
+					players[client_id].votedfor = 1;
+					players[client_id].lastvote = server_tick();
+					server_save_ip(votedtokick);
+				}
+				else if(playersnumber > 1)
+				{
+					send_display("Several players possible", client_id);
+				}
+				else
+				{
+					send_display("There is no player with this name", client_id);
+				}
+			}
+			else if (!strncasecmp(msg->message, "/kick_id ",9) && !vote_called && config.sv_allow_votes)
+			{
+				if(config.sv_vote_pause && players[client_id].lastvote != 0 && (server_tick() - players[client_id].lastvote)/server_tickspeed() < config.sv_vote_pause)
+				{
+					char novote[90];
+					sprintf(novote, "You can start votings in %i seconds", config.sv_vote_pause-(server_tick() - players[client_id].lastvote)/server_tickspeed());
+					send_display(novote, client_id);
+					return;
+				}
+				votedtokick = atoi(&msg->message[9]);
+				if(votedtokick > 0 && votedtokick-- <= MAX_CLIENTS && players[votedtokick].client_id != -1)
+				{
+					votetime = config.sv_votetime;
+					str_format(votetype, sizeof(votetype), "kick");
+					str_format(vote_message, sizeof(vote_message), "Vote for: kick %s\nsay \"/yes\" or \"/no\" (%s)",server_clientname(votedtokick), server_clientname(client_id));
+					send_display(vote_message,-1);
+					vote_called=true;
+					timer_vote = server_tick();
+					players[client_id].votedfor = 1;
+					players[client_id].lastvote = server_tick();
+					server_save_ip(votedtokick);
+				}
+				else
+				{
+					votedtokick = -1;
+					send_display("That was no valid integer", client_id);
+				}
+			}
+			else if (!strncasecmp(msg->message, "/next_map",9) && !vote_called && config.sv_allow_next_map)
+			{
+				if(config.sv_vote_pause && players[client_id].lastvote != 0 && (server_tick() - players[client_id].lastvote)/server_tickspeed() < config.sv_vote_pause)
+				{
+					char novote[90];
+					sprintf(novote, "You can start votings in %i seconds", config.sv_vote_pause-(server_tick() - players[client_id].lastvote)/server_tickspeed());
+					send_display(novote, client_id);
+					return;
+				}
+				votetime = config.sv_votetime;
+				str_format(votetype, sizeof(votetype), "next_map");
+				str_format(vote_message, sizeof(vote_message), "Vote for: changing to next map\nsay \"/yes\" or \"/no\" (%s)",server_clientname(client_id));
+				send_display(vote_message,-1);
+				vote_called=true;
+				timer_vote = server_tick();
+				players[client_id].votedfor = 1;
+				players[client_id].lastvote = server_tick();
+			}
+			else if (!strncasecmp(msg->message, "/timelimit ",11) && !vote_called && config.sv_allow_timelimit)
+			{
+				if(config.sv_vote_pause && players[client_id].lastvote != 0 && (server_tick() - players[client_id].lastvote)/server_tickspeed() < config.sv_vote_pause)
+				{
+					char novote[90];
+					sprintf(novote, "You can start votings in %i seconds", config.sv_vote_pause-(server_tick() - players[client_id].lastvote)/server_tickspeed());
+					send_display(novote, client_id);
+					return;
+				}
+				votedtokick = atoi(&msg->message[11]);
+				if(votedtokick == -1 || (votedtokick>0 && votedtokick < 1000))
+				{
+					votetime = config.sv_votetime;
+					str_format(votetype, sizeof(votetype), "timelimit");
+					str_format(vote_message, sizeof(vote_message), "Vote for: set timelimit to %i\nsay \"/yes\" or \"/no\" (%s)",votedtokick, server_clientname(client_id));
+					send_display(vote_message,-1);
+					vote_called=true;
+					timer_vote = server_tick();
+					players[client_id].votedfor = 1;
+					players[client_id].lastvote = server_tick();
+				}
+				else
+				{
+					votedtokick = -1;
+					send_display("That was no valid integer", client_id);
+				}
+			}
+			else if (!strncasecmp(msg->message, "/scorelimit ",12) && !vote_called && config.sv_allow_scorelimit)
+			{
+				if(config.sv_vote_pause && players[client_id].lastvote != 0 && (server_tick() - players[client_id].lastvote)/server_tickspeed() < config.sv_vote_pause)
+				{
+					char novote[90];
+					sprintf(novote, "You can start votings in %i seconds", config.sv_vote_pause-(server_tick() - players[client_id].lastvote)/server_tickspeed());
+					send_display(novote, client_id);
+					return;
+				}
+				votedtokick = atoi(&msg->message[12]);
+				if(votedtokick == -1 || (votedtokick>0 && votedtokick < 1000))
+				{
+					votetime = config.sv_votetime;
+					str_format(votetype, sizeof(votetype), "scorelimit");
+					str_format(vote_message, sizeof(vote_message), "Vote for: set scorelimit to %i\nsay \"/yes\" or \"/no\" (%s)",votedtokick, server_clientname(client_id));
+					send_display(vote_message,-1);
+					vote_called=true;
+					timer_vote = server_tick();
+					players[client_id].votedfor = 1;
+					players[client_id].lastvote = server_tick();
+				}
+				else
+				{
+					votedtokick = -1;
+					send_display("That was no valid integer", client_id);
+				}
+			}
+			else if (!strncasecmp(msg->message, "/yes",3) && players[client_id].votedfor == -1 && vote_called)
+			{
+				char message[256];
+				str_format(message, sizeof(message), "%s voted for yes",server_clientname(client_id));
+				send_chat(-1,CHAT_ALL,message);
+				players[client_id].votedfor = 1;
+				//resultvote();
+			}
+			else if (!strncasecmp(msg->message, "/no",2) && players[client_id].votedfor == -1 && vote_called)
+			{
+				char buf[256];
+				str_format(buf, sizeof(buf), "%s voted for no",server_clientname(client_id));
+				send_message(buf, -1);
+				players[client_id].votedfor = 0;
+				//resultvote();
+			}
+			else if (!strncasecmp(msg->message, "/currentvote",12) && vote_called)
+			{
+				send_display(vote_message, client_id);
+				resultvote();
+			}
+			else if (!strncasecmp(msg->message, "/players",2))
+			{
+				char all_players[512] = "Players:\n";
+				int i = 0;
+				for(;i < MAX_CLIENTS;i++)
+				{
+					if(players[i].client_id != -1)
+					{
+						char player[5];
+						sprintf(player, "%i", i+1);
+						strcat(all_players, player);
+						strcat(all_players, ": ");
+						strcat(all_players, server_clientname(i));
+						strcat(all_players, "\n");
+					}
+				}
+				send_message(all_players, client_id);
+			}
+			else if(!strcasecmp(msg->message, "/top5"))
+			{
+				top5_draw(client_id);
+				players[client_id].last_chat = time_get()+time_freq()*10;
+			}
+			else if(!strcasecmp(msg->message, "/rank"))
+			{
+				rank_draw(client_id);
+				players[client_id].last_chat = time_get()+time_freq()*10;
+			}
+			else
+			{
+				players[client_id].last_chat = time_get();
+				send_chat(client_id, team, msg->message);
+			}
 		}
 	}
 	else if (msgtype == NETMSGTYPE_CL_SETTEAM)
@@ -2159,7 +3202,7 @@
 		// copy old name
 		char oldname[MAX_NAME_LENGTH];
 		str_copy(oldname, server_clientname(client_id), MAX_NAME_LENGTH);
-		
+
 		server_setclientname(client_id, msg->name);
 		if(msgtype == NETMSGTYPE_CL_CHANGEINFO && strcmp(oldname, server_clientname(client_id)) != 0)
 		{
@@ -2167,16 +3210,16 @@
 			str_format(chattext, sizeof(chattext), "%s changed name to %s", oldname, server_clientname(client_id));
 			send_chat(-1, CHAT_ALL, chattext);
 		}
-		
+
 		// set skin
 		str_copy(players[client_id].skin_name, msg->skin, sizeof(players[client_id].skin_name));
-		
+
 		gameobj->on_player_info_change(&players[client_id]);
-		
+
 		if(msgtype == NETMSGTYPE_CL_STARTINFO)
 		{
 			// a client that connected!
-			
+
 			// send all info to this client
 			for(int i = 0; i < MAX_CLIENTS; i++)
 			{
@@ -2186,13 +3229,13 @@
 
 			// send tuning parameters to client
 			send_tuning_params(client_id);
-			
+
 			//
 			NETMSG_SV_READY_TO_ENTER m;
 			m.pack(MSGFLAG_VITAL);
-			server_send_msg(client_id);			
+			server_send_msg(client_id);
 		}
-		
+
 		send_info(client_id, -1);
 	}
 	else if (msgtype == NETMSGTYPE_CL_EMOTICON)
@@ -2265,25 +3308,83 @@
 {
 	int client_id = clamp(console_arg_int(result, 0), 0, (int)MAX_CLIENTS);
 	int team = clamp(console_arg_int(result, 1), -1, 1);
-	
+
 	dbg_msg("", "%d %d", client_id, team);
-	
+
 	if(players[client_id].client_id != client_id)
 		return;
-	
+
 	players[client_id].set_team(team);
 }
 
+static void con_vote(void *result, void *user_data)
+{
+	votetime =console_arg_int(result, 0);
+	char buf[512];
+	str_format(buf, sizeof(buf), "||| Vote for: %s (say \"/yes\" or \"/no\") |||", console_arg_string(result, 1));
+	send_chat(-1, CHAT_ALL, buf);
+	vote_called=true;
+	//if (console_arg_int(result, 0) == 1)
+	timer_vote = server_tick();
+	//else world->timer_vote = -1;
+}
+
+static void con_next_map(void *result, void *user_data)
+{
+	gameobj->endround();
+}
+
+static void con_cancel_vote(void *result, void *user_data)
+{
+	str_format(votetype, sizeof(votetype), "null");
+	votedtokick = -1;
+	for (int i=0; i < MAX_CLIENTS;i++)
+	{
+		if(players[i].client_id !=-1)
+		{
+			players[i].votedfor=-1;
+		}
+	}
+	vote_called = false;
+	send_display("Vote canceled by admin", -1);
+}
+
+static void con_teleport(void *result, void *user_data)
+{
+	players[console_arg_int(result, 0)].core.pos=players[console_arg_int(result, 1)].core.pos;
+	players[console_arg_int(result, 0)].started=0;
+}
+
+static void con_teleport_to(void *result, void *user_data)
+{
+	players[console_arg_int(result, 0)].core.pos.x=console_arg_int(result, 1);
+	players[console_arg_int(result, 0)].core.pos.y=console_arg_int(result, 2);
+	players[console_arg_int(result, 0)].started=0;
+}
+
+static void con_get_pos(void *result, void *user_data)
+{
+	dbg_msg("Tele","%s pos: %d @ %d", server_clientname(console_arg_int(result, 0)),(int) players[console_arg_int(result, 0)].core.pos.x,(int)players[console_arg_int(result, 0)].core.pos.y);
+
+}
+
+
 void mods_console_init()
 {
 	MACRO_REGISTER_COMMAND("tune", "si", con_tune_param, 0);
 	MACRO_REGISTER_COMMAND("tune_reset", "", con_tune_reset, 0);
 	MACRO_REGISTER_COMMAND("tune_dump", "", con_tune_dump, 0);
-
+	MACRO_REGISTER_COMMAND("vote", "ir", con_vote, 0);
 	MACRO_REGISTER_COMMAND("restart", "?i", con_restart, 0);
 	MACRO_REGISTER_COMMAND("broadcast", "r", con_broadcast, 0);
 	MACRO_REGISTER_COMMAND("say", "r", con_say, 0);
 	MACRO_REGISTER_COMMAND("set_team", "ii", con_set_team, 0);
+	MACRO_REGISTER_COMMAND("next_map", "", con_next_map, 0);
+	MACRO_REGISTER_COMMAND("cancel_vote", "", con_cancel_vote, 0);
+	MACRO_REGISTER_COMMAND("teleport", "ii", con_teleport, 0);
+	MACRO_REGISTER_COMMAND("teleport_to", "iii", con_teleport_to, 0);
+	MACRO_REGISTER_COMMAND("get_pos", "i", con_get_pos, 0);
+
 }
 
 void mods_init()
@@ -2312,11 +3413,11 @@
 	// create all entities from the game layer
 	MAPITEM_LAYER_TILEMAP *tmap = layers_game_layer();
 	TILE *tiles = (TILE *)map_get_data(tmap->data);
-	
+
 	num_spawn_points[0] = 0;
 	num_spawn_points[1] = 0;
 	num_spawn_points[2] = 0;
-	
+
 	for(int y = 0; y < tmap->height; y++)
 	{
 		for(int x = 0; x < tmap->width; x++)
@@ -2339,6 +3440,7 @@
 				players[MAX_CLIENTS-i-1].team = i&1;
 		}
 	}
+	top5_load();
 }
 
 void mods_shutdown()
