1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#include "broadcast.h"
4
5#include <engine/graphics.h>
6#include <engine/shared/config.h>
7#include <engine/textrender.h>
8
9#include <generated/protocol.h>
10
11#include <game/client/components/important_alert.h>
12#include <game/client/components/motd.h>
13#include <game/client/components/scoreboard.h>
14#include <game/client/gameclient.h>
15
16void CBroadcast::OnReset()
17{
18 m_BroadcastTick = 0;
19 m_BroadcastRenderOffset = -1.0f;
20 TextRender()->DeleteTextContainer(TextContainerIndex&: m_TextContainerIndex);
21}
22
23void CBroadcast::OnWindowResize()
24{
25 m_BroadcastRenderOffset = -1.0f;
26 TextRender()->DeleteTextContainer(TextContainerIndex&: m_TextContainerIndex);
27}
28
29void CBroadcast::OnRender()
30{
31 if(Client()->State() != IClient::STATE_ONLINE && Client()->State() != IClient::STATE_DEMOPLAYBACK)
32 return;
33
34 RenderServerBroadcast();
35}
36
37void CBroadcast::RenderServerBroadcast()
38{
39 if(GameClient()->m_Scoreboard.IsActive() ||
40 GameClient()->m_Motd.IsActive() ||
41 GameClient()->m_ImportantAlert.IsActive() ||
42 !g_Config.m_ClShowBroadcasts)
43 {
44 return;
45 }
46
47 const float SecondsRemaining = (m_BroadcastTick - Client()->GameTick(Conn: g_Config.m_ClDummy)) / (float)Client()->GameTickSpeed();
48 if(SecondsRemaining <= 0.0f)
49 {
50 TextRender()->DeleteTextContainer(TextContainerIndex&: m_TextContainerIndex);
51 return;
52 }
53
54 const float Height = 300.0f;
55 const float Width = Height * Graphics()->ScreenAspect();
56 Graphics()->MapScreen(TopLeftX: 0.0f, TopLeftY: 0.0f, BottomRightX: Width, BottomRightY: Height);
57
58 if(m_BroadcastRenderOffset < 0.0f)
59 m_BroadcastRenderOffset = Width / 2.0f - TextRender()->TextWidth(Size: 12.0f, pText: m_aBroadcastText, StrLength: -1, LineWidth: Width) / 2.0f;
60
61 if(!m_TextContainerIndex.Valid())
62 {
63 CTextCursor Cursor;
64 Cursor.SetPosition(vec2(m_BroadcastRenderOffset, 40.0f));
65 Cursor.m_FontSize = 12.0f;
66 Cursor.m_LineWidth = Width;
67 TextRender()->CreateTextContainer(TextContainerIndex&: m_TextContainerIndex, pCursor: &Cursor, pText: m_aBroadcastText);
68 }
69 if(m_TextContainerIndex.Valid())
70 {
71 const float Alpha = SecondsRemaining >= 1.0f ? 1.0f : SecondsRemaining;
72 ColorRGBA TextColor = TextRender()->DefaultTextColor();
73 TextColor.a *= Alpha;
74 ColorRGBA OutlineColor = TextRender()->DefaultTextOutlineColor();
75 OutlineColor.a *= Alpha;
76 TextRender()->RenderTextContainer(TextContainerIndex: m_TextContainerIndex, TextColor, TextOutlineColor: OutlineColor);
77 }
78}
79
80void CBroadcast::OnMessage(int MsgType, void *pRawMsg)
81{
82 if(MsgType == NETMSGTYPE_SV_BROADCAST)
83 {
84 const CNetMsg_Sv_Broadcast *pMsg = (CNetMsg_Sv_Broadcast *)pRawMsg;
85 DoBroadcast(pText: pMsg->m_pMessage);
86 }
87}
88
89void CBroadcast::DoBroadcast(const char *pText)
90{
91 str_copy(dst&: m_aBroadcastText, src: pText);
92 m_BroadcastTick = Client()->GameTick(Conn: g_Config.m_ClDummy) + Client()->GameTickSpeed() * 10;
93 m_BroadcastRenderOffset = -1.0f;
94 TextRender()->DeleteTextContainer(TextContainerIndex&: m_TextContainerIndex);
95
96 if(g_Config.m_ClPrintBroadcasts)
97 {
98 char aLine[sizeof(m_aBroadcastText)];
99 while((pText = str_next_token(str: pText, delim: "\n", buffer: aLine, buffer_size: sizeof(aLine))))
100 {
101 if(aLine[0] != '\0')
102 {
103 GameClient()->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "broadcast", pStr: aLine, PrintColor: color_cast<ColorRGBA>(hsl: ColorHSLA(g_Config.m_ClMessageHighlightColor)));
104 }
105 }
106 }
107}
108