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 <base/color.h>
6#include <base/log.h>
7#include <base/log_color.h>
8
9#include <engine/graphics.h>
10#include <engine/shared/config.h>
11#include <engine/textrender.h>
12
13#include <generated/protocol.h>
14
15#include <game/client/components/important_alert.h>
16#include <game/client/components/motd.h>
17#include <game/client/components/scoreboard.h>
18#include <game/client/gameclient.h>
19
20void CBroadcast::OnReset()
21{
22 m_BroadcastTick = 0;
23 m_BroadcastRenderOffset = -1.0f;
24 TextRender()->DeleteTextContainer(TextContainerIndex&: m_TextContainerIndex);
25}
26
27void CBroadcast::OnWindowResize()
28{
29 m_BroadcastRenderOffset = -1.0f;
30 TextRender()->DeleteTextContainer(TextContainerIndex&: m_TextContainerIndex);
31}
32
33void CBroadcast::OnRender()
34{
35 if(Client()->State() != IClient::STATE_ONLINE && Client()->State() != IClient::STATE_DEMOPLAYBACK)
36 return;
37
38 RenderServerBroadcast();
39}
40
41void CBroadcast::RenderServerBroadcast()
42{
43 if(GameClient()->m_Scoreboard.IsActive() ||
44 GameClient()->m_Motd.IsActive() ||
45 GameClient()->m_ImportantAlert.IsActive() ||
46 !g_Config.m_ClShowBroadcasts)
47 {
48 return;
49 }
50
51 const float SecondsRemaining = (m_BroadcastTick - Client()->GameTick(Conn: g_Config.m_ClDummy)) / (float)Client()->GameTickSpeed();
52 if(SecondsRemaining <= 0.0f)
53 {
54 TextRender()->DeleteTextContainer(TextContainerIndex&: m_TextContainerIndex);
55 return;
56 }
57
58 const float Height = 300.0f;
59 const float Width = Height * Graphics()->ScreenAspect();
60 Graphics()->MapScreenToSize(Width, Height);
61
62 if(m_BroadcastRenderOffset < 0.0f)
63 m_BroadcastRenderOffset = Width / 2.0f - TextRender()->TextWidth(Size: 12.0f, pText: m_aBroadcastText, StrLength: -1, LineWidth: Width) / 2.0f;
64
65 if(!m_TextContainerIndex.Valid())
66 {
67 CTextCursor Cursor;
68 Cursor.SetPosition(vec2(m_BroadcastRenderOffset, 40.0f));
69 Cursor.m_FontSize = 12.0f;
70 Cursor.m_LineWidth = Width;
71 TextRender()->CreateTextContainer(TextContainerIndex&: m_TextContainerIndex, pCursor: &Cursor, pText: m_aBroadcastText);
72 }
73 if(m_TextContainerIndex.Valid())
74 {
75 const float Alpha = SecondsRemaining >= 1.0f ? 1.0f : SecondsRemaining;
76 ColorRGBA TextColor = TextRender()->DefaultTextColor();
77 TextColor.a *= Alpha;
78 ColorRGBA OutlineColor = TextRender()->DefaultTextOutlineColor();
79 OutlineColor.a *= Alpha;
80 TextRender()->RenderTextContainer(TextContainerIndex: m_TextContainerIndex, TextColor, TextOutlineColor: OutlineColor);
81 }
82}
83
84void CBroadcast::OnMessage(int MsgType, void *pRawMsg)
85{
86 if(MsgType == NETMSGTYPE_SV_BROADCAST)
87 {
88 const CNetMsg_Sv_Broadcast *pMsg = (CNetMsg_Sv_Broadcast *)pRawMsg;
89 DoBroadcast(pText: pMsg->m_pMessage);
90 }
91}
92
93void CBroadcast::DoBroadcast(const char *pText)
94{
95 str_copy(dst&: m_aBroadcastText, src: pText);
96 m_BroadcastTick = Client()->GameTick(Conn: g_Config.m_ClDummy) + Client()->GameTickSpeed() * 10;
97 m_BroadcastRenderOffset = -1.0f;
98 TextRender()->DeleteTextContainer(TextContainerIndex&: m_TextContainerIndex);
99
100 if(g_Config.m_ClPrintBroadcasts)
101 {
102 const LOG_COLOR LogColor = color_cast<LOG_COLOR>(rgb: color_cast<ColorRGBA>(hsl: ColorHSLA(g_Config.m_ClMessageHighlightColor)));
103 char aLine[sizeof(m_aBroadcastText)];
104 while((pText = str_next_token(str: pText, delim: "\n", buffer: aLine, buffer_size: sizeof(aLine))))
105 {
106 if(aLine[0] != '\0')
107 {
108 log_info_color(LogColor, "broadcast", "%s", aLine);
109 }
110 }
111 }
112}
113