1 /*
2 * Copyright (C) 2001-2013 The Exult Team
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <iostream>
24 #include <cstring>
25
26 #include "SDL_events.h"
27
28 #include "Gump_manager.h"
29 #include "Configuration.h"
30 #include "Gump_button.h"
31 #include "Gump_ToggleButton.h"
32 #include "GameplayOptions_gump.h"
33 #include "exult.h"
34 #include "exult_flx.h"
35 #include "game.h"
36 #include "gamewin.h"
37 #include "mouse.h"
38 #include "cheat.h"
39 #include "Face_stats.h"
40 #include "Text_button.h"
41 #include "Enabled_button.h"
42 #include "font.h"
43 #include "array_size.h"
44
45 using std::string;
46
47 static const int rowy[] = { 4, 16, 124, 28, 40, 52, 64, 76, 88, 100, 112, 148, 136 };
48
49 static const int colx[] = { 35, 50, 120, 195, 192 };
50
51 static const char *oktext = "OK";
52 static const char *canceltext = "CANCEL";
53
54 static int framerates[] = { 2, 4, 6, 8, 10, -1 };
55 // -1 is placeholder for custom framerate
56 static const int num_default_rates = array_size(framerates) - 1;
57
58
framestring(int fr)59 static string framestring(int fr) {
60 char buf[100];
61 sprintf(buf, "%i fps", fr);
62 return buf;
63 }
64
65 static const char *pathfind_texts[3] = {"no", "single", "double"};
66
67 using GameplayOptions_button = CallbackTextButton<GameplayOptions_gump>;
68 using GameplayTextToggle = CallbackToggleTextButton<GameplayOptions_gump>;
69 using GameplayEnabledToggle = CallbackEnabledButton<GameplayOptions_gump>;
70
close()71 void GameplayOptions_gump::close() {
72 save_settings();
73 done = true;
74 }
75
cancel()76 void GameplayOptions_gump::cancel() {
77 done = true;
78 }
79
build_buttons()80 void GameplayOptions_gump::build_buttons() {
81 std::vector<std::string> stats = {"Disabled", "Left", "Middle", "Right"};
82 buttons[id_facestats] = std::make_unique<GameplayTextToggle>(this, &GameplayOptions_gump::toggle_facestats,
83 std::move(stats), facestats, colx[3], rowy[0], 59);
84
85 std::vector<std::string> textbgcolor = {
86 "Disabled",
87 "Solid Light Gray", "Dark Purple", "Bright Yellow", "Light Blue",
88 "Dark Green", "Dark Red", "Purple", "Orange", "Light Gray", "Green",
89 "Yellow", "Pale Blue", "Dark Green", "Red", "Bright White",
90 "Dark gray", "White"
91 };
92 buttons[id_text_bg] = std::make_unique<GameplayTextToggle>(this, &GameplayOptions_gump::toggle_text_bg,
93 std::move(textbgcolor), text_bg, colx[3] - 41, rowy[1], 100);
94 if (sman->can_use_paperdolls() && (GAME_BG ||
95 Game::get_game_type() == EXULT_DEVEL_GAME))
96 buttons[id_paperdolls] = std::make_unique<GameplayEnabledToggle>(this, &GameplayOptions_gump::toggle_paperdolls,
97 paperdolls, colx[3], rowy[12], 59);
98 buttons[id_fastmouse] = std::make_unique<GameplayEnabledToggle>(this, &GameplayOptions_gump::toggle_fastmouse,
99 fastmouse, colx[3], rowy[3], 59);
100 buttons[id_mouse3rd] = std::make_unique<GameplayEnabledToggle>(this, &GameplayOptions_gump::toggle_mouse3rd,
101 mouse3rd, colx[3], rowy[4], 59);
102 buttons[id_doubleclick] = std::make_unique<GameplayEnabledToggle>(this, &GameplayOptions_gump::toggle_doubleclick,
103 doubleclick, colx[3], rowy[5], 59);
104 buttons[id_rightclick_close] = std::make_unique<GameplayEnabledToggle>(this, &GameplayOptions_gump::toggle_rightclick_close,
105 rightclick_close, colx[3], rowy[6], 59);
106
107 std::vector<std::string> pathfind_text = {"Disabled", "Single", "Double"};
108 buttons[id_right_pathfind] = std::make_unique<GameplayTextToggle>(this, &GameplayOptions_gump::toggle_right_pathfind,
109 std::move(pathfind_text), right_pathfind, colx[3], rowy[7], 59);
110 buttons[id_gumps_pause] = std::make_unique<GameplayEnabledToggle>(this, &GameplayOptions_gump::toggle_gumps_pause,
111 gumps_pause, colx[3], rowy[8], 59);
112 buttons[id_cheats] = std::make_unique<GameplayEnabledToggle>(this, &GameplayOptions_gump::toggle_cheats,
113 cheats, colx[3], rowy[9], 59);
114 buttons[id_frames] = std::make_unique<GameplayTextToggle>(this, &GameplayOptions_gump::toggle_frames,
115 frametext, frames, colx[3], rowy[10], 59);
116
117 std::vector<std::string> smooth_text = {"Disabled", "25%", "50%", "75%", "100%"};
118 buttons[id_smooth_scrolling] = std::make_unique<GameplayTextToggle>(this, &GameplayOptions_gump::toggle_smooth_scrolling,
119 std::move(smooth_text), smooth_scrolling, colx[3], rowy[2], 59);
120 }
121
load_settings()122 void GameplayOptions_gump::load_settings() {
123 fastmouse = gwin->get_fastmouse(true);
124 mouse3rd = gwin->get_mouse3rd();
125 cheats = cheat();
126 if (gwin->is_in_exult_menu()) {
127 config->value("config/gameplay/facestats", facestats, -1);
128 facestats += 1;
129 } else
130 facestats = Face_stats::get_state() + 1;
131 doubleclick = 0;
132 paperdolls = false;
133 string pdolls;
134 paperdolls = sman->are_paperdolls_enabled();
135 doubleclick = gwin->get_double_click_closes_gumps();
136 rightclick_close = gumpman->can_right_click_close();
137 right_pathfind = gwin->get_allow_right_pathfind();
138 text_bg = gwin->get_text_bg() + 1;
139 gumps_pause = !gumpman->gumps_dont_pause_game();
140 int realframes = 1000 / gwin->get_std_delay();
141
142 frames = -1;
143 framerates[num_default_rates] = realframes;
144 for (int i = 0; i < num_default_rates; i++) {
145 if (realframes == framerates[i]) {
146 frames = i;
147 break;
148 }
149 }
150
151 int num_framerates = num_default_rates;
152 if (frames == -1) {
153 num_framerates++;
154 frames = num_default_rates;
155 }
156 frametext.clear();
157 for (int i = 0; i < num_framerates; i++) {
158 frametext.emplace_back(framestring(framerates[i]));
159 }
160 smooth_scrolling = gwin->is_lerping_enabled() / 25;
161 }
162
GameplayOptions_gump()163 GameplayOptions_gump::GameplayOptions_gump() : Modal_gump(nullptr, EXULT_FLX_GAMEPLAYOPTIONS_SHP, SF_EXULT_FLX) {
164 set_object_area(TileRect(0, 0, 0, 0), 8, 162);//++++++ ???
165
166 for (auto& btn : buttons)
167 btn.reset();
168
169 load_settings();
170
171 build_buttons();
172
173 // Ok
174 buttons[id_ok] = std::make_unique<GameplayOptions_button>(this, &GameplayOptions_gump::close,
175 oktext, colx[0], rowy[11]);
176 // Cancel
177 buttons[id_cancel] = std::make_unique<GameplayOptions_button>(this, &GameplayOptions_gump::cancel,
178 canceltext, colx[4], rowy[11]);
179 }
180
save_settings()181 void GameplayOptions_gump::save_settings() {
182 gwin->set_text_bg(text_bg - 1);
183 config->set("config/gameplay/textbackground", text_bg - 1, false);
184 int fps = framerates[frames];
185 gwin->set_std_delay(1000 / fps);
186 config->set("config/video/fps", fps, false);
187 gwin->set_fastmouse(fastmouse != 0);
188 config->set("config/gameplay/fastmouse", fastmouse ? "yes" : "no", false);
189 gwin->set_mouse3rd(mouse3rd != 0);
190 config->set("config/gameplay/mouse3rd", mouse3rd ? "yes" : "no", false);
191 gwin->set_double_click_closes_gumps(doubleclick != 0);
192 config->set("config/gameplay/double_click_closes_gumps",
193 doubleclick ? "yes" : "no", false);
194 gumpman->set_right_click_close(rightclick_close != 0);
195 config->set("config/gameplay/right_click_closes_gumps",
196 rightclick_close ? "yes" : "no" , false);
197 cheat.set_enabled(cheats != 0);
198 if (gwin->is_in_exult_menu())
199 config->set("config/gameplay/facestats", facestats - 1 , false);
200 else {
201 while (facestats != Face_stats::get_state() + 1)
202 Face_stats::AdvanceState();
203 Face_stats::save_config(config);
204 }
205 if (sman->can_use_paperdolls() && (GAME_BG ||
206 Game::get_game_type() == EXULT_DEVEL_GAME)) {
207 sman->set_paperdoll_status(paperdolls != 0);
208 config->set("config/gameplay/bg_paperdolls",
209 paperdolls ? "yes" : "no", false);
210 }
211
212 gwin->set_allow_right_pathfind(right_pathfind);
213 config->set("config/gameplay/allow_right_pathfind", pathfind_texts[right_pathfind], false);
214
215 gumpman->set_gumps_dont_pause_game(!gumps_pause);
216 config->set("config/gameplay/gumps_dont_pause_game", gumps_pause ? "no" : "yes", false);
217
218 if (smooth_scrolling < 0) smooth_scrolling = 0;
219 else if (smooth_scrolling > 4) smooth_scrolling = 4;
220 gwin->set_lerping_enabled(smooth_scrolling * 25);
221 config->set("config/gameplay/smooth_scrolling", smooth_scrolling * 25, false);
222 config->write_back();
223 }
224
paint()225 void GameplayOptions_gump::paint() {
226 Gump::paint();
227 for (auto& btn : buttons)
228 if (btn)
229 btn->paint();
230
231 Font *font = fontManager.get_font("SMALL_BLACK_FONT");
232 Image_window8 *iwin = gwin->get_win();
233
234 font->paint_text(iwin->get_ib8(), "Status Bars:", x + colx[0], y + rowy[0] + 1);
235 font->paint_text(iwin->get_ib8(), "Text Background:", x + colx[0], y + rowy[1] + 1);
236 if (buttons[id_paperdolls])
237 font->paint_text(iwin->get_ib8(), "Paperdolls:", x + colx[0], y + rowy[12] + 1);
238 #ifndef __IPHONEOS__
239 font->paint_text(iwin->get_ib8(), "Fullscreen Fast Mouse:", x + colx[0], y + rowy[3] + 1);
240 font->paint_text(iwin->get_ib8(), "Use Middle Mouse Button:", x + colx[0], y + rowy[4] + 1);
241 #endif
242 font->paint_text(iwin->get_ib8(), "Doubleclick closes Gumps:", x + colx[0], y + rowy[5] + 1);
243 font->paint_text(iwin->get_ib8(), "Right click closes Gumps:", x + colx[0], y + rowy[6] + 1);
244 font->paint_text(iwin->get_ib8(), "Right click Pathfinds:", x + colx[0], y + rowy[7] + 1);
245 font->paint_text(iwin->get_ib8(), "Gumps pause game:", x + colx[0], y + rowy[8] + 1);
246 font->paint_text(iwin->get_ib8(), "Cheats:", x + colx[0], y + rowy[9] + 1);
247 font->paint_text(iwin->get_ib8(), "Speed:", x + colx[0], y + rowy[10] + 1);
248 font->paint_text(iwin->get_ib8(), "Smooth scrolling:", x + colx[0], y + rowy[2] + 1);
249 gwin->set_painted();
250 }
251
mouse_down(int mx,int my,int button)252 bool GameplayOptions_gump::mouse_down(int mx, int my, int button) {
253 // Only left and right buttons
254 if (button != 1 && button != 3) return false;
255
256 // We'll eat the mouse down if we've already got a button down
257 if (pushed) return true;
258
259 // First try checkmark
260 pushed = Gump::on_button(mx, my);
261
262 // Try buttons at bottom.
263 if (!pushed) {
264 for (auto& btn : buttons) {
265 if (btn && btn->on_button(mx, my)) {
266 pushed = btn.get();
267 break;
268 }
269 }
270 }
271
272 if (pushed && !pushed->push(button)) // On a button?
273 pushed = nullptr;
274
275 return button == 1 || pushed != nullptr;
276 }
277
mouse_up(int mx,int my,int button)278 bool GameplayOptions_gump::mouse_up(int mx, int my, int button) {
279 // Not Pushing a button?
280 if (!pushed) return false;
281
282 if (pushed->get_pushed() != button) return button == 1;
283
284 bool res = false;
285 pushed->unpush(button);
286 if (pushed->on_button(mx, my))
287 res = pushed->activate(button);
288 pushed = nullptr;
289 return res;
290 }
291