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/keys.h> |
5 | #include <engine/shared/config.h> |
6 | #include <engine/textrender.h> |
7 | |
8 | #include <game/client/gameclient.h> |
9 | #include <game/generated/protocol.h> |
10 | |
11 | #include "motd.h" |
12 | |
13 | CMotd::CMotd() |
14 | { |
15 | m_aServerMotd[0] = '\0'; |
16 | m_ServerMotdTime = 0; |
17 | m_ServerMotdUpdateTime = 0; |
18 | } |
19 | |
20 | void CMotd::Clear() |
21 | { |
22 | m_ServerMotdTime = 0; |
23 | Graphics()->DeleteQuadContainer(ContainerIndex&: m_RectQuadContainer); |
24 | TextRender()->DeleteTextContainer(TextContainerIndex&: m_TextContainerIndex); |
25 | } |
26 | |
27 | bool CMotd::IsActive() const |
28 | { |
29 | return time() < m_ServerMotdTime; |
30 | } |
31 | |
32 | void CMotd::OnStateChange(int NewState, int OldState) |
33 | { |
34 | if(OldState == IClient::STATE_ONLINE || OldState == IClient::STATE_OFFLINE) |
35 | Clear(); |
36 | } |
37 | |
38 | void CMotd::OnWindowResize() |
39 | { |
40 | Graphics()->DeleteQuadContainer(ContainerIndex&: m_RectQuadContainer); |
41 | TextRender()->DeleteTextContainer(TextContainerIndex&: m_TextContainerIndex); |
42 | } |
43 | |
44 | void CMotd::OnRender() |
45 | { |
46 | if(Client()->State() != IClient::STATE_ONLINE && Client()->State() != IClient::STATE_DEMOPLAYBACK) |
47 | return; |
48 | |
49 | if(!IsActive()) |
50 | return; |
51 | |
52 | const float FontSize = 32.0f; // also the size of the margin and rect rounding |
53 | const float ScreenHeight = 40.0f * FontSize; // multiple of the font size to get perfect alignment |
54 | const float ScreenWidth = ScreenHeight * Graphics()->ScreenAspect(); |
55 | Graphics()->MapScreen(TopLeftX: 0.0f, TopLeftY: 0.0f, BottomRightX: ScreenWidth, BottomRightY: ScreenHeight); |
56 | |
57 | const float RectHeight = 26.0f * FontSize; |
58 | const float RectWidth = 630.0f + 2.0f * FontSize; |
59 | const float RectX = ScreenWidth / 2.0f - RectWidth / 2.0f; |
60 | const float RectY = 160.0f; |
61 | |
62 | if(m_RectQuadContainer == -1) |
63 | { |
64 | Graphics()->SetColor(r: 0.0f, g: 0.0f, b: 0.0f, a: 0.5f); |
65 | m_RectQuadContainer = Graphics()->CreateRectQuadContainer(x: RectX, y: RectY, w: RectWidth, h: RectHeight, r: FontSize, Corners: IGraphics::CORNER_ALL); |
66 | Graphics()->SetColor(r: 1.0f, g: 1.0f, b: 1.0f, a: 1.0f); |
67 | } |
68 | |
69 | if(m_RectQuadContainer != -1) |
70 | { |
71 | Graphics()->TextureClear(); |
72 | Graphics()->RenderQuadContainer(ContainerIndex: m_RectQuadContainer, QuadDrawNum: -1); |
73 | } |
74 | |
75 | const float TextWidth = RectWidth - 2.0f * FontSize; |
76 | const float TextX = RectX + FontSize; |
77 | const float TextY = RectY + FontSize; |
78 | |
79 | if(!m_TextContainerIndex.Valid()) |
80 | { |
81 | CTextCursor Cursor; |
82 | TextRender()->SetCursor(pCursor: &Cursor, x: TextX, y: TextY, FontSize, Flags: TEXTFLAG_RENDER); |
83 | Cursor.m_LineWidth = TextWidth; |
84 | TextRender()->CreateTextContainer(TextContainerIndex&: m_TextContainerIndex, pCursor: &Cursor, pText: ServerMotd()); |
85 | } |
86 | |
87 | if(m_TextContainerIndex.Valid()) |
88 | TextRender()->RenderTextContainer(TextContainerIndex: m_TextContainerIndex, TextColor: TextRender()->DefaultTextColor(), TextOutlineColor: TextRender()->DefaultTextOutlineColor()); |
89 | } |
90 | |
91 | void CMotd::OnMessage(int MsgType, void *pRawMsg) |
92 | { |
93 | if(Client()->State() == IClient::STATE_DEMOPLAYBACK) |
94 | return; |
95 | |
96 | if(MsgType == NETMSGTYPE_SV_MOTD) |
97 | { |
98 | const CNetMsg_Sv_Motd *pMsg = static_cast<CNetMsg_Sv_Motd *>(pRawMsg); |
99 | |
100 | // copy it manually to process all \n |
101 | const char *pMsgStr = pMsg->m_pMessage; |
102 | const size_t MotdLen = str_length(str: pMsgStr) + 1; |
103 | const char *pLast = m_aServerMotd; // for console printing |
104 | for(size_t i = 0, k = 0; i < MotdLen && k < sizeof(m_aServerMotd); i++, k++) |
105 | { |
106 | // handle incoming "\\n" |
107 | if(pMsgStr[i] == '\\' && pMsgStr[i + 1] == 'n') |
108 | { |
109 | m_aServerMotd[k] = '\n'; |
110 | i++; // skip the 'n' |
111 | } |
112 | else |
113 | m_aServerMotd[k] = pMsgStr[i]; |
114 | |
115 | // print the line to the console when receiving the newline character |
116 | if(g_Config.m_ClPrintMotd && m_aServerMotd[k] == '\n') |
117 | { |
118 | m_aServerMotd[k] = '\0'; |
119 | m_pClient->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "motd" , pStr: pLast, PrintColor: color_cast<ColorRGBA>(hsl: ColorHSLA(g_Config.m_ClMessageHighlightColor))); |
120 | m_aServerMotd[k] = '\n'; |
121 | pLast = m_aServerMotd + k + 1; |
122 | } |
123 | } |
124 | m_aServerMotd[sizeof(m_aServerMotd) - 1] = '\0'; |
125 | if(g_Config.m_ClPrintMotd && *pLast != '\0') |
126 | m_pClient->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "motd" , pStr: pLast, PrintColor: color_cast<ColorRGBA>(hsl: ColorHSLA(g_Config.m_ClMessageHighlightColor))); |
127 | |
128 | m_ServerMotdUpdateTime = time(); |
129 | if(m_aServerMotd[0] && g_Config.m_ClMotdTime) |
130 | m_ServerMotdTime = m_ServerMotdUpdateTime + time_freq() * g_Config.m_ClMotdTime; |
131 | else |
132 | m_ServerMotdTime = 0; |
133 | TextRender()->DeleteTextContainer(TextContainerIndex&: m_TextContainerIndex); |
134 | } |
135 | } |
136 | |
137 | bool CMotd::OnInput(const IInput::CEvent &Event) |
138 | { |
139 | if(IsActive() && Event.m_Flags & IInput::FLAG_PRESS && Event.m_Key == KEY_ESCAPE) |
140 | { |
141 | Clear(); |
142 | return true; |
143 | } |
144 | return false; |
145 | } |
146 | |