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 <engine/graphics.h>
4#include <engine/shared/config.h>
5#include <engine/textrender.h>
6
7#include <game/generated/protocol.h>
8
9#include <game/client/gameclient.h>
10
11#include <game/client/components/motd.h>
12#include <game/client/components/scoreboard.h>
13
14#include "broadcast.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(m_pClient->m_Scoreboard.Active() || m_pClient->m_Motd.IsActive() || !g_Config.m_ClShowBroadcasts)
40 return;
41 const float SecondsRemaining = (m_BroadcastTick - Client()->GameTick(Conn: g_Config.m_ClDummy)) / (float)Client()->GameTickSpeed();
42 if(SecondsRemaining <= 0.0f)
43 {
44 TextRender()->DeleteTextContainer(TextContainerIndex&: m_TextContainerIndex);
45 return;
46 }
47
48 const float Height = 300.0f;
49 const float Width = Height * Graphics()->ScreenAspect();
50 Graphics()->MapScreen(TopLeftX: 0.0f, TopLeftY: 0.0f, BottomRightX: Width, BottomRightY: Height);
51
52 if(m_BroadcastRenderOffset < 0.0f)
53 m_BroadcastRenderOffset = Width / 2.0f - TextRender()->TextWidth(Size: 12.0f, pText: m_aBroadcastText, StrLength: -1, LineWidth: Width) / 2.0f;
54
55 if(!m_TextContainerIndex.Valid())
56 {
57 CTextCursor Cursor;
58 TextRender()->SetCursor(pCursor: &Cursor, x: m_BroadcastRenderOffset, y: 40.0f, FontSize: 12.0f, Flags: TEXTFLAG_RENDER);
59 Cursor.m_LineWidth = Width;
60 TextRender()->CreateTextContainer(TextContainerIndex&: m_TextContainerIndex, pCursor: &Cursor, pText: m_aBroadcastText);
61 }
62 if(m_TextContainerIndex.Valid())
63 {
64 const float Alpha = SecondsRemaining >= 1.0f ? 1.0f : SecondsRemaining;
65 ColorRGBA TextColor = TextRender()->DefaultTextColor();
66 TextColor.a *= Alpha;
67 ColorRGBA OutlineColor = TextRender()->DefaultTextOutlineColor();
68 OutlineColor.a *= Alpha;
69 TextRender()->RenderTextContainer(TextContainerIndex: m_TextContainerIndex, TextColor, TextOutlineColor: OutlineColor);
70 }
71}
72
73void CBroadcast::OnMessage(int MsgType, void *pRawMsg)
74{
75 if(MsgType == NETMSGTYPE_SV_BROADCAST)
76 {
77 OnBroadcastMessage(pMsg: (CNetMsg_Sv_Broadcast *)pRawMsg);
78 }
79}
80
81void CBroadcast::OnBroadcastMessage(const CNetMsg_Sv_Broadcast *pMsg)
82{
83 str_copy(dst&: m_aBroadcastText, src: pMsg->m_pMessage);
84 m_BroadcastTick = Client()->GameTick(Conn: g_Config.m_ClDummy) + Client()->GameTickSpeed() * 10;
85 m_BroadcastRenderOffset = -1.0f;
86 TextRender()->DeleteTextContainer(TextContainerIndex&: m_TextContainerIndex);
87
88 if(g_Config.m_ClPrintBroadcasts)
89 {
90 const char *pText = m_aBroadcastText;
91 char aLine[sizeof(m_aBroadcastText)];
92 while((pText = str_next_token(str: pText, delim: "\n", buffer: aLine, buffer_size: sizeof(aLine))))
93 {
94 if(aLine[0] != '\0')
95 {
96 m_pClient->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "broadcast", pStr: aLine, PrintColor: color_cast<ColorRGBA>(hsl: ColorHSLA(g_Config.m_ClMessageHighlightColor)));
97 }
98 }
99 }
100}
101