mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Add multi view
This commit is contained in:
parent
422ff844b8
commit
d16fb877dc
|
@ -31,7 +31,7 @@ float CCamera::ZoomProgress(float CurrentTime) const
|
|||
void CCamera::ScaleZoom(float Factor)
|
||||
{
|
||||
float CurrentTarget = m_Zooming ? m_ZoomSmoothingTarget : m_Zoom;
|
||||
ChangeZoom(CurrentTarget * Factor);
|
||||
ChangeZoom(CurrentTarget * Factor, g_Config.m_ClSmoothZoomTime);
|
||||
}
|
||||
|
||||
float CCamera::MaxZoomLevel()
|
||||
|
@ -44,7 +44,7 @@ float CCamera::MinZoomLevel()
|
|||
return 0.01f;
|
||||
}
|
||||
|
||||
void CCamera::ChangeZoom(float Target)
|
||||
void CCamera::ChangeZoom(float Target, int Smoothness)
|
||||
{
|
||||
if(Target > MaxZoomLevel() || Target < MinZoomLevel())
|
||||
{
|
||||
|
@ -64,7 +64,7 @@ void CCamera::ChangeZoom(float Target)
|
|||
m_ZoomSmoothingTarget = Target;
|
||||
m_ZoomSmoothing = CCubicBezier::With(Current, Derivative, 0, m_ZoomSmoothingTarget);
|
||||
m_ZoomSmoothingStart = Now;
|
||||
m_ZoomSmoothingEnd = Now + (float)g_Config.m_ClSmoothZoomTime / 1000;
|
||||
m_ZoomSmoothingEnd = Now + (float)Smoothness / 1000;
|
||||
|
||||
m_Zooming = true;
|
||||
}
|
||||
|
@ -198,6 +198,9 @@ void CCamera::ConZoomPlus(IConsole::IResult *pResult, void *pUserData)
|
|||
if(pSelf->m_pClient->m_Snap.m_SpecInfo.m_Active || pSelf->GameClient()->m_GameInfo.m_AllowZoom || pSelf->Client()->State() == IClient::STATE_DEMOPLAYBACK)
|
||||
{
|
||||
pSelf->ScaleZoom(ZoomStep);
|
||||
|
||||
if(pSelf->GameClient()->m_MultiViewActivated)
|
||||
pSelf->GameClient()->m_MultiViewPersonalZoom++;
|
||||
}
|
||||
}
|
||||
void CCamera::ConZoomMinus(IConsole::IResult *pResult, void *pUserData)
|
||||
|
@ -206,12 +209,19 @@ void CCamera::ConZoomMinus(IConsole::IResult *pResult, void *pUserData)
|
|||
if(pSelf->m_pClient->m_Snap.m_SpecInfo.m_Active || pSelf->GameClient()->m_GameInfo.m_AllowZoom || pSelf->Client()->State() == IClient::STATE_DEMOPLAYBACK)
|
||||
{
|
||||
pSelf->ScaleZoom(1 / ZoomStep);
|
||||
|
||||
if(pSelf->GameClient()->m_MultiViewActivated)
|
||||
pSelf->GameClient()->m_MultiViewPersonalZoom--;
|
||||
}
|
||||
}
|
||||
void CCamera::ConZoom(IConsole::IResult *pResult, void *pUserData)
|
||||
{
|
||||
CCamera *pSelf = (CCamera *)pUserData;
|
||||
float TargetLevel = pResult->NumArguments() ? pResult->GetFloat(0) : g_Config.m_ClDefaultZoom;
|
||||
((CCamera *)pUserData)->ChangeZoom(std::pow(ZoomStep, TargetLevel - 10));
|
||||
pSelf->ChangeZoom(std::pow(ZoomStep, TargetLevel - 10), g_Config.m_ClSmoothZoomTime);
|
||||
|
||||
if(pSelf->GameClient()->m_MultiViewActivated)
|
||||
pSelf->GameClient()->m_MultiViewPersonalZoom = 0;
|
||||
}
|
||||
void CCamera::ConSetView(IConsole::IResult *pResult, void *pUserData)
|
||||
{
|
||||
|
@ -221,3 +231,8 @@ void CCamera::ConSetView(IConsole::IResult *pResult, void *pUserData)
|
|||
clamp(pResult->GetInteger(0) * 32.0f, 200.0f, pSelf->Collision()->GetWidth() * 32 - 200.0f),
|
||||
clamp(pResult->GetInteger(1) * 32.0f, 200.0f, pSelf->Collision()->GetWidth() * 32 - 200.0f));
|
||||
}
|
||||
|
||||
void CCamera::SetZoom(float Target, int Smoothness)
|
||||
{
|
||||
ChangeZoom(Target, Smoothness);
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ class CCamera : public CComponent
|
|||
float m_ZoomSmoothingEnd;
|
||||
|
||||
void ScaleZoom(float Factor);
|
||||
void ChangeZoom(float Target);
|
||||
void ChangeZoom(float Target, int Smoothness);
|
||||
float ZoomProgress(float CurrentTime) const;
|
||||
|
||||
float MinZoomLevel();
|
||||
|
@ -52,6 +52,8 @@ public:
|
|||
virtual void OnConsoleInit() override;
|
||||
virtual void OnReset() override;
|
||||
|
||||
void SetZoom(float Target, int Smoothness);
|
||||
|
||||
private:
|
||||
static void ConZoomPlus(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConZoomMinus(IConsole::IResult *pResult, void *pUserData);
|
||||
|
|
|
@ -106,7 +106,7 @@ void CHud::RenderGameTimer()
|
|||
}
|
||||
else if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_RACETIME)
|
||||
{
|
||||
//The Warmup timer is negative in this case to make sure that incompatible clients will not see a warmup timer
|
||||
// The Warmup timer is negative in this case to make sure that incompatible clients will not see a warmup timer
|
||||
Time = (Client()->GameTick(g_Config.m_ClDummy) + m_pClient->m_Snap.m_pGameInfoObj->m_WarmupTimer) / Client()->GameTickSpeed();
|
||||
}
|
||||
else
|
||||
|
@ -1474,7 +1474,7 @@ void CHud::RenderSpectatorHud()
|
|||
|
||||
// draw the text
|
||||
char aBuf[128];
|
||||
str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Spectate"), m_pClient->m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW ? m_pClient->m_aClients[m_pClient->m_Snap.m_SpecInfo.m_SpectatorID].m_aName : Localize("Free-View"));
|
||||
str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Spectate"), GameClient()->m_MultiViewActivated ? Localize("Multi-View") : m_pClient->m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW ? m_pClient->m_aClients[m_pClient->m_Snap.m_SpecInfo.m_SpectatorID].m_aName : Localize("Free-View"));
|
||||
TextRender()->Text(m_Width - 174.0f, m_Height - 15.0f + (15.f - 8.f) / 2.f, 8.0f, aBuf, -1.0f);
|
||||
}
|
||||
|
||||
|
@ -1527,7 +1527,11 @@ void CHud::OnRender()
|
|||
{
|
||||
RenderAmmoHealthAndArmor(&m_pClient->m_Snap.m_aCharacters[SpectatorID].m_Cur);
|
||||
}
|
||||
if(SpectatorID != SPEC_FREEVIEW && m_pClient->m_Snap.m_aCharacters[SpectatorID].m_HasExtendedData && g_Config.m_ClShowhudDDRace && GameClient()->m_GameInfo.m_HudDDRace)
|
||||
if(SpectatorID != SPEC_FREEVIEW &&
|
||||
m_pClient->m_Snap.m_aCharacters[SpectatorID].m_HasExtendedData &&
|
||||
g_Config.m_ClShowhudDDRace &&
|
||||
(!GameClient()->m_MultiViewActivated || GameClient()->m_MultiViewShowHud) &&
|
||||
GameClient()->m_GameInfo.m_HudDDRace)
|
||||
{
|
||||
RenderPlayerState(SpectatorID);
|
||||
}
|
||||
|
|
|
@ -149,6 +149,17 @@ void CSpectator::ConSpectateClosest(IConsole::IResult *pResult, void *pUserData)
|
|||
pSelf->Spectate(NewSpectatorID);
|
||||
}
|
||||
|
||||
void CSpectator::ConMultiView(IConsole::IResult *pResult, void *pUserData)
|
||||
{
|
||||
CSpectator *pSelf = (CSpectator *)pUserData;
|
||||
int Input = pResult->GetInteger(0);
|
||||
|
||||
if(Input == -1)
|
||||
std::fill(std::begin(pSelf->GameClient()->m_aMultiViewId), std::end(pSelf->GameClient()->m_aMultiViewId), false); // remove everyone from multiview
|
||||
else if(Input < MAX_CLIENTS && Input >= 0)
|
||||
pSelf->GameClient()->m_aMultiViewId[Input] = !pSelf->GameClient()->m_aMultiViewId[Input]; // activate or deactivate one player from multiview
|
||||
}
|
||||
|
||||
CSpectator::CSpectator()
|
||||
{
|
||||
OnReset();
|
||||
|
@ -162,6 +173,7 @@ void CSpectator::OnConsoleInit()
|
|||
Console()->Register("spectate_next", "", CFGFLAG_CLIENT, ConSpectateNext, this, "Spectate the next player");
|
||||
Console()->Register("spectate_previous", "", CFGFLAG_CLIENT, ConSpectatePrevious, this, "Spectate the previous player");
|
||||
Console()->Register("spectate_closest", "", CFGFLAG_CLIENT, ConSpectateClosest, this, "Spectate the closest player");
|
||||
Console()->Register("spectate_multiview", "i[id]", CFGFLAG_CLIENT, ConMultiView, this, "Add/remove Client-IDs to spectate them exclusivly (-1 to reset)");
|
||||
}
|
||||
|
||||
bool CSpectator::OnCursorMove(float x, float y, IInput::ECursorType CursorType)
|
||||
|
@ -186,7 +198,12 @@ void CSpectator::OnRender()
|
|||
if(m_WasActive)
|
||||
{
|
||||
if(m_SelectedSpectatorID != NO_SELECTION)
|
||||
{
|
||||
if(m_SelectedSpectatorID != MULTI_VIEW)
|
||||
Spectate(m_SelectedSpectatorID);
|
||||
|
||||
GameClient()->m_MultiViewActivated = m_SelectedSpectatorID == MULTI_VIEW;
|
||||
}
|
||||
m_WasActive = false;
|
||||
}
|
||||
return;
|
||||
|
@ -213,6 +230,7 @@ void CSpectator::OnRender()
|
|||
float TeeSizeMod = 1.0f;
|
||||
float RoundRadius = 30.0f;
|
||||
bool Selected = false;
|
||||
bool MultiViewSelected = false;
|
||||
int TotalPlayers = 0;
|
||||
int PerLine = 8;
|
||||
float BoxMove = -10.0f;
|
||||
|
@ -253,34 +271,48 @@ void CSpectator::OnRender()
|
|||
if((Client()->State() == IClient::STATE_DEMOPLAYBACK && m_pClient->m_DemoSpecID == SPEC_FREEVIEW) ||
|
||||
(Client()->State() != IClient::STATE_DEMOPLAYBACK && m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SPEC_FREEVIEW))
|
||||
{
|
||||
Graphics()->DrawRect(Width / 2.0f - (ObjWidth - 20.0f), Height / 2.0f - 280.0f, 270.0f, 60.0f, ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f), IGraphics::CORNER_ALL, 20.0f);
|
||||
Graphics()->DrawRect(Width / 2.0f - (ObjWidth - 20.0f), Height / 2.0f - 280.0f, ((ObjWidth * 2.0f) / 3.0f) - 40.0f, 60.0f, ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f), IGraphics::CORNER_ALL, 20.0f);
|
||||
}
|
||||
|
||||
if(GameClient()->m_MultiViewActivated)
|
||||
{
|
||||
Graphics()->DrawRect(Width / 2.0f - (ObjWidth - 20.0f) + (ObjWidth * 2.0f / 3.0f), Height / 2.0f - 280.0f, ((ObjWidth * 2.0f) / 3.0f) - 40.0f, 60.0f, ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f), IGraphics::CORNER_ALL, 20.0f);
|
||||
}
|
||||
|
||||
if(Client()->State() == IClient::STATE_DEMOPLAYBACK && m_pClient->m_Snap.m_LocalClientID >= 0 && m_pClient->m_DemoSpecID == SPEC_FOLLOW)
|
||||
{
|
||||
Graphics()->DrawRect(Width / 2.0f - (ObjWidth - 310.0f), Height / 2.0f - 280.0f, 270.0f, 60.0f, ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f), IGraphics::CORNER_ALL, 20.0f);
|
||||
Graphics()->DrawRect(Width / 2.0f - (ObjWidth - 20.0f) + (ObjWidth * 2.0f * 2.0f / 3.0f), Height / 2.0f - 280.0f, ((ObjWidth * 2.0f) / 3.0f) - 40.0f, 60.0f, ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f), IGraphics::CORNER_ALL, 20.0f);
|
||||
}
|
||||
|
||||
if(m_SelectorMouse.x >= -(ObjWidth - 20.0f) && m_SelectorMouse.x <= -(ObjWidth - 290 + 10.0f) &&
|
||||
if(m_SelectorMouse.x >= -(ObjWidth - 20.0f) && m_SelectorMouse.x <= -(ObjWidth - 20.0f) + ((ObjWidth * 2.0f) / 3.0f) - 40.0f &&
|
||||
m_SelectorMouse.y >= -280.0f && m_SelectorMouse.y <= -220.0f)
|
||||
{
|
||||
m_SelectedSpectatorID = SPEC_FREEVIEW;
|
||||
Selected = true;
|
||||
}
|
||||
TextRender()->TextColor(1.0f, 1.0f, 1.0f, Selected ? 1.0f : 0.5f);
|
||||
TextRender()->Text(Width / 2.0f - (ObjWidth - 60.0f), Height / 2.0f - 280.f + (60.f - BigFontSize) / 2.f, BigFontSize, Localize("Free-View"), -1.0f);
|
||||
TextRender()->Text(Width / 2.0f - (ObjWidth - 40.0f), Height / 2.0f - 280.f + (60.f - BigFontSize) / 2.f, BigFontSize, Localize("Free-View"), -1.0f);
|
||||
|
||||
if(m_SelectorMouse.x >= -(ObjWidth - 20.0f) + (ObjWidth * 2.0f / 3.0f) && m_SelectorMouse.x <= -(ObjWidth - 20.0f) + (ObjWidth * 2.0f / 3.0f) + ((ObjWidth * 2.0f) / 3.0f) - 40.0f &&
|
||||
m_SelectorMouse.y >= -280.0f && m_SelectorMouse.y <= -220.0f)
|
||||
{
|
||||
m_SelectedSpectatorID = MULTI_VIEW;
|
||||
MultiViewSelected = true;
|
||||
}
|
||||
TextRender()->TextColor(1.0f, 1.0f, 1.0f, MultiViewSelected ? 1.0f : 0.5f);
|
||||
TextRender()->Text(Width / 2.0f - (ObjWidth - 40.0f) + (ObjWidth * 2.0f / 3.0f), Height / 2.0f - 280.f + (60.f - BigFontSize) / 2.f, BigFontSize, Localize("Multi-View"), -1.0f);
|
||||
|
||||
if(Client()->State() == IClient::STATE_DEMOPLAYBACK && m_pClient->m_Snap.m_LocalClientID >= 0)
|
||||
{
|
||||
Selected = false;
|
||||
if(m_SelectorMouse.x > -(ObjWidth - 290.0f) && m_SelectorMouse.x <= -(ObjWidth - 590.0f) &&
|
||||
if(m_SelectorMouse.x >= -(ObjWidth - 20.0f) + (ObjWidth * 2.0f * 2.0f / 3.0f) && m_SelectorMouse.x <= -(ObjWidth - 20.0f) + (ObjWidth * 2.0f * 2.0f / 3.0f) + ((ObjWidth * 2.0f) / 3.0f) - 40.0f &&
|
||||
m_SelectorMouse.y >= -280.0f && m_SelectorMouse.y <= -220.0f)
|
||||
{
|
||||
m_SelectedSpectatorID = SPEC_FOLLOW;
|
||||
Selected = true;
|
||||
}
|
||||
TextRender()->TextColor(1.0f, 1.0f, 1.0f, Selected ? 1.0f : 0.5f);
|
||||
TextRender()->Text(Width / 2.0f - (ObjWidth - 350.0f), Height / 2.0f - 280.0f + (60.f - BigFontSize) / 2.f, BigFontSize, Localize("Follow"), -1.0f);
|
||||
TextRender()->Text(Width / 2.0f - (ObjWidth - 40.0f) + (ObjWidth * 2.0f * 2.0f / 3.0f), Height / 2.0f - 280.0f + (60.f - BigFontSize) / 2.f, BigFontSize, Localize("Follow"), -1.0f);
|
||||
}
|
||||
|
||||
float x = -(ObjWidth - 35.0f), y = StartY;
|
||||
|
|
|
@ -10,6 +10,7 @@ class CSpectator : public CComponent
|
|||
{
|
||||
enum
|
||||
{
|
||||
MULTI_VIEW = -4,
|
||||
NO_SELECTION = -3,
|
||||
};
|
||||
|
||||
|
@ -30,6 +31,7 @@ class CSpectator : public CComponent
|
|||
static void ConSpectateNext(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConSpectatePrevious(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConSpectateClosest(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConMultiView(IConsole::IResult *pResult, void *pUserData);
|
||||
|
||||
public:
|
||||
CSpectator();
|
||||
|
|
|
@ -604,7 +604,11 @@ void CGameClient::UpdatePositions()
|
|||
// spectator position
|
||||
if(m_Snap.m_SpecInfo.m_Active)
|
||||
{
|
||||
if(Client()->State() == IClient::STATE_DEMOPLAYBACK && m_DemoSpecID != SPEC_FOLLOW && m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW)
|
||||
if(m_MultiViewActivated)
|
||||
{
|
||||
HandleMultiView();
|
||||
}
|
||||
else if(Client()->State() == IClient::STATE_DEMOPLAYBACK && m_DemoSpecID != SPEC_FOLLOW && m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW)
|
||||
{
|
||||
m_Snap.m_SpecInfo.m_Position = mix(
|
||||
vec2(m_Snap.m_aCharacters[m_Snap.m_SpecInfo.m_SpectatorID].m_Prev.m_X, m_Snap.m_aCharacters[m_Snap.m_SpecInfo.m_SpectatorID].m_Prev.m_Y),
|
||||
|
@ -623,11 +627,28 @@ void CGameClient::UpdatePositions()
|
|||
}
|
||||
}
|
||||
|
||||
if(!m_MultiViewActivated && m_MultiView.m_IsInit)
|
||||
ResetMultiView();
|
||||
|
||||
UpdateRenderedCharacters();
|
||||
}
|
||||
|
||||
void CGameClient::OnRender()
|
||||
{
|
||||
// check if multi view got activated
|
||||
if(!m_MultiView.m_IsInit && m_MultiViewActivated)
|
||||
{
|
||||
int TeamId = 0;
|
||||
if(m_Snap.m_SpecInfo.m_SpectatorID >= 0)
|
||||
TeamId = m_Teams.Team(m_Snap.m_SpecInfo.m_SpectatorID);
|
||||
|
||||
if(!InitMultiViewFromFreeview(TeamId))
|
||||
{
|
||||
dbg_msg("MultiView", "No players found to spectate");
|
||||
m_MultiViewActivated = false;
|
||||
}
|
||||
}
|
||||
|
||||
// update the local character and spectate position
|
||||
UpdatePositions();
|
||||
|
||||
|
@ -843,6 +864,18 @@ void CGameClient::OnMessage(int MsgId, CUnpacker *pUnpacker, int Conn, bool Dumm
|
|||
pChar->ResetPrediction();
|
||||
m_GameWorld.ReleaseHooked(pMsg->m_Victim);
|
||||
}
|
||||
|
||||
// if we are spectating a static id set (team 0) and somebody killed, we remove him from the list
|
||||
if(IsMultiViewIdSet() && m_aMultiViewId[pMsg->m_Victim] && !m_aClients[pMsg->m_Victim].m_Spec)
|
||||
{
|
||||
// is multi view even activated and we are not spectating a solo guy
|
||||
if(m_MultiViewActivated && !m_MultiView.m_Solo && m_MultiView.m_Team == 0)
|
||||
m_aMultiViewId[pMsg->m_Victim] = false;
|
||||
|
||||
// if everyone of a team killed, we have no ids to spectate anymore, so we disable multi view
|
||||
if(!IsMultiViewIdSet())
|
||||
m_MultiViewActivated = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1666,7 +1699,17 @@ void CGameClient::OnNewSnapshot()
|
|||
m_aDDRaceMsgSent[i] = true;
|
||||
}
|
||||
|
||||
if(m_aShowOthers[g_Config.m_ClDummy] == SHOW_OTHERS_NOT_SET || m_aShowOthers[g_Config.m_ClDummy] != g_Config.m_ClShowOthers)
|
||||
if(m_MultiViewActivated)
|
||||
{
|
||||
// dont show other teams while spectating in multi view
|
||||
CNetMsg_Cl_ShowOthers Msg;
|
||||
Msg.m_Show = SHOW_OTHERS_ONLY_TEAM;
|
||||
Client()->SendPackMsgActive(&Msg, MSGFLAG_VITAL);
|
||||
|
||||
// update state
|
||||
m_aShowOthers[g_Config.m_ClDummy] = SHOW_OTHERS_ONLY_TEAM;
|
||||
}
|
||||
else if(m_aShowOthers[g_Config.m_ClDummy] == SHOW_OTHERS_NOT_SET || m_aShowOthers[g_Config.m_ClDummy] != g_Config.m_ClShowOthers)
|
||||
{
|
||||
{
|
||||
CNetMsg_Cl_ShowOthers Msg;
|
||||
|
@ -3350,3 +3393,214 @@ void CGameClient::SnapCollectEntities()
|
|||
m_vSnapEntities.push_back({Ent.m_Item, Ent.m_pData, pDataEx});
|
||||
}
|
||||
}
|
||||
|
||||
void CGameClient::HandleMultiView()
|
||||
{
|
||||
bool IsTeamZero = IsMultiViewIdSet();
|
||||
bool Init = false;
|
||||
int AmountPlayers = 0;
|
||||
vec2 Minpos, Maxpos;
|
||||
float TmpVel = 0.0f;
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
// look at players who are vanished
|
||||
if(m_MultiView.m_aVanish[i])
|
||||
{
|
||||
// not in freeze anymore and the delay is over
|
||||
if(m_MultiView.m_aLastFreeze[i] + 6.0f <= Client()->LocalTime() && m_aClients[i].m_FreezeEnd == 0)
|
||||
{
|
||||
m_MultiView.m_aVanish[i] = false;
|
||||
m_MultiView.m_aLastFreeze[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// we look at team 0 and the player is not in the spec list
|
||||
if(IsTeamZero && !m_aMultiViewId[i])
|
||||
continue;
|
||||
|
||||
// player is vanished
|
||||
if(m_MultiView.m_aVanish[i])
|
||||
continue;
|
||||
|
||||
// the player is not in the team we are spectating
|
||||
if(m_Teams.Team(i) != m_MultiView.m_Team)
|
||||
continue;
|
||||
|
||||
vec2 PlayerPos;
|
||||
if(m_Snap.m_aCharacters[i].m_Active)
|
||||
PlayerPos = vec2(m_aClients[i].m_RenderPos.x, m_aClients[i].m_RenderPos.y);
|
||||
else if(m_aClients[i].m_Spec) // tee is in spec
|
||||
PlayerPos = m_aClients[i].m_SpecChar;
|
||||
else
|
||||
continue;
|
||||
|
||||
// player is far away and frozen
|
||||
if(distance(m_MultiView.m_OldPos, PlayerPos) > 1100 && m_aClients[i].m_FreezeEnd != 0)
|
||||
{
|
||||
// check if the player is frozen for more than 3 seconds, if so vanish him
|
||||
if(m_MultiView.m_aLastFreeze[i] == 0.0f)
|
||||
m_MultiView.m_aLastFreeze[i] = Client()->LocalTime();
|
||||
else if(m_MultiView.m_aLastFreeze[i] + 3.0f <= Client()->LocalTime())
|
||||
m_MultiView.m_aVanish[i] = true;
|
||||
}
|
||||
else if(m_MultiView.m_aLastFreeze[i] != 0)
|
||||
m_MultiView.m_aLastFreeze[i] = 0;
|
||||
|
||||
// set the minimum and maximum position
|
||||
if(!Init)
|
||||
{
|
||||
Minpos = PlayerPos;
|
||||
Maxpos = PlayerPos;
|
||||
Init = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Minpos.x = std::min(Minpos.x, PlayerPos.x);
|
||||
Maxpos.x = std::max(Maxpos.x, PlayerPos.x);
|
||||
Minpos.y = std::min(Minpos.y, PlayerPos.y);
|
||||
Maxpos.y = std::max(Maxpos.y, PlayerPos.y);
|
||||
}
|
||||
|
||||
// sum up the velocity of all players we are spectating
|
||||
const CNetObj_Character &CurrentCharacter = m_Snap.m_aCharacters[i].m_Cur;
|
||||
TmpVel += (length(vec2(CurrentCharacter.m_VelX / 256.0f, CurrentCharacter.m_VelY / 256.0f)) * 50) / 32.0f;
|
||||
AmountPlayers++;
|
||||
}
|
||||
|
||||
// if we have found no players, we disable multi view
|
||||
if(AmountPlayers == 0)
|
||||
{
|
||||
m_MultiViewActivated = false;
|
||||
return;
|
||||
}
|
||||
|
||||
vec2 TargetPos = vec2((Minpos.x + Maxpos.x) / 2.0f, (Minpos.y + Maxpos.y) / 2.0f);
|
||||
// dont hide the position hud if its only one player
|
||||
m_MultiViewShowHud = AmountPlayers == 1;
|
||||
// get the average velocity
|
||||
float AvgVel = clamp(TmpVel / AmountPlayers ? TmpVel / (float)AmountPlayers : 0.0f, 0.0f, 1000.0f);
|
||||
|
||||
if(m_MultiView.m_OldPersonalZoom == m_MultiViewPersonalZoom)
|
||||
m_Camera.SetZoom(CalculateMultiViewZoom(Minpos, Maxpos, AvgVel), g_Config.m_ClMultiViewZoomSmoothness);
|
||||
else
|
||||
m_Camera.SetZoom(CalculateMultiViewZoom(Minpos, Maxpos, AvgVel), 50);
|
||||
|
||||
m_Snap.m_SpecInfo.m_Position = m_MultiView.m_OldPos + ((TargetPos - m_MultiView.m_OldPos) * CalculateMultiViewMultiplier(TargetPos));
|
||||
m_MultiView.m_OldPos = m_Snap.m_SpecInfo.m_Position;
|
||||
m_Snap.m_SpecInfo.m_UsePosition = true;
|
||||
}
|
||||
|
||||
bool CGameClient::InitMultiViewFromFreeview(int Team)
|
||||
{
|
||||
float Width, Height;
|
||||
CleanMultiViewIds();
|
||||
m_MultiView.m_IsInit = true;
|
||||
|
||||
// get the current view coordinates
|
||||
RenderTools()->CalcScreenParams(Graphics()->ScreenAspect(), m_Camera.m_Zoom, &Width, &Height);
|
||||
vec2 AxisX = vec2(m_Camera.m_Center.x - (Width / 2), m_Camera.m_Center.x + (Width / 2));
|
||||
vec2 AxisY = vec2(m_Camera.m_Center.y - (Height / 2), m_Camera.m_Center.y + (Height / 2));
|
||||
|
||||
m_MultiView.m_Team = Team;
|
||||
|
||||
if(Team > 0)
|
||||
return true; // spectating a team, not necessary to search the players in view
|
||||
else
|
||||
{
|
||||
int Count = 0;
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
vec2 PlayerPos;
|
||||
|
||||
// get the position of the player
|
||||
if(m_Snap.m_aCharacters[i].m_Active)
|
||||
PlayerPos = vec2(m_Snap.m_aCharacters[i].m_Cur.m_X, m_Snap.m_aCharacters[i].m_Cur.m_Y);
|
||||
else if(m_aClients[i].m_Spec)
|
||||
PlayerPos = m_aClients[i].m_SpecChar;
|
||||
else
|
||||
continue;
|
||||
|
||||
// player isnt in the correct team
|
||||
if(m_Teams.Team(i) != Team)
|
||||
continue;
|
||||
|
||||
if(PlayerPos.x != 0 && PlayerPos.y != 0)
|
||||
{
|
||||
// is the player in view
|
||||
if(PlayerPos.x > AxisX.x && PlayerPos.x < AxisX.y && PlayerPos.y > AxisY.x && PlayerPos.y < AxisY.y)
|
||||
{
|
||||
m_aMultiViewId[i] = true;
|
||||
Count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we are spectating only one player
|
||||
m_MultiView.m_Solo = Count == 1;
|
||||
|
||||
// found players to spectate
|
||||
return Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
float CGameClient::CalculateMultiViewMultiplier(vec2 CameraPos)
|
||||
{
|
||||
float MaxCameraDist = 200.0f;
|
||||
float MinCameraDist = 20.0f;
|
||||
float MaxVel = 0.1f;
|
||||
float MinVel = 0.007f;
|
||||
|
||||
float CurrentCameraDistance = distance(m_MultiView.m_OldPos, CameraPos);
|
||||
|
||||
return clamp(MapValue(MaxCameraDist, MinCameraDist, MaxVel, MinVel, CurrentCameraDistance), MinVel, 1.0f);
|
||||
}
|
||||
|
||||
float CGameClient::CalculateMultiViewZoom(vec2 MinPos, vec2 MaxPos, float Vel)
|
||||
{
|
||||
float Ratio = Graphics()->ScreenAspect();
|
||||
float ZoomX = 0.0f, ZoomY;
|
||||
|
||||
// only calc two axis if the aspect ratio is not 1:1
|
||||
if(Ratio != 1.0f)
|
||||
ZoomX = ZoomX = (0.001309f - 0.000328 * Ratio) * (MaxPos.x - MinPos.x) + (0.741413f - 0.032959 * Ratio);
|
||||
|
||||
// calculate the according zoom with linear function
|
||||
ZoomY = ZoomY = 0.001309f * (MaxPos.y - MinPos.y) + 0.741413f;
|
||||
// choose the highest zoom
|
||||
float Zoom = std::max(ZoomX, ZoomY);
|
||||
// zoom out to maximum 10 percent of the current zoom for 70 velocity
|
||||
float Diff = clamp(MapValue(70.0f, 15.0f, Zoom * 0.10f, 0.0f, Vel), 0.0f, Zoom * 0.10f);
|
||||
// zoom should stay inbetween 1.1 and 20.0
|
||||
Zoom = clamp(Zoom + Diff, 1.1f, 20.0f);
|
||||
// add the user preference
|
||||
Zoom -= (Zoom * 0.075f) * m_MultiViewPersonalZoom;
|
||||
m_MultiView.m_OldPersonalZoom = m_MultiViewPersonalZoom;
|
||||
|
||||
return Zoom;
|
||||
}
|
||||
|
||||
float CGameClient::MapValue(float MaxValue, float MinValue, float MaxRange, float MinRange, float Value)
|
||||
{
|
||||
return (MaxRange - MinRange) / (MaxValue - MinValue) * (Value - MinValue) + MinRange;
|
||||
}
|
||||
|
||||
void CGameClient::ResetMultiView()
|
||||
{
|
||||
m_MultiView.m_Solo = false;
|
||||
m_MultiView.m_IsInit = false;
|
||||
m_MultiViewActivated = false;
|
||||
m_MultiViewPersonalZoom = 0;
|
||||
}
|
||||
|
||||
void CGameClient::CleanMultiViewIds()
|
||||
{
|
||||
std::fill(std::begin(m_aMultiViewId), std::end(m_aMultiViewId), false);
|
||||
std::fill(std::begin(m_MultiView.m_aLastFreeze), std::end(m_MultiView.m_aLastFreeze), 0.0f);
|
||||
std::fill(std::begin(m_MultiView.m_aVanish), std::end(m_MultiView.m_aVanish), false);
|
||||
}
|
||||
|
||||
bool CGameClient::IsMultiViewIdSet()
|
||||
{
|
||||
return std::any_of(std::begin(m_aMultiViewId), std::end(m_aMultiViewId), [](bool IsSet) { return IsSet; });
|
||||
}
|
||||
|
|
|
@ -698,6 +698,11 @@ public:
|
|||
|
||||
const std::vector<CSnapEntities> &SnapEntities() { return m_vSnapEntities; }
|
||||
|
||||
int m_MultiViewPersonalZoom;
|
||||
bool m_MultiViewShowHud;
|
||||
bool m_MultiViewActivated;
|
||||
bool m_aMultiViewId[MAX_CLIENTS];
|
||||
|
||||
private:
|
||||
std::vector<CSnapEntities> m_vSnapEntities;
|
||||
void SnapCollectEntities();
|
||||
|
@ -726,6 +731,28 @@ private:
|
|||
float m_LastZoom;
|
||||
float m_LastScreenAspect;
|
||||
bool m_LastDummyConnected;
|
||||
|
||||
void ResetMultiView();
|
||||
void HandleMultiView();
|
||||
bool IsMultiViewIdSet();
|
||||
void CleanMultiViewIds();
|
||||
bool InitMultiViewFromFreeview(int Team);
|
||||
float CalculateMultiViewMultiplier(vec2 CameraPos);
|
||||
float CalculateMultiViewZoom(vec2 MinPos, vec2 MaxPos, float Vel);
|
||||
float MapValue(float MaxValue, float MinValue, float MaxRange, float MinRange, float Value);
|
||||
|
||||
struct SMultiView
|
||||
{
|
||||
bool m_Solo;
|
||||
bool m_IsInit;
|
||||
bool m_aVanish[MAX_CLIENTS];
|
||||
vec2 m_OldPos;
|
||||
int m_Team;
|
||||
int m_OldPersonalZoom;
|
||||
float m_aLastFreeze[MAX_CLIENTS];
|
||||
};
|
||||
|
||||
SMultiView m_MultiView;
|
||||
};
|
||||
|
||||
ColorRGBA CalculateNameColor(ColorHSLA TextColorHSL);
|
||||
|
|
|
@ -90,6 +90,8 @@ MACRO_CONFIG_INT(ClDyncamFollowFactor, cl_dyncam_follow_factor, 60, 0, 200, CFGF
|
|||
MACRO_CONFIG_INT(ClDyncamSmoothness, cl_dyncam_smoothness, 0, 0, 100, CFGFLAG_CLIENT | CFGFLAG_SAVE | CFGFLAG_INSENSITIVE, "Transition amount of the camera movement, 0=instant, 100=slow and smooth")
|
||||
MACRO_CONFIG_INT(ClDyncamStabilizing, cl_dyncam_stabilizing, 0, 0, 100, CFGFLAG_CLIENT | CFGFLAG_SAVE | CFGFLAG_INSENSITIVE, "Amount of camera slowdown during fast cursor movement. High value can cause delay in camera movement")
|
||||
|
||||
MACRO_CONFIG_INT(ClMultiViewZoomSmoothness, cl_multi_view_zoom_smoothness, 700, 0, 5000, CFGFLAG_CLIENT, "Set the smoothness of the multi view zoom (in ms, higher = slower)")
|
||||
|
||||
MACRO_CONFIG_INT(EdSmoothZoomTime, ed_smooth_zoom_time, 250, 0, 5000, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Time of smooth zoom animation in the editor in ms (0 for off)")
|
||||
MACRO_CONFIG_INT(EdLimitMaxZoomLevel, ed_limit_max_zoom_level, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Specifies, if zooming in the editor should be limited or not (0 = no limit)")
|
||||
MACRO_CONFIG_INT(EdZoomTarget, ed_zoom_target, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Zoom to the current mouse target")
|
||||
|
|
Loading…
Reference in a new issue