#include "Flatline.h" #include "Oni_Character.h" #include "Flatline_Client.h" #include "Flatline_Server.h" #include "Flatline_Events.h" #include //#include #include #include #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; const char * Rejection_Messages[][255] = { {"Server is full"}, {"-2"}, {"-3"}, {"-4"}, {"-5"}, }; #define BETTER_SYNC void DoRareSync( short Player, sockaddr_in * sender ) { flatline_packet sync = {0}; if (Player > max_connections || !PlayerList[ Player ] ) return; // DDrConsole_PrintF( "Sending sync data for player %i, new index %u", Player, PlayerList[ Player ]->rare_sync_index); sender->sin_addr.S_un.S_addr = htonl(sender->sin_addr.S_un.S_addr); sync.id = RARE_SYNC_DATA; sprintf( sync.rare_sync_data.Class, TMrInstance_GetInstanceName( PlayerList[ Player ]->Chr->ONCC ) ); //using ->Inventory instead of ->Chr->Inventory to keep the index and Inventory in sync, just in case. memcpy( &(sync.rare_sync_data.Inventory), &(PlayerList[ Player ]->Inventory), sizeof(Inventory) ); //WEAPONS ARE DISABLED. Why? Pain in the arse to sync. sync.rare_sync_data.Inventory.Weapons[0] = NULL; sync.rare_sync_data.Inventory.Weapons[1] = NULL; sync.rare_sync_data.Inventory.Weapons[2] = NULL; sync.rare_sync_data.PlayerNum = Player; sync.rare_sync_data.index = PlayerList[ Player ]->rare_sync_index; NetTCPServer_Send( sender, (char*)&sync, sizeof(rare_sync_data) + FLATLINE_HEADER ); } enum { JustSpawned, FirstPass, SecondPass, NoPass, }; bool FLrServer_PacketCallback(char* data, int datalen, int from) { int i, j; bool found_player = 0; flatline_packet * packet = (flatline_packet*)data; static int recieved = 0; sockaddr_in sender; sender.sin_family = AF_INET; sender.sin_port = htons(27777); sender.sin_addr = *((struct in_addr*)(int*)&from); //packet->data[datalen] = '\0'; //DDrConsole_PrintF("Packet \r%d recieved from %i", ++recieved, from); //if data[0] != CONNECT_SEND, search in playerlist for ip address switch(packet->id) { flatline_packet connect_recv; player_info * playah; //rewrite this when we get TCP support. //rewrite this before we get TCP support* //the way of seeing if there is room for players sucks. case CONNECT_SEND: ; connect_recv.id = CONNECT_REPLY; //if(Players[i].ip == sender.sin_addr.S_un.S_addr) break; //needs to send an error message sender.sin_addr.S_un.S_addr = htonl(sender.sin_addr.S_un.S_addr); playah = FLrServer_AddPlayer(from,packet->connect_send.name, 0, 0); DDrConsole_PrintF("%s connected from %s", packet->connect_send.name, inet_ntoa(sender.sin_addr ) ); if(!((int)playah > -5 && (int)playah <= 0)) { flatline_packet new_char = {0}; CharacterObject* Char; connect_recv.connect_reply.goodtogo = 1; connect_recv.connect_reply.player_slot = playah->list_slot; DDrConsole_PrintF("Slot: %i", playah->list_slot); //sending this several times to make sure it gets through. Really need to make up some form of packet tracking. NetTCPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER); NetTCPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER); NetTCPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER); NetTCPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER); NetTCPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER); Sleep(100); new_char.id = NEW_PLAYER; Char = &new_char.new_player.Character; memset(Char, 0, sizeof(CharacterObject)); Char->Header.Type = 'CHAR'; Char->OSD.Options = chr_dontaim; for(j = 0; j < max_connections; j++) { if(PlayerList[j] != 0) { new_char.new_player.Playernumber = j; sprintf(Char->OSD.Name,"%s",PlayerList[j]->name); sprintf(Char->OSD.Class, "%s", TMrInstance_GetInstanceName(PlayerList[j]->Chr->ONCC)); DDrConsole_PrintF("Class %s", Char->OSD.Class ); sprintf(Char->OSD.Class, "konoko_generic"); NetTCPServer_Send((sockaddr *) &sender, (char*)&new_char, sizeof(new_player) + FLATLINE_HEADER ); } } } else { //fix the error messages... DDrConsole_PrintF("Server is full. :("); connect_recv.connect_reply.goodtogo = 0; sender.sin_addr.S_un.S_addr = htonl(sender.sin_addr.S_un.S_addr); memcpy(&connect_recv.connect_reply.message,"Server is full.", sizeof("Server is full.")); NetTCPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(bool)*2 + FLATLINE_HEADER + sizeof("Server is full.")); } break; case CONNECT_REPLY: break; //do nothing...a server shouldn't recieve this type of packet. case MESSAGE: for(i = 0; i < MAX_PLAYERS; i++) { //DDrConsole_PrintF("%i : %i | %s : %s", from, Players[i].ip, inet_ntoa(*(struct in_addr*)&from), inet_ntoa(*(struct in_addr*)&(Players[i].ip))); if(Players[i].ip == sender.sin_addr.S_un.S_addr) { found_player = 1; break; } } if(found_player == 0) return true; else { char message_buffer[512] = {0}; flatline_packet message; int message_size; data[datalen] = 0; DDrConsole_PrintF("%s: %s", Players[i].name, packet->data); sprintf(message_buffer, "%s: %s", Players[i].name, packet->data); message.id = MESSAGE; message_size = sprintf(message.data, "%s", message_buffer); COrMessage_Print(message_buffer, "chat", 0); UDPServer_SendToAll(&message, message_size + 1 + FLATLINE_HEADER); break; } case CHANGE_NAME: ; //wtf, needed or i get an error. // DDrConsole_PrintF("Changing Name to: %s", packet->data); for(i = 0; i < MAX_PLAYERS; i++) { if(PlayerList[i] && PlayerList[i]->ip == sender.sin_addr.S_un.S_addr) { found_player = 1; break; } } if(found_player == 0) break; else { bool name_exists = 0; for(j = 0; j < MAX_PLAYERS; j++) { if(PlayerList[j] && !strcmp(packet->data, PlayerList[j]->name)) { name_exists = 1; break; } } if(!name_exists) { FLsUpdateName( i, packet->data ); } break; } case PLAYER_INPUT: for(i = 0; i < max_connections; i++) { if(PlayerList[i] != 0 && PlayerList[i]->ip == sender.sin_addr.S_un.S_addr) { found_player = 1; break; } } if(found_player == 0) break; else { input_struct * packet_input = &packet->input_struct; PlayerList[i]->Actions1 = packet_input->Actions1; PlayerList[i]->Actions2 = packet_input->Actions2; PlayerList[i]->MouseDeltaX = packet_input->MouseDeltaX; PlayerList[i]->MouseDeltaY = packet_input->MouseDeltaY; PlayerList[i]->LastInputTime = packet_input->Time; break; } case RARE_SYNC_DATA_REQUEST: DoRareSync( packet->sync_request , &sender); break; case PK_PONG: for(i = 0; i < max_connections; i++) { if(PlayerList[i] != 0 && PlayerList[i]->ip == sender.sin_addr.S_un.S_addr) { found_player = 1; break; } } if(found_player == 0) break; if(packet->ping != lastPingTime) { PlayerList[i]->Ping = 999; } else { PlayerList[i]->Ping = GetTickCount() - packet->ping; } break; default: DDrConsole_PrintF("Warning, recieved badly formed packet!"); break; } return true; } bool FLrServer_Run() { // Get the local hostname char szHostName[255]; struct hostent *host_entry; gethostname(szHostName, 255); host_entry=gethostbyname(szHostName); DDrConsole_PrintF("Server started at %s...", inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list)); return NetUDPServer_Listen(27777, FLrServer_PacketCallback); } short TRrAnimation_GetType(char* anim) { return *(short*)(anim + 0x15A); } void ONrCharacter_SetAnimationInternal(Character* Char, ActiveCharacter* AChar, short inFromState, short inNextAnimType, const void *TRAM) { ONCC *ONCC = Char->ONCC; void *TRAC = ONCC->TRAC; short index = Char->Number; short animType; if (TRAM == 0) return; animType = TRrAnimation_GetType(TRAM); AChar->Animation = TRAM; AChar->Frame = 0; AChar->AnimationFromState = inFromState; AChar->AnimationType = animType; AChar->NextAnimationType= inNextAnimType; AChar->AnimationToState = TRrAnimation_GetTo(TRAM); return; } RGBA green = {0, 0xFF, 0, 0}; RGBA red = {0, 0, 0xFF, 0}; RGBA grey = {0x80,0x80,0x80,0x80}; //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 CHANGE_NAME: if(PlayerList[(char)packet.data[0]]) { char message_buffer[1024]; sprintf(message_buffer,"%s changed their name to %s", PlayerList[(char)packet.data[0]]->name, packet.data + 1); COrMessage_Print(message_buffer, "name_change", 0); sprintf_s(PlayerList[packet.data[0]]->name, 32, "%s", packet.data + 1); } 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) ; sprintf_s(Players[chr_index].name, 32, "%s", ((new_player*)(packet.data))->Character.OSD.Name); } //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(PlayerList[i]->player_data.Health == 0) { short breakfast = 1; } 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 = NoPass; 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; PlayerList[Player]->NeedToSetFP = 1; } } } break; default: DDrConsole_PrintF("Warning, recieved badly formed packet!"); break; } } } bool FLrClient_Run(flatline_packet* packet) { char data[1400]; uint16_t len; int j; int sent_bytes; client_connected = 0; //starts the connection DDrConsole_PrintF("Connecting to server %s on socket %i", inet_ntoa(address.sin_addr), client_sock); sent_bytes = NetUDPSocket_Send(client_sock, (sockaddr*)&address, (char*)packet, 255); if(sent_bytes == SOCKET_ERROR) { NetCatchError(); } //loops once per second waiting for a reply. for(j = 0; j < CONNECTION_TIMEOUT; j++) { while(NetUDPSocket_Recieve(client_sock, (sockaddr_storage *) &client_address, data, &len)){ packet = (flatline_packet*)data; if(packet->id == CONNECT_REPLY) { if(packet->connect_reply.goodtogo){ client_connected = 1; client_slot = ((connect_reply*)packet->data)->player_slot; PlayerList[client_slot] = Players+client_slot; PlayerList[client_slot]->Chr = ONgGameState->PlayerCharacter; DDrConsole_PrintColored("Connection successful!",0,green, grey); sprintf_s( PlayerList[client_slot]->name, 32, "%s", player_name ); //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; } else { DDrConsole_PrintF("Connection rejected: %s", ((connect_reply*)packet->data)->message); return false; break; } } } if(client_connected) break; DDrConsole_PrintF("Connection timing out in %i seconds...", CONNECTION_TIMEOUT - j); Sleep(1000); } //the client timed out without recieving an error message. if(!client_connected) { DDrConsole_PrintColored("Connection timed out.",0,red, grey); return false; } return true; } //wtf, this needs cleaned up... player_info *FLr_FindEmptySlot() { int j; for(j = 0; j < MAX_PLAYERS; j++) { if (Players[j].ip == 0) { return &Players[j]; } } return 0; } extern uint16_t max_connections; uint16_t FLr_FindEmptyListSlot() { int j; for(j = 0; j < max_connections; j++) { if (PlayerList[j] == 0) { return j; } } return -1; } typedef struct { uint16_t x; uint16_t y; } IMtPoint2D; static flatline_packet cache_input = {0}; 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) { uint32_t i; flatline_packet all_input = {0}; int16_t InputIndex = 0; 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; input_packet.input_struct.Actions1 = ((GameState*)(ONgGameState))->Input.Current.Actions1; input_packet.input_struct.Actions2 = ((GameState*)(ONgGameState))->Input.Current.Actions2; input_packet.input_struct.MouseDeltaX = ((GameState*)(ONgGameState))->Input.MouseDeltaX; input_packet.input_struct.MouseDeltaY = ((GameState*)(ONgGameState))->Input.MouseDeltaY; sent_bytes = NetUDPSocket_Send(client_sock,(sockaddr *) &address, (char*)&input_packet, sizeof(input_struct) + FLATLINE_HEADER); //return ONgGameState; } if(!(server_started || client_connected)) return ONgGameState; all_input.id = PK_ALL_INPUT; if(server_started && ONgGameState->GameTime % 120 == 0) { 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; } for(i = 0; i < max_connections; i++) { ActiveCharacter * Active_Player; Character* Player; GameInput * Active_Input; if(PlayerList[i] == 0) continue; Player = PlayerList[i]->Chr; Active_Player = ONrGetActiveCharacter( PlayerList[i]->Chr); if(!Player) { DDrConsole_Print("Warning, missing Character!"); continue; } if(server_started && PlayerList[i]->Chr->Health > 0 ) { //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; if(Active_Player) { all_input.all_input[InputIndex].Position = Active_Player->PhyContext->Position; } all_input.all_input[InputIndex].PlayerNum = i; InputIndex++; } //Set the health properly first. if( client_connected && PlayerList[i]->DataApplied == FirstPass ) { ONrCharacter_SetHitPoints( PlayerList[i]->Chr, PlayerList[i]->player_data.Health); } //If the player is dead if( PlayerList[i]->Chr->Health == 0 ) { const short TicksToRespawn = 3 * 60; //Permanently kill off dumb AI if(PlayerList[i]->flags & PF_SCRIPTEDAI) { FLrPlayerDisconnect( i ); continue; } //Just to know if we have started counting off the respawn if(PlayerList[i]->state != STATE_DEAD) { PlayerList[i]->state = STATE_DEAD; PlayerList[i]->DeathTime = ONgGameState->GameTime; if(i == client_slot) { ONrGameState_Timer_Start( "", TicksToRespawn ); } if(server_started) { FLsPublic_Event( EV_KILLED, &i ); } } //Server respawning if(server_started) { int Actions; if(i == 0) { Actions = ONgGameState->Input.Current.Actions1; } else { Actions = PlayerList[i]->Actions1; } if(ONgGameState->GameTime - PlayerList[i]->DeathTime > TicksToRespawn && (Actions & (Action_Punch | Action_Kick)) ) { FLrPlayerRespawn( i ); FLsPublic_Event( EV_RESPAWN, &i ); } else { continue; } } else //clients?! { continue; } } PlayerList[i]->state = STATE_ALIVE; if(Active_Player == 0) continue; //Active_Player->PlayingFilm.Flags = 1; Active_Input = &(Active_Player->Input); if(server_started && ShouldSendUpdate( i, PlayerList[i]->Chr, Active_Player) ) { player_data * data; flatline_packet data_out = {0}; data_out.id = PLAYER_DATA; data = (void*)&(data_out.data); data->PlayerNum = i; 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; 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) { data->throw_data.throwing = Players[Active_Player->throwing].list_slot; memcpy(data->throw_data.throwName, TMrInstance_GetInstanceName(Active_Player->targetThrow), 31); data->throw_data.throwFrame = ONrGetActiveCharacter(Active_Player->targetThrow)->Frame; } if( PlayerList[i]->OldClass != PlayerList[i]->Chr->ONCC || memcmp( &(PlayerList[i]->Inventory), &(PlayerList[i]->Chr->Inventory), sizeof(Inventory) ) ) { PlayerList[i]->OldClass = PlayerList[i]->Chr->ONCC; memcpy( &(PlayerList[i]->Inventory), &(PlayerList[i]->Chr->Inventory), sizeof(Inventory) ); PlayerList[i]->rare_sync_index++; } data->rare_sync_index = PlayerList[i]->rare_sync_index; data->Ping = PlayerList[i]->Ping; memcpy( &(PlayerList[i]->player_data), data, sizeof(player_data) ); UDPServer_SendToAll(&data_out, sizeof(player_data) + FLATLINE_HEADER); } if( (server_started && i !=0) || !server_started ) { Active_Input->Stop.Actions1 = ~PlayerList[i]->Actions1 & Active_Input->Current.Actions1; Active_Input->Stop.Actions2 = ~PlayerList[i]->Actions2 & Active_Input->Current.Actions2; Active_Input->Start.Actions1 = ~Active_Input->Current.Actions1 & PlayerList[i]->Actions1; Active_Input->Start.Actions2 = ~Active_Input->Current.Actions2 & PlayerList[i]->Actions2; Active_Input->Current.Actions1 = PlayerList[i]->Actions1; Active_Input->Current.Actions2 = PlayerList[i]->Actions2; Active_Input->Stopped.Actions1 = ~Active_Input->Current.Actions1; Active_Input->Stopped.Actions2 = ~Active_Input->Current.Actions2; Active_Input->MouseDeltaX = PlayerList[i]->MouseDeltaX; Active_Input->MouseDeltaY = PlayerList[i]->MouseDeltaY; if( !server_started && PlayerList[i]->player_data.Health != 0 && PlayerList[i]->Chr->Health != 0) { void* OldAnimation; void* Animation; player_data* pd = &PlayerList[i]->player_data; //This is getting crazy. WTB new packet system if(PlayerList[i]->NeedToSetFP) { PlayerList[i]->Chr->Facing = PlayerList[i]->Facing; PlayerList[i]->Chr->DesiredFacing = PlayerList[i]->DesiredFacing; if(*(int*)&PlayerList[i]->Chr->Position.X != 0x7f800000) { Active_Player->PhyContext->Position = Player->Location = PlayerList[i]->Position; } PlayerList[i]->NeedToSetFP = 0; } 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)) { // get a pointer to the animation TMrInstance_GetDataPtr( 'TRAM', pd->Animation, &Animation); if (Animation != OldAnimation) { short num_frames; bool updateAnimation = true; // if the character is dead, make sure this animation is appropriate for death /* if (Player->Flags & ONcCharacterFlag_Dead) { 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; } } } //animation check if (PlayerList[i]->player_data.throw_data.throwName[0] != 0) { if(PlayerList[pd->throw_data.throwing]) { 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) { Target->Frame += 2; Target->thrownBy = Player->Number; } } } } else { DDrConsole_PrintF("Warning, tried to throw nonexistant player %hi", pd->throw_data.throwing ); } } //throw check } //second pass } //if not dead } //if( (server_started && i !=0) || !server_started ) //Check for character switching requests if(server_started && PlayerList[i]->player_data.Health != 0 && PlayerList[i]->Chr->Health != 0 && 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) { 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; } void FLrPlayerDisconnect( int Player ) { if(server_started) { //FLsPublic_Event(EV_DISCONNECT, &Player ); MultiplayerStatus.PleaseUpdateAllPlayers = 1; } //Kill off the character in another function, please //ONrCharacter_SetHitPoints( PlayerList[Player]->Chr, 0); memset(PlayerList[Player], 0, sizeof(player_info)); PlayerList[Player] = 0; return; } void FLrPlayerRespawn( int Player ) { PlayerList[Player]->state = STATE_ALIVE; ONrCorpse_Create(PlayerList[Player]->Chr); ONrCharacter_SetHitPoints( PlayerList[Player]->Chr, PlayerList[Player]->Chr->MaxHealth ); } void* ScoreboardInstance = 0; void FLrRun_Scores() { if(client_connected || server_started) { if(!ScoreboardInstance){ void* TSFFTahoma; TMrInstance_GetDataPtr( 'TSFF', "Tahoma", &TSFFTahoma); TSrContext_New( TSFFTahoma, 7, 1, 1, 0, &ScoreboardInstance); } if(ScoreboardInstance){ const int white = 0x00FFFFFF; const int green = 0x0000FF00; const int red = 0x00FF0000; int i; char DrawString[255]; const int LineHeight = 15; IMtPoint2D DrawLocation = {20, 20}; TSrContext_SetShade(ScoreboardInstance, white); TSrContext_DrawText(ScoreboardInstance, "Oni Flatline build " __DATE__ " " __TIME__, 255, 0, &DrawLocation); DrawLocation.y += LineHeight; TSrContext_DrawText(ScoreboardInstance, "Name", 255, 0, &DrawLocation); DrawLocation.x += 150; TSrContext_DrawText(ScoreboardInstance, "Score", 255, 0, &DrawLocation); DrawLocation.x += 50; TSrContext_DrawText(ScoreboardInstance, "Ping", 255, 0, &DrawLocation); for(i = 0; i Chr == 0) continue; DrawLocation.x = 20; DrawLocation.y += LineHeight; if(PlayerList[i]->Chr && PlayerList[i]->Chr->Health == 0) { TSrContext_SetShade(ScoreboardInstance, red); } else if (i == client_slot) { TSrContext_SetShade(ScoreboardInstance, green); } TSrContext_DrawText(ScoreboardInstance, PlayerList[i]->name, 255, 0, &DrawLocation); TSrContext_SetShade(ScoreboardInstance, white); DrawLocation.x += 150; sprintf(DrawString, "%i", PlayerList[i]->Chr->Damage); TSrContext_DrawText(ScoreboardInstance, DrawString, 255, 0, &DrawLocation); DrawLocation.x += 50; sprintf(DrawString, "%i", PlayerList[i]->player_data.Ping); TSrContext_DrawText(ScoreboardInstance, DrawString, 255, 0, &DrawLocation); } } } } bool FlatlineInitialize() { memset( Players, 0, sizeof( player_info ) * MAX_PLAYERS ); memset( PlayerList, 0, 4 * MAX_PLAYERS ); memset( &MultiplayerStatus, 0, sizeof( multiplayer_status )); return 1; }