1 /** @file m_ctrl.cpp Controls menu page and associated widgets.
2 *
3 * @authors Copyright © 2005-2017 Jaakko Keränen <jaakko.keranen@iki.fi>
4 * @authors Copyright © 2005-2014 Daniel Swanson <danij@dengine.net>
5 *
6 * @par License
7 * GPL: http://www.gnu.org/licenses/gpl.html
8 *
9 * <small>This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version. This program is distributed in the hope that it
13 * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15 * Public License for more details. You should have received a copy of the GNU
16 * General Public License along with this program; if not, write to the Free
17 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18 * 02110-1301 USA</small>
19 */
20
21 #include "common.h"
22 #include "m_ctrl.h"
23
24 #include <cstring>
25 #include <cctype>
26 #include <cstdio>
27
28 #include "hu_menu.h"
29 #include "hu_stuff.h"
30 #include "menu/page.h"
31 #include "menu/widgets/inputbindingwidget.h"
32 #include "menu/widgets/labelwidget.h"
33
34 using namespace de;
35
36 namespace common {
37 namespace menu {
38
39 static controlconfig_t controlConfig[] =
40 {
41 { "Movement", 0, 0, 0, 0 },
42 { "Forward", 0, "walk", 0, CCF_NON_INVERSE },
43 { "Backward", 0, "walk", 0, CCF_INVERSE },
44 { "Strafe Left", 0, "sidestep", 0, CCF_INVERSE },
45 { "Strafe Right", 0, "sidestep", 0, CCF_NON_INVERSE },
46 { "Turn Left", 0, "turn", 0, CCF_STAGED | CCF_INVERSE | CCF_SIDESTEP_MODIFIER },
47 { "Turn Right", 0, "turn", 0, CCF_STAGED | CCF_NON_INVERSE | CCF_SIDESTEP_MODIFIER },
48 { "Jump", 0, 0, "impulse jump", 0 },
49 { "Use", 0, 0, "impulse use", 0 },
50 { "Fly Up", 0, "zfly", 0, CCF_STAGED | CCF_NON_INVERSE },
51 { "Fly Down", 0, "zfly", 0, CCF_STAGED | CCF_INVERSE },
52 { "Fall To Ground", 0, 0, "impulse falldown", 0 },
53 { "Speed", 0, "speed", 0, 0 },
54 { "Strafe", 0, "strafe", 0, 0 },
55
56 { "Looking", 0, 0, 0, 0 },
57 { "Look Up", 0, "look", 0, CCF_STAGED | CCF_NON_INVERSE },
58 { "Look Down", 0, "look", 0, CCF_STAGED | CCF_INVERSE },
59 { "Look Center", 0, 0, "impulse lookcenter", 0 },
60
61 { "Weapons", 0, 0, 0, 0 },
62 { "Attack/Fire", 0, "attack", 0, 0 },
63 { "Next Weapon", 0, 0, "impulse nextweapon", 0 },
64 { "Previous Weapon", 0, 0, "impulse prevweapon", 0 },
65
66 #if __JDOOM__ || __JDOOM64__
67 { "Fist/Chainsaw", 0, 0, "impulse weapon1", 0 },
68 { "Chainsaw/Fist", 0, 0, "impulse weapon8", 0 },
69 { "Pistol", 0, 0, "impulse weapon2", 0 },
70 { "Super SG/Shotgun", 0, 0, "impulse weapon3", 0 },
71 { "Shotgun/Super SG", 0, 0, "impulse weapon9", 0 },
72 { "Chaingun", 0, 0, "impulse weapon4", 0 },
73 { "Rocket Launcher", 0, 0, "impulse weapon5", 0 },
74 { "Plasma Rifle", 0, 0, "impulse weapon6", 0 },
75 { "BFG 9000", 0, 0, "impulse weapon7", 0 },
76 #endif
77 #if __JDOOM64__
78 { "Unmaker", 0, 0, "impulse weapon10", 0 },
79 #endif
80
81 #if __JHERETIC__
82 { "Gauntlets/Staff", 0, 0, "impulse weapon1", 0 },
83 { "Elvenwand", 0, 0, "impulse weapon2", 0 },
84 { "Crossbow", 0, 0, "impulse weapon3", 0 },
85 { "Dragon Claw", 0, 0, "impulse weapon4", 0 },
86 { "Hellstaff", 0, 0, "impulse weapon5", 0 },
87 { "Phoenix Rod", 0, 0, "impulse weapon6", 0 },
88 { "Firemace", 0, 0, "impulse weapon7", 0 },
89 #endif
90
91 #if __JHEXEN__
92 { "Weapon 1", 0, 0, "impulse weapon1", 0 },
93 { "Weapon 2", 0, 0, "impulse weapon2", 0 },
94 { "Weapon 3", 0, 0, "impulse weapon3", 0 },
95 { "Weapon 4", 0, 0, "impulse weapon4", 0 },
96 #endif
97
98 #if __JHERETIC__ || __JHEXEN__
99 { "Inventory", 0, 0, 0, 0 },
100 { "Move Left", 0, 0, "impulse previtem", CCF_REPEAT },
101 { "Move Right", 0, 0, "impulse nextitem", CCF_REPEAT },
102 { "Use Item", 0, 0, "impulse useitem", 0 },
103 { "Panic!", 0, 0, "impulse panic", 0 },
104 #endif
105
106 #ifdef __JHERETIC__
107 { /* (char const *) TXT_TXT_INV_INVULNERABILITY */ "Invincibility", 0, 0, "impulse invulnerability", 0 },
108 { (char const *) TXT_TXT_INV_INVISIBILITY, 0, 0, "impulse invisibility", 0 },
109 { (char const *) TXT_TXT_INV_HEALTH, 0, 0, "impulse health", 0 },
110 { (char const *) TXT_TXT_INV_SUPERHEALTH, 0, 0, "impulse superhealth", 0 },
111 { (char const *) TXT_TXT_INV_TOMEOFPOWER, 0, 0, "impulse tome", 0 },
112 { (char const *) TXT_TXT_INV_TORCH, 0, 0, "impulse torch", 0 },
113 { /* (char const *) TXT_TXT_INV_FIREBOMB */ "Time Bomb", 0, 0, "impulse firebomb", 0 },
114 { (char const *) TXT_TXT_INV_EGG, 0, 0, "impulse egg", 0 },
115 { (char const *) TXT_TXT_INV_FLY, 0, 0, "impulse fly", 0 },
116 { (char const *) TXT_TXT_INV_TELEPORT, 0, 0, "impulse teleport", 0 },
117 #endif
118
119 #ifdef __JHEXEN__
120 { (char const *) TXT_TXT_INV_TORCH, 0, 0, "impulse torch", 0 },
121 { (char const *) TXT_TXT_INV_HEALTH, 0, 0, "impulse health", 0 },
122 { (char const *) TXT_TXT_INV_SUPERHEALTH, 0, 0, "impulse mysticurn", 0 },
123 { (char const *) TXT_TXT_INV_BOOSTMANA, 0, 0, "impulse krater", 0 },
124 { (char const *) TXT_TXT_INV_SPEED, 0, 0, "impulse speedboots", 0 },
125 { (char const *) TXT_TXT_INV_BLASTRADIUS, 0, 0, "impulse blast", 0 },
126 { (char const *) TXT_TXT_INV_TELEPORT, 0, 0, "impulse teleport", 0 },
127 { (char const *) TXT_TXT_INV_TELEPORTOTHER, 0, 0, "impulse teleportother", 0 },
128 { (char const *) TXT_TXT_INV_POISONBAG, 0, 0, "impulse poisonbag", 0 },
129 { (char const *) TXT_TXT_INV_INVULNERABILITY, 0, 0, "impulse invulnerability", 0 },
130 { (char const *) TXT_TXT_INV_SUMMON, 0, 0, "impulse darkservant", 0 },
131 { (char const *) TXT_TXT_INV_EGG, 0, 0, "impulse egg", 0 },
132 #endif
133
134 { "Chat", 0, 0, 0, 0 },
135 { "Open Chat", 0, 0, "beginchat", CCF_MULTIPLAYER },
136
137 #if __JDOOM__ || __JDOOM64__
138 { "Green Chat", 0, 0, "beginchat 0", CCF_MULTIPLAYER },
139 { "Indigo Chat", 0, 0, "beginchat 1", CCF_MULTIPLAYER },
140 { "Brown Chat", 0, 0, "beginchat 2", CCF_MULTIPLAYER },
141 { "Red Chat", 0, 0, "beginchat 3", CCF_MULTIPLAYER },
142 #endif
143
144 #if __JHERETIC__
145 { "Green Chat", 0, 0, "beginchat 0", CCF_MULTIPLAYER },
146 { "Yellow Chat", 0, 0, "beginchat 1", CCF_MULTIPLAYER },
147 { "Red Chat", 0, 0, "beginchat 2", CCF_MULTIPLAYER },
148 { "Blue Chat", 0, 0, "beginchat 3", CCF_MULTIPLAYER },
149 #endif
150
151 { "Send Message", "chat", 0, "chatcomplete", 0 },
152 { "Cancel Message", "chat", 0, "chatcancel", 0 },
153 { "Macro 1", "chat", 0, "chatsendmacro 0", 0 },
154 { "Macro 2", "chat", 0, "chatsendmacro 1", 0 },
155 { "Macro 3", "chat", 0, "chatsendmacro 2", 0 },
156 { "Macro 4", "chat", 0, "chatsendmacro 3", 0 },
157 { "Macro 5", "chat", 0, "chatsendmacro 4", 0 },
158 { "Macro 6", "chat", 0, "chatsendmacro 5", 0 },
159 { "Macro 7", "chat", 0, "chatsendmacro 6", 0 },
160 { "Macro 8", "chat", 0, "chatsendmacro 7", 0 },
161 { "Macro 9", "chat", 0, "chatsendmacro 8", 0 },
162 { "Macro 10", "chat", 0, "chatsendmacro 9", 0 },
163 { "Backspace", "chat", 0, "chatdelete", CCF_REPEAT },
164
165 { "Map", 0, 0, 0, 0 },
166 { "Show/Hide Map", 0, 0, "impulse automap", 0 },
167 { "Zoom In", 0, "mapzoom", 0, CCF_NON_INVERSE },
168 { "Zoom Out", 0, "mapzoom", 0, CCF_INVERSE },
169 { "Zoom Maximum", "map", 0, "impulse zoommax", 0 },
170 { "Pan Left", 0, "mappanx", 0, CCF_INVERSE },
171 { "Pan Right", 0, "mappanx", 0, CCF_NON_INVERSE },
172 { "Pan Up", 0, "mappany", 0, CCF_NON_INVERSE },
173 { "Pan Down", 0, "mappany", 0, CCF_INVERSE },
174 { "Toggle Follow", "map", 0, "impulse follow", 0 },
175 { "Toggle Rotation", "map", 0, "impulse rotate", 0 },
176 { "Add Mark", "map", 0, "impulse addmark", 0 },
177 { "Clear Marks", "map", 0, "impulse clearmarks", 0 },
178
179 { "HUD", 0, 0, 0, 0 },
180 { "Show HUD", 0, 0, "impulse showhud", 0 },
181 { "Show Score", 0, 0, "impulse showscore", CCF_REPEAT },
182 { "Smaller View", 0, 0, "sub view-size 1", CCF_REPEAT },
183 { "Larger View", 0, 0, "add view-size 1", CCF_REPEAT },
184
185 { "Msg Refresh", 0, 0, "impulse msgrefresh", 0 },
186
187 { "Shortcuts", 0, 0, 0, 0 },
188 { "Show Taskbar", 0, 0, "taskbar", 0 },
189 { "Pause Game", 0, 0, "pause", 0 },
190 #if !__JDOOM64__
191 { "Help Screen", "shortcut", 0, "helpscreen", 0 },
192 #endif
193 { "End Game", "shortcut", 0, "endgame", 0 },
194 { "Save Game", "shortcut", 0, "menu savegame", 0 },
195 { "Load Game", "shortcut", 0, "menu loadgame", 0 },
196 { "Quick Save", "shortcut", 0, "quicksave", 0 },
197 { "Quick Load", "shortcut", 0, "quickload", 0 },
198 { "Sound Options", "shortcut", 0, "menu soundoptions", 0 },
199 { "Toggle Messages", "shortcut", 0, "toggle msg-show", 0 },
200 { "Gamma Adjust", "shortcut", 0, "togglegamma", 0 },
201 { "Screenshot", "shortcut", 0, "screenshot", 0 },
202 { "Quit", "shortcut", 0, "quit", 0 },
203
204 { "Menu", 0, 0, 0, 0 },
205 { "Show/Hide Menu", "shortcut", 0, "menu", 0 },
206 { "Previous Menu", "menu", 0, "menuback", CCF_REPEAT },
207 { "Move Up", "menu", 0, "menuup", CCF_REPEAT },
208 { "Move Down", "menu", 0, "menudown", CCF_REPEAT },
209 { "Move Left", "menu", 0, "menuleft", CCF_REPEAT },
210 { "Move Right", "menu", 0, "menuright", CCF_REPEAT },
211 { "Select", "menu", 0, "menuselect", 0 },
212
213 { "On-Screen Questions", 0, 0, 0, 0 },
214 { "Answer Yes", "message", 0, "messageyes", 0 },
215 { "Answer No", "message", 0, "messageno", 0 },
216 { "Cancel", "message", 0, "messagecancel", 0 },
217
218 // { "Virtual Reality", 0, 0, 0, 0 },
219 // { "Reset Tracking", 0, 0, "resetriftpose", 0 }
220 };
221
222 static void Hu_MenuDrawControlsPage(Page const &page, Vector2i const &offset);
223
Hu_MenuActivateBindingsGrab(Widget &,Widget::Action)224 void Hu_MenuActivateBindingsGrab(Widget &, Widget::Action)
225 {
226 // Start grabbing for this control.
227 DD_SetInteger(DD_SYMBOLIC_ECHO, true);
228 }
229
Hu_MenuInitControlsPage()230 void Hu_MenuInitControlsPage()
231 {
232 Page *page = Hu_MenuAddPage(new Page("ControlOptions", Vector2i(32, 40), 0, Hu_MenuDrawControlsPage));
233 page->setLeftColumnWidth(.4f);
234 page->setTitle("Controls");
235 page->setPredefinedFont(MENU_FONT1, FID(GF_FONTA));
236 page->setPreviousPage(Hu_MenuPagePtr("Options"));
237
238 int group = 0;
239 int const configCount = sizeof(controlConfig) / sizeof(controlConfig[0]);
240 for(int i = 0; i < configCount; ++i)
241 {
242 controlconfig_t *binds = &controlConfig[i];
243
244 char const *labelText = binds->text;
245 if (labelText && (PTR2INT(labelText) > 0 && PTR2INT(labelText) < NUMTEXT))
246 {
247 labelText = GET_TXT(PTR2INT(labelText));
248 }
249
250 if (!binds->command && !binds->controlName)
251 {
252 // Inert.
253 page->addWidget(new LabelWidget(labelText))
254 .setGroup(++group)
255 .setColor(MENU_COLOR2);
256 }
257 else
258 {
259 page->addWidget(new LabelWidget(labelText))
260 .setLeft()
261 .setGroup(group);
262
263 InputBindingWidget *binding = new InputBindingWidget;
264 binding->binds = binds;
265 binding->setRight();
266 binding->setGroup(group);
267 binding->setAction(Widget::Activated, Hu_MenuActivateBindingsGrab);
268 binding->setAction(Widget::FocusGained, Hu_MenuDefaultFocusAction);
269
270 page->addWidget(binding);
271 }
272 }
273 }
274
Hu_MenuDrawControlsPage(Page const &,Vector2i const &)275 static void Hu_MenuDrawControlsPage(Page const & /*page*/, Vector2i const & /*offset*/)
276 {
277 Vector2i origin(SCREENWIDTH / 2, (SCREENHEIGHT / 2) + ((SCREENHEIGHT / 2 - 5) / cfg.common.menuScale));
278 Hu_MenuDrawPageHelp("Select to assign new, [Del] to clear", origin);
279 }
280
Hu_MenuControlGrabDrawer(char const * niceName,float alpha)281 void Hu_MenuControlGrabDrawer(char const *niceName, float alpha)
282 {
283 DGL_Enable(DGL_TEXTURE_2D);
284
285 FR_SetFont(FID(GF_FONTA));
286 FR_LoadDefaultAttrib();
287 FR_SetLeading(0);
288 FR_SetColorAndAlpha(cfg.common.menuTextColors[1][CR], cfg.common.menuTextColors[1][CG], cfg.common.menuTextColors[1][CB], alpha);
289 FR_DrawTextXY3("Press key or move controller for", SCREENWIDTH/2, SCREENHEIGHT/2-2, ALIGN_BOTTOM, Hu_MenuMergeEffectWithDrawTextFlags(DTF_ONLY_SHADOW));
290
291 FR_SetFont(FID(GF_FONTB));
292 FR_SetColorAndAlpha(cfg.common.menuTextColors[2][CR], cfg.common.menuTextColors[2][CG], cfg.common.menuTextColors[2][CB], alpha);
293 FR_DrawTextXY3(niceName, SCREENWIDTH/2, SCREENHEIGHT/2+2, ALIGN_TOP, Hu_MenuMergeEffectWithDrawTextFlags(DTF_ONLY_SHADOW));
294
295 DGL_Disable(DGL_TEXTURE_2D);
296 }
297
298 } // namespace menu
299 } // namespace common
300
301