about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMagnus Auvinen <magnus.auvinen@gmail.com>2007-08-04 18:23:26 +0000
committerMagnus Auvinen <magnus.auvinen@gmail.com>2007-08-04 18:23:26 +0000
commit1eadf9942ad07ba3c60f9a027cf232a351fa9b05 (patch)
tree0c513cbd05f37049c40c2a199d44020202134f73
parentc89e2d0dc89fec398f111807013b1091322f6f51 (diff)
downloadzcatch-1eadf9942ad07ba3c60f9a027cf232a351fa9b05.tar.gz
zcatch-1eadf9942ad07ba3c60f9a027cf232a351fa9b05.zip
fixed handling of versions. added error messages when disconnected. updated the connecting gui. fixed no streched clouds
-rw-r--r--src/engine/client/client.cpp109
-rw-r--r--src/engine/interface.h15
-rw-r--r--src/engine/network.cpp47
-rw-r--r--src/engine/network.h3
-rw-r--r--src/engine/packet.h5
-rw-r--r--src/engine/server/server.cpp12
-rw-r--r--src/engine/versions.h2
-rw-r--r--src/game/client/game_client.cpp72
-rw-r--r--src/game/client/menu.cpp85
9 files changed, 247 insertions, 103 deletions
diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp
index 96491fc8..148f0f47 100644
--- a/src/engine/client/client.cpp
+++ b/src/engine/client/client.cpp
@@ -241,6 +241,7 @@ static void client_send_info()
 	game_start_time = -1;
 
 	msg_pack_start_system(NETMSG_INFO, MSGFLAG_VITAL);
+	msg_pack_string(TEEWARS_NETVERSION_STRING, 64);
 	msg_pack_string(config.player_name, 128);
 	msg_pack_string(config.clan_name, 128);
 	msg_pack_string(config.password, 128);
@@ -380,22 +381,15 @@ static void client_serverbrowse_update()
 }
 
 // ------ state handling -----
-enum
-{
-	STATE_OFFLINE,
-	STATE_CONNECTING,
-	STATE_LOADING,
-	STATE_ONLINE,
-	STATE_BROKEN,
-	STATE_QUIT,
-};
-
 static int state;
-static int client_get_state() { return state; }
+int client_state() { return state; }
 static void client_set_state(int s)
 {
 	dbg_msg("game", "state change. last=%d current=%d", state, s);
+	int old = state;
 	state = s;
+	if(old != s)
+		modc_statechange(state, old);
 }
 
 
@@ -424,14 +418,14 @@ void client_connect(const char *server_address_str)
 		dbg_msg("client", "could not find the address of %s, connecting to localhost", buf);
 	
 	net.connect(&server_address);
-	client_set_state(STATE_CONNECTING);	
+	client_set_state(CLIENTSTATE_CONNECTING);	
 }
 
 void client_disconnect()
 {
 	client_send_error("disconnected");
 	net.disconnect("disconnected");
-	client_set_state(STATE_OFFLINE);
+	client_set_state(CLIENTSTATE_OFFLINE);
 	map_unload();
 }
 
@@ -472,66 +466,28 @@ static void client_debug_render()
 	
 }
 
-static void client_render()
+void client_quit()
 {
-	gfx_clear(0.0f,0.0f,0.0f);
-	
-	// this should be moved around abit
-	// TODO: clean this shit up!
-	if(client_get_state() == STATE_ONLINE)
-	{
-		modc_render();
-		
-		// debug render stuff
-		client_debug_render();
-		
-	}
-	else if (client_get_state() != STATE_CONNECTING && client_get_state() != STATE_LOADING)
-	{
-		//netaddr4 server_address;
-		int status = modmenu_render();
-		if (status == -1)
-			client_set_state(STATE_QUIT);
-	}
-	else if (client_get_state() == STATE_CONNECTING || client_get_state() == STATE_LOADING)
-	{
-		static int64 start = time_get();
-		static int tee_texture;
-		static int connecting_texture;
-		static bool inited = false;
-		
-		if (!inited)
-		{
-			tee_texture = gfx_load_texture("data/gui_tee.png");
-			connecting_texture = gfx_load_texture("data/gui_connecting.png");
-				
-			inited = true;
-		}
-
-		gfx_mapscreen(0,0,400.0f,300.0f);
-
-		float t = (time_get() - start) / (double)time_freq();
-
-		float speed = 2*sin(t);
-
-		speed = 1.0f;
+	client_set_state(CLIENTSTATE_QUITING);
+}
 
-		float x = 208 + sin(t*speed) * 32;
-		float w = sin(t*speed + 3.149) * 64;
+const char *client_error_string()
+{
+	return net.error_string();
+}
 
-		ui_do_image(tee_texture, x, 95, w, 64);
-		ui_do_image(connecting_texture, 88, 150, 256, 64);
-		
-		if(inp_key_down(input::esc))
-			client_disconnect();
-	}
+static void client_render()
+{
+	gfx_clear(0.0f,0.0f,0.0f);
+	modc_render();
+	client_debug_render();
 }
 
 static void client_error(const char *msg)
 {
 	dbg_msg("game", "error: %s", msg);
 	client_send_error(msg);
-	client_set_state(STATE_BROKEN);
+	client_set_state(CLIENTSTATE_QUITING);
 }
 
 static void client_process_packet(NETPACKET *packet)
@@ -621,7 +577,7 @@ static void client_process_packet(NETPACKET *packet)
 			{
 				const char *map = msg_unpack_string();
 				dbg_msg("client/network", "connection accepted, map=%s", map);
-				client_set_state(STATE_LOADING);
+				client_set_state(CLIENTSTATE_LOADING);
 				
 				if(map_load(map))
 				{
@@ -729,7 +685,7 @@ static void client_process_packet(NETPACKET *packet)
 						if(recived_snapshots == 2)
 						{
 							local_start_time = time_get();
-							client_set_state(STATE_ONLINE);
+							client_set_state(CLIENTSTATE_ONLINE);
 						}
 						
 						int64 now = time_get();
@@ -777,18 +733,19 @@ static void client_pump_network()
 	net.update();
 
 	// check for errors		
-	if(client_get_state() != STATE_OFFLINE && net.state() == NETSTATE_OFFLINE)
+	if(client_state() != CLIENTSTATE_OFFLINE && net.state() == NETSTATE_OFFLINE)
 	{
 		// TODO: add message to the user there
-		client_set_state(STATE_OFFLINE);
+		client_set_state(CLIENTSTATE_OFFLINE);
+		dbg_msg("client", "offline error='%s'", net.error_string());
 	}
 
 	//
-	if(client_get_state() == STATE_CONNECTING && net.state() == NETSTATE_ONLINE)
+	if(client_state() == CLIENTSTATE_CONNECTING && net.state() == NETSTATE_ONLINE)
 	{
 		// we switched to online
 		dbg_msg("client", "connected, sending info");
-		client_set_state(STATE_LOADING);
+		client_set_state(CLIENTSTATE_LOADING);
 		client_send_info();
 	}
 	
@@ -824,7 +781,7 @@ static void client_run(const char *direct_connect_server)
 	modc_init();
 
 	// init menu
-	modmenu_init();
+	modmenu_init(); // TODO: remove
 	
 	// open socket
 	net.open(0, 0);
@@ -888,7 +845,7 @@ static void client_run(const char *direct_connect_server)
 		}
 
 		// send input
-		if(client_get_state() == STATE_ONLINE)
+		if(client_state() == CLIENTSTATE_ONLINE)
 		{
 			if(server_spam_address)
 				client_disconnect();
@@ -901,7 +858,7 @@ static void client_run(const char *direct_connect_server)
 			}
 		}
 		
-		if(client_get_state() == STATE_OFFLINE && server_spam_address)
+		if(client_state() == CLIENTSTATE_OFFLINE && server_spam_address)
 			client_connect(server_spam_address);
 		
 		// update input
@@ -943,7 +900,7 @@ static void client_run(const char *direct_connect_server)
 		gfx_swap();
 		
 		// check conditions
-		if(client_get_state() == STATE_BROKEN || client_get_state() == STATE_QUIT)
+		if(client_state() == CLIENTSTATE_QUITING)
 			break;
 
 		// be nice
@@ -958,10 +915,6 @@ static void client_run(const char *direct_connect_server)
 			reporttime += reportinterval;
 		}
 		
-		/*if (input::pressed(input::esc))
-			if (get_state() == STATE_CONNECTING || get_state() == STATE_ONLINE)
-				disconnect();*/
-
 		// update frametime
 		frametime = (time_get()-frame_start_time)/(float)time_freq();
 	}
diff --git a/src/engine/interface.h b/src/engine/interface.h
index 6a4953ac..5d3e2fe6 100644
--- a/src/engine/interface.h
+++ b/src/engine/interface.h
@@ -21,6 +21,12 @@ enum
 	/*
 	IMG_BGR,
 	IMG_BGRA,*/
+	
+	CLIENTSTATE_OFFLINE=0,
+	CLIENTSTATE_CONNECTING,
+	CLIENTSTATE_LOADING,
+	CLIENTSTATE_ONLINE,
+	CLIENTSTATE_QUITING,
 };
 
 struct snap_item
@@ -667,6 +673,12 @@ void modc_shutdown();
 */
 void modc_render();
 
+/*
+	Function: modc_statechange
+		Called every time client changes state.
+*/
+void modc_statechange(int new_state, int old_state);
+
 
 
 /*
@@ -748,6 +760,8 @@ int client_send_msg();
 int client_tick();
 float client_intratick();
 int client_tickspeed();
+int client_state();
+const char *client_error_string();
 
 void gfx_pretty_text(float x, float y, float size, const char *text);
 float gfx_pretty_text_width(float size, const char *text, int length = -1);
@@ -771,6 +785,7 @@ struct server_info
 
 void client_connect(const char *address);
 void client_disconnect();
+void client_quit();
 
 void client_serverbrowse_refresh(int lan);
 int client_serverbrowse_getlist(server_info **servers);
diff --git a/src/engine/network.cpp b/src/engine/network.cpp
index 93f4e158..838c5f5d 100644
--- a/src/engine/network.cpp
+++ b/src/engine/network.cpp
@@ -1,4 +1,5 @@
 #include <baselib/system.h>
+#include <string.h>
 
 #include "network.h"
 #include "ringbuffer.h"
@@ -87,7 +88,7 @@ struct NETCONNECTION
 	
 	int64 last_recv_time;
 	int64 last_send_time;
-	const char *error_string;
+	char error_string[256];
 	
 	NETADDR4 peeraddr;
 	NETSOCKET socket;
@@ -133,7 +134,7 @@ static void conn_reset(NETCONNECTION *conn)
 	}
 		
 	conn->state = NETWORK_CONNSTATE_OFFLINE;
-	conn->error_string = 0;
+	mem_zero(conn->error_string, sizeof(conn->error_string));
 	conn->last_send_time = 0;
 	conn->last_recv_time = 0;
 	conn->token = -1;
@@ -145,6 +146,12 @@ static const char *conn_error(NETCONNECTION *conn)
 {
 	return conn->error_string;
 }
+
+static void conn_set_error(NETCONNECTION *conn, const char *str)
+{
+	strcpy(conn->error_string, str);
+}
+
 /*
 static int conn_state(NETCONNECTION *conn)
 {
@@ -243,9 +250,12 @@ static int conn_connect(NETCONNECTION *conn, NETADDR4 *addr)
 	return 0;
 }
 
-static void conn_disconnect(NETCONNECTION *conn)
+static void conn_disconnect(NETCONNECTION *conn, const char *reason)
 {
-	conn_send(conn, NETWORK_PACKETFLAG_CLOSE, 0, 0);
+	if(reason)
+		conn_send(conn, NETWORK_PACKETFLAG_CLOSE, strlen(reason)+1, reason);
+	else
+		conn_send(conn, NETWORK_PACKETFLAG_CLOSE, 0, 0);
 	conn_reset(conn);
 }
 
@@ -258,6 +268,11 @@ static int conn_feed(NETCONNECTION *conn, NETPACKETDATA *p, NETADDR4 *addr)
 	if(p->flags&NETWORK_PACKETFLAG_CLOSE)
 	{
 		conn_reset(conn);
+		if(p->data_size)
+			conn_set_error(conn, (char *)p->data);
+		else
+			conn_set_error(conn, "no reason given");
+		dbg_msg("conn", "closed reason='%s'", conn_error(conn));
 		return 0;
 	}
 	
@@ -360,10 +375,10 @@ static int conn_feed(NETCONNECTION *conn, NETPACKETDATA *p, NETADDR4 *addr)
 
 
 
-static void conn_update(NETCONNECTION *conn)
+static int conn_update(NETCONNECTION *conn)
 {
 	if(conn->state == NETWORK_CONNSTATE_OFFLINE || conn->state == NETWORK_CONNSTATE_ERROR)
-		return;
+		return 0;
 	
 	// check for timeout
 	if(conn->state != NETWORK_CONNSTATE_OFFLINE &&
@@ -372,7 +387,7 @@ static void conn_update(NETCONNECTION *conn)
 	{
 		//dbg_msg("connection", "state = %d->%d", conn->state, NETWORK_CONNSTATE_ERROR);
 		conn->state = NETWORK_CONNSTATE_ERROR;
-		conn->error_string = "timeout";
+		conn_set_error(conn, "timeout");
 	}
 	
 	// check for large buffer errors
@@ -380,7 +395,7 @@ static void conn_update(NETCONNECTION *conn)
 	{
 		//dbg_msg("connection", "state = %d->%d", conn->state, NETWORK_CONNSTATE_ERROR);
 		conn->state = NETWORK_CONNSTATE_ERROR;
-		conn->error_string = "too weak connection (out of buffer)";
+		conn_set_error(conn, "too weak connection (out of buffer)");
 	}
 	
 	if(conn->buffer.first())
@@ -390,7 +405,7 @@ static void conn_update(NETCONNECTION *conn)
 		{
 			//dbg_msg("connection", "state = %d->%d", conn->state, NETWORK_CONNSTATE_ERROR);
 			conn->state = NETWORK_CONNSTATE_ERROR;
-			conn->error_string = "too weak connection (not acked for 3 seconds)";
+			conn_set_error(conn, "too weak connection (not acked for 3 seconds)");
 		}
 	}
 	
@@ -494,7 +509,8 @@ int net_server_drop(NETSERVER *s, int client_id, const char *reason)
 {
 	// TODO: insert lots of checks here
 	dbg_msg("net_server", "client dropped. cid=%d reason=\"%s\"", client_id, reason);
-	conn_reset(&s->slots[client_id].conn);
+	conn_disconnect(&s->slots[client_id].conn, reason);
+	//conn_reset(&s->slots[client_id].conn);
 	return 0;
 }
 
@@ -503,7 +519,7 @@ int net_server_update(NETSERVER *s)
 	for(int i = 0; i < NETWORK_MAX_CLIENTS; i++)
 	{
 		conn_update(&s->slots[i].conn);
-		if(conn_error(&s->slots[i].conn))
+		if(s->slots[i].conn.state == NETWORK_CONNSTATE_ERROR)
 			net_server_drop(s, i, conn_error(&s->slots[i].conn));
 	}
 	return 0;
@@ -674,7 +690,7 @@ int net_client_update(NETCLIENT *c)
 {
 	// TODO: implement me
 	conn_update(&c->conn);
-	if(conn_error(&c->conn))
+	if(c->conn.state == NETWORK_CONNSTATE_ERROR)
 		net_client_disconnect(c, conn_error(&c->conn));
 	return 0;
 }
@@ -683,7 +699,7 @@ int net_client_disconnect(NETCLIENT *c, const char *reason)
 {
 	// TODO: do this more graceful
 	dbg_msg("net_client", "disconnected. reason=\"%s\"", reason);
-	conn_disconnect(&c->conn);
+	conn_disconnect(&c->conn, 0);
 	return 0;
 }
 
@@ -786,3 +802,8 @@ void net_client_stats(NETCLIENT *c, NETSTATS *stats)
 {
 	*stats = c->conn.stats;
 }
+
+const char *net_client_error_string(NETCLIENT *c)
+{
+	return conn_error(&c->conn);
+}
diff --git a/src/engine/network.h b/src/engine/network.h
index e251f13e..adcd6d38 100644
--- a/src/engine/network.h
+++ b/src/engine/network.h
@@ -56,6 +56,7 @@ int net_client_close(NETCLIENT *c);
 int net_client_update(NETCLIENT *c);
 int net_client_state(NETCLIENT *c);
 void net_client_stats(NETCLIENT *c, NETSTATS *stats);
+const char *net_client_error_string(NETCLIENT *c);
 
 
 // wrapper classes for c++
@@ -99,6 +100,8 @@ public:
 	int send(NETPACKET *packet) { return net_client_send(ptr, packet); }
 	int update() { return net_client_update(ptr); }
 	
+	const char *error_string() { return net_client_error_string(ptr); }
+	
 	int state() { return net_client_state(ptr); }
 	void stats(NETSTATS *stats) { net_client_stats(ptr, stats); }
 };
diff --git a/src/engine/packet.h b/src/engine/packet.h
index 1700665d..79c969c2 100644
--- a/src/engine/packet.h
+++ b/src/engine/packet.h
@@ -11,6 +11,10 @@ enum
 {
 	NETMSG_NULL=0,
 	
+	// the first thing sent by the client
+	// contains the version info for the client
+	NETMSG_INFO=1,
+	
 	// sent by server
 	NETMSG_MAP,
 	NETMSG_SNAP,
@@ -18,7 +22,6 @@ enum
 	NETMSG_SNAPSMALL,
 	
 	// sent by client
-	NETMSG_INFO,
 	NETMSG_ENTERGAME,
 	NETMSG_INPUT,
 	NETMSG_SNAPACK,
diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp
index c20821eb..6a2b7b8f 100644
--- a/src/engine/server/server.cpp
+++ b/src/engine/server/server.cpp
@@ -397,6 +397,18 @@ public:
 			// system message
 			if(msg == NETMSG_INFO)
 			{
+				char version[64];
+				strncpy(version, msg_unpack_string(), 64);
+				if(strcmp(version, TEEWARS_NETVERSION_STRING) != 0)
+				//if(strcmp(version, "ERROR") != 0)
+				{
+					// OH FUCK! wrong version, drop him
+					char reason[256];
+					sprintf(reason, "wrong version. server is running %s.", TEEWARS_NETVERSION_STRING);
+					net.drop(cid, reason);
+					return;
+				}
+				
 				strncpy(clients[cid].name, msg_unpack_string(), MAX_NAME_LENGTH);
 				strncpy(clients[cid].clan, msg_unpack_string(), MAX_CLANNAME_LENGTH);
 				const char *password = msg_unpack_string();
diff --git a/src/engine/versions.h b/src/engine/versions.h
index 7b4fdc2a..34d8d79d 100644
--- a/src/engine/versions.h
+++ b/src/engine/versions.h
@@ -1,3 +1,3 @@
 #define TEEWARS_NETVERSION 0xffffffff
-//#define TEEWARS_NETVERSION_STRING "dev v2"
+#define TEEWARS_NETVERSION_STRING "0.2-dev"
 #define TEEWARS_VERSION "0.2.0-dev"
diff --git a/src/game/client/game_client.cpp b/src/game/client/game_client.cpp
index 57618202..8fdf9ade 100644
--- a/src/game/client/game_client.cpp
+++ b/src/game/client/game_client.cpp
@@ -127,7 +127,7 @@ void select_sprite(int id, int flags=0, int sx=0, int sy=0)
 	select_sprite(&data->sprites[id], flags, sx, sy);
 }
 
-static void draw_sprite(float x, float y, float size)
+void draw_sprite(float x, float y, float size)
 {
 	gfx_quads_draw(x, y, size*sprite_w_scale, size*sprite_h_scale);
 }
@@ -830,7 +830,7 @@ static void render_tee(animstate *anim, int skin, vec2 dir, vec2 pos)
 	gfx_quads_end();	
 }
 
-static void draw_round_rect(float x, float y, float w, float h, float r)
+void draw_round_rect(float x, float y, float w, float h, float r)
 {
 	int num = 8;
 	for(int i = 0; i < num; i+=2)
@@ -1194,7 +1194,7 @@ void ingamemenu_render()
 	
 }
 
-void modc_render()
+void render_game()
 {	
 	animstate idlestate;
 	anim_eval(&data->animations[ANIM_BASE], 0, &idlestate);
@@ -1394,8 +1394,8 @@ void modc_render()
 		{
 			float parallax_amount = 0.55f;
 			select_sprite(cloud_sprites[i]);
-			gfx_quads_drawTL((cloud_pos[i].x+fmod(client_localtime()*cloud_speed[i]+i*100.0f, 1700.0f))+screen_x*parallax_amount,
-				cloud_pos[i].y+screen_y*parallax_amount, 300, 300);
+			draw_sprite((cloud_pos[i].x+fmod(client_localtime()*cloud_speed[i]+i*100.0f, 1700.0f))+screen_x*parallax_amount,
+				cloud_pos[i].y+screen_y*parallax_amount, 300);
 		}
 		gfx_quads_end();
 
@@ -1829,6 +1829,68 @@ void modc_render()
 	}
 }
 
+void modc_render()
+{
+	// this should be moved around abit
+	if(client_state() == CLIENTSTATE_ONLINE)
+	{
+		render_game();
+	}
+	else // if (client_state() != CLIENTSTATE_CONNECTING && client_state() != CLIENTSTATE_LOADING)
+	{
+		//netaddr4 server_address;
+		if(modmenu_render() == -1)
+			client_quit();
+
+	}
+	/*
+	else if (client_state() == CLIENTSTATE_CONNECTING || client_state() == CLIENTSTATE_LOADING)
+	{
+		static int64 start = time_get();
+		static int tee_texture;
+		static int connecting_texture;
+		static bool inited = false;
+		
+		// TODO: ugly, remove this
+		if (!inited)
+		{
+			tee_texture = gfx_load_texture("data/gui_tee.png");
+			connecting_texture = gfx_load_texture("data/gui_connecting.png");
+				
+			inited = true;
+		}
+
+		gfx_mapscreen(0,0,400.0f,300.0f);
+
+		float t = (time_get() - start) / (double)time_freq();
+
+		float speed = 2*sin(t);
+
+		speed = 1.0f;
+
+		float x = 208 + sin(t*speed) * 32;
+		float w = sin(t*speed + 3.149) * 64;
+
+		ui_do_image(tee_texture, x, 95, w, 64);
+		ui_do_image(connecting_texture, 88, 150, 256, 64);
+		
+		if(inp_key_down(input::esc))
+			client_disconnect();
+	}*/
+}
+
+
+void menu_do_disconnected();
+void menu_do_connecting();
+
+void modc_statechange(int state, int old)
+{
+	if(state == CLIENTSTATE_OFFLINE)
+	 	menu_do_disconnected();
+	if(state == CLIENTSTATE_CONNECTING)
+		menu_do_connecting();
+}
+
 void modc_message(int msg)
 {
 	if(msg == MSG_CHAT)
diff --git a/src/game/client/menu.cpp b/src/game/client/menu.cpp
index d74282ff..41ef9307 100644
--- a/src/game/client/menu.cpp
+++ b/src/game/client/menu.cpp
@@ -143,6 +143,7 @@ extern pretty_font *current_font;
 
 extern void render_sun(float x, float y);
 extern void select_sprite(int id, int flags=0, int sx=0, int sy=0);
+extern void draw_sprite(float x, float y, float size);
 
 void draw_background(float t)
 {
@@ -156,11 +157,11 @@ void draw_background(float t)
     gfx_texture_set(data->images[IMAGE_CLOUDS].id);
     gfx_quads_begin();
 		select_sprite(SPRITE_CLOUD1);
-		gfx_quads_drawTL(3500 - fmod(t * 20 + 2000, 4524), 0, 512, 512);
+		draw_sprite(3500 - fmod(t * 20 + 2000, 4524), 250, 512);
 		select_sprite(SPRITE_CLOUD2);
-		gfx_quads_drawTL(3000 - fmod(t * 50 + 2000, 4024), 150, 512, 512);
+		draw_sprite(3000 - fmod(t * 50 + 2000, 4024), 150+250, 512);
 		select_sprite(SPRITE_CLOUD3);
-		gfx_quads_drawTL(4000 - fmod(t * 60 + 500, 4512), 300, 256, 256);
+		draw_sprite(4000 - fmod(t * 60 + 500, 4512), 300+130, 256);
     gfx_quads_end();
 
     gfx_texture_set(data->images[IMAGE_MENU_BACKGROUND].id);
@@ -681,6 +682,8 @@ static int do_server_list(float x, float y, int *scroll_index, int *selected_ind
 enum
 {
 	SCREEN_MAIN,
+	SCREEN_DISCONNECTED,
+	SCREEN_CONNECTING,
 	SCREEN_SETTINGS_GENERAL,
 	SCREEN_SETTINGS_CONTROLS,
 	SCREEN_SETTINGS_VIDEO,
@@ -704,6 +707,8 @@ const float row5_y = row4_y + 40;
 const float row6_y = row5_y + 40;
 const float row7_y = row6_y + 40;
 
+static char address[128] = "localhost:8303";
+	
 static int main_render()
 {
 	static bool inited = false;
@@ -718,8 +723,6 @@ static int main_render()
 	int last_selected_index = selected_index;
 	do_server_list(20, 160, &scoll_index, &selected_index, 8);
 	
-	static char address[32] = "localhost:8303";
-
 	ui_do_edit_box(address, 280, 425, 300, 36, address, sizeof(address));
 
 	if (last_selected_index != selected_index && selected_index != -1)
@@ -1176,6 +1179,74 @@ static int kerning_render()
 	return 0;
 }
 
+extern void draw_round_rect(float x, float y, float w, float h, float r);
+
+static int render_popup(const char *caption, const char *text, const char *button_text)
+{
+	float tw;
+
+	float w = 700;
+	float h = 300;
+	float x = 800/2-w/2;
+	float y = 600/2-h/2;
+
+	gfx_blend_normal();
+	
+	gfx_texture_set(-1);
+	gfx_quads_begin();
+	gfx_quads_setcolor(0,0,0,0.50f);
+	draw_round_rect(x, y, w, h, 40.0f);
+	gfx_quads_end();
+
+	tw = gfx_pretty_text_width(48.0f, caption);
+	ui_do_label(x+w/2-tw/2, y+20, caption, 48.0f);
+	
+	tw = gfx_pretty_text_width(32.0f, text);
+	ui_do_label(x+w/2-tw/2, y+130, text, 32.0f);
+
+	static int back_button = 0;
+	if(ui_do_button(&back_button, button_text, 0, x+w/2-100, y+220, 200, 48, draw_teewars_button))
+		return 1;
+		
+	return 0;
+}
+
+static int disconnected_render()
+{
+	if(strlen(client_error_string()) == 0)
+		screen = SCREEN_MAIN;
+	else
+	{
+		if(render_popup("Disconnected", client_error_string(), "Back"))
+			screen = SCREEN_MAIN;
+	}
+	return 0;
+}
+
+static int connecting_render()
+{
+	char buf[256];
+	sprintf(buf, "Server: %s", address);
+	if(render_popup("Connecting", buf, "Abort"))
+	{
+		client_disconnect();
+		screen = SCREEN_MAIN;
+	}
+	return 0;
+}
+
+
+void menu_do_disconnected()
+{
+	screen = SCREEN_DISCONNECTED;
+}
+
+
+void menu_do_connecting()
+{
+	screen = SCREEN_CONNECTING;
+}
+
 static int menu_render()
 {
 	// background color
@@ -1201,6 +1272,8 @@ static int menu_render()
 	switch (screen)
 	{
 		case SCREEN_MAIN: return main_render();
+		case SCREEN_DISCONNECTED: return disconnected_render();
+		case SCREEN_CONNECTING: return connecting_render();
 		case SCREEN_SETTINGS_GENERAL:
 		case SCREEN_SETTINGS_CONTROLS:
 		case SCREEN_SETTINGS_VIDEO:
@@ -1282,6 +1355,8 @@ int modmenu_render()
 
 	input::clear_char();
 	input::clear_key();
+	
+	//if(r)
 
 	return r;
 }