diff --git a/src/game/client/components/hud.cpp b/src/game/client/components/hud.cpp index 662a71245..6d27c78d1 100644 --- a/src/game/client/components/hud.cpp +++ b/src/game/client/components/hud.cpp @@ -19,10 +19,20 @@ CHud::CHud() { // won't work if zero m_AverageFPS = 1.0f; + OnReset(); } void CHud::OnReset() { + m_CheckpointDiff = 0.0f; + m_DDRaceTime = 0; + m_LastReceivedTimeTick = 0; + m_CheckpointTick = 0; + m_DDRaceTick = 0; + m_FinishTime = false; + m_ServerRecord = -1.0f; + m_PlayerRecord = -1.0f; + m_DDRaceTimeReceived = false; } void CHud::RenderGameTimer() @@ -307,6 +317,86 @@ void CHud::RenderHealthAndAmmo() Graphics()->QuadsEnd(); } +void CHud::RenderTime() +{ + // check racestate + if(m_FinishTime && m_LastReceivedTimeTick + Client()->GameTickSpeed()*2 < Client()->GameTick()) + { + m_FinishTime = false; + m_DDRaceTimeReceived = false; + return; + } + + if(m_DDRaceTime) + { + char aBuf[64]; + if(m_FinishTime) + { + str_format(aBuf, sizeof(aBuf), "Finish time: %02d:%02d.%02d", m_DDRaceTime/6000, m_DDRaceTime/100-m_DDRaceTime/6000 * 60, m_DDRaceTime % 100); + TextRender()->Text(0, 150*Graphics()->ScreenAspect()-TextRender()->TextWidth(0,12,aBuf,-1)/2, 20, 12, aBuf, -1); + } + else if(m_DDRaceTimeReceived) + { + str_format(aBuf, sizeof(aBuf), "%02d:%02d.%d", m_DDRaceTime/60, m_DDRaceTime%60, m_DDRaceTick/10); + TextRender()->Text(0, 150*Graphics()->ScreenAspect()-TextRender()->TextWidth(0,12,"00:00.0",-1)/2, 20, 12, aBuf, -1); // use fixed value for text width so its not shaky + } + + if(m_CheckpointTick+Client()->GameTickSpeed()*6 > Client()->GameTick()) + { + str_format(aBuf, sizeof(aBuf), "%+5.2f", m_CheckpointDiff); + + // calculate alpha (4 sec 1 than get lower the next 2 sec) + float a = 1.0f; + if(m_CheckpointTick+Client()->GameTickSpeed()*4 < Client()->GameTick() && m_CheckpointTick+Client()->GameTickSpeed()*6 > Client()->GameTick()) + { + // lower the alpha slowly to blend text out + a = ((float)(m_CheckpointTick+Client()->GameTickSpeed()*6) - (float)Client()->GameTick()) / (float)(Client()->GameTickSpeed()*2); + } + + if(m_CheckpointDiff > 0) + TextRender()->TextColor(1.0f,0.5f,0.5f,a); // red + else if(m_CheckpointDiff < 0) + TextRender()->TextColor(0.5f,1.0f,0.5f,a); // green + else if(!m_CheckpointDiff) + TextRender()->TextColor(1,1,1,a); // white + TextRender()->Text(0, 150*Graphics()->ScreenAspect()-TextRender()->TextWidth(0, 10, aBuf, -1)/2, 33, 10, aBuf, -1); + + TextRender()->TextColor(1,1,1,1); + } + } + + static int LastChangeTick = 0; + if(LastChangeTick != Client()->PredGameTick()) + { + m_DDRaceTick += 100/Client()->GameTickSpeed(); + LastChangeTick = Client()->PredGameTick(); + } + + if(m_DDRaceTick >= 100) + m_DDRaceTick = 0; +} + +void CHud::RenderRecord() +{ + if(m_ServerRecord > 0 ) + { + char aBuf[64]; + str_format(aBuf, sizeof(aBuf), "Server best:"); + TextRender()->Text(0, 5, 40, 6, aBuf, -1); + str_format(aBuf, sizeof(aBuf), "%02d:%05.2f", (int)m_ServerRecord/60, m_ServerRecord-((int)m_ServerRecord/60*60)); + TextRender()->Text(0, 53, 40, 6, aBuf, -1); + } + + if(m_PlayerRecord > 0 ) + { + char aBuf[64]; + str_format(aBuf, sizeof(aBuf), "Personal best:"); + TextRender()->Text(0, 5, 47, 6, aBuf, -1); + str_format(aBuf, sizeof(aBuf), "%02d:%05.2f", (int)m_PlayerRecord/60, m_PlayerRecord-((int)m_PlayerRecord/60*60)); + TextRender()->Text(0, 53, 47, 6, aBuf, -1); + } +} + void CHud::OnRender() { if(!m_pClient->m_Snap.m_pGameobj) @@ -318,8 +408,11 @@ void CHud::OnRender() if(m_pClient->m_Snap.m_pLocalInfo && m_pClient->m_Snap.m_pLocalInfo->m_Team == -1) Spectate = true; - if(m_pClient->m_Snap.m_pLocalCharacter && !Spectate && !(m_pClient->m_Snap.m_pGameobj && m_pClient->m_Snap.m_pGameobj->m_GameOver)) + if(m_pClient->m_Snap.m_pLocalCharacter && !Spectate && !(m_pClient->m_Snap.m_pGameobj && m_pClient->m_Snap.m_pGameobj->m_GameOver)) { RenderHealthAndAmmo(); + RenderTime(); + } + RenderGameTimer(); RenderSuddenDeath(); @@ -330,5 +423,44 @@ void CHud::OnRender() RenderConnectionWarning(); RenderTeambalanceWarning(); RenderVoting(); + RenderRecord(); RenderCursor(); + +} + +void CHud::OnMessage(int MsgType, void *pRawMsg) +{ + if(MsgType == NETMSGTYPE_SV_DDRACETIME) + { + m_DDRaceTimeReceived = true; + + CNetMsg_Sv_DDRaceTime *pMsg = (CNetMsg_Sv_DDRaceTime *)pRawMsg; + m_DDRaceTime = pMsg->m_Time; + m_DDRaceTick = 0; + + m_LastReceivedTimeTick = Client()->GameTick(); + + m_FinishTime = pMsg->m_Finish ? true : false; + + if(pMsg->m_Check) + { + m_CheckpointDiff = (float)pMsg->m_Check/100; + m_CheckpointTick = Client()->GameTick(); + } + } + else if(MsgType == NETMSGTYPE_SV_KILLMSG) + { + CNetMsg_Sv_KillMsg *pMsg = (CNetMsg_Sv_KillMsg *)pRawMsg; + if(pMsg->m_Victim == m_pClient->m_Snap.m_LocalCid) + { + m_CheckpointTick = 0; + m_DDRaceTime = 0; + } + } + else if(MsgType == NETMSGTYPE_SV_RECORD) + { + CNetMsg_Sv_Record *pMsg = (CNetMsg_Sv_Record *)pRawMsg; + m_ServerRecord = (float)pMsg->m_ServerTimeBest/100; + m_PlayerRecord = (float)pMsg->m_PlayerTimeBest/100; + } } diff --git a/src/game/client/components/hud.h b/src/game/client/components/hud.h index 50f6b3b1f..b3ade916e 100644 --- a/src/game/client/components/hud.h +++ b/src/game/client/components/hud.h @@ -7,6 +7,17 @@ class CHud : public CComponent float m_Width; float m_AverageFPS; + float m_CheckpointDiff; + int m_DDRaceTime; + int m_LastReceivedTimeTick; + int m_CheckpointTick; + int m_DDRaceTick; + bool m_FinishTime; + float m_ServerRecord; + float m_PlayerRecord; + bool m_DDRaceTimeReceived; + + void RenderCursor(); void RenderFps(); @@ -18,6 +29,8 @@ class CHud : public CComponent void RenderSuddenDeath(); void RenderScoreHud(); void RenderWarmupTimer(); + void RenderTime(); + void RenderRecord(); void MapscreenToGroup(float CenterX, float CenterY, struct CMapItemGroup *PGroup); public: @@ -25,6 +38,7 @@ public: virtual void OnReset(); virtual void OnRender(); + virtual void OnMessage(int MsgType, void *pRawMsg); }; #endif diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index b37a3794c..1a8c0dc91 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -607,7 +607,7 @@ void CCharacter::OnFinish() if(str_comp_num(Server()->ClientName(m_pPlayer->GetCID()), "nameless tee", 12) != 0) GameServer()->Score()->SaveScore(m_pPlayer->GetCID(), time, this); } - + bool NeedToSendNewRecord = false; // update server best time if(GameServer()->m_pController->m_CurrentRecord == 0 || time < GameServer()->m_pController->m_CurrentRecord) { @@ -615,7 +615,8 @@ void CCharacter::OnFinish() if(str_comp_num(Server()->ClientName(m_pPlayer->GetCID()), "nameless tee", 12) != 0) { GameServer()->m_pController->m_CurrentRecord = time; //dbg_msg("character", "Finish"); -// GetPlayer()->SendServerRecord(); + NeedToSendNewRecord = true; + } } @@ -625,6 +626,43 @@ void CCharacter::OnFinish() if(!GameServer()->Score()->PlayerData(m_pPlayer->GetCID())->m_CurrentTime || GameServer()->Score()->PlayerData(m_pPlayer->GetCID())->m_CurrentTime > time) { GameServer()->Score()->PlayerData(m_pPlayer->GetCID())->m_CurrentTime = time; + NeedToSendNewRecord = true; + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->m_IsUsingDDRaceClient) + { + if(!g_Config.m_SvHideScore || i == m_pPlayer->GetCID()) + { + CNetMsg_Sv_PlayerTime Msg; + char aBuf[16]; + str_format(aBuf, sizeof(aBuf), "%.0f", time*100.0f); // damn ugly but the only way i know to do it + int TimeToSend; + sscanf(aBuf, "%d", &TimeToSend); + Msg.m_Time = TimeToSend; + Msg.m_Cid = m_pPlayer->GetCID(); + Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, i); + } + } + } + } + + if(NeedToSendNewRecord && GetPlayer()->m_IsUsingDDRaceClient) { + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->m_IsUsingDDRaceClient) + { + GameServer()->SendRecord(i); + } + } + } + + if(GetPlayer()->m_IsUsingDDRaceClient) { + CNetMsg_Sv_DDRaceTime Msg; + Msg.m_Time = (int)(time * 100.0f); + Msg.m_Check = 0; + Msg.m_Finish = 1; + + Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, m_pPlayer->GetCID()); } int TTime = 0-(int)time; @@ -707,42 +745,69 @@ void CCharacter::Tick() { if (m_DDRaceState == DDRACE_STARTED) { int IntTime = (int)m_Time; - if(m_BroadTime) - str_format(aBuftime, sizeof(aBuftime), "%s%d:%s%d", ((IntTime/60) > 9)?"":"0", IntTime/60, ((IntTime%60) > 9)?"":"0", IntTime%60); - else - str_format(aBuftime, sizeof(aBuftime), ""); - - if(m_CpActive != -1 && m_CpTick > Server()->Tick()) - { - if(pData->m_BestTime && pData->m_aBestCpTime[m_CpActive] != 0) + + if(m_pPlayer->m_IsUsingDDRaceClient) { + CNetMsg_Sv_DDRaceTime Msg; + Msg.m_Time = IntTime; + Msg.m_Check = 0; + Msg.m_Finish = 0; + + if(m_CpActive != -1 && m_CpTick > Server()->Tick()) + { + if(pData->m_BestTime && pData->m_aBestCpTime[m_CpActive] != 0) + { + float Diff = (m_CpCurrent[m_CpActive] - pData->m_aBestCpTime[m_CpActive])*100; + Msg.m_Check = (int)Diff; + } + } + + Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, m_pPlayer->GetCID()); + } else { + if(m_BroadTime) + str_format(aBuftime, sizeof(aBuftime), "%s%d:%s%d", ((IntTime/60) > 9)?"":"0", IntTime/60, ((IntTime%60) > 9)?"":"0", IntTime%60); + else + str_format(aBuftime, sizeof(aBuftime), ""); + + if(m_CpActive != -1 && m_CpTick > Server()->Tick()) + { + if(pData->m_BestTime && pData->m_aBestCpTime[m_CpActive] != 0) + { + char aTmp[128]; + float Diff = m_CpCurrent[m_CpActive] - pData->m_aBestCpTime[m_CpActive]; + str_format(aTmp, sizeof(aTmp), "\nCheckpoint | Diff : %+5.2f", Diff); + strcat(aBuftime, aTmp); + } + } + if( g_Config.m_SvBroadcast[0] != 0 && m_BroadCast) { char aTmp[128]; - float Diff = m_CpCurrent[m_CpActive] - pData->m_aBestCpTime[m_CpActive]; - str_format(aTmp, sizeof(aTmp), "\nCheckpoint | Diff : %+5.2f", Diff); + str_format(aTmp, sizeof(aTmp), "\n%s\n", g_Config.m_SvBroadcast); strcat(aBuftime, aTmp); } + if(Server()->Tick() >= (m_LastBroadcast + Server()->TickSpeed())) + { + GameServer()->SendBroadcast(aBuftime, m_pPlayer->GetCID()); + m_LastBroadcast = Server()->Tick(); + } } + + - if( g_Config.m_SvBroadcast[0] != 0 && m_BroadCast) - { - char aTmp[128]; - str_format(aTmp, sizeof(aTmp), "\n%s\n", g_Config.m_SvBroadcast); - strcat(aBuftime, aTmp); - } - if(Server()->Tick() >= (m_LastBroadcast + Server()->TickSpeed())) - { - GameServer()->SendBroadcast(aBuftime, m_pPlayer->GetCID()); - m_LastBroadcast = Server()->Tick(); - } + + + } - else + else if(!m_pPlayer->m_IsUsingDDRaceClient) { if( g_Config.m_SvBroadcast[0] != 0 && (Server()->Tick() > (m_LastBroadcast + (Server()->TickSpeed() * 9)))) { - char aTmp[128],aYourBest[64],aServerBest[64]; + char aTmp[128], aYourBest[64],aServerBest[64]; str_format(aYourBest, sizeof(aYourBest), "Your Best:'%s%d:%s%d'", ((pData->m_BestTime / 60) < 10)?"0":"", (int)(pData->m_BestTime / 60), (((int)pData->m_BestTime % 60) < 10)?"0":"", (int)pData->m_BestTime % 60); + CPlayerData *pData = GameServer()->Score()->PlayerData(m_pPlayer->GetCID()); + str_format(aServerBest, sizeof(aServerBest), "Server Best:'%s%d:%s%d'", ((GameServer()->m_pController->m_CurrentRecord / 60) < 10)?"0":"", (int)(GameServer()->m_pController->m_CurrentRecord / 60), (((int)GameServer()->m_pController->m_CurrentRecord % 60) < 10)?"0":"", (int)GameServer()->m_pController->m_CurrentRecord % 60); + str_format(aTmp, sizeof(aTmp), "%s\n%s %s", g_Config.m_SvBroadcast, (GameServer()->m_pController->m_CurrentRecord)?aServerBest:"", (pData->m_BestTime)?aYourBest:""); GameServer()->SendBroadcast(aTmp, m_pPlayer->GetCID()); m_LastBroadcast = Server()->Tick(); diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index c99dcc753..13aa84c4a 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -339,6 +339,13 @@ void CGameContext::SendBroadcast(const char *pText, int ClientId) Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, ClientId); } +void CGameContext::SendRecord(int ClientId) { + CNetMsg_Sv_Record RecordsMsg; + RecordsMsg.m_PlayerTimeBest = Score()->PlayerData(ClientId)->m_BestTime * 100.0f;// + RecordsMsg.m_ServerTimeBest = m_pController->m_CurrentRecord * 100.0f;//TODO: finish this + Server()->SendPackMsg(&RecordsMsg, MSGFLAG_VITAL, ClientId); +} + // void CGameContext::StartVote(const char *pDesc, const char *pCommand) { @@ -961,10 +968,34 @@ void CGameContext::OnMessage(int MsgId, CUnpacker *pUnpacker, int ClientId) else if (MsgId == NETMSGTYPE_CL_ISDDRACE) { pPlayer->m_IsUsingDDRaceClient = true; + char aBuf[128]; - str_format(aBuf, sizeof(aBuf), "%d use DDRace Client", pPlayer->GetCID()); + str_format(aBuf, sizeof(aBuf), "%d use DDRace Client", ClientId); dbg_msg("DDRace", aBuf); + + //first update his teams state ((CGameControllerDDRace*)m_pController)->m_Teams.SendTeamsState(ClientId); + + //second give him records + SendRecord(ClientId); + + + //third give him others current time for table score + if(g_Config.m_SvHideScore) return; + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(m_apPlayers[i] && Score()->PlayerData(i)->m_CurrentTime > 0) + { + char aBuf[16]; + str_format(aBuf, sizeof(aBuf), "%.0f", Score()->PlayerData(i)->m_CurrentTime*100.0f); // damn ugly but the only way i know to do it + int TimeToSend; + sscanf(aBuf, "%d", &TimeToSend); + CNetMsg_Sv_PlayerTime Msg; + Msg.m_Time = TimeToSend; + Msg.m_Cid = i; + Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, ClientId); + } + } } else if(MsgId == NETMSGTYPE_CL_CHANGEINFO || MsgId == NETMSGTYPE_CL_STARTINFO) { diff --git a/src/game/server/gamecontext.h b/src/game/server/gamecontext.h index aeea03e5b..df4ef6fd6 100644 --- a/src/game/server/gamecontext.h +++ b/src/game/server/gamecontext.h @@ -249,6 +249,7 @@ public: void SendEmoticon(int ClientId, int Emoticon); void SendWeaponPickup(int ClientId, int Weapon); void SendBroadcast(const char *pText, int ClientId); + void SendRecord(int ClientId); static void SendChatResponse(const char *pLine, void *pUser); static void SendChatResponseAll(const char *pLine, void *pUser);