1 /* ---------------------------------------------------------------------- *
2 * lchelp.c
3 * This file is part of lincity.
4 * Lincity is copyright (c) I J Peters 1995-1997, (c) Greg Sharp 1997-2001.
5 * ---------------------------------------------------------------------- */
6 #include "lcconfig.h"
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include "lcstring.h"
10 #include <ctype.h>
11 #include "common.h"
12 #include "lctypes.h"
13 #include "fileutil.h"
14 #include "lin-city.h"
15 #include "lchelp.h"
16 #include "mouse.h"
17 #include "geometry.h"
18 #include "lcintl.h"
19 #include "module_buttons.h"
20 #include "screen.h"
21
22 /* About help history:
23 History count starts at 0, but is immediately incremented to 1.
24 Current page is stored at help_button_history[help_history_count-1],
25 which is the top of the stack. When "back" is clicked, history count
26 is decremented by 2, and then incremented by one.
27 */
28
29 void
activate_help(char * hp)30 activate_help (char *hp)
31 {
32 help_flag = 1;
33 help_history_count = 0;
34 help_return_val = 0;
35 #ifdef USE_EXPANDED_FONT
36 Fgl_setwritemode (WRITEMODE_MASKED | FONT_EXPANDED);
37 #else
38 Fgl_setfontcolors (HELPBACKGROUNDCOLOUR, TEXT_FG_COLOUR);
39 #endif
40 draw_help_page (hp);
41 }
42
43 void
do_help_mouse(int x,int y,int mbutton)44 do_help_mouse (int x, int y, int mbutton)
45 {
46 Rect* mw = &scr.main_win;
47 if (mouse_in_rect(mw, x, y)) {
48 do_help_buttons (x, y);
49 return;
50 }
51 if (block_help_exit)
52 return;
53
54 help_flag = 0;
55 #ifdef USE_EXPANDED_FONT
56 Fgl_setwritemode (WRITEMODE_OVERWRITE | FONT_EXPANDED);
57 #else
58 Fgl_setfontcolors (TEXT_BG_COLOUR, TEXT_FG_COLOUR);
59 #endif
60 refresh_main_screen ();
61 }
62
63 void
draw_help_page(char * helppage)64 draw_help_page (char *helppage)
65 {
66 Rect* mw = &scr.main_win;
67 char *helppage_full, *helppage_short;
68 int i, y;
69 FILE *inf;
70 char help_line[MAX_HELP_LINE];
71
72 /* In ask-dir page if user presses "yes" create directory in main loop */
73 #if defined (commentout)
74 if ((strcmp (helppage, "opening.hlp") == 0)
75 && (strcmp (help_button_history[help_history_count - 1],
76 "ask-dir.hlp") == 0)) {
77 make_dir_ok_flag = 1;
78 }
79 #endif
80
81 /* Return pages have arguments. It is always true that "-2" means "Out"
82 and "-1" means "Back". Semantics for other arguments depend upon
83 the name of the source page (e.g. load game or choose residence).
84 Most of the times (except "Back"), this will exit the help system. */
85 if (strncmp (helppage, "return", 6) == 0) {
86 sscanf (&(helppage[6]), "%d", &help_return_val);
87
88 /* If "Back" was clicked */
89 if (help_return_val == -1 && help_history_count > 1) {
90 strcpy (helppage, help_button_history[help_history_count - 2]);
91 help_history_count -= 2;
92 goto continue_with_help;
93 }
94
95 /* XXX: WCK: residential selection is really ugly */
96 if (help_history_count > 0 &&
97 strcmp (help_button_history[help_history_count - 1],
98 "res.tmp") == 0)
99 {
100 switch (help_return_val) {
101 case (-2):
102 case (-1):
103 case (0):
104 #if defined (commentout)
105 case (1):
106 selected_module_type = CST_RESIDENCE_LL;
107 selected_module_cost = get_group_cost (GROUP_RESIDENCE_LL);
108 break;
109 case (2):
110 selected_module_type = CST_RESIDENCE_ML;
111 selected_module_cost = get_group_cost (GROUP_RESIDENCE_ML);
112 break;
113 case (3):
114 selected_module_type = CST_RESIDENCE_HL;
115 selected_module_cost = get_group_cost (GROUP_RESIDENCE_HL);
116 break;
117 case (4):
118 selected_module_type = CST_RESIDENCE_LH;
119 selected_module_cost = get_group_cost (GROUP_RESIDENCE_LH);
120 break;
121 case (5):
122 selected_module_type = CST_RESIDENCE_MH;
123 selected_module_cost = get_group_cost (GROUP_RESIDENCE_MH);
124 break;
125 case (6):
126 selected_module_type = CST_RESIDENCE_HH;
127 selected_module_cost = get_group_cost (GROUP_RESIDENCE_HH);
128 break;
129 #endif
130 case (1):
131 set_selected_module (CST_RESIDENCE_LL);
132 break;
133 case (2):
134 set_selected_module (CST_RESIDENCE_ML);
135 break;
136 case (3):
137 set_selected_module (CST_RESIDENCE_HL);
138 break;
139 case (4):
140 set_selected_module (CST_RESIDENCE_LH);
141 break;
142 case (5):
143 set_selected_module (CST_RESIDENCE_MH);
144 break;
145 case (6):
146 set_selected_module (CST_RESIDENCE_HH);
147 break;
148 }
149 }
150 else if (help_history_count > 0 &&
151 strcmp (help_button_history[help_history_count - 1],
152 "menu.hlp") == 0)
153 {
154 switch (help_return_val) {
155 case 1:
156 save_flag = 1;
157 break;
158 case 2:
159 prefs_flag = 1;
160 break;
161 case 3:
162 quit_flag = 1;
163 break;
164 }
165 }
166 else if (help_history_count > 0 &&
167 strcmp (help_button_history[help_history_count - 1],
168 "opening.hlp") == 0)
169 {
170 switch (help_return_val)
171 {
172 case (-2):
173 case (-1):
174 case (0):
175 /* Random villiage */
176 new_city (&main_screen_originx, &main_screen_originy, 1);
177 adjust_main_origin (main_screen_originx,main_screen_originy,0);
178 break;
179 case (1):
180 /* Bare board */
181 new_city (&main_screen_originx, &main_screen_originy, 0);
182 adjust_main_origin (main_screen_originx,main_screen_originy,0);
183 break;
184 case (2):
185 /* Network start */
186 network_flag = 1;
187 break;
188 }
189 }
190 else if (help_history_count > 0 &&
191 strcmp (help_button_history[help_history_count - 1],
192 "newgame.hlp") == 0)
193 {
194 switch (help_return_val)
195 {
196 case (0):
197 /* Random villiage */
198 new_city (&main_screen_originx, &main_screen_originy, 1);
199 adjust_main_origin (main_screen_originx,main_screen_originy,0);
200 break;
201 case (1):
202 /* Bare board */
203 new_city (&main_screen_originx, &main_screen_originy, 0);
204 adjust_main_origin (main_screen_originx,main_screen_originy,0);
205 break;
206 case (2):
207 /* Network start */
208 network_flag = 1;
209 break;
210 }
211 }
212 else if (help_history_count > 0 &&
213 strcmp (help_button_history[help_history_count - 1],
214 "openload.hlp") == 0)
215 {
216 switch (help_return_val)
217 {
218 case (-2):
219 case (-1):
220 case (0):
221 new_city (&main_screen_originx, &main_screen_originy, 1);
222 adjust_main_origin (main_screen_originx,main_screen_originy,0);
223 break;
224 case (1):
225 redraw_mouse ();
226 load_opening_city ("good_times.scn");
227 adjust_main_origin (main_screen_originx,main_screen_originy,0);
228 hide_mouse ();
229 break;
230 case (2):
231 load_opening_city ("bad_times.scn");
232 adjust_main_origin (main_screen_originx,main_screen_originy,0);
233 break;
234 case (9):
235 load_flag = 1;
236 break;
237 }
238 }
239 else if (help_history_count > 0 &&
240 strcmp (help_button_history[help_history_count - 1],
241 "loadgame.hlp") == 0)
242 {
243 switch (help_return_val)
244 {
245 case (1):
246 redraw_mouse ();
247 load_opening_city ("good_times.scn");
248 adjust_main_origin (main_screen_originx,main_screen_originy,0);
249 hide_mouse ();
250 break;
251 case (2):
252 load_opening_city ("bad_times.scn");
253 adjust_main_origin (main_screen_originx,main_screen_originy,0);
254 break;
255 case (9):
256 load_flag = 1;
257 break;
258 }
259 }
260 #if defined (commentout)
261 else if (help_history_count > 0 &&
262 strcmp (help_button_history[help_history_count - 1],
263 "ask-dir.hlp") == 0)
264 {
265 if (help_return_val == 1) {
266 /* Clicking "no" means no directory is created */
267 do_error (_("Sorry, lincity cannot run without this directory. Exiting."));
268 } else if (help_return_val == -2) {
269 /* Clicking "out" means we want to create directory,
270 and then go to opening screen. */
271 /* Warning: Note that "opening.hlp" is the same length
272 as "ask-dir.hlp". */
273 make_dir_ok_flag = 1;
274 strcpy (helppage, "opening.hlp");
275 goto continue_with_help;
276 }
277 }
278 #endif
279
280 block_help_exit = 0;
281 help_flag = 0;
282
283 /* GCS Remove overlay */
284 if (main_screen_flag == MAIN_SCREEN_EQUALS_MINI) {
285 main_screen_flag = MAIN_SCREEN_NORMAL_FLAG;
286 }
287
288 /* Fix origin */
289 #ifdef USE_EXPANDED_FONT
290 Fgl_setwritemode (WRITEMODE_OVERWRITE | FONT_EXPANDED);
291 #else
292 Fgl_setfontcolors (TEXT_BG_COLOUR, TEXT_FG_COLOUR);
293 #endif
294 refresh_main_screen ();
295 return;
296 }
297
298 continue_with_help:
299 /* This buffer is just a copy of helppage. Sometimes helppage is an
300 entry within help_button_s[], which gets overwritten when the page
301 is parsed. */
302 if ((helppage_short = (char*) malloc (strlen(helppage) + 1)) == 0) {
303 malloc_failure ();
304 }
305 strcpy (helppage_short, helppage);
306
307 /* Right click on mini-screen */
308 if (strncmp (helppage, "mini-screen.hlp", 15) == 0) {
309 draw_big_mini_screen ();
310 } else if (strncmp (helppage, "mini-in-main.hlp", 17) == 0) {
311 /* do nothing */
312 } else {
313 /* This buffer is for the full path of the help file.
314 The file might be either in the help directory (most cases),
315 or in the temp directory (dynamically created pages). */
316 if ((helppage_full = (char *) malloc (lc_save_dir_len
317 + strlen (help_path)
318 + strlen(helppage) + 2)) == 0) {
319 malloc_failure ();
320 }
321
322 /* Open the file */
323 sprintf (helppage_full, "%s%s", help_path, helppage);
324 if ((inf = fopen (helppage_full, "r")) == 0) {
325 sprintf (helppage_full, "%s%c%s", lc_save_dir,
326 PATH_SLASH, helppage);
327 if ((inf = fopen (helppage_full, "r")) == 0) {
328 sprintf (helppage_full, "%s%s", help_path, HELPERRORPAGE);
329 if ((inf = fopen (helppage_full, "r")) == 0)
330 do_error ("Help error");
331 }
332 }
333
334 /* Parse and render help file */
335 numof_help_buttons = 0;
336 Fgl_fillbox (mw->x, mw->y, mw->w, mw->h, HELPBACKGROUNDCOLOUR);
337 while (feof (inf) == 0) {
338 if (fgets (help_line, MAX_HELP_LINE, inf) == 0)
339 break;
340 undosify_string (help_line); /* GCS testing... */
341 parse_helpline (help_line);
342 }
343 fclose (inf);
344
345 /* For ask-dir, we add path info */
346 if (strncmp (helppage_short, "ask-dir.hlp", 11) == 0) {
347 parse_helpline ("tcolour 0 255");
348 y = 100;
349 for (i = 0; i < askdir_lines; i++) {
350 sprintf (help_line, "text -1 %d %s", y, askdir_path[i]);
351 parse_helpline (help_line);
352 y += 14;
353 }
354 }
355 free (helppage_full);
356 }
357
358 /* At this point, most of the page has been rendered. Now we have
359 to draw in the "BACK" and "OUT" buttons. */
360 if (help_history_count > 0) {
361 parse_helpline ("tcolour 122 153");
362 /* TRANSLATOR: Only translate "BACK" */
363 parse_helpline (_("tbutton 4 387 return-1 BACK"));
364 }
365 parse_helpline ("tcolour 188 153");
366 /* TRANSLATOR: Only translate "OUT" */
367 parse_helpline (_("tbutton 370 387 return-2 OUT"));
368 parse_helpline ("tcolour -1 -1");
369
370 /* Add help page to history. If history is going to overflow,
371 throw out oldest page. */
372 strcpy (help_button_history[help_history_count], helppage_short);
373 help_history_count++;
374 if (help_history_count >= MAX_HELP_HISTORY) {
375 for (i = 0; i < (MAX_HELP_HISTORY - 1); i++)
376 strcpy (help_button_history[i], help_button_history[i + 1]);
377 help_history_count--;
378 }
379
380 free (helppage_short);
381 }
382
383 void
refresh_help_page(void)384 refresh_help_page (void)
385 {
386 help_history_count -= 1;
387 draw_help_page (help_button_history[help_history_count]);
388 }
389
390 void
parse_helpline(char * s)391 parse_helpline (char *s)
392 {
393 if (strncmp (s, "text", 4) == 0)
394 parse_textline (s);
395 else if (strncmp (s, "icon", 4) == 0)
396 parse_iconline (s);
397 else if (strncmp (s, "button", 6) == 0)
398 parse_buttonline (s);
399 else if (strncmp (s, "tbutton", 7) == 0)
400 parse_tbuttonline (s);
401 else if (strncmp (s, "tcolour", 7) == 0)
402 parse_tcolourline (s);
403 }
404
405 void
parse_tcolourline(char * st)406 parse_tcolourline (char *st)
407 {
408 char s[100];
409 int f, b;
410 strcpy (s, st); /* hpux fix? we can live with this. */
411
412 sscanf (s, "tcolour %d %d", &f, &b);
413 if (f < 0 || b < 0)
414 Fgl_setfontcolors (TEXT_BG_COLOUR, TEXT_FG_COLOUR);
415 else
416 Fgl_setfontcolors (b, f);
417 }
418
419 void
parse_textline(char * st)420 parse_textline (char *st)
421 {
422 Rect* mw = &scr.main_win;
423 int i, j, x, y;
424 sscanf (st, "text %d %d", &x, &y);
425 /* find start of string */
426 i = 0;
427 for (j = 0; j < 3; j++)
428 {
429 while (isspace (st[i]) == 0)
430 {
431 if (st[i] == 0)
432 return; /* just silently ignore */
433
434 i++;
435 }
436 while (isspace (st[i]) != 0)
437 {
438 if (st[i] == 0)
439 return;
440 i++;
441 }
442 }
443 st += i;
444 /* get rid of the newline */
445 if (st[strlen (st) - 1] == 0xa)
446 st[strlen (st) - 1] = 0;
447 if (x < 0) {
448 /* centre text if x is negative */
449 x = (mw->w / 2) - (strlen (st) * 4);
450 if (x < 0)
451 return; /* line was too long */
452 } else {
453 /* otherwise adjust x location to within center zone */
454 x = x + (mw->w - 440) / 2;
455 }
456 /* check to see if text runs off the end */
457 if ((int) (strlen (st) * 8) > (mw->w - x))
458 return;
459 Fgl_write (mw->x + x, mw->y + y, st);
460 }
461
462
463 void
parse_iconline(char * st)464 parse_iconline (char *st)
465 {
466 int i, j, x, y;
467 sscanf (st, "icon %d %d", &x, &y);
468 /* find start of string */
469 i = 0;
470 for (j = 0; j < 3; j++)
471 {
472 while (isspace (st[i]) == 0)
473 {
474 if (st[i] == 0)
475 return; /* just silently ignore */
476 i++;
477 }
478 while (isspace (st[i]) != 0)
479 {
480 if (st[i] == 0)
481 return;
482 i++;
483 }
484 }
485 st += i;
486 /* get rid of the newline */
487 if (st[strlen (st) - 1] == 0xa)
488 st[strlen (st) - 1] = 0;
489 draw_help_icon (x, y, st);
490 }
491
492 void
draw_help_icon(int x,int y,char * icon)493 draw_help_icon (int x, int y, char *icon)
494 {
495 Rect* mw = &scr.main_win;
496 int i, l, w, h;
497 char ss[LC_PATH_MAX];
498 FILE *inf;
499 strcpy (ss, graphic_path);
500 strcat (ss, icon);
501 if ((inf = fopen (ss, "rb")) == NULL) {
502 return;
503 }
504 fseek (inf, 0L, SEEK_END);
505 l = ftell (inf);
506 fseek (inf, 0L, SEEK_SET);
507 if (l == 256)
508 w = h = 16;
509 else if (l == 1024)
510 w = h = 32;
511 else if (l == 2304)
512 w = h = 48;
513 else if (l == 4096)
514 w = h = 64;
515 else
516 {
517 fclose (inf);
518 return;
519 }
520 for (i = 0; i < l; i++)
521 *(help_graphic + i) = fgetc (inf);
522 fclose (inf);
523
524 /* Adjust x location to within center zone */
525 x = x + (mw->w - 440) / 2;
526
527 if (x > 0 && y > 0 && ((x + w) < mw->w) && ((y + h) < mw->h))
528 Fgl_putbox (mw->x + x, mw->y + y, w, h, help_graphic);
529 return;
530 }
531
532 void
parse_buttonline(char * st)533 parse_buttonline (char *st)
534 {
535 Rect* mw = &scr.main_win;
536 int i, j, x, y, w, h;
537 sscanf (st, "button %d %d %d %d", &x, &y, &w, &h);
538 /* find start of string */
539 i = 0;
540 for (j = 0; j < 5; j++)
541 {
542 while (isspace (st[i]) == 0)
543 {
544 if (st[i] == 0)
545 return; /* just silently ignore */
546
547 i++;
548 }
549 while (isspace (st[i]) != 0)
550 {
551 if (st[i] == 0)
552 return;
553 i++;
554 }
555 }
556 st += i;
557 /* get rid of the newline */
558 if (st[strlen (st) - 1] == 0xa)
559 st[strlen (st) - 1] = 0;
560
561 if (x < 0) {
562 /* centre x of box if x is negative */
563 x = (mw->w / 2) - (w / 2);
564 if (x < 0)
565 return; /* line was too long */
566 } else {
567 /* otherwise adjust x location to within center zone */
568 x = x + (mw->w - 440) / 2;
569 }
570
571 /* see if the button runs off the end */
572 if ((x + w) > mw->w)
573 return;
574 if (numof_help_buttons >= MAX_NUMOF_HELP_BUTTONS)
575 return;
576 help_button_x[numof_help_buttons] = x + mw->x;
577 help_button_y[numof_help_buttons] = y + mw->y;
578 help_button_w[numof_help_buttons] = w;
579 help_button_h[numof_help_buttons] = h;
580 if (strlen (st) >= MAX_LENOF_HELP_FILENAME)
581 return;
582 strcpy (help_button_s[numof_help_buttons], st);
583 numof_help_buttons++;
584 /* draw the box */
585 Fgl_hline (mw->x + x, mw->y + y,
586 mw->x + x + w, HELPBUTTON_COLOUR);
587 Fgl_hline (mw->x + x, mw->y + y + h,
588 mw->x + x + w, HELPBUTTON_COLOUR);
589 Fgl_line (mw->x + x, mw->y + y,
590 mw->x + x, mw->y + y + h, HELPBUTTON_COLOUR);
591 Fgl_line (mw->x + x + w, mw->y + y,
592 mw->x + x + w, mw->y + y + h, HELPBUTTON_COLOUR);
593 }
594
595 void
do_help_buttons(int x,int y)596 do_help_buttons (int x, int y)
597 {
598 int i;
599 if (numof_help_buttons <= 0)
600 return;
601 for (i = 0; i < numof_help_buttons; i++)
602 if (x > help_button_x[i]
603 && x < (help_button_x[i] + help_button_w[i])
604 && y > help_button_y[i]
605 && y < (help_button_y[i] + help_button_h[i]))
606 {
607 hide_mouse ();
608 draw_help_page (help_button_s[i]);
609 redraw_mouse ();
610 break;
611 }
612 }
613
614 void
parse_tbuttonline(char * st)615 parse_tbuttonline (char *st)
616 {
617 char s[100], ss[120], s1[100];
618 int i, j, x, y;
619 strcpy (s1, st); /* hpux fix? we can live with this. */
620
621 sscanf (s1, "tbutton %d %d %s", &x, &y, s);
622 /* find start of string */
623 i = 0;
624 for (j = 0; j < 4; j++) {
625 while (isspace (st[i]) == 0) {
626 if (st[i] == 0)
627 return; /* just silently ignore */
628 i++;
629 }
630 while (isspace (st[i]) != 0) {
631 if (st[i] == 0)
632 return;
633 i++;
634 }
635 }
636 st += i;
637 /* get rid of the newline */
638 if (st[strlen (st) - 1] == 0xa)
639 st[strlen (st) - 1] = 0;
640 if (x < 0)
641 x -= 2; /* needed to keep text centred */
642
643 sprintf (ss, "text %d %d ", x + 2, y + 2);
644 strcat (ss, st);
645 parse_textline (ss);
646 sprintf (ss, "button %d %d %d %d %s", x, y, (strlen (st) * 8) + 4, 12, s);
647 parse_buttonline (ss);
648 }
649