Index: Daodan/MSVC/Flatline.c
===================================================================
--- Daodan/MSVC/Flatline.c	(revision 581)
+++ Daodan/MSVC/Flatline.c	(revision 582)
@@ -4,10 +4,13 @@
 #include "Flatline_Server.h"
 #include "Flatline_Events.h"
+#include <Windows.h>
 //#include <sys/time.h>
 #include <time.h>
+#include <float.h>
+#define isnan(x) ((x) != (x))
 uint32_t last1 = 0; uint32_t last2 = 0;
 player_info Players[MAX_PLAYERS] = {{0}, {0}, {0}, {0}};
 player_info * PlayerList[MAX_CONNECTIONS] = {0};
-
+multiplayer_status MultiplayerStatus;
 unsigned int lastPingTime;
 
@@ -207,5 +210,5 @@
 		break;
 	case PK_PONG:
-				for(i = 0; i < max_connections; i++) {
+		for(i = 0; i < max_connections; i++) {
 			if(PlayerList[i] != 0 && PlayerList[i]->ip == sender.sin_addr.S_un.S_addr) {
 				found_player = 1;
@@ -221,5 +224,5 @@
 		else
 		{
-			PlayerList[i]->Ping = (ONgGameState->GameTime - packet->ping) * 1000 / 60; 
+			PlayerList[i]->Ping = GetTickCount() - packet->ping;
 		}
 		break;
@@ -278,6 +281,154 @@
 //FLrClient_Run
 //Looping function that waits for packets from the server.
-
 int client_slot = 0;
+
+void FLrClient_GetPackets()
+{
+	flatline_packet packet;
+	uint16_t len;
+	//#define SPAM_INPUT
+#ifdef SPAM_INPUT
+	struct timeval lasttime;
+	struct timeval thistime;
+	gettimeofday(&lasttime, 0);
+#endif
+	
+
+		while(NetUDPSocket_Recieve(client_sock, (sockaddr_storage *) &client_address, &packet, &len)) {
+			//packet = (flatline_packet*)data;
+			//DDrConsole_PrintF("Data recieved, length %i, type %i", len, ((flatline_packet*)data)->id);
+			switch(packet.id) {
+			case MESSAGE:
+				COrMessage_Print(packet.data, "chat", 0);
+				break;
+			case CONNECT_SEND:
+				;if(1) {
+					flatline_packet connect_recv;
+					memcpy(&connect_recv.connect_reply.message,"This isn't a server!", sizeof("This isn't a server!"));
+					NetUDPSocket_Send(client_sock, (sockaddr *) &address, (char*)&connect_recv, sizeof(bool) + FLATLINE_HEADER + sizeof("This isn't a server!"));			
+				}
+			case CONNECT_REPLY:
+				break; //extra packet or something.
+			case NEW_PLAYER:
+				;if(1) { //haxhaxhax
+					CharacterObject* Char = &(packet.new_player.Character);
+					uint32_t chr_index = 0;
+					Character* PC;
+					DDrConsole_PrintF("%i |  %i", packet.new_player.Playernumber ,client_slot);
+					//Char->OSD.Options = 0;
+					if(packet.new_player.Playernumber == client_slot) {
+						PlayerList[packet.new_player.Playernumber] = &Players[0];
+						PC = (ONgGameState->PlayerCharacter);
+						Players[0].Chr = PC;
+
+					}
+					else {
+						ONrGameState_NewCharacter(Char, NULL, NULL, &chr_index);
+						ONgGameState->CharacterStorage[chr_index].charType = 0;
+						PlayerList[packet.new_player.Playernumber] = &Players[chr_index];
+						Players[chr_index].Chr = &(ONgGameState->CharacterStorage[chr_index]);
+						Players[chr_index].Chr->Flags &= 0xFFBFFFFF;
+						Players[chr_index].spawnnumber = chr_index;
+						DDrConsole_PrintF("Spawning player %s, class %s, slot  %i", ((new_player*)(packet.data))->Character.OSD.Name, ((new_player*)(packet.data))->Character.OSD.Class,chr_index) ;
+					}
+					//Players[((new_player*)(packet.data))->Playernumber].spawnnumber = ONrGameState_NewCharacter(&(((new_player*)(packet.data))->Character), NULL, NULL, 0);
+					break;
+				}
+			case PLAYER_DATA:
+				if(1) { //haxhaxhax
+					player_data* pd = &packet.player_data;
+					uint16_t i = pd->PlayerNum;
+
+					pd = (void*)packet.data;
+
+
+					if (i > max_connections) break;
+					if( !PlayerList[i] ) break;
+
+					memcpy( &(PlayerList[i]->player_data), pd, sizeof(player_data) );
+
+					if( !server_started && pd->rare_sync_index > PlayerList[i]->rare_sync_index )
+					{
+						int sent_bytes;
+						flatline_packet sync_request = {0};
+						sync_request.id = RARE_SYNC_DATA_REQUEST;
+						sync_request.sync_request = i;
+						DDrConsole_PrintF( "Requesting sync data for player %i, old index %u", i, PlayerList[i]->rare_sync_index);
+						sent_bytes = NetUDPSocket_Send(client_sock,(sockaddr *) &address, (char*)&sync_request, FLATLINE_HEADER + sizeof(int) );
+					}
+
+					PlayerList[i]->DataApplied = 0;
+
+
+					break;
+				}
+			case RARE_SYNC_DATA:
+				if(1) {
+					sl_arg hax[2];
+					int dontuse;
+					uint16_t i = packet.rare_sync_data.PlayerNum;
+
+					if (i > max_connections) break;
+					if( !PlayerList[i] ) break;
+
+					//WEAPONS ARE DISABLED. Why? Pain in the arse to sync.
+					packet.rare_sync_data.Inventory.Weapons[0] = NULL;
+					packet.rare_sync_data.Inventory.Weapons[1] = NULL;
+					packet.rare_sync_data.Inventory.Weapons[2] = NULL;
+					//			TMrInstance_GetDataPtr( 'ONCC', packet.rare_sync_data.Class, PlayerList[ i ]->Chr->ONCC );
+
+					//add the target character
+					hax[0].type = sl_int32;
+					hax[0].value_int32 = PlayerList[ packet.rare_sync_data.PlayerNum ]->spawnnumber;
+
+					//add the new class
+					//fix this later so we cant buffer overflow :O
+					hax[1].type = sl_str32;
+					hax[1].value_str32 = packet.rare_sync_data.Class;
+
+					//we are directly calling a bsl function instead of using the normal method for two reasons
+					//1. it has all the checking built in
+					iSetCharacterClass( 0, 2, hax, &dontuse, &dontuse, hax );
+					//DDrConsole_PrintF( "Recieved sync data for player %i, class %s, old index %u, new index %u", i, packet.rare_sync_data.Class, PlayerList[i]->rare_sync_index, packet.rare_sync_data.index);
+					memcpy( &(PlayerList[ i ]->Chr->Inventory), &(packet.rare_sync_data.Inventory), sizeof(Inventory ));
+
+					PlayerList[i]->rare_sync_index = packet.rare_sync_data.index;
+				}
+				break;
+			case FLATLINE_EVENT:
+				FLcEventHandler( packet.flatline_event.event_index, packet.flatline_event.intArray );
+				break;
+			case PK_PING:
+				packet.id = PK_PONG;
+				NetUDPSocket_Send(client_sock, (sockaddr *) &address, (char*)&packet, FLATLINE_HEADER + 4);		
+				break;
+			case PK_ALL_INPUT:
+				if(1)
+				{
+					int Player, i;
+					for(i = 0; packet.all_input[i].PlayerNum != -1; i++)
+					{
+						Player = packet.all_input[i].PlayerNum;
+						if(PlayerList[Player])
+						{
+							PlayerList[Player]->Actions1 = packet.all_input[Player].Actions1;
+							PlayerList[Player]->Actions2 = packet.all_input[Player].Actions2;
+							PlayerList[Player]->MouseDeltaX = packet.all_input[Player].MouseDeltaX;
+							PlayerList[Player]->MouseDeltaY = packet.all_input[Player].MouseDeltaY;
+							PlayerList[Player]->Facing = packet.all_input[Player].Facing;
+							PlayerList[Player]->DesiredFacing = packet.all_input[Player].DesiredFacing;
+							PlayerList[Player]->Position = packet.all_input[Player].Position;
+						}
+					}
+				}
+				break;
+			default:
+				DDrConsole_PrintF("Warning, recieved badly formed packet!");
+				break;
+			}
+	}
+}
+
+
 bool FLrClient_Run(flatline_packet* packet)
 {
@@ -302,4 +453,5 @@
 			if(packet->id == CONNECT_REPLY) {
 				if(packet->connect_reply.goodtogo){
+
 					client_connected = 1;
 
@@ -313,6 +465,17 @@
 					//disable local input.
 					DDrPatch_NOOP(0x004FA929, 5 + 6 + 5);
+					
+					//Disable local turning
+					//DDrPatch_NOOP(0x004F7EA8, 2);
+					//DDrPatch_Byte( 0x004F7EB1 , 0xE9);
+					//DDrPatch_MakeJump( 0x004F7EB1, 0x004F8030 );
+
+
+					//DDrPatch_Byte(0x04ED6FB, 0xEB);
 
 					//DDrConsole_PrintF("Slot %i",  ((connect_reply*)packet)->player_slot);
+					//DDrPatch_NOOP(0x43B23,0x10);
+					//DDrPatch_NOOP(0x4EC248,(0x5A-0x48));
+					//DDrPatch_NOOP(0x4EC861, 6);
 					break;
 				}
@@ -333,183 +496,5 @@
 		return false;
 	}
-	else
-	{
-		ActiveCharacter * Active;
-		flatline_packet packet;
-		//#define SPAM_INPUT
-#ifdef SPAM_INPUT
-		struct timeval lasttime;
-		struct timeval thistime;
-		gettimeofday(&lasttime, 0);
-#endif
-		while(1) {
-#ifdef SPAM_INPUT
-			gettimeofday(&thistime, 0);
-
-			//DDrConsole_PrintF("%i.%i | %i.%i | %i.%i",lasttime.tv_sec, lasttime.tv_usec, thistime.tv_sec, thistime.tv_usec,
-			//	thistime.tv_sec - lasttime.tv_sec, thistime.tv_usec - lasttime.tv_usec);
-			//checks to see if enough time has passed since the last input update (by default once every 10ms)
-			if( 
-				((thistime.tv_sec > lasttime.tv_sec) && ((thistime.tv_usec + 1000000 - lasttime.tv_usec ) > update_rate * 1000) )
-				|| ((thistime.tv_sec == lasttime.tv_sec) && ((thistime.tv_usec - lasttime.tv_usec ) > update_rate * 1000))
-				) {
-
-					flatline_packet input_packet;
-					lasttime.tv_usec = ++thistime.tv_usec; //in case recieving packets takes less than 1 ms.
-
-					input_packet.id = PLAYER_INPUT;
-
-					if( ((GameState*)(ONgGameState))->Input.Current.Actions1 != last1 || ((GameState*)(ONgGameState))->Input.Current.Actions2 != last2) {
-						last1 =((GameState*)(ONgGameState))->Input.Current.Actions1;
-						last2 =((GameState*)(ONgGameState))->Input.Current.Actions2;
-					}
-
-					((input_struct*)(void*)(input_packet.data))->Actions1 = ((GameState*)(ONgGameState))->Input.Current.Actions1;
-					((input_struct*)(void*)(input_packet.data))->Actions2 = ((GameState*)(ONgGameState))->Input.Current.Actions2;
-					((input_struct*)(void*)(input_packet.data))->MouseDeltaX = ((GameState*)(ONgGameState))->Input.MouseDeltaX;
-					((input_struct*)(void*)(input_packet.data))->MouseDeltaY = ((GameState*)(ONgGameState))->Input.MouseDeltaY;
-					sent_bytes = NetUDPSocket_Send(client_sock,(sockaddr *) &address, (char*)&input_packet, sizeof(input_struct) + FLATLINE_HEADER);			
-					//if(sent_bytes == SOCKET_ERROR)	NetCatchError();
-			}
-#endif
-			if(NetUDPSocket_Recieve(client_sock, (sockaddr_storage *) &client_address, &packet, &len)) {
-				//packet = (flatline_packet*)data;
-				//DDrConsole_PrintF("Data recieved, length %i, type %i", len, ((flatline_packet*)data)->id);
-				switch(packet.id) {
-				case MESSAGE:
-					COrMessage_Print(packet.data, "chat", 0);
-					break;
-				case CONNECT_SEND:
-					;if(1) {
-						flatline_packet connect_recv;
-						memcpy(&connect_recv.connect_reply.message,"This isn't a server!", sizeof("This isn't a server!"));
-						NetUDPSocket_Send(client_sock, (sockaddr *) &address, (char*)&connect_recv, sizeof(bool) + FLATLINE_HEADER + sizeof("This isn't a server!"));			
-					}
-				case CONNECT_REPLY:
-					break; //extra packet or something.
-				case NEW_PLAYER:
-					;if(1) { //haxhaxhax
-						CharacterObject* Char = &(packet.new_player.Character);
-						uint32_t chr_index = 0;
-						Character* PC;
-						DDrConsole_PrintF("%i |  %i", packet.new_player.Playernumber ,client_slot);
-						//Char->OSD.Options = 0;
-						if(packet.new_player.Playernumber == client_slot) {
-							PlayerList[packet.new_player.Playernumber] = &Players[0];
-							PC = (ONgGameState->PlayerCharacter);
-							Players[0].Chr = PC;
-
-						}
-						else {
-							ONrGameState_NewCharacter(Char, NULL, NULL, &chr_index);
-							ONgGameState->CharacterStorage[chr_index].charType = 0;
-							PlayerList[packet.new_player.Playernumber] = &Players[chr_index];
-							Players[chr_index].Chr = &(ONgGameState->CharacterStorage[chr_index]);
-							Players[chr_index].Chr->Flags &= 0xFFBFFFFF;
-							Players[chr_index].spawnnumber = chr_index;
-							DDrConsole_PrintF("Spawning player %s, class %s, slot  %i", ((new_player*)(packet.data))->Character.OSD.Name, ((new_player*)(packet.data))->Character.OSD.Class,chr_index) ;
-						}
-						//Players[((new_player*)(packet.data))->Playernumber].spawnnumber = ONrGameState_NewCharacter(&(((new_player*)(packet.data))->Character), NULL, NULL, 0);
-						break;
-					}
-				case PLAYER_DATA:
-					if(1) { //haxhaxhax
-						player_data* pd = &packet.player_data;
-						uint16_t i = pd->PlayerNum;
-						GameInput * Active_Input;
-						pd = (void*)packet.data;
-
-						//DDrConsole_PrintF("Got data for Player %i, %x", i, PlayerList[i]);
-						if (i > max_connections) break;
-						if( !PlayerList[i] ) break;
-						//PlayerList[i]->Chr = ((GameState *)ONgGameState)->CharacterStorage;
-
-/*						PlayerList[i]->Actions1 = pd->Inputs.Actions1;
-						PlayerList[i]->Actions2 = pd->Inputs.Actions2;
-						PlayerList[i]->MouseDeltaX = pd->Inputs.MouseDeltaX;
-						PlayerList[i]->MouseDeltaY = pd->Inputs.MouseDeltaY;*/
-						memcpy( &(PlayerList[i]->player_data), pd, sizeof(player_data) );
-
-						if( !server_started && pd->rare_sync_index > PlayerList[i]->rare_sync_index )
-						{
-							int sent_bytes;
-							flatline_packet sync_request = {0};
-							sync_request.id = RARE_SYNC_DATA_REQUEST;
-							sync_request.sync_request = i;
-							DDrConsole_PrintF( "Requesting sync data for player %i, old index %u", i, PlayerList[i]->rare_sync_index);
-							sent_bytes = NetUDPSocket_Send(client_sock,(sockaddr *) &address, (char*)&sync_request, FLATLINE_HEADER + sizeof(int) );
-						}
-
-						PlayerList[i]->DataApplied = 0;
-
-
-						break;
-					}
-				case RARE_SYNC_DATA:
-					if(1) {
-						sl_arg hax[2];
-						int dontuse;
-						uint16_t i = packet.rare_sync_data.PlayerNum;
-
-						if (i > max_connections) break;
-						if( !PlayerList[i] ) break;
-
-						//WEAPONS ARE DISABLED. Why? Pain in the arse to sync.
-						packet.rare_sync_data.Inventory.Weapons[0] = NULL;
-						packet.rare_sync_data.Inventory.Weapons[1] = NULL;
-						packet.rare_sync_data.Inventory.Weapons[2] = NULL;
-						//			TMrInstance_GetDataPtr( 'ONCC', packet.rare_sync_data.Class, PlayerList[ i ]->Chr->ONCC );
-
-						//add the target character
-						hax[0].type = sl_int32;
-						hax[0].value_int32 = PlayerList[ packet.rare_sync_data.PlayerNum ]->spawnnumber;
-
-						//add the new class
-						//fix this later so we cant buffer overflow :O
-						hax[1].type = sl_str32;
-						hax[1].value_str32 = packet.rare_sync_data.Class;
-
-						//we are directly calling a bsl function instead of using the normal method for two reasons
-						//1. it has all the checking built in
-						iSetCharacterClass( 0, 2, hax, &dontuse, &dontuse, hax );
-						//DDrConsole_PrintF( "Recieved sync data for player %i, class %s, old index %u, new index %u", i, packet.rare_sync_data.Class, PlayerList[i]->rare_sync_index, packet.rare_sync_data.index);
-						memcpy( &(PlayerList[ i ]->Chr->Inventory), &(packet.rare_sync_data.Inventory), sizeof(Inventory ));
-
-						PlayerList[i]->rare_sync_index = packet.rare_sync_data.index;
-					}
-					break;
-				case FLATLINE_EVENT:
-					FLcEventHandler( packet.flatline_event.event_index, packet.flatline_event.intArray );
-					break;
-				case PK_PING:
-					packet.id = PK_PONG;
-					NetUDPSocket_Send(client_sock, (sockaddr *) &address, (char*)&packet, FLATLINE_HEADER + 4);		
-					break;
-				case PK_ALL_INPUT:
-					if(1)
-					{
-						int Player;
-						for(Player = 0; Player < MAX_CONNECTIONS; Player++)
-						{
-							if(PlayerList[Player])
-							{
-								PlayerList[Player]->Actions1 = packet.all_input[Player].Actions1;
-								PlayerList[Player]->Actions2 = packet.all_input[Player].Actions2;
-								PlayerList[Player]->MouseDeltaX = packet.all_input[Player].MouseDeltaX;
-								PlayerList[Player]->MouseDeltaY = packet.all_input[Player].MouseDeltaY;
-							}
-						}
-					}
-					break;
-				default:
-					DDrConsole_PrintF("Warning, recieved badly formed packet!");
-					break;
-				}
-			}
-			else {
-				Sleep(1);
-			}
-		}
-	}
+
 	return true;
 }
@@ -543,20 +528,36 @@
 } IMtPoint2D;
 static flatline_packet cache_input = {0};
-extern void* TSrTest;
+enum
+{
+	FirstPass,
+	SecondPass,
+	NoPass,
+};
+bool ShouldSendUpdate( int i, Character* Player, ActiveCharacter* Active_Player )
+{
+	return
+		MultiplayerStatus.PleaseUpdateAllPlayers ? 1 :
+		strcmp(PlayerList[i]->player_data.Animation, 
+		TMrInstance_GetInstanceName(Active_Player->Animation)) ? 1 :
+		PlayerList[i]->player_data.Health != Player->Health ? 1 : 0;
+}
+
 void * ONICALL FLrInput_Update_Keys(void) 
 {
 	uint16_t i;
 	flatline_packet all_input = {0};
-	ActiveCharacter * Active_Player = ONgGameState->ActiveCharacters;
-	Active_Player->PhyContext->Rotation;
-	Active_Player->PhyContext->Position;
-	ONgGameState->PlayerCharacter->Position;
-
+	int16_t InputIndex = 0;
+	//ActiveCharacter * Active_Player = ONgGameState->ActiveCharacters;
+	
 	if(client_connected) 
 	{
 		int sent_bytes;
 		flatline_packet input_packet = {0};
+
+		FLrClient_GetPackets();
+
 		input_packet.id = PLAYER_INPUT;
 		input_packet.input_struct.Time = ONgGameState->GameTime;
+//		((GameState*)(ONgGameState))->Input.Current.Actions1 |= Action_Backward | Action_StepLeft;
 		input_packet.input_struct.Actions1 = ((GameState*)(ONgGameState))->Input.Current.Actions1;
 		input_packet.input_struct.Actions2 = ((GameState*)(ONgGameState))->Input.Current.Actions2;
@@ -577,4 +578,12 @@
 	{
 		FLsPingAll();
+	}
+
+	if(server_started && PlayerList[0])
+	{
+		PlayerList[0]->Actions1 = ONgGameState->Input.Current.Actions1;
+		PlayerList[0]->Actions2 = ONgGameState->Input.Current.Actions2;
+		PlayerList[0]->MouseDeltaX = ONgGameState->Input.MouseDeltaX;
+		PlayerList[0]->MouseDeltaY = ONgGameState->Input.MouseDeltaY;
 	}
 
@@ -584,20 +593,25 @@
 		GameInput * Active_Input;
 		if(PlayerList[i] == 0) continue;
-
-
-		if(i == 0) {
-			all_input.all_input[i].Actions1 = ((GameState*)(ONgGameState))->Input.Current.Actions1;
-			all_input.all_input[i].Actions2 = ((GameState*)(ONgGameState))->Input.Current.Actions2;
-			all_input.all_input[i].MouseDeltaX = ONgGameState->Input.MouseDeltaX;
-			all_input.all_input[i].MouseDeltaY = ONgGameState->Input.MouseDeltaY;
-		}
-		else{
-			all_input.all_input[i].Actions1 = PlayerList[i]->Actions1;
-			all_input.all_input[i].Actions2 = PlayerList[i]->Actions2;
-			all_input.all_input[i].MouseDeltaX = PlayerList[i]->MouseDeltaX;
-			all_input.all_input[i].MouseDeltaY = PlayerList[i]->MouseDeltaY;
-		}
-
 		Player = PlayerList[i]->Chr;
+		if(server_started)
+		{
+
+			//Set up input packets
+
+			all_input.all_input[InputIndex].Actions1 = PlayerList[i]->Actions1;
+			all_input.all_input[InputIndex].Actions2 = PlayerList[i]->Actions2;
+			all_input.all_input[InputIndex].MouseDeltaX = PlayerList[i]->MouseDeltaX;
+			all_input.all_input[InputIndex].MouseDeltaY = PlayerList[i]->MouseDeltaY;
+
+			all_input.all_input[InputIndex].Facing = Player->Facing;
+			all_input.all_input[InputIndex].DesiredFacing = Player->DesiredFacing;
+
+			//Infinity...
+			*(int *)&all_input.all_input[InputIndex].Position.X = 0x7f800000;
+
+			all_input.all_input[InputIndex].PlayerNum = i;
+			InputIndex++;
+		}
+
 		if( Player->Health == 0) 
 		{
@@ -614,5 +628,5 @@
 			}
 
-			if(server_started & i == 0)
+			if(server_started && i == 0)
 			{
 				Actions =  ONgGameState->Input.Current.Actions1;
@@ -641,9 +655,17 @@
 
 		Active_Player = ONrGetActiveCharacter( PlayerList[i]->Chr);
-
+		
 		if(Active_Player == 0) continue;
+
+
+
+		//Active_Player->PlayingFilm.Flags = 1;
 		Active_Input = &(Active_Player->Input);
-
-		if(server_started && strcmp(PlayerList[i]->player_data.Animation, TMrInstance_GetInstanceName(Active_Player->Animation))) 
+		if(server_started)
+		{
+			all_input.all_input[InputIndex - 1].Position = Active_Player->PhyContext->Position;
+		}
+		if(server_started && 
+			ShouldSendUpdate( i, PlayerList[i]->Chr, Active_Player) )
 		{
 			player_data * data;
@@ -656,10 +678,13 @@
 			data->Health = PlayerList[i]->Chr->Health;
 			data->MaxHealth = PlayerList[i]->Chr->MaxHealth;
-			data->Position = PlayerList[i]->Chr->Position;
-			data->Facing = PlayerList[i]->Chr->Facing;
-			data->DesiredFacing = PlayerList[i]->Chr->DesiredFacing;
-			data->Position = Active_Player->PhyContext->Position;
+			//data->Position = PlayerList[i]->Chr->Position;
+			//data->Facing = PlayerList[i]->Chr->Facing;
+			//data->DesiredFacing = PlayerList[i]->Chr->DesiredFacing;
+			//data->Position = Active_Player->PhyContext->Position;
 			memcpy(data->Animation, TMrInstance_GetInstanceName(Active_Player->Animation), 31);
 			data->Frame = Active_Player->Frame;
+
+			data->UD = Active_Player->HeadPitch;	
+			data->LR = Active_Player->HeadFacing;
 
 			if(Active_Player->targetThrow)
@@ -688,5 +713,5 @@
 		}
 
-		if( (server_started && i !=0)  || (!server_started/* && i != client_slot*/) ) 
+		if( (server_started && i !=0)  || !server_started ) 
 		{
 			Active_Input->Stop.Actions1 = ~PlayerList[i]->Actions1 & Active_Input->Current.Actions1;
@@ -707,148 +732,204 @@
 				void* Animation;
 				player_data* pd = &PlayerList[i]->player_data;
-
-
-				//Note to self: sort out which needs to be applied the first time and which the second.
-				switch(PlayerList[i]->DataApplied)
+				
+				PlayerList[i]->Chr->Facing = PlayerList[i]->Facing;					
+				PlayerList[i]->Chr->DesiredFacing = PlayerList[i]->DesiredFacing;
+				
+				if(*(int*)&PlayerList[i]->Chr->Position.X != 0x7f800000)
 				{
-				case 1:
-					PlayerList[i]->DataApplied = 2;
-					break;
-				case 0:
-					PlayerList[i]->DataApplied = 1;
-				case 2:
-					continue;
-				}
-				
-				Player->Health = PlayerList[i]->player_data.Health;
-				PlayerList[i]->Chr->MaxHealth = PlayerList[i]->player_data.MaxHealth;
-
-				PlayerList[i]->Chr->Facing = PlayerList[i]->player_data.Facing;
-				PlayerList[i]->Chr->DesiredFacing = PlayerList[i]->player_data.DesiredFacing;
-
-/*				PlayerList[i]->Actions1 = PlayerList[i]->player_data.Inputs.Actions1;
-				PlayerList[i]->Actions2 = PlayerList[i]->player_data.Inputs.Actions2;
-				PlayerList[i]->MouseDeltaX = PlayerList[i]->player_data.Inputs.MouseDeltaX;
-				PlayerList[i]->MouseDeltaY = PlayerList[i]->player_data.Inputs.MouseDeltaY;*/
-				Active_Player->PhyContext->Position = PlayerList[i]->player_data.Position;
-				OldAnimation = Active_Player->Animation;
-
-				if (!(Player->Flags & ONcCharacterFlag_BeingThrown) &&
-					(pd->Animation != 0))
+					Active_Player->PhyContext->Position = PlayerList[i]->Position;					
+				}
+				else
 				{
-					// get a pointer to the animation
-
-					TMrInstance_GetDataPtr(
-						'TRAM',
-						pd->Animation,
-						&Animation);
-					if (Animation != OldAnimation)
+					int breakfast = 0;
+				}
+				/*
+				if(isnan(Active_Player->PhyContext->Position.Y) || 
+					isnan(Active_Player->PhyContext->Position.X) || 
+					isnan(Active_Player->PhyContext->Position.Z) )
+				{
+					//DDrConsole_PrintF("Player is NAN! %x %x", Active_Player->PhyContext->Position.Y, PlayerList[i]->Height);
+					DDrConsole_PrintF("Player is NAN! %x %x %x", Active_Player->PhyContext->Position.X, Active_Player->PhyContext->Position.Y, Active_Player->PhyContext->Position.Z);
+					//DDrConsole_PrintF("Velocity %x %x %x", Active_Player->PhyContext->Velocity.X, Active_Player->PhyContext->Velocity.Y, Active_Player->PhyContext->Velocity.Z);
+					
+					
+				}
+				*/
+
+				if( PlayerList[i]->DataApplied == FirstPass )
+				{
+					PlayerList[i]->DataApplied = SecondPass;
+
+					Player->Health = PlayerList[i]->player_data.Health;
+					PlayerList[i]->Chr->MaxHealth = PlayerList[i]->player_data.MaxHealth;
+
+				}
+				else if( PlayerList[i]->DataApplied == SecondPass )
+				{
+					OldAnimation = Active_Player->Animation;
+
+					PlayerList[i]->DataApplied = NoPass;
+
+					PlayerList[i]->player_data.Frame++;
+
+					if (!(Player->Flags & ONcCharacterFlag_BeingThrown) &&
+						(pd->Animation[0] != 0))
 					{
-						short	num_frames;
-						bool	updateAnimation = true;
-
-						// if the character is dead, make sure this animation is appropriate for death
-						/*
-						if (Player->Flags & ONcCharacterFlag_Dead)
+						// get a pointer to the animation
+
+						TMrInstance_GetDataPtr(
+							'TRAM',
+							pd->Animation,
+							&Animation);
+						if (Animation != OldAnimation)
 						{
-						short	curToState = TRrAnimation_GetTo(Active_Player->Animation);
-						short	newToState = TRrAnimation_GetTo(animation);
-
-						// if we are currently heading towards fallen and the new animation would not
-						// then this is a better animation to run when we are dead
-						if ((ONrAnimState_IsFallen(curToState)) &&
-						(!ONrAnimState_IsFallen(newToState)))
-						{
-						updateAnimation = false;
-						}
-						}
-						*/
-						if ((updateAnimation) && (Active_Player->Animation == Animation))
-						{
-							int		oldFrame = Active_Player->Frame;
-							int		newFrame = pd->Frame;
-
-							if (abs(oldFrame - newFrame) < 2)
+							short	num_frames;
+							bool	updateAnimation = true;
+
+							// if the character is dead, make sure this animation is appropriate for death
+							/*
+							if (Player->Flags & ONcCharacterFlag_Dead)
 							{
-								updateAnimation = false;
+							short	curToState = TRrAnimation_GetTo(Active_Player->Animation);
+							short	newToState = TRrAnimation_GetTo(animation);
+
+							// if we are currently heading towards fallen and the new animation would not
+							// then this is a better animation to run when we are dead
+							if ((ONrAnimState_IsFallen(curToState)) &&
+							(!ONrAnimState_IsFallen(newToState)))
+							{
+							updateAnimation = false;
+							}
+							}
+							*/
+							if ((updateAnimation) && (Active_Player->Animation == Animation))
+							{
+								int		oldFrame = Active_Player->Frame;
+								int		newFrame = pd->Frame;
+
+								if (abs(oldFrame - newFrame) < 2)
+								{
+									updateAnimation = false;
+								}
+							}
+
+							if (updateAnimation)
+							{
+								// set the characters animation
+								/*	ONrCharacter_SetAnimationInternal(Player,
+								Active_Player,
+								Active_Player->AnimationToState,
+								0,
+								Animation);
+								ONrCharacter_NewAnimationHook(Player, Active_Player);*/
+								//Player->Flags |= 0x00000010;
+								ONrCharacter_SetAnimationExternal(Player, TRrAnimation_GetFrom(Animation), Animation, 0);
+								//ONrCharacter_NewAnimationHook(Player, Active_Player);
+							}
+
+							num_frames = TRrAnimation_GetDuration(Active_Player->Animation);
+
+							if (pd->Frame == num_frames)
+							{
+								Active_Player->Frame = num_frames - 1;
+								//Active_Player->Frame = 0;
+							}
+							else
+							{
+								Active_Player->Frame = pd->Frame;
 							}
 						}
-
-						if (updateAnimation)
+					} //animation check
+
+					if (PlayerList[i]->player_data.throw_data.throwName[0] != 0)
+					{
+						short throwTarget = PlayerList[pd->throw_data.throwing]->spawnnumber;
+						if ((throwTarget != Active_Player->throwing) &&
+							(pd->throw_data.throwFrame < 10))
 						{
-							// set the characters animation
-							/*	ONrCharacter_SetAnimationInternal(Player,
-							Active_Player,
-							Active_Player->AnimationToState,
-							0,
-							Animation);
-							ONrCharacter_NewAnimationHook(Player, Active_Player);*/
-							//Player->Flags |= 0x00000010;
-							ONrCharacter_SetAnimationExternal(Player, TRrAnimation_GetFrom(Animation), Animation, 0);
-							//ONrCharacter_NewAnimationHook(Player, Active_Player);
-						}
-
-						num_frames = TRrAnimation_GetDuration(Active_Player->Animation);
-
-						if (pd->Frame == num_frames)
-						{
-							Active_Player->Frame = num_frames - 1;
-							//Active_Player->Frame = 0;
-						}
-						else
-						{
-							Active_Player->Frame = pd->Frame;
-						}
-					}
-				}
-
-				if (PlayerList[i]->player_data.throw_data.throwName[0] != 0)
-				{
-					short throwTarget = PlayerList[pd->throw_data.throwing]->spawnnumber;
-					if ((throwTarget != Active_Player->throwing) &&
-						(pd->throw_data.throwFrame < 10))
-					{
-						void	*throw_animation;
-						ActiveCharacter* Target;
-						// get the animation
-
-						TMrInstance_GetDataPtr(
-							'TRAM',
-							pd->throw_data.throwName,
-							&throw_animation);
-						//if (error) return;
-
-						// set the throw target
-						Active_Player->ThrowTargetCharacter = &ONgGameState->CharacterStorage[throwTarget];
-						Target = ONrGetActiveCharacter(Active_Player->ThrowTargetCharacter);
-						if ((Target->Animation != throw_animation) &&
-							(OldAnimation != Animation) &&
-							!(Active_Player->ThrowTargetCharacter->Flags & ONcCharacterFlag_BeingThrown))
-						{
-							// set the throw variables
-							Active_Player->targetThrow	= throw_animation;
-							Active_Player->throwing		= throwTarget;
-
-							// run the throw
-							ONrCharacter_NewAnimationHook(Player, Active_Player);
-
-							if (Active_Player->ThrowTargetCharacter)
+							void	*throw_animation;
+							ActiveCharacter* Target;
+							// get the animation
+
+							TMrInstance_GetDataPtr(
+								'TRAM',
+								pd->throw_data.throwName,
+								&throw_animation);
+							//if (error) return;
+
+							// set the throw target
+							Active_Player->ThrowTargetCharacter = &ONgGameState->CharacterStorage[throwTarget];
+							Target = ONrGetActiveCharacter(Active_Player->ThrowTargetCharacter);
+							if ((Target->Animation != throw_animation) &&
+								(OldAnimation != Animation) &&
+								!(Active_Player->ThrowTargetCharacter->Flags & ONcCharacterFlag_BeingThrown))
 							{
-								Target->Frame += 2;
-								Target->thrownBy = Player->Number;
+								// set the throw variables
+								Active_Player->targetThrow	= throw_animation;
+								Active_Player->throwing		= throwTarget;
+
+								// run the throw
+								ONrCharacter_NewAnimationHook(Player, Active_Player);
+
+								if (Active_Player->ThrowTargetCharacter)
+								{
+									Target->Frame += 2;
+									Target->thrownBy = Player->Number;
+								}
 							}
 						}
-					}
-				}
-
-			}
-		}
+					} //throw check
+				} //second pass
+			} //if not dead
+		} //if( (server_started && i !=0)  || !server_started ) 
+		
+		//Check for character switching requests
+		if(server_started && PlayerList[i]->Actions1 & Action_Block && PlayerList[i]->ShapeshiftCooldown < ONgGameState->GameTime)
+		{
+			int error;
+
+
+
+			ONCC *newClass;
+			short numClasses = (short)TMrInstance_GetTagCount('ONCC');
+			/*
+			if(Active_Player->Input.Start.Actions1 & Action_Block)
+			{
+				//This might not be getting hit. Find out why, eh?
+				PlayerList[i]->ShapeshiftCooldown = ONgGameState->GameTime + 15;
+			}
+			else
+			{
+				PlayerList[i]->ShapeshiftCooldown = ONgGameState->GameTime + 5;
+			}
+			*/
+			if (PlayerList[i]->Actions1 & Action_Crouch) {
+				Player->ONCCnumber += numClasses - 1;
+			}
+			else {
+				Player->ONCCnumber += 1;
+			}
+
+			if (numClasses > 0) {
+				Player->ONCCnumber = Player->ONCCnumber % numClasses;
+
+				error = TMrInstance_GetDataPtr_ByNumber('ONCC', Player->ONCCnumber, &newClass); 
+
+				if ((newClass != NULL) && (!error)) {
+					ONrCharacter_SetCharacterClass(Player, newClass);
+				}
+			}
+
+		}
+
 
 	}
 	if(server_started)
 	{
-		UDPServer_SendToAll(&all_input, FLATLINE_HEADER + sizeof(player_input) * 32);
-	}
-
+		all_input.all_input[InputIndex].PlayerNum = -1;
+		UDPServer_SendToAll(&all_input, 
+			FLATLINE_HEADER + sizeof(player_input) * InputIndex + sizeof(int16_t));
+	}
+	MultiplayerStatus.PleaseUpdateAllPlayers = 0;
 	return ONgGameState;
 }
@@ -859,4 +940,5 @@
 	{
 		//FLsPublic_Event(EV_DISCONNECT, &Player );
+		MultiplayerStatus.PleaseUpdateAllPlayers = 1;
 	}
 	//Kill off the character in another function, please
@@ -932,2 +1014,11 @@
 	}
 }
+
+bool FlatlineInitialize()
+{
+	
+	memset( Players, 0, sizeof( player_info ) * MAX_PLAYERS );
+	memset( PlayerList, 0, 4 * MAX_PLAYERS );
+	memset( &MultiplayerStatus, 0, sizeof( multiplayer_status ));
+	return 1;
+}
Index: Daodan/MSVC/Flatline.h
===================================================================
--- Daodan/MSVC/Flatline.h	(revision 581)
+++ Daodan/MSVC/Flatline.h	(revision 582)
@@ -116,7 +116,12 @@
 typedef struct {
 	uint16_t PlayerNum;
-	Vector3 Position;
-	float Facing;
-	float DesiredFacing;
+	//Vector3 Position;
+	
+	//float Facing;
+	//float DesiredFacing;
+
+	float UD;
+	float LR;
+
 	uint32_t Health;
 	uint32_t MaxHealth;
@@ -130,4 +135,5 @@
 	int Deaths;
 	uint16_t Ping;
+
 } player_data;
 
@@ -146,8 +152,12 @@
 
 typedef struct {
+	int16_t PlayerNum;
 	float MouseDeltaX;
 	float MouseDeltaY;
 	uint32_t Actions1;
 	uint32_t Actions2;
+	float Facing;
+	float DesiredFacing;
+	Vector3 Position;
 } player_input;
 
@@ -210,4 +220,14 @@
 
 
+typedef struct {
+	//Server Only
+	bool PleaseUpdateAllPlayers;
+	//Client stuff (can be used by server "client")
+
+	//Move from random scattered bools to these, please.
+	bool ClientConnected;
+	unsigned int ClientSlot;
+	bool ServerStatus;
+} multiplayer_status;
 
 enum {
@@ -227,8 +247,15 @@
 	uint16_t spawnnumber;
 	uint16_t list_slot;
+	
+	//Todo: move into struct for slightly faster copying
 	float MouseDeltaX;
 	float MouseDeltaY;
 	uint32_t Actions1;
 	uint32_t Actions2;
+	float Facing;
+	float DesiredFacing;
+	//float Height;
+	Vector3 Position;
+
 	unsigned int LastInputTime;
 	input_struct CacheInput;
@@ -242,4 +269,6 @@
 	uint32_t Ping;
 	bool DataApplied;
+	
+	uint32_t ShapeshiftCooldown;
 } player_info;
 
@@ -260,5 +289,5 @@
 extern player_info Players[];
 extern player_info * PlayerList[];
-
+extern multiplayer_status MultiplayerStatus;
 int UDPServer_SendToAll(void* packet, int size);
 
@@ -271,5 +300,5 @@
 void FLrPlayerRespawn( int Player );
 int FLrEvent_GetNumArgs( int eventIndex );
-
+bool FlatlineInitialize();
 extern unsigned int lastPingTime;
 #endif
Index: Daodan/MSVC/Flatline_BSL.c
===================================================================
--- Daodan/MSVC/Flatline_BSL.c	(revision 581)
+++ Daodan/MSVC/Flatline_BSL.c	(revision 582)
@@ -72,4 +72,5 @@
 uint16_t ONICALL connect_to_server(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
 {
+	//TODO: Move this into the client initialization. Doing it like this is silly.
 	if(	NetPlatform_Initalize()) {
 		static flatline_packet packet;
@@ -128,5 +129,5 @@
 uint16_t ONICALL kick(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
 {
-	FLrPlayerDisconnect(args[0].value_int32 - 1);
+	FLrPlayerDisconnect(args[0].value_int32);
 	FLsPublic_Event(EV_DISCONNECT, &args[0].value_int32);
 	return 0;
@@ -226,5 +227,4 @@
 	SLrScript_Command_Register_Void("kick", "Kicks a client from the server", "clientnum:int", kick);
 	SLrScript_Command_Register_Void("con", "Activates a console", "con:int", con);
-	//SLrScript_Command_Register_ReturnType("ai2_spawn","creates and starts an AI from a character object","ai_name:string [force_spawn:string{\"force\"} | ]", sl_void, spawnAI);
 	SLrScript_Command_Register_Void("ping", "pong!", "", ping);
 }
Index: Daodan/MSVC/Flatline_Net.c
===================================================================
--- Daodan/MSVC/Flatline_Net.c	(revision 581)
+++ Daodan/MSVC/Flatline_Net.c	(revision 582)
@@ -207,7 +207,11 @@
 }
 
+
+
 DWORD WINAPI StartServer(void* lol){
-	NetPlatform_Initalize();
-	FLrServer_Run();
+	if(NetPlatform_Initalize() && FlatlineInitialize())
+	{
+		FLrServer_Run();
+	}
 	return 0;
 } 
@@ -215,5 +219,8 @@
 DWORD WINAPI StartClient(void* lol){
 	//NetPlatform_Initalize();
-	FLrClient_Run((flatline_packet*)lol);
+	if(FlatlineInitialize())
+	{
+		FLrClient_Run((flatline_packet*)lol);
+	}
 	return 0;
 } 
Index: Daodan/MSVC/Flatline_Server.c
===================================================================
--- Daodan/MSVC/Flatline_Server.c	(revision 581)
+++ Daodan/MSVC/Flatline_Server.c	(revision 582)
@@ -1,4 +1,5 @@
 #include "Flatline.h"
 #include "Flatline_Server.h"
+#include <Windows.h>
 
 //I hereby apologize for the uglyness of the below code. 
@@ -92,4 +93,6 @@
 		sprintf(PlayerList[playerlist_slot]->name,"%.31s",name);
 		
+		MultiplayerStatus.PleaseUpdateAllPlayers = 1;
+
 		return &Players[player_slot];
 	}
@@ -146,5 +149,5 @@
 	flatline_packet ping;
 	ping.id = PK_PING;
-	lastPingTime = ping.ping = ONgGameState->GameTime;
+	lastPingTime = ping.ping = GetTickCount();
 	UDPServer_SendToAll(&ping, FLATLINE_HEADER + 4);
 }
Index: Daodan/MSVC/Oni_GameState.h
===================================================================
--- Daodan/MSVC/Oni_GameState.h	(revision 581)
+++ Daodan/MSVC/Oni_GameState.h	(revision 582)
@@ -769,5 +769,5 @@
   int field_8;
   ONCC* ONCC;
-  __int16 field_10;
+  __int16 ONCCnumber;
   __int16 Team;
   char Name[32];
@@ -799,5 +799,5 @@
   int BNV;
   int GraphNode;
-  int PelvisHeight;
+  float PelvisHeight;
   int field_190;
   Inventory Inventory;
@@ -1257,6 +1257,6 @@
   int field_21AC;
   Vector3 field_21B0;
-  int HeadFacing;
-  int HeadPitch;
+  float HeadFacing;
+  float HeadPitch;
   int field_21C4;
   int field_21C8;
@@ -1322,4 +1322,20 @@
 typedef struct
 {
+	char name[64];	// Must be same as ONcMaxLevelName above (for TE)
+	
+	void *env;
+	void *objectsetup;
+	void *markers;
+	void *flags;
+	void *triggers;
+	
+	void *Sky;
+	float	SkyHeight;
+
+
+} OniLevel;
+
+typedef struct
+{
   int TimerMode;
   char TimerName[32];
@@ -1379,5 +1395,5 @@
   int field_148;
   int field_14C;
-  int Level;
+  OniLevel* Level;
   int field_154;
   MotionBlur MotionBlur_[64];
Index: Daodan/MSVC/Oni_Symbols.h
===================================================================
--- Daodan/MSVC/Oni_Symbols.h	(revision 581)
+++ Daodan/MSVC/Oni_Symbols.h	(revision 582)
@@ -229,3 +229,6 @@
 //typedef void		( *_ONiGameState_FindAutoPromptMessage)(char* Note, void* ptr);
 DefFunc( void, ONiGameState_FindAutoPromptMessage, (char* Note, void* ptr), 0x004FDBE0 );
+DefFunc( void, ONrCharacter_SetCharacterClass, (Character* Char, ONCC* Class), 0x004D7C30 );
+DefFunc( short, TMrInstance_GetDataPtr_ByNumber, (int tag, int number, void** out), 0x00423680 );
+DefFunc( uint32_t, TMrInstance_GetTagCount, (int tag), 0x004236F0);
 #endif
