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