1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "ultima/shared/std/string.h"
24 #include "ultima/nuvie/core/nuvie_defs.h"
25 #include "ultima/nuvie/conf/configuration.h"
26 #include "ultima/nuvie/misc/u6_misc.h"
27 #include "ultima/nuvie/fonts/font_manager.h"
28 #include "ultima/nuvie/fonts/font.h"
29 #include "ultima/nuvie/screen/game_palette.h"
30 #include "ultima/nuvie/gui/gui.h"
31 #include "ultima/nuvie/gui/widgets/msg_scroll.h"
32 #include "ultima/nuvie/portraits/portrait.h"
33 #include "ultima/nuvie/core/player.h"
34 #include "ultima/nuvie/gui/widgets/converse_gump.h"
35 #include "ultima/nuvie/actors/actor_manager.h"
36 #include "ultima/nuvie/actors/actor.h"
37 #include "ultima/nuvie/keybinding/keys.h"
38
39 namespace Ultima {
40 namespace Nuvie {
41
42 #define CURSOR_COLOR 248
43
44 // ConverseGump Class
45
ConverseGump(Configuration * cfg,Font * f,Screen * s)46 ConverseGump::ConverseGump(Configuration *cfg, Font *f, Screen *s) {
47 // uint16 x, y;
48
49 init(cfg, f);
50 Game *game = Game::get_game();
51 game_type = game->get_game_type();
52
53 scroll_width = 30;
54 scroll_height = 8;
55
56 // x = 8;
57 // y = 8;
58 int gump_h;
59 uint8 min_h, default_c;
60 Std::string height_str;
61 min_w = game->get_min_converse_gump_width();
62 uint16 x_off = game->get_game_x_offset();
63 uint16 y_off = game->get_game_y_offset();
64 int game_h = game->get_game_height();
65
66 if (game_type == NUVIE_GAME_SE) {
67 default_c = 216;
68 min_h = 185;
69 } else if (game_type == NUVIE_GAME_MD) {
70 default_c = 136;
71 min_h = 181;
72 } else {// U6
73 default_c = 218;
74 min_h = 152;
75 }
76 cfg->value(config_get_game_key(cfg) + "/converse_height", height_str, "default");
77
78 if (game->is_orig_style()) {
79 gump_h = game_h;
80 } else {
81 if (height_str == "default") {
82 if (game_h > min_h * 1.5) // big enough that we probably don't want to take up the whole screen
83 gump_h = min_h;
84 else
85 gump_h = game_h;
86 } else {
87 cfg->value(config_get_game_key(cfg) + "/converse_height", gump_h, game_h);
88 if (gump_h < min_h)
89 gump_h = min_h;
90 else if (gump_h > game_h)
91 gump_h = game_h;
92 }
93 }
94
95 GUI_Widget::Init(NULL, x_off, y_off, game->get_converse_gump_width(), (uint16)gump_h);
96 npc_portrait = NULL;
97 avatar_portrait = NULL;
98 keyword_list = NULL;
99
100 font = game->get_font_manager()->get_conv_font();
101
102 found_break_char = false;
103 cursor_wait = 0;
104
105 if (game->is_forcing_solid_converse_bg()) {
106 solid_bg = true;
107 force_solid_bg = true;
108 } else {
109 force_solid_bg = false;
110 cfg->value(config_get_game_key(config) + "/converse_solid_bg", solid_bg, false);
111 }
112
113 int c;
114 cfg->value(config_get_game_key(config) + "/converse_bg_color", c, default_c);
115 if (c < 256)
116 converse_bg_color = (uint8)c;
117
118 cursor_position = 0;
119
120 portrait_width = frame_w = game->get_portrait()->get_portrait_width();
121 portrait_height = frame_h = game->get_portrait()->get_portrait_height();
122 if (game_type == NUVIE_GAME_U6) {
123 frame_w = portrait_width + 8;
124 frame_h = portrait_height + 9;
125 }
126 //DEBUG(0, LEVEL_DEBUGGING, "\nMin w = %d\n", frame_w + 12 + 210);
127 }
128
~ConverseGump()129 ConverseGump::~ConverseGump() {
130 if (npc_portrait)
131 free(npc_portrait);
132 if (avatar_portrait)
133 free(avatar_portrait);
134 conv_keywords.clear();
135 permitted_input_keywords.clear();
136 }
137
set_talking(bool state,Actor * actor)138 void ConverseGump::set_talking(bool state, Actor *actor) {
139 if (state == true) {
140 Game::get_game()->get_keybinder()->set_enable_joy_repeat(false);
141 found_break_char = true;
142 conv_keywords.clear();
143 permitted_input_keywords.clear();
144 Show();
145 set_input_mode(false);
146 clear_scroll();
147 set_found_break_char(true);
148 bool altar = (game_type == NUVIE_GAME_U6 // Singularity is excluded on purpose
149 && actor->get_actor_num() >= 192 && actor->get_actor_num() <= 199);
150 if (!altar) {
151 add_keyword("name");
152 add_keyword("job");
153 add_keyword("bye");
154 }
155 bool cant_join = (game_type == NUVIE_GAME_U6 // statues and altars
156 && actor->get_actor_num() >= 189 && actor->get_actor_num() <= 200);
157 if (actor->is_in_party())
158 add_keyword("leave");
159 else if (!cant_join)
160 add_keyword("join");
161 if (game_type == NUVIE_GAME_U6 && !altar) {
162 add_keyword("rune");
163 add_keyword("mantra");
164 }
165 keyword_list = &conv_keywords;
166
167 if (avatar_portrait) {
168 free(avatar_portrait);
169 avatar_portrait = NULL;
170 }
171
172 cursor_position = 0;
173 } else {
174 Game::get_game()->get_keybinder()->set_enable_joy_repeat(true);
175 }
176
177 MsgScroll::set_talking(state);
178 }
179
set_actor_portrait(Actor * a)180 void ConverseGump::set_actor_portrait(Actor *a) {
181 if (npc_portrait)
182 free(npc_portrait);
183
184 if (Game::get_game()->get_portrait()->has_portrait(a))
185 npc_portrait = get_portrait_data(a);
186 else
187 npc_portrait = NULL;
188
189 if (avatar_portrait == NULL) {
190 Actor *p = Game::get_game()->get_player()->get_actor();
191 Actor *p1 = Game::get_game()->get_actor_manager()->get_actor(1);
192 avatar_portrait = get_portrait_data(p->get_actor_num() != 0 ? p : p1); // don't use portrait 0 when in a vehicle
193 }
194 }
195
get_portrait_data(Actor * a)196 unsigned char *ConverseGump::get_portrait_data(Actor *a) {
197 if (game_type == NUVIE_GAME_U6) {
198 return create_framed_portrait(a);
199 }
200
201 Portrait *p = Game::get_game()->get_portrait();
202 return p->get_portrait_data(a);
203 }
204
create_framed_portrait(Actor * a)205 unsigned char *ConverseGump::create_framed_portrait(Actor *a) { //FIXME U6 specific.
206 //uint8 FRAME_W = portrait_width + 8;
207 uint16 i;
208 Portrait *p = Game::get_game()->get_portrait();
209 unsigned char *portrait_data = p->get_portrait_data(a);
210 unsigned char *framed_data = (unsigned char *)malloc(frame_w * frame_h);
211
212 memset(framed_data, 255, frame_w * frame_h);
213
214 memset(framed_data, 0, frame_w);
215 memset(framed_data + (frame_h - 1)*frame_w, 0, frame_w);
216 memset(framed_data + 1 * frame_w + 2, 53, 57);
217 memset(framed_data + 2 * frame_w + 2, 57, 59);
218
219 memset(framed_data + 3 * frame_w + 4, 0, 57);
220
221 //top left corner
222 framed_data[1 * frame_w] = 0;
223 framed_data[1 * frame_w + 1] = 138;
224 framed_data[2 * frame_w] = 0;
225 framed_data[2 * frame_w + 1] = 139;
226 framed_data[3 * frame_w] = 0;
227 framed_data[3 * frame_w + 1] = 139;
228 framed_data[3 * frame_w + 2] = 57;
229 framed_data[3 * frame_w + 3] = 143;
230
231 for (i = 0; i < portrait_height; i++) {
232 framed_data[(i + 4)*frame_w] = 0;
233 framed_data[(i + 4)*frame_w + 1] = 139;
234 framed_data[(i + 4)*frame_w + 2] = 57;
235 framed_data[(i + 4)*frame_w + 3] = 142;
236
237 memcpy(&framed_data[(i + 4)*frame_w + 4], &portrait_data[i * p->get_portrait_width()], portrait_width);
238
239 framed_data[(i + 4)*frame_w + 4 + portrait_width] = 0;
240 framed_data[(i + 4)*frame_w + 4 + portrait_width + 1] = 57;
241 framed_data[(i + 4)*frame_w + 4 + portrait_width + 2] = 53;
242 framed_data[(i + 4)*frame_w + 4 + portrait_width + 3] = 0;
243 }
244
245 memset(framed_data + (frame_h - 5)*frame_w + 3, 142, 57);
246 memset(framed_data + (frame_h - 4)*frame_w + 2, 57, 60);
247 memset(framed_data + (frame_h - 3)*frame_w + 1, 139, 61);
248 memset(framed_data + (frame_h - 2)*frame_w + 1, 142, 62);
249
250 //bottom left
251 framed_data[(frame_h - 5)*frame_w] = 0;
252 framed_data[(frame_h - 5)*frame_w + 1] = 139;
253 framed_data[(frame_h - 5)*frame_w + 2] = 57;
254 framed_data[(frame_h - 4)*frame_w] = 0;
255 framed_data[(frame_h - 4)*frame_w + 1] = 139;
256 framed_data[(frame_h - 3)*frame_w] = 0;
257 framed_data[(frame_h - 2)*frame_w] = 0;
258
259 //top right
260 framed_data[1 * frame_w + 59] = 50;
261 framed_data[1 * frame_w + 59 + 1] = 49;
262 framed_data[1 * frame_w + 59 + 2] = 49;
263 framed_data[1 * frame_w + 59 + 3] = 15;
264 framed_data[1 * frame_w + 59 + 4] = 0;
265 framed_data[2 * frame_w + 59 + 2] = 15;
266 framed_data[2 * frame_w + 59 + 3] = 49;
267 framed_data[2 * frame_w + 59 + 4] = 0;
268 framed_data[3 * frame_w + 59 + 2] = 57;
269 framed_data[3 * frame_w + 59 + 3] = 49;
270 framed_data[3 * frame_w + 59 + 4] = 0;
271 framed_data[4 * frame_w + 59 + 3] = 50;
272
273 //bottom right
274 framed_data[(frame_h - 5)*frame_w + 60] = 143;
275 framed_data[(frame_h - 5)*frame_w + 61] = 57;
276 framed_data[(frame_h - 5)*frame_w + 62] = 53;
277 framed_data[(frame_h - 5)*frame_w + 63] = 0;
278 framed_data[(frame_h - 4)*frame_w + 62] = 53;
279 framed_data[(frame_h - 4)*frame_w + 63] = 0;
280 framed_data[(frame_h - 3)*frame_w + 62] = 173;
281 framed_data[(frame_h - 3)*frame_w + 63] = 0;
282 framed_data[(frame_h - 2)*frame_w + 63] = 0;
283
284 free(portrait_data);
285
286 return framed_data;
287 }
288
set_permitted_input(const char * allowed)289 void ConverseGump::set_permitted_input(const char *allowed) {
290 permitted_input_keywords.clear();
291 keyword_list = &permitted_input_keywords;
292 MsgScroll::set_permitted_input(allowed);
293
294 if (yes_no_only) {
295 add_keyword("yes");
296 add_keyword("no");
297 } else if (aye_nay_only) {
298 add_keyword("aye");
299 add_keyword("nay");
300 } else if (numbers_only) {
301 add_keyword("0");
302 add_keyword("1");
303 add_keyword("2");
304 add_keyword("3");
305 add_keyword("4");
306 add_keyword("5");
307 add_keyword("6");
308 add_keyword("7");
309 add_keyword("8");
310 add_keyword("9");
311 }
312
313 cursor_position = 0;
314 }
315
clear_permitted_input()316 void ConverseGump::clear_permitted_input() {
317 keyword_list = &conv_keywords;
318 MsgScroll::clear_permitted_input();
319 }
320
321 /*
322 void ConverseGump::add_token(MsgText *token)
323 {
324 DEBUG(0,LEVEL_ALERT, "TOKEN: %s\n", token->s.c_str());
325
326 display_text.push_back(*token);
327 }
328 */
329
display_string(Std::string s,Font * f,bool include_on_map_window)330 void ConverseGump::display_string(Std::string s, Font *f, bool include_on_map_window) {
331 if (s.empty())
332 return;
333
334 MsgScroll::display_string(strip_whitespace_after_break(s), f, include_on_map_window);//, MSGSCROLL_NO_MAP_DISPLAY);
335 }
336
strip_whitespace_after_break(Std::string s)337 Std::string ConverseGump::strip_whitespace_after_break(Std::string s) {
338 Std::string::iterator iter;
339 for (iter = s.begin(); iter != s.end();) {
340 if (found_break_char == true) {
341 char c = *iter;
342 if (c == ' ' || c == '\t' || c == '\n' || c == '*') {
343 iter = s.erase(iter);
344 } else {
345 found_break_char = false;
346 iter++;
347 }
348 } else {
349 char c = *iter;
350 if (c == '*') {
351 found_break_char = true;
352 }
353 iter++;
354 }
355 }
356
357 return s;
358 }
359
parse_token(MsgText * token)360 bool ConverseGump::parse_token(MsgText *token) {
361 int at_idx = token->s.findFirstOf('@', 0);
362 int i = 0;
363 int len = (int)token->s.length();
364 while (at_idx != -1 && i < len) {
365 Std::string keyword = "";
366 for (i = at_idx + 1; i < len; i++) {
367 char c = token->s[i];
368 if (Common::isAlpha(c)) {
369 keyword.push_back(c);
370 }
371
372 if (!Common::isAlpha(c) || i == len - 1) {
373 token->s.erase(at_idx, 1);
374 i--;
375 at_idx = token->s.findFirstOf('@', i);
376 break;
377 }
378 }
379 DEBUG(0, LEVEL_WARNING, "%s", keyword.c_str());
380 add_keyword(keyword);
381 }
382
383 parse_fm_towns_token(token);
384 return MsgScroll::parse_token(token);
385 }
386
387 // Add FM-Towns keywords which take the form. +actor_numKeyword+ eg. +5runes+
388 // Only add keyword if the player has met the actor given by the actor_num
parse_fm_towns_token(MsgText * token)389 void ConverseGump::parse_fm_towns_token(MsgText *token) {
390 int at_idx = token->s.findFirstOf('+', 0);
391 int i = 0;
392 int len = (int)token->s.length();
393 bool has_met = false;
394 while (at_idx != -1 && i < len) {
395 i = at_idx + 1;
396 char c = token->s[i];
397 if (i < len && Common::isDigit(c)) {
398 const char *c_str = token->s.c_str();
399 uint16 actor_num = (int)strtol(&c_str[i], NULL, 10);
400 if (actor_num < 256) {
401 Actor *actor = Game::get_game()->get_actor_manager()->get_actor(actor_num);
402 if (actor) {
403 has_met = actor->is_met();
404 }
405 }
406 for (; Common::isDigit(c_str[i]);)
407 i++;
408 }
409
410 Std::string keyword = "";
411 for (; i < len; i++) {
412 char ch = token->s[i];
413
414 if (Common::isAlpha(ch)) {
415 keyword.push_back(ch);
416 }
417
418 if (!Common::isAlpha(ch) || i == len - 1) {
419 token->s.erase(at_idx, (i - at_idx) + 1);
420 i -= i - at_idx;
421 at_idx = token->s.findFirstOf('+', i);
422 break;
423 }
424 }
425 DEBUG(0, LEVEL_WARNING, "%s", keyword.c_str());
426 if (has_met) { //only add keyword if the player has met the actor in question.
427 add_keyword(keyword);
428 has_met = false;
429 }
430 }
431
432 return;
433 }
434
add_keyword(Std::string keyword)435 void ConverseGump::add_keyword(Std::string keyword) {
436 keyword = " *" + keyword;
437
438 Std::list<MsgText>::iterator iter;
439 for (iter = keyword_list->begin(); iter != keyword_list->end(); iter++) {
440 if (string_i_compare((*iter).s, keyword)) {
441 return;
442 }
443 }
444
445 MsgText m_text;
446 m_text.s = keyword;
447 m_text.font = font;
448 keyword_list->push_back(m_text);
449 }
450
get_token_string_at_pos(uint16 x,uint16 y)451 Std::string ConverseGump::get_token_string_at_pos(uint16 x, uint16 y) {
452 uint16 total_length = 0;
453 uint16 tmp_y = area.top + portrait_height + 8 + 3 + 4;
454 Std::list<MsgText>::iterator iter;
455 for (iter = keyword_list->begin(); iter != keyword_list->end(); iter++) {
456 MsgText t = *iter;
457 uint16 token_len = font->getStringWidth(t.s.c_str());
458
459 // if(token_len + total_length >= (26 * 8))
460 if (portrait_width / 2 + portrait_width + token_len + total_length + 8 >= min_w - 4) {
461 total_length = 0;
462 tmp_y += 10;
463 }
464 //t.font->drawString(screen, t.s.c_str(), area.left + portrait_width / 2 + portrait_width + 8 + total_length * 8, y + portrait_height + 8, 0);
465 if (x > area.left + portrait_width / 2 + portrait_width + 8 + total_length && x < area.left + portrait_width / 2 + portrait_width + 8 + total_length + token_len) {
466 if (y > tmp_y && y < tmp_y + 8) {
467 if (!is_permanent_keyword(t.s))
468 keyword_list->erase(iter);
469 return t.s;
470 }
471 }
472 total_length += token_len;
473 }
474 return "";
475 }
476
get_token_at_cursor()477 Std::string ConverseGump::get_token_at_cursor() {
478 uint16 i = 0;
479 Std::list<MsgText>::iterator iter;
480 for (iter = keyword_list->begin(); iter != keyword_list->end(); i++, iter++) {
481 if (i == cursor_position) {
482 Std::string keyword = (*iter).s;
483 if (!is_permanent_keyword(keyword)) {
484 keyword_list->erase(iter);
485 if (permit_input)
486 keyword = keyword.at(2); // only return first char after " *"
487 }
488 return keyword;
489 }
490 }
491
492 return "";
493 }
494
input_buf_add_char(char c)495 bool ConverseGump::input_buf_add_char(char c) {
496 input_char = 0;
497 if (permit_input != NULL)
498 input_buf_remove_char();
499 input_buf.push_back(c);
500 return true;
501 }
502
input_buf_remove_char()503 bool ConverseGump::input_buf_remove_char() {
504 if (input_buf.length()) {
505 input_buf.erase(input_buf.length() - 1, 1);
506 return true;
507 }
508
509 return false;
510 }
511
Display(bool full_redraw)512 void ConverseGump::Display(bool full_redraw) {
513 MsgText *token;
514 //Std::list<MsgText>::iterator iter;
515 uint16 total_length = 0;
516 uint16 y = area.top + portrait_height + 8 + 3;
517
518 if (converse_bg_color != 255 || force_solid_bg) {
519 if (solid_bg)
520 screen->fill(converse_bg_color, area.left, area.top, area.width(), area.height());
521 else
522 screen->stipple_8bit(converse_bg_color, area.left, area.top, area.width(), area.height());
523 }
524
525 bool use_transparency = (game_type == NUVIE_GAME_U6) ? false : true;
526
527 if (npc_portrait) {
528 screen->blit(area.left + 4, area.top + 4, npc_portrait, 8, frame_w, frame_h, frame_w, use_transparency);
529 }
530
531 if (!page_break && input_mode && avatar_portrait && is_talking()) {
532 screen->blit(area.left + portrait_width / 2 + 4, y, avatar_portrait, 8, frame_w, frame_h, frame_w, use_transparency);
533 Std::list<MsgText>::iterator iter;
534 sint16 i = 0;
535 for (iter = keyword_list->begin(); iter != keyword_list->end(); i++, iter++) {
536 MsgText t = *iter;
537 uint16 token_len = font->getStringWidth(t.s.c_str());
538 // if(token_len + total_length >= (26 * 8))
539 if (portrait_width / 2 + portrait_width + token_len + total_length + 8 >= min_w - 4) {
540 total_length = 0;
541 y += 10;
542 }
543 t.font->drawString(screen, t.s.c_str(), area.left + portrait_width / 2 + portrait_width + 8 + total_length, y + 4, 0, 0);
544 if (cursor_position == i) {
545 screen->fill(CURSOR_COLOR, area.left + portrait_width / 2 + portrait_width + 16 + total_length, y + 4 + 8, token_len - 8, 1);
546 }
547 total_length += token_len;
548 //total_length += t.s.length();
549 }
550 y += 16;
551 font->drawString(screen, " *", area.left + portrait_width / 2 + portrait_width + 8, y, 0, 0);
552 font->drawString(screen, input_buf.c_str(), area.left + portrait_width / 2 + portrait_width + 8 + font->getStringWidth(" *"), y, 0, 0);
553 drawCursor(area.left + portrait_width / 2 + portrait_width + 8 + font->getStringWidth(" *") + font->getStringWidth(input_buf.c_str()), y);
554 if (cursor_position == keyword_list->size()) {
555 screen->fill(CURSOR_COLOR, area.left + portrait_width / 2 + portrait_width + 16, y + 8, font->getStringWidth(input_buf.c_str()) + 8, 1);
556 }
557 }
558
559 y = area.top + 4;
560 total_length = 0;
561 Std::list<MsgLine *>::iterator iter;
562 for (iter = msg_buf.begin(); iter != msg_buf.end(); iter++) {
563 MsgLine *msg_line = *iter;
564 Std::list<MsgText *>::iterator iter1;
565
566 for (iter1 = msg_line->text.begin(); iter1 != msg_line->text.end() ; iter1++) {
567 token = *iter1;
568
569 total_length += token->font->drawString(screen, token->s.c_str(), area.left + 4 + frame_w + 4 + total_length, y + 4, 0, 0); //FIX for hardcoded font height
570
571 //token->s.length();
572 //token->font->drawChar(screen, ' ', area.left + portrait_width + 8 + total_length * 8, y, 0);
573 //total_length += 1;
574
575 }
576 y += 10;
577 total_length = 0;
578 }
579
580 //font->drawString(screen, conv_str.c_str(), area.left, area.top);
581 screen->update(area.left, area.top, area.width(), area.height());
582 }
583
584
KeyDown(const Common::KeyState & keyState)585 GUI_status ConverseGump::KeyDown(const Common::KeyState &keyState) {
586 Common::KeyState key = keyState;
587 char ascii = get_ascii_char_from_keysym(key);
588
589 if (page_break || !is_talking()) {
590 page_break = false;
591 just_finished_page_break = true;
592 if (!input_mode)
593 Game::get_game()->get_gui()->unlock_input();
594 if (!is_holding_buffer_empty() || !input_mode || !is_talking()) {
595 clear_scroll();
596 process_holding_buffer(); // Process any text in the holding buffer.
597 }
598 return (GUI_YUM);
599 }
600
601 if (!input_mode || !Common::isPrint(ascii)) {
602 KeyBinder *keybinder = Game::get_game()->get_keybinder();
603 ActionType a = keybinder->get_ActionType(key);
604 switch (keybinder->GetActionKeyType(a)) {
605 case WEST_KEY:
606 key.keycode = Common::KEYCODE_LEFT;
607 break;
608 case EAST_KEY:
609 key.keycode = Common::KEYCODE_RIGHT;
610 break;
611 case SOUTH_KEY:
612 key.keycode = Common::KEYCODE_DOWN;
613 break;
614 case NORTH_KEY:
615 key.keycode = Common::KEYCODE_UP;
616 break;
617 case CANCEL_ACTION_KEY:
618 key.keycode = Common::KEYCODE_ESCAPE;
619 break;
620 case DO_ACTION_KEY:
621 key.keycode = Common::KEYCODE_RETURN;
622 break;
623 default:
624 if (keybinder->handle_always_available_keys(a)) return GUI_YUM;
625 break;
626 }
627 }
628
629 switch (key.keycode) {
630 case Common::KEYCODE_LEFT:
631 if (cursor_at_input_section() && input_char != 0)
632 input_char = 0;
633 else {
634 if (!cursor_at_input_section() || !input_buf_remove_char()) {
635 if (cursor_position == 0) {
636 cursor_position = keyword_list->size();
637 } else {
638 cursor_position--;
639 }
640 }
641 }
642 break;
643 case Common::KEYCODE_RIGHT:
644 if (cursor_at_input_section() && input_char != 0 && permit_input == NULL)
645 input_buf_add_char(get_char_from_input_char());
646 else
647 cursor_position = (cursor_position + 1) % (keyword_list->size() + 1);
648 break;
649 case Common::KEYCODE_DOWN:
650 cursor_move_to_input();
651 increase_input_char();
652 break;
653 case Common::KEYCODE_UP:
654 cursor_move_to_input();
655 decrease_input_char();
656 break;
657 case Common::KEYCODE_ESCAPE:
658 if (permit_inputescape) {
659 // reset input buffer
660 permit_input = NULL;
661 if (input_mode)
662 set_input_mode(false);
663 }
664 return (GUI_YUM);
665 case Common::KEYCODE_KP_ENTER:
666 case Common::KEYCODE_RETURN:
667 if (permit_inputescape || !cursor_at_input_section()
668 || input_char != 0) { // input_char should only be permit_input
669 if (!cursor_at_input_section())
670 input_add_string(get_token_at_cursor());
671 else {
672 if (input_char != 0)
673 input_buf_add_char(get_char_from_input_char());
674 }
675 //if(input_mode)
676 set_input_mode(false);
677 clear_scroll();
678 found_break_char = true; //strip leading whitespace.
679 cursor_reset();
680 }
681
682 return (GUI_YUM);
683 case Common::KEYCODE_BACKSPACE :
684 if (input_mode)
685 input_buf_remove_char();
686 break;
687 default: // alphanumeric characters
688 if (input_mode && Common::isPrint(ascii)) {
689 cursor_move_to_input();
690 if (permit_input == NULL) {
691 if (!numbers_only || Common::isDigit(ascii))
692 if (input_char != 0)
693 input_buf_add_char(get_char_from_input_char());
694 input_buf_add_char(ascii);
695 } else if (strchr(permit_input, ascii) || strchr(permit_input, tolower(ascii))) {
696 input_buf_add_char(toupper(ascii));
697 set_input_mode(false);
698 clear_scroll();
699 found_break_char = true;
700 }
701 }
702 break;
703 }
704 return GUI_YUM;
705 }
706
MouseUp(int x,int y,Shared::MouseButton button)707 GUI_status ConverseGump::MouseUp(int x, int y, Shared::MouseButton button) {
708 Std::string token_str;
709
710 if (page_break || !is_talking()) { // any click == scroll-to-end
711 page_break = false;
712 just_finished_page_break = true;
713 if (!input_mode)
714 Game::get_game()->get_gui()->unlock_input();
715
716 if (!is_holding_buffer_empty() || !input_mode || !is_talking()) {
717 clear_scroll();
718 process_holding_buffer(); // Process any text in the holding buffer.
719 }
720 return (GUI_YUM);
721 } else if (button == 1) { // left click == select word
722 if (input_mode) {
723 token_str = get_token_string_at_pos(x, y);
724 if (token_str.length() > 0) {
725 input_add_string(token_str);
726 set_input_mode(false);
727 clear_scroll();
728 found_break_char = true; //strip leading whitespace.
729 }
730 }
731 }
732 /*
733 else if(button == 3) // right click == send input
734 if(permit_inputescape && input_mode)
735 {
736 set_input_mode(false);
737 return(GUI_YUM);
738 }
739 */
740 return (GUI_YUM);
741 }
742
input_add_string(Std::string token_str)743 void ConverseGump::input_add_string(Std::string token_str) {
744 input_buf.clear();
745 for (uint16 i = 0; i < token_str.length(); i++) {
746 if (Common::isAlnum(token_str[i]) && (!permit_input || strchr(permit_input, token_str[i])
747 || strchr(permit_input, tolower(token_str[i]))))
748 input_buf_add_char(token_str[i]);
749 }
750 }
751
is_permanent_keyword(Std::string keyword)752 bool ConverseGump::is_permanent_keyword(Std::string keyword) {
753 return (string_i_compare(keyword, " *buy") || string_i_compare(keyword, " *sell")
754 || string_i_compare(keyword, " *bye") || string_i_compare(keyword, " *spells")
755 || string_i_compare(keyword, " *reagents"));
756 }
757
drawCursor(uint16 x,uint16 y)758 void ConverseGump::drawCursor(uint16 x, uint16 y) {
759 if (input_char != 0) {
760 font->drawChar(screen, get_char_from_input_char(), x, y);
761 } else {
762 MsgScroll::drawCursor(x, y);
763 }
764 }
765
766 } // End of namespace Nuvie
767 } // End of namespace Ultima
768