#include "Flatline.h" #include "../Oni_Character.h" #include "../Oni_GameState.h" #include "../Oni_Symbols.h" #include "Flatline_Client.h" #include "Flatline_Server.h" #include "Flatline_Events.h" #include "../Daodan_Utility.h" #include //#include #include #include #define isnan(x) ((x) != (x)) player_info Players[MAX_PLAYERS]; player_info * PlayerList[MAX_CONNECTIONS] = {0}; multiplayer_status MultiplayerStatus; unsigned int lastPingTime; const char * Rejection_Messages[][255] = { {"Server is full"}, {"-2"}, {"-3"}, {"-4"}, {"-5"}, }; typedef struct { uint16_t x; uint16_t y; } IMtPoint2D; extern uint16_t max_connections; short TRrAnimation_GetType(const void* 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 = (void*)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; } //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; } uint16_t FLr_FindEmptyListSlot() { int j; for(j = 0; j < max_connections; j++) { if (PlayerList[j] == 0) { return j; } } return -1; } void * ONICALL FLrInput_Update_Keys(void) { int32_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 = ONgGameState->Input.Current.Actions1; input_packet.input_struct.Actions2 = ONgGameState->Input.Current.Actions2; input_packet.input_struct.MouseDeltaX = ONgGameState->Input.MouseDeltaX; input_packet.input_struct.MouseDeltaY = ONgGameState->Input.MouseDeltaY; input_packet.input_struct.DesiredFacing = ONgGameState->PlayerCharacter->DesiredFacing; 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; 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 && i != 0 ) { PlayerList[i]->Chr->DesiredFacing = PlayerList[i]->FacingFromClient; } //Set the health properly first. //Always overridden by the server because of the chance of random damage and such if( client_connected && DoWeUpdateThis( PlayerList[i]->UpdateFlags, PFlag_Health) ) { PlayerList[i]->Chr->MaxHealth = PlayerList[i]->Health.MaxHealth; ONrCharacter_SetHitPoints( PlayerList[i]->Chr, PlayerList[i]->Health.Health); //PlayerList[i]->UpdateFlags &= ~( 1 << PFlag_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]->InputFromClient.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( client_connected && DoWeUpdateThis( PlayerList[i]->UpdateFlags, PFlag_Class ) ) { if(PlayerList[i]->Class) { ONrCharacter_SetCharacterClass( PlayerList[i]->Chr, PlayerList[i]->Class ); } PlayerList[i]->UpdateFlags &= ~( 1 << PFlag_Class ); } if( client_connected && DoWeUpdateThis( PlayerList[i]->UpdateFlags, PFlag_Facing ) ) { PlayerList[i]->Chr->Facing = PlayerList[i]->Facings.Facing; if(i != client_slot) { PlayerList[i]->Chr->DesiredFacing = PlayerList[i]->Facings.DesiredFacing; } PlayerList[i]->UpdateFlags &= ~( 1 << PFlag_Facing ); } if(Active_Player == 0) continue; // Active_Player->PlayingFilm.Flags = 1; Active_Input = &(Active_Player->Input); if( (server_started && i !=0) || !server_started ) { Active_Input->Stop.Actions1 = ~PlayerList[i]->Input.Actions1 & Active_Input->Current.Actions1; Active_Input->Stop.Actions2 = ~PlayerList[i]->Input.Actions2 & Active_Input->Current.Actions2; Active_Input->Start.Actions1 = ~Active_Input->Current.Actions1 & PlayerList[i]->Input.Actions1; Active_Input->Start.Actions2 = ~Active_Input->Current.Actions2 & PlayerList[i]->Input.Actions2; Active_Input->Current.Actions1 = PlayerList[i]->Input.Actions1; Active_Input->Current.Actions2 = PlayerList[i]->Input.Actions2; Active_Input->Stopped.Actions1 = ~Active_Input->Current.Actions1; Active_Input->Stopped.Actions2 = ~Active_Input->Current.Actions2; if(client_connected && i == client_slot) { Active_Input->MouseDeltaX = ONgGameState->Input.MouseDeltaX; Active_Input->MouseDeltaY = ONgGameState->Input.MouseDeltaY; } else { Active_Input->MouseDeltaX = PlayerList[i]->Input.MouseDeltaX; Active_Input->MouseDeltaY = PlayerList[i]->Input.MouseDeltaY; } } { void* ConsoleAnimation = 0; TMrInstance_GetDataPtr( 'TRAM', "KONOKOwatch_idle", &ConsoleAnimation); if(!Active_Player->IsInAir && Active_Input->Current.Actions1 & (Action_Console | Action_PauseScreen) && !(PlayerList[i]->Chr->Flags & ONcCharacterFlag_BeingThrown) && Active_Player->ThrowTargetCharacter != -1) { if(ConsoleAnimation && ConsoleAnimation != Active_Player->Animation) { ONrCharacter_SetAnimationExternal(PlayerList[i]->Chr, Active_Player->AnimationFromState, ConsoleAnimation, 10); Player->Flags |= 0x00200000; Active_Player->ForcedAnimationFrames = -1;// TRrAnimation_GetDuration(ConsoleAnimation); } } else if(Active_Input->Stopped.Actions1 & (Action_Console | Action_PauseScreen) ) { Active_Player->ForcedAnimationFrames = 0; } } //Check for character switching requests if(server_started && PlayerList[i]->Chr->Health != 0 && PlayerList[i]->InputFromClient.Actions1 & Action_Block) { if( 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; } */ PlayerList[i]->ShapeshiftCooldown = ONgGameState->GameTime + 15; if (PlayerList[i]->InputFromClient.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); } } } } else { PlayerList[i]->ShapeshiftCooldown = 0; } if(client_connected) { if( DoWeUpdateThis( PlayerList[i]->UpdateFlags, PFlag_Position) ) { //Active_Player->PhyContext->Position = PlayerList[i]->Position; Active_Player->PhyContext->Position.X = (PlayerList[i]->Position.X + Active_Player->PhyContext->Position.X) / 2; Active_Player->PhyContext->Position.Y = (PlayerList[i]->Position.Y + Active_Player->PhyContext->Position.Y) / 2; Active_Player->PhyContext->Position.Z = (PlayerList[i]->Position.Z + Active_Player->PhyContext->Position.Z) / 2; PlayerList[i]->UpdateFlags &= ~( 1 << PFlag_Position ); } if (!(Player->Flags & ONcCharacterFlag_BeingThrown) && DoWeUpdateThis( PlayerList[i]->UpdateFlags, PFlag_Animation) && (PlayerList[i]->Animation)) { // get a pointer to the animation if (PlayerList[i]->Animation != Active_Player->Animation) { /////////////////////////////////// //TODO: Check age of animation /////////////////////////////////// // set the characters animation /*ONrCharacter_SetAnimationInternal(Player, Active_Player, Active_Player->AnimationToState, 0, PlayerList[i]->Animation);*/ //ONrCharacter_NewAnimationHook(Player, Active_Player); ONrCharacter_SetAnimationExternal(Player, TRrAnimation_GetFrom(PlayerList[i]->Animation), PlayerList[i]->Animation, 1); //ONrCharacter_NewAnimationHook(Player, Active_Player); } } PlayerList[i]->UpdateFlags &= ~( 1 << PFlag_Animation ); //Disabled Frame syncing for now. In most cases it won't be useful. if(0 && DoWeUpdateThis( PlayerList[i]->UpdateFlags, PFlag_FramePing) && PlayerList[i]->Frame != -1 //&& !DoWeUpdateThis( PlayerList[i]->UpdateFlags, PFlag_Animation) ) { if( abs(PlayerList[i]->Frame - Active_Player->Frame) > 2 ) { short AnimationLength; AnimationLength = TRrAnimation_GetDuration(Active_Player->Animation); if (PlayerList[i]->Frame >= AnimationLength) { Active_Player->Frame = AnimationLength - 1; //Active_Player->Frame = 0; } else { Active_Player->Frame = PlayerList[i]->Frame; } } } PlayerList[i]->UpdateFlags &= ~( 1 << PFlag_FramePing ); //Increment frame in case we were waiting PlayerList[i]->Frame++; if (DoWeUpdateThis( PlayerList[i]->UpdateFlags, PFlag_Throws) && PlayerList[i]->ThrowData.throwName[0] != 0) { if(PlayerList[PlayerList[i]->ThrowData.throwing]) { short throwTarget = PlayerList[PlayerList[i]->ThrowData.throwing]->spawnnumber; /*if ((throwTarget != Active_Player->throwing) && (PlayerList[i]->ThrowData.throwFrame < 10))*/ { void *throw_animation; ActiveCharacter* Target; // get the animation TMrInstance_GetDataPtr( 'TRAM', PlayerList[i]->ThrowData.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->thrownBy == - { // 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; //DDrConsole_PrintF("Thrown by player %hi", Player->Number ); //DDrStartupMessage("Thrown by player %hi", Player->Number ); Target->thrownBy = Player->Number & 0x00ff; } } } } else { DDrConsole_PrintF("Warning, tried to throw nonexistant player %hi", PlayerList[i]->ThrowData.throwing ); } } //Always discard old throw data, even if it isnt applied PlayerList[i]->UpdateFlags &= ~( 1 << PFlag_Throws ); } } if(server_started) { if(ONgGameState->GameTime % 120 == 0) { FLsPingAll(); } if(PlayerList[0]) { PlayerList[0]->InputFromClient.Actions1 = ONgGameState->Input.Current.Actions1; PlayerList[0]->InputFromClient.Actions2 = ONgGameState->Input.Current.Actions2; PlayerList[0]->InputFromClient.MouseDeltaX = ONgGameState->Input.MouseDeltaX; PlayerList[0]->InputFromClient.MouseDeltaY = ONgGameState->Input.MouseDeltaY; } FLsSendPlayerData(); } 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; const int blue = 0x000000FF; int i; char DrawString[255]; const int LineHeight = 15; IMtPoint2D DrawLocation = {25, 20}; TSrContext_SetShade(ScoreboardInstance, white); TSrContext_DrawText(ScoreboardInstance, "Oni Flatline build " __DATE__ " " __TIME__, 255, 0, &DrawLocation); TSrContext_SetShade(ScoreboardInstance, white); DrawLocation.y += LineHeight; DrawLocation.x = 25; 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 = 10; DrawLocation.y += LineHeight; sprintf(DrawString, "%i.", i ); TSrContext_DrawText(ScoreboardInstance, DrawString, 255, 0, &DrawLocation); DrawLocation.x += 15; 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]->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 )); COrCommand_Execute("chr_draw_all_characters = 1;"); AI2rSmite(NULL, UUcFalse); return 1; }