1/*
2 * LegacyClonk
3 *
4 * Copyright (c) RedWolf Design
5 * Copyright (c) 2005, Sven2
6 * Copyright (c) 2017-2021, The LegacyClonk Team and contributors
7 *
8 * Distributed under the terms of the ISC license; see accompanying file
9 * "COPYING" for details.
10 *
11 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12 * See accompanying file "TRADEMARK" for details.
13 *
14 * To redistribute this file separately, substitute the full license texts
15 * for the above references.
16 */
17
18// handles input dialogs, last-message-buffer, MessageBoard-commands
19
20#pragma once
21
22#include "C4Constants.h"
23#include "C4EnumeratedObjectPtr.h"
24#include "C4Gui.h"
25#include "C4GuiDialogs.h"
26#include "C4KeyboardInput.h"
27
28#include <unordered_map>
29
30const int32_t C4MSGB_BackBufferMax = 20;
31
32// chat input dialog
33class C4ChatInputDialog : public C4GUI::InputDialog
34{
35public:
36 enum Mode
37 {
38 All = 0,
39 Allies,
40 Say
41 };
42
43private:
44 typedef C4GUI::InputDialog BaseClass;
45 class C4KeyBinding *pKeyHistoryUp, *pKeyHistoryDown, *pKeyAbort, *pKeyNickComplete, *pKeyPlrControl, *pKeyGamepadControl, *pKeyBackClose;
46
47 bool fObjInput; // input queried by script?
48 bool fUppercase; // script input converted to uppercase
49 class C4Object *pTarget; // target object for script callback
50 int32_t iPlr; // target player for script callback
51
52 // last message lookup
53 int32_t BackIndex;
54
55 bool fProcessed; // set if chat input has been processed
56
57 static C4ChatInputDialog *pInstance; // singleton-instance
58
59private:
60 bool KeyHistoryUpDown(bool fUp);
61 bool KeyCompleteNick(); // complete nick at cursor pos of edit
62 bool KeyPlrControl(C4KeyCodeEx key);
63 bool KeyGamepadControlDown(C4KeyCodeEx key);
64 bool KeyGamepadControlUp(C4KeyCodeEx key);
65 bool KeyGamepadControlPressed(C4KeyCodeEx key);
66 bool KeyBackspaceClose(); // close if chat text box is empty (on backspace)
67
68protected:
69 // chat input callback
70 C4GUI::InputResult OnChatInput(C4GUI::Edit *edt, bool fPasting, bool fPastingMore);
71 void OnChatCancel();
72 virtual void OnClosed(bool fOK) override;
73
74 virtual const char *GetID() override { return "ChatDialog"; }
75
76public:
77 C4ChatInputDialog(bool fObjInput, C4Object *pScriptTarget, bool fUpperCase, Mode mode, int32_t iPlr, const StdStrBuf &rsInputQuery); // construct by screen ratios
78 ~C4ChatInputDialog();
79
80 // place on top of normal dialogs
81 virtual int32_t GetZOrdering() override { return C4GUI_Z_CHAT; }
82
83 // align by screen, not viewport
84 virtual bool IsFreePlaceDialog() override { return true; }
85
86 // place more to the bottom of the screen
87 virtual bool IsBottomPlacementDialog() override { return true; }
88
89 // true for dialogs that receive full keyboard and mouse input even in shared mode
90 virtual bool IsExclusiveDialog() override { return true; }
91
92 // don't enable mouse just for this dlg
93 virtual bool IsMouseControlled() override { return false; }
94
95 // usually processed by edit;
96 // but may reach this if the user managed to deselect the edit control
97 virtual bool OnEnter() override { OnChatInput(edt: pEdit, fPasting: false, fPastingMore: false); return true; }
98
99 static bool IsShown() { return !!pInstance; } // external query fn whether dlg is visible
100 static C4ChatInputDialog *GetInstance() { return pInstance; }
101
102 bool IsScriptQueried() const { return fObjInput; }
103 class C4Object *GetScriptTargetObject() const { return pTarget; }
104 int32_t GetScriptTargetPlayer() const { return iPlr; }
105 bool IsEmpty() const;
106};
107
108class C4MessageBoardCommand
109{
110public:
111 std::string script;
112 enum Restriction { C4MSGCMDR_Escaped = 0, C4MSGCMDR_Plain, C4MSGCMDR_Identifier };
113 Restriction restriction;
114
115 C4MessageBoardCommand() {}
116 C4MessageBoardCommand(const std::string &script, Restriction restriction) : script(script), restriction(restriction) {}
117 void CompileFunc(StdCompiler *pComp);
118 bool operator==(const C4MessageBoardCommand &other) const;
119};
120
121class C4MessageInput
122{
123public:
124 static constexpr auto SPEED = "speed";
125 C4MessageInput() { Default(); }
126 ~C4MessageInput() { Clear(); }
127 void Default();
128 void Clear();
129 bool Init();
130
131private:
132 // last input messages to be accessed via 'up'/'down' in input dialog
133 char BackBuffer[C4MSGB_BackBufferMax][C4MaxMessage];
134
135 // MessageBoard-commands
136private:
137 std::unordered_map<std::string, C4MessageBoardCommand> Commands;
138
139public:
140 void AddCommand(const std::string &strCommand, const std::string &strScript, C4MessageBoardCommand::Restriction eRestriction = C4MessageBoardCommand::C4MSGCMDR_Escaped);
141 C4MessageBoardCommand *GetCommand(const std::string &strName);
142 void RemoveCommand(const std::string &command);
143
144 // Input
145public:
146 bool CloseTypeIn();
147 bool StartTypeIn(bool fObjInput = false, C4Object *pObj = nullptr, bool fUpperCase = false, C4ChatInputDialog::Mode mode = C4ChatInputDialog::All, int32_t iPlr = -1, const StdStrBuf &rsInputQuery = StdStrBuf());
148 bool KeyStartTypeIn(C4ChatInputDialog::Mode mode);
149 bool IsTypeIn();
150 C4ChatInputDialog *GetTypeIn() { return C4ChatInputDialog::GetInstance(); }
151 void StoreBackBuffer(const char *szMessage);
152 const char *GetBackBuffer(int32_t iIndex);
153 bool ProcessInput(const char *szText);
154 bool ProcessCommand(const char *szCommand);
155
156public:
157 void ClearPointers(C4Object *pObj);
158 void AbortMsgBoardQuery(C4Object *pObj, int32_t iPlr);
159
160 friend class C4ChatInputDialog;
161 friend class C4Game;
162};
163
164// script query to ask a player for a string
165class C4MessageBoardQuery
166{
167public:
168 C4EnumeratedObjectPtr pCallbackObj; // callback target object
169 StdStrBuf sInputQuery; // question being asked to the player
170 bool fAnswered; // if set, an answer packet is in the queue (NOSAVE, as the queue isn't saved either!)
171 bool fIsUppercase; // if set, any input is converted to uppercase be4 sending to script
172
173 // linked list to allow for multiple queries
174 C4MessageBoardQuery *pNext;
175
176 // ctors
177 C4MessageBoardQuery(C4Object *pCallbackObj, const StdStrBuf &rsInputQuery, bool fIsUppercase)
178 : pCallbackObj(pCallbackObj), fAnswered(false), fIsUppercase(fIsUppercase), pNext(nullptr)
179 {
180 sInputQuery.Copy(Buf2: rsInputQuery);
181 }
182
183 C4MessageBoardQuery() : fAnswered(false), fIsUppercase(false), pNext(nullptr) {}
184
185 // use default copy ctor
186
187 // compilation
188 void CompileFunc(StdCompiler *pComp);
189};
190