1 /* ---------------------------------------------------------------------- *
2  * mouse.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 "common.h"
11 #include "lctypes.h"
12 #include "lcintl.h"
13 #include "lin-city.h"
14 #include "mouse.h"
15 #include "engglobs.h"
16 #include "cliglobs.h"
17 #include "engine.h"
18 #include "screen.h"
19 #include "mps.h"
20 #include "fileutil.h"
21 #include "lchelp.h"
22 #include "pbar.h"
23 #include "lclib.h"
24 #include "module_buttons.h"
25 
26 #define DEBUG_MT_CODE 1
27 
28 extern Update_Scoreboard update_scoreboard;
29 
30 /* ---------------------------------------------------------------------- *
31  * Private global variables
32  * ---------------------------------------------------------------------- */
33 static struct mouse_button_struct buttons[NUM_BUTTONS];
34 static int mt_length;
35 static int mt_grp;
36 static char mt_name[20];
37 static short mouse_buffer_fresh = 0;
38 
39 void check_bulldoze_area (int x, int y);
40 
41 /* Mouse registry */
42 
43 static int mhandle_count;
44 
45 static Mouse_Handle * mhandle_first;
46 static Mouse_Handle * mhandle_last;
47 static Mouse_Handle * mhandle_current;
48 
49 /* ---------------------------------------------------------------------- *
50  * cs_mouse_handler
51  * --
52  * If the event was a mouse click or mouse release, enc_button contains
53  * the button identifier (e.g. LC_MOUSE_LEFTBUTTON) or'd with the
54  * action identifier (e.g. LC_MOUSE_RELEASE).  If the event was just a
55  * mouse move, then enc_button is 0.  You cannot specify multiple
56  * mouse buttons clicked at the same time using this interface.
57  * ---------------------------------------------------------------------- */
58 
59 void
cs_mouse_handler(int enc_button,int dx,int dy)60 cs_mouse_handler (int enc_button, int dx, int dy)
61 {
62     int x, y;
63     int button = enc_button & ~LC_MOUSE_RELEASE & ~LC_MOUSE_PRESS;
64     int button_pressed = enc_button & LC_MOUSE_PRESS;
65     int button_released = enc_button & LC_MOUSE_RELEASE;
66     int button_idx = button - 1;
67 
68     x = cs_mouse_x;
69     y = cs_mouse_y;
70 
71 #if defined (SVGALIB)
72     cs_mouse_x += dx * MOUSE_SENSITIVITY;
73     cs_mouse_y += dy * MOUSE_SENSITIVITY;
74 #else
75     cs_mouse_x += dx;
76     cs_mouse_y += dy;
77 #endif
78 
79 #if defined (SVGALIB)
80     if (cs_mouse_x >= cs_mouse_xmax)
81 	cs_mouse_x = cs_mouse_xmax;
82     if (cs_mouse_y >= cs_mouse_ymax)
83 	cs_mouse_y = cs_mouse_ymax;
84     if (cs_mouse_x < 0)
85 	cs_mouse_x = 0;
86     if (cs_mouse_y < 0)
87 	cs_mouse_y = 0;
88 #endif
89 
90     if (cs_mouse_x != x || cs_mouse_y != y)
91 	move_mouse (cs_mouse_x, cs_mouse_y);
92     x = cs_mouse_x;
93     y = cs_mouse_y;
94 
95     /* see if we are all the way up */
96     if (!mouse_initialized)
97 	return;
98 
99     /* button press */
100     if (button_pressed) {
101 
102 	/* maintain button press status */
103 	pixel_to_mappoint(cs_mouse_x, cs_mouse_y,
104 			  &buttons[button_idx].mappoint_x,
105 			  &buttons[button_idx].mappoint_y);
106 	buttons[button_idx].x = cs_mouse_x;
107 	buttons[button_idx].y = cs_mouse_y;
108 	buttons[button_idx].pressed = 1;
109 
110 	/* Try the event list before moving on to special cases */
111 	if (!mouse_handle_click(x, y, button)) {
112 	    switch (button) {
113 	    case LC_MOUSE_LEFTBUTTON:
114 		if (market_cb_flag) {
115 		    do_market_cb_mouse (x, y);
116 		    break;
117 		}
118 		else if (port_cb_flag) {
119 		    do_port_cb_mouse (x, y);
120 		    break;
121 		}
122 		else if (help_flag) {
123 		    do_help_mouse (x, y, button);
124 		    break;
125 		}
126 		else if (prefs_flag) {
127 		    do_prefs_mouse (x, y, button);
128 		    break;
129 		}
130 
131 		else if (load_flag || save_flag)
132 		    return;
133 
134 		/* This is the main screen */
135 		if (mouse_in_rect(&scr.main_win,x,y)) {
136 		    do_mouse_main_win(x, y, button);
137 		    refresh_main_screen ();
138 		    break;
139 		}
140 
141 		/* GCS Remove overlay  */
142 		/* This use of mouse clicks seems to contradict
143 		    Corey's mouse handler code */
144 		if (main_screen_flag == MAIN_SCREEN_EQUALS_MINI) {
145 		    main_screen_flag = MAIN_SCREEN_NORMAL_FLAG;
146 		    refresh_main_screen ();
147 		}
148 
149 		/* Other points too */
150 		do_mouse_other_buttons(x, y, button);
151 
152 		break;
153 
154 	    case LC_MOUSE_RIGHTBUTTON:
155 	    case LC_MOUSE_MIDDLEBUTTON:
156 		/* GCS FIX: This is my fix for right clicks on
157 		   main screen during yn_dialogs causing dialog to
158 		   be overwritten by screen content (similar effect
159 		   for market_cb overwritten by mps).  This fix could
160 		   be better, but will be better to confirm behavior
161 		   for X version before deciding final fix.
162 		*/
163 		if (market_cb_flag) {
164 		    // should dismiss cb?
165 		    break;
166 		}
167 		else if (port_cb_flag) {
168 		    // should dismiss cb?
169 		    break;
170 		}
171 		else if (help_flag) {
172 		    // do_help_mouse (x, y, button);   maybe should??
173 		    break;
174 		}
175 		else if (prefs_flag) {
176 		    break;
177 		}
178 		else if (db_flag) {
179 		    break;
180 		}
181 		else if (db_okflag) {
182 		    break;
183 		}
184 		else if (load_flag || save_flag)
185 		    return;
186 
187 		/* GCS Remove overlay  */
188 		if (main_screen_flag == MAIN_SCREEN_EQUALS_MINI) {
189 		    main_screen_flag = MAIN_SCREEN_NORMAL_FLAG;
190 		    refresh_main_screen ();
191 		}
192 
193 		/* This is the main screen */
194 		if (mouse_in_rect(&scr.main_win,x,y)) {
195 		    do_mouse_main_win(x, y, button);
196 		    refresh_main_screen ();
197 		    break;
198 		}
199 
200 		/* Other points too */
201 		do_mouse_other_buttons(x, y, button);
202 
203 		break;
204 
205 	    default:
206 		printf("Unknown mouse button in cs_mouse_handler\n");
207 	    }
208 	} /* mouse_handle_click couldn't. */
209     } else if (button_released) {
210 	button = enc_button - 16; /* probably shouldn't use this temporarily */
211 
212 	pixel_to_mappoint(cs_mouse_x, cs_mouse_y,
213 			  &buttons[button_idx].r_mappoint_x,
214 			  &buttons[button_idx].r_mappoint_y);
215 
216 	buttons[button_idx].r_x = cs_mouse_x;
217 	buttons[button_idx].r_y = cs_mouse_y;
218 	buttons[button_idx].pressed = 0;
219 
220 	switch (button) {
221 	case LC_MOUSE_LEFTBUTTON:
222 	    mt_draw(cs_mouse_x, cs_mouse_y, MT_SUCCESS);
223 	    break;
224 	case LC_MOUSE_RIGHTBUTTON:
225 	    break;
226 	case LC_MOUSE_MIDDLEBUTTON:
227 	    break;
228 	default:
229 	    break;
230 	};
231 	button = 0; /* backwards compatibility */
232 
233 	/* mouse moved */
234     } else {
235 	if (buttons[LC_MOUSE_LEFTBUTTON-1].pressed
236 	    && GROUP_IS_TRANSPORT(selected_module_group))
237 	{
238 	    mt_draw(cs_mouse_x, cs_mouse_y, MT_CONTINUE);
239 	}
240     }
241     cs_mouse_button = button;
242 }
243 
244 void
move_mouse(int x,int y)245 move_mouse (int x, int y)
246 {
247     Rect* mw = &scr.main_win;
248     int size;
249 
250     size = (main_groups[selected_module_group].size) * 16;
251 
252     /* GCS: we don't check for load_flag/save_flag because these guys
253        set db_flag = 1 */
254     if (mouse_in_rect(&scr.main_win,x,y)
255 	&& market_cb_flag == 0 && port_cb_flag == 0
256 	&& prefs_flag == 0 && help_flag == 0
257 	&& db_flag == 0 && db_okflag == 0)
258     {
259 	int mwoffset_x;
260 	int mwoffset_y;
261 	if (x > (mw->x + mw->w) - size)
262 	    x = (mw->x + mw->w) - size;
263 	if (y > (mw->y + mw->h) - size)
264 	    y = (mw->y + mw->h) - size;
265 	mwoffset_x = mw->x % 16;
266 	mwoffset_y = mw->y % 16;
267 	x -= mwoffset_x;
268 	y -= mwoffset_y;
269 	x &= 0xff0;
270 	y &= 0xff0;
271 	x += mwoffset_x;
272 	y += mwoffset_y;
273 
274 	hide_mouse ();
275 	mouse_hide_count--;
276 	draw_square_mouse (x, y, size);
277     }
278     else
279     {
280 	hide_mouse ();
281 	mouse_hide_count--;
282 	draw_normal_mouse (x, y);
283 	if (mappoint_stats_flag != 0 && market_cb_flag == 0
284 	    && port_cb_flag == 0)
285 	{
286 	    mappoint_stats_flag = 0;
287 	    update_scoreboard.mps = 1;
288 	}
289     }
290 }
291 
292 void
hide_mouse(void)293 hide_mouse (void)
294 {
295     mouse_hide_count++;
296     if (mouse_hide_count == 1) {
297 	if (mouse_type == MOUSE_TYPE_SQUARE)
298 	    hide_square_mouse ();
299 	else
300 	    hide_normal_mouse ();
301     }
302 }
303 
304 void
redraw_mouse(void)305 redraw_mouse (void)
306 {
307     mouse_hide_count--;
308     if (mouse_hide_count > 0)
309 	return;
310     mouse_hide_count = 0;
311     if (mouse_type == MOUSE_TYPE_SQUARE)
312 	redraw_square_mouse ();
313     else
314 	redraw_normal_mouse ();
315 }
316 
317 void
draw_square_mouse(int x,int y,int size)318 draw_square_mouse (int x, int y, int size)	/* size is pixels */
319 {
320     if (mouse_type == MOUSE_TYPE_NORMAL) {
321 	hide_normal_mouse ();
322 	mouse_type = MOUSE_TYPE_SQUARE;
323 	kmouse_val = 16;
324     }
325     omx = x;
326     omy = y;
327 #if defined (WIN32)
328     cs_square_mouse_visible = 1;
329     RefreshArea (omx - 2, omy - 2, omx + size + 1, omy + size + 1);
330 #else
331     Fgl_getbox (x - 2, y - 2, size + 4, 2, under_square_mouse_pointer_top);
332     Fgl_getbox (x - 2, y, 2, size, under_square_mouse_pointer_left);
333     Fgl_getbox (x + size, y, 2, size, under_square_mouse_pointer_right);
334     Fgl_getbox (x - 2, y + size, size + 4, 2, under_square_mouse_pointer_bottom);
335     mouse_buffer_fresh = 1;
336 
337     Fgl_hline (x - 2, y - 2, x + size + 1, yellow (31));
338     Fgl_hline (x - 1, y - 1, x + size, blue (31));
339     Fgl_hline (x - 2, y + size + 1, x + size + 1, yellow (31));
340     Fgl_hline (x - 1, y + size, x + size, blue (31));
341     Fgl_line (x - 2, y - 1, x - 2, y + size + 1, yellow (31));
342     Fgl_line (x - 1, y, x - 1, y + size, blue (31));
343     Fgl_line (x + size + 1, y - 1, x + size + 1, y + size + 1, yellow (31));
344     Fgl_line (x + size, y, x + size, y + size, blue (31));
345 #endif
346 }
347 
348 void
hide_square_mouse(void)349 hide_square_mouse (void)
350 {
351     int size;
352 
353     size = (main_groups[selected_module_group].size) * 16;
354 #if defined (WIN32)
355     cs_square_mouse_visible = 0;
356     RefreshArea (omx - 3, omy - 3, omx + size + 2, omy + size + 2);
357 #else
358     if (mouse_buffer_fresh) {
359       Fgl_putbox (omx - 2, omy - 2, size + 4, 2, under_square_mouse_pointer_top);
360       Fgl_putbox (omx - 2, omy, 2, size, under_square_mouse_pointer_left);
361       Fgl_putbox (omx + size, omy, 2, size, under_square_mouse_pointer_right);
362       Fgl_putbox (omx - 2, omy + size, size + 4, 2,
363 		  under_square_mouse_pointer_bottom);
364       mouse_buffer_fresh = 0;
365     } else {
366       //      printf ("Mouse buffer stale in hide_mouse!  Not putting back!\n");
367     }
368 #endif
369 }
370 
371 void
redraw_square_mouse(void)372 redraw_square_mouse (void)
373 {
374     int size;
375 
376     size = (main_groups[selected_module_group].size) * 16;
377 
378 #if defined (WIN32)
379     cs_square_mouse_visible = 1;
380     RefreshArea (omx - 2, omy - 2, omx + size + 1, omy + size + 1);
381 #else
382     Fgl_getbox (omx - 2, omy - 2, size + 4, 2, under_square_mouse_pointer_top);
383     Fgl_getbox (omx - 2, omy, 2, size, under_square_mouse_pointer_left);
384     Fgl_getbox (omx + size, omy, 2, size, under_square_mouse_pointer_right);
385     Fgl_getbox (omx - 2, omy + size, size + 4, 2, under_square_mouse_pointer_bottom);
386     mouse_buffer_fresh = 1;
387 
388     Fgl_hline (omx - 2, omy - 2, omx + size + 1, yellow (31));
389     Fgl_hline (omx - 1, omy - 1, omx + size, blue (31));
390     Fgl_hline (omx - 2, omy + size + 1, omx + size + 1, yellow (31));
391     Fgl_hline (omx - 1, omy + size, omx + size, blue (31));
392     Fgl_line (omx - 2, omy - 1, omx - 2, omy + size + 1, yellow (31));
393     Fgl_line (omx - 1, omy, omx - 1, omy + size, blue (31));
394     Fgl_line (omx + size + 1, omy - 1, omx + size + 1, omy + size + 1, yellow (31));
395     Fgl_line (omx + size, omy, omx + size, omy + size, blue (31));
396 #endif
397 }
398 
399 void
draw_normal_mouse(int x,int y)400 draw_normal_mouse (int x, int y)
401 {
402     if (mouse_type == MOUSE_TYPE_SQUARE) {
403 	hide_square_mouse ();
404 	mouse_type = MOUSE_TYPE_NORMAL;
405 	kmouse_val = 8;
406     }
407 #if defined (SVGALIB)
408     Fgl_getbox (x, y, 8, 8, under_mouse_pointer);
409     if (x > cs_mouse_xmax - 8 || y > cs_mouse_ymax - 8) {
410 	Fgl_enableclipping ();
411 	Fgl_setclippingwindow (0, 0, cs_mouse_xmax, cs_mouse_ymax);
412 	Fgl_putbox (x, y, 8, 8, mouse_pointer);
413 	Fgl_disableclipping ();
414     } else {
415 	Fgl_putbox (x, y, 8, 8, mouse_pointer);
416     }
417 #endif
418     mox = x;
419     moy = y;
420 }
421 
422 void
hide_normal_mouse(void)423 hide_normal_mouse (void)
424 {
425 #if defined (SVGALIB)
426     if (mox > cs_mouse_xmax - 8 || moy > cs_mouse_ymax - 8) {
427 	Fgl_enableclipping ();
428 	Fgl_setclippingwindow (0, 0, cs_mouse_xmax, cs_mouse_ymax);
429 	Fgl_putbox (mox, moy, 8, 8, under_mouse_pointer);
430 	Fgl_disableclipping ();
431     } else {
432 	Fgl_putbox (mox, moy, 8, 8, under_mouse_pointer);
433     }
434 #endif
435 }
436 
437 void
redraw_normal_mouse(void)438 redraw_normal_mouse (void)
439 {
440 #if defined (SVGALIB)
441     if (mox > cs_mouse_xmax - 8 || moy > cs_mouse_ymax - 8) {
442 	Fgl_enableclipping ();
443 	Fgl_setclippingwindow (0, 0, cs_mouse_xmax, cs_mouse_ymax);
444 	Fgl_getbox (mox, moy, 8, 8, under_mouse_pointer);
445 	Fgl_putbox (mox, moy, 8, 8, mouse_pointer);
446 	Fgl_disableclipping ();
447     } else {
448 	/* may have changed */
449 	Fgl_getbox (mox, moy, 8, 8, under_mouse_pointer);
450 	Fgl_putbox (mox, moy, 8, 8, mouse_pointer);
451     }
452 #endif
453 }
454 
455 void
do_mouse_main_win(int px,int py,int button)456 do_mouse_main_win (int px, int py, int button)
457 {
458     Rect* mw = &scr.main_win;
459     int size;
460     int x, y; /* mappoint */
461     int mod_x, mod_y; /* upper left coords of module clicked on */
462     int mps_result;
463 
464     if (button == LC_MOUSE_MIDDLEBUTTON)
465 	return;
466 
467     pixel_to_mappoint(px, py, &x, &y);
468 
469     if (MP_TYPE(x,y) == CST_USED) {
470 	mod_x = MP_INFO(x,y).int_1;
471 	mod_y = MP_INFO(x,y).int_2;
472     } else {
473 	mod_x = x;
474 	mod_y = y;
475     }
476 
477     /* Bring up mappoint_stats for any right mouse click */
478     /* XXX: Environmental (right click) MPS should show the clicked
479        square, not the master square */
480     if (button == LC_MOUSE_RIGHTBUTTON) {
481 	mps_set(mod_x, mod_y, MPS_ENV);
482 	return;
483     }
484 
485     /* Check rocket launches */
486     /* XXX: put this in modules/rocket.c */
487     /* XXX: wait for second click to ask for launch */
488     if (button == LC_MOUSE_LEFTBUTTON) {
489 	if (MP_TYPE(mod_x,mod_y) >= CST_ROCKET_5 &&
490 	    MP_TYPE(mod_x,mod_y) <= CST_ROCKET_7) {
491 	  if (ask_launch_rocket_click (mod_x,mod_y)) {
492 	    launch_rocket (mod_x, mod_y);
493 	  }
494 	}
495     }
496 
497     /* Handle multitransport */
498     if (button == LC_MOUSE_LEFTBUTTON &&
499 	GROUP_IS_TRANSPORT(selected_module_group)) {
500 	if (mt_draw (px, py, MT_START)) {
501 	    /* We need to set mps to current location, since the user might
502 	       click on the transport to see the mps */
503 
504 	    mps_set(mod_x, mod_y, MPS_MAP);
505 	    return;
506 	}
507     }
508 
509     /* Handle bulldozing */
510     if (selected_module_type == CST_GREEN && button != LC_MOUSE_RIGHTBUTTON) {
511 	check_bulldoze_area (x, y);
512 	return;
513     }
514 
515     /* Bring up mappoint_stats for certain left mouse clicks */
516     /* XXX: Need to check market and port double-clicks here */
517     if (MP_TYPE(x,y) != CST_GREEN) {
518 	mps_result = mps_set(mod_x, mod_y, MPS_MAP);
519 
520 	if (mps_result >= 1) {
521 	    if (MP_GROUP(mod_x,mod_y) == GROUP_MARKET)
522 	    {
523 		clicked_market_cb (mod_x, mod_y);
524 		return;
525 	    }
526 	    else if (MP_GROUP(mod_x,mod_y) == GROUP_PORT)
527 	    {
528 		clicked_port_cb (mod_x, mod_y);
529 		return;
530 	    }
531 	}
532 	return;
533     }
534 
535     /* OK, by now we are certain that the user wants to place the item.
536        Set the origin based on the size of the selected_module_type, and
537        see if the selected item will fit. */
538     size = main_groups[selected_module_group].size;
539     if (px > (mw->x + mw->w) - size*16)
540 	px = (mw->x + mw->w) - size*16;
541     if (py > (mw->y + mw->h) - size*16)
542 	py = (mw->y + mw->h) - size*16;
543     pixel_to_mappoint(px, py, &x, &y);
544 
545     if (size >= 2)
546     {
547 	if (MP_TYPE(x + 1,y) != CST_GREEN
548 	    || MP_TYPE(x,y + 1) != CST_GREEN
549 	    || MP_TYPE(x + 1,y + 1) != CST_GREEN)
550 	    return;
551     }
552     if (size >= 3)
553     {
554 	if (MP_TYPE(x + 2,y) != CST_GREEN
555 	    || MP_TYPE(x + 2,y + 1) != CST_GREEN
556 	    || MP_TYPE(x + 2,y + 2) != CST_GREEN
557 	    || MP_TYPE(x + 1,y + 2) != CST_GREEN
558 	    || MP_TYPE(x,y + 2) != CST_GREEN)
559 	    return;
560     }
561     if (size == 4)
562     {
563 	if (MP_TYPE(x + 3,y) != CST_GREEN
564 	    || MP_TYPE(x + 3,y + 1) != CST_GREEN
565 	    || MP_TYPE(x + 3,y + 2) != CST_GREEN
566 	    || MP_TYPE(x + 3,y + 3) != CST_GREEN
567 	    || MP_TYPE(x + 2,y + 3) != CST_GREEN
568 	    || MP_TYPE(x + 1,y + 3) != CST_GREEN
569 	    || MP_TYPE(x,y + 3) != CST_GREEN)
570 	    return;
571     }
572 
573     /* Place the selected item */
574     switch (place_item (x, y, selected_module_type)) {
575     case 0:
576 	/* Success */
577 	break;
578     case -1:
579 	/* Not enough money */
580 	no_credit_build_msg (selected_module_group);
581 	break;
582     case -2:
583 	/* Improper port placement */
584 	/* TRANSLATORS: The part about the cup of tea is one of Ian's
585 	   jokes, but the part about ports needing to be connected
586 	   to rivers is true.  */
587 	if (yn_dial_box (_("WARNING"),
588 			 _("Ports need to be"),
589 			 _("connected to rivers!"),
590 			 _("Want to make a cup of tea?")) != 0)
591 	    while (yn_dial_box (_("TEA BREAK"),
592 				_("Boil->pour->wait->stir"),
593 				_("stir->pour->stir->wait->drink...ahhh"),
594 				_("Have you finished yet?")) == 0);
595 	break;
596     }
597 }
598 
599 void
do_mouse_other_buttons(int x,int y,int button)600 do_mouse_other_buttons (int x, int y, int button)
601 {
602     Rect* mw = &scr.main_win;
603 
604     if (0) {} /* XXX: Cute, very cute */
605 
606     /* main screen border scroll areas */
607 
608     /* up */
609     else if (x >= (mw->x - 8) && x < (mw->x + mw->w + 8)
610 	     && y >= (mw->y - 8) && y < mw->y) {
611 	int new_origin_y;
612 	if (button == LC_MOUSE_RIGHTBUTTON) {
613 	    new_origin_y = main_screen_originy - RIGHT_MOUSE_MOVE_VAL;
614 	} else {
615 	    new_origin_y = main_screen_originy - 1;
616 	}
617 	adjust_main_origin (main_screen_originx, new_origin_y, 1);
618     }
619     /* down */
620     else if (x >= (mw->x - 8) && x < (mw->x + mw->w + 8)
621 	     && y > (mw->y + mw->h)
622 	     && y < (mw->y + mw->h + 16)) {	/* 16 for bigger area */
623 	int new_origin_y;
624 	if (button == LC_MOUSE_RIGHTBUTTON) {
625 	    new_origin_y = main_screen_originy + RIGHT_MOUSE_MOVE_VAL;
626 	} else {
627 	    new_origin_y = main_screen_originy + 1;
628 	}
629 	adjust_main_origin (main_screen_originx, new_origin_y, 1);
630     }
631     /* left */
632     else if (x >= (mw->x - 16) && x < mw->x
633 	     && y >= (mw->y - 8) && y < (mw->y + mw->h + 8)) {
634 	int new_origin_x;
635 	if (button == LC_MOUSE_RIGHTBUTTON) {
636 	    new_origin_x = main_screen_originx - RIGHT_MOUSE_MOVE_VAL;
637 	} else {
638 	    new_origin_x = main_screen_originx - 1;
639 	}
640 	adjust_main_origin (new_origin_x, main_screen_originy, 1);
641     }
642     /* right */
643     else if (x > (mw->x + mw->w)
644 	     && x < (mw->x + mw->w + 8)
645 	     && y > (mw->y - 8) && y < (mw->y + mw->w + 8)) {
646 	int new_origin_x;
647 	if (button == LC_MOUSE_RIGHTBUTTON) {
648 	    new_origin_x = main_screen_originx + RIGHT_MOUSE_MOVE_VAL;
649 	} else {
650 	    new_origin_x = main_screen_originx + 1;
651 	}
652 	adjust_main_origin (new_origin_x, main_screen_originy, 1);
653     }
654 
655     /* This is the mini window. Clicking here move the main window
656        to this point
657     */
658 
659 /*** Miniscreen selector buttons removed in CVS Revision 1.24 ***/
660 
661     /* this is the menu button */
662     else if (mouse_in_rect (&scr.menu_button,x,y)) {
663 	activate_help ("menu.hlp");
664     }
665 
666     /* this is the help button */
667     else if (mouse_in_rect (&scr.help_button,x,y)) {
668 	activate_help ("index.hlp");
669     }
670 
671     /* this is the results (stats) button */
672     else if (mouse_in_rect (&scr.results_button,x,y)) {
673 	if (button == LC_MOUSE_RIGHTBUTTON)
674 	    return;
675 	window_results ();
676     }
677 
678     /* XXX: WCK: This is broken; should be a mouse handler in
679        mps.c anyway */
680     /* Advance mps screen if clicked on */
681     else if (mouse_in_rect (&scr.mappoint_stats,x,y)) {
682 	if (button == LC_MOUSE_RIGHTBUTTON) {
683 	    switch (mps_global_style) {
684 	    case MPS_GLOBAL_FINANCE:
685 		activate_help ("finance.hlp");
686 		break;
687 	    case MPS_GLOBAL_OTHER_COSTS:
688 		activate_help ("other-costs.hlp");
689 		break;
690 	    case MPS_GLOBAL_HOUSING:
691 		activate_help ("housing.hlp");
692 		break;
693 	    }
694 	    return;
695 	}
696 	mps_global_advance();
697     }
698 
699    /* Advance monthgraph screen if clicked on */
700     else if (mouse_in_rect (&scr.monthgraph,x,y)) {
701 	if (button == LC_MOUSE_RIGHTBUTTON) {
702 	    if (monthgraph_style == MONTHGRAPH_STYLE_ECONOMY) {
703 		activate_help ("economy.hlp");
704 	    } else {
705 		activate_help ("sustain.hlp");
706 	    }
707 	    return;
708 	}
709 	advance_monthgraph_style ();
710 	refresh_monthgraph ();
711     }
712 
713     /*
714       // no more buttons to click on, see if it's help for somewhere else.
715       // ***************************
716     */
717 
718     if (mouse_in_rect (&scr.pbar_area,x,y)) {
719       pbar_mouse(x, y, button);
720       return;
721     }
722 
723     if (button == LC_MOUSE_RIGHTBUTTON) {
724 
725 #if defined (FINANCE_WINDOW)
726 
727       /* now check for finance window */
728       if (x >= FINANCE_X && x <= (FINANCE_X + FINANCE_W)
729 	  && y >= FINANCE_Y && y <= (FINANCE_Y + FINANCE_H))
730 	{
731 	  activate_help ("finance.hlp");
732 	  return;
733 	}
734 #endif
735 
736 
737 #if defined (commentout)
738       /* GCS FIX -- This is obsolete, right??? */
739       /*     -- If so, can delete scr.sust from geometry.c */
740       /* now check for the sustain window */
741       else if (mouse_in_rect (&scr.sust,x,y)) {
742 	activate_help ("sustain.hlp");
743 	return;
744       }
745 #endif
746     }
747 }
748 
749 
750 void
check_bulldoze_area(int x,int y)751 check_bulldoze_area (int x, int y)
752 {
753     int xx, yy, g;
754     if (MP_TYPE(x,y) == CST_USED) {
755 	xx = MP_INFO(x,y).int_1;
756 	yy = MP_INFO(x,y).int_2;
757     } else {
758 	xx = x;
759 	yy = y;
760     }
761     g = MP_GROUP(xx,yy);
762 
763     /* GCS: Free bulldozing of most recently placed item is disabled.
764        Still not sure how this can be done w/ multiplayer. */
765     if (g == GROUP_MONUMENT && monument_bul_flag == 0) {
766 	if (yn_dial_box (_("WARNING"),
767 			 _("Bulldozing a monument costs"),
768 			 _("a lot of money."),
769 			 _("Want to bulldoze?")) == 0)
770 	    return;
771 	monument_bul_flag = 1;
772     }
773     else if (g == GROUP_RIVER && river_bul_flag == 0) {
774 	if (yn_dial_box (_("WARNING"),
775 			 _("Bulldozing a section of river"),
776 			 _("costs a lot of money."),
777 			 _("Want to bulldoze?")) == 0)
778 	    return;
779 	river_bul_flag = 1;
780     }
781     else if (g == GROUP_SHANTY && shanty_bul_flag == 0) {
782 	if (yn_dial_box (_("WARNING"),
783 			 _("Bulldozing a shanty town costs a"),
784 			 _("lot of money and may cause a fire."),
785 			 _("Want to bulldoze?")) == 0)
786 	    return;
787 	shanty_bul_flag = 1;
788     }
789     else if (g == GROUP_TIP) {
790 	ok_dial_box ("nobull-tip.mes", BAD, 0L);
791 	return;
792     }
793 
794     bulldoze_item (xx,yy);
795 }
796 
797 /* XXX: mouse.c?  wtf! */
798 void
fire_area(int x,int y)799 fire_area (int x, int y)
800 {
801   do_bulldoze_area (CST_FIRE_1, x, y);
802   refresh_main_screen ();
803   /*
804     // update transport or we get stuff put in
805     // the area from connected tracks etc.
806   */
807 }
808 
809 /* Called from event handler when middle button is held while moving
810    the mouse.  Will probably handle multi-transport eventually */
811 
812 /* XXX: Need to put this in a header somewhere */
813 
814 void
drag_screen(void)815 drag_screen (void)
816 {
817     int cur_mappoint_x = 0;
818     int cur_mappoint_y = 0;
819 
820     int cur_winpoint_x = 0;
821     int cur_winpoint_y = 0;
822 
823     int origin_x = 0;
824     int origin_y = 0;
825 
826     int in_main_window;
827 
828     if (buttons[LC_MOUSE_MIDDLEBUTTON-1].mappoint_x == 0)
829 	return;   /* Not pressed in main window */
830 
831     in_main_window = pixel_to_mappoint(cs_mouse_x, cs_mouse_y,
832 				       &cur_mappoint_x, &cur_mappoint_y);
833 
834     pixel_to_winpoint(cs_mouse_x, cs_mouse_y, &cur_winpoint_x, &cur_winpoint_y);
835 
836     origin_x =
837 	    buttons[LC_MOUSE_MIDDLEBUTTON-1].mappoint_x - cur_winpoint_x;
838     origin_y =
839 	    buttons[LC_MOUSE_MIDDLEBUTTON-1].mappoint_y - cur_winpoint_y;
840 
841     adjust_main_origin (origin_x, origin_y, 1);
842 }
843 
844 void
do_market_cb_template(int x,int y,int is_market_cb)845 do_market_cb_template (int x, int y, int is_market_cb)
846 {
847     Rect* mcb = &scr.market_cb;
848     int is_sell;
849 
850     hide_mouse ();
851     if (!mouse_in_rect(mcb,x,y)) {
852 	if (is_market_cb) {
853 	    close_market_cb ();
854 	} else {
855 	    close_port_cb ();
856 	}
857 	redraw_mouse ();
858 	return;
859     }
860 
861     if (x >= mcb->x + 8 && x <= mcb->x + 6 * 8) {
862 	is_sell = 0;
863     } else if (x >= mcb->x + 10 * 8 && x <= mcb->x + mcb->w - 8) {
864 	is_sell = 1;
865     } else {
866 	redraw_mouse ();
867 	return;
868     }
869 
870     /* jobs */
871     if (is_market_cb && y >= mcb->y + 36 + (CB_SPACE * 0)
872       && y <= mcb->y + 52 + (CB_SPACE * 0))	{
873 	int flag = is_sell ? FLAG_MS_JOBS : FLAG_MB_JOBS;
874 	MP_INFO(mcbx,mcby).flags ^= flag;
875 	draw_cb_box (0, is_sell, MP_INFO(mcbx,mcby).flags & flag);
876     }
877     /* food */
878     else if (y >= mcb->y + 36 + (CB_SPACE * 1)
879       && y <= mcb->y + 52 + (CB_SPACE * 1)) {
880 	int flag = is_sell ? FLAG_MS_FOOD : FLAG_MB_FOOD;
881 	MP_INFO(mcbx,mcby).flags ^= flag;
882 	draw_cb_box (1, is_sell, MP_INFO(mcbx,mcby).flags & flag);
883     }
884     /* coal */
885     else if (y >= mcb->y + 36 + (CB_SPACE * 2)
886       && y <= mcb->y + 52 + (CB_SPACE * 2)) {
887 	int flag = is_sell ? FLAG_MS_COAL : FLAG_MB_COAL;
888 	MP_INFO(mcbx,mcby).flags ^= flag;
889 	draw_cb_box (2, is_sell, MP_INFO(mcbx,mcby).flags & flag);
890     }
891     /* ore */
892     else if (y >= mcb->y + 36 + (CB_SPACE * 3)
893       && y <= mcb->y + 52 + (CB_SPACE * 3)) {
894 	int flag = is_sell ? FLAG_MS_ORE : FLAG_MB_ORE;
895 	MP_INFO(mcbx,mcby).flags ^= flag;
896 	draw_cb_box (3, is_sell, MP_INFO(mcbx,mcby).flags & flag);
897     }
898     /* goods */
899     else if (y >= mcb->y + 36 + (CB_SPACE * 4)
900       && y <= mcb->y + 52 + (CB_SPACE * 4)) {
901 	int flag = is_sell ? FLAG_MS_GOODS : FLAG_MB_GOODS;
902 	MP_INFO(mcbx,mcby).flags ^= flag;
903 	draw_cb_box (4, is_sell, MP_INFO(mcbx,mcby).flags & flag);
904     }
905     /* steel */
906     else if (y >= mcb->y + 36 + (CB_SPACE * 5)
907       && y <= mcb->y + 52 + (CB_SPACE * 5)) {
908 	int flag = is_sell ? FLAG_MS_STEEL : FLAG_MB_STEEL;
909 	MP_INFO(mcbx,mcby).flags ^= flag;
910 	draw_cb_box (5, is_sell, MP_INFO(mcbx,mcby).flags & flag);
911     }
912 
913     redraw_mouse ();
914 
915 #if defined (NETWORK_ENABLE)
916     if (MP_INFO(mcbx,mcby).flags != old_flags) {
917 	send_flags (mcbx,mcby);
918     }
919 #endif
920 }
921 
922 void
do_market_cb_mouse(int x,int y)923 do_market_cb_mouse (int x, int y)
924 {
925     do_market_cb_template (x, y, 1);
926 }
927 
928 void
do_port_cb_mouse(int x,int y)929 do_port_cb_mouse (int x, int y)
930 {
931     do_market_cb_template (x, y, 0);
932 }
933 
934 void
no_credit_build_msg(int selected_group)935 no_credit_build_msg (int selected_group)
936 {
937 #ifdef GROUP_POWER_SOURCE_NO_CREDIT
938   if (selected_group == GROUP_POWER_SOURCE) {
939     ok_dial_box ("no-credit-solar-power.mes", BAD, 0L);
940     return;
941   }
942 #endif
943 #ifdef GROUP_UNIVERSITY_NO_CREDIT
944   if (selected_group == GROUP_UNIVERSITY) {
945     ok_dial_box ("no-credit-university.mes", BAD, 0L);
946     return;
947   }
948 #endif
949 #ifdef GROUP_PARKLAND_NO_CREDIT
950   if (selected_group == GROUP_PARKLAND) {
951     ok_dial_box ("no-credit-parkland.mes", BAD, 0L);
952     return;
953   }
954 #endif
955 #ifdef GROUP_RECYCLE_NO_CREDIT
956   if (selected_group == GROUP_RECYCLE) {
957     ok_dial_box ("no-credit-recycle.mes", BAD, 0L);
958     return;
959   }
960 #endif
961 #ifdef GROUP_ROCKET
962   if (selected_group == GROUP_ROCKET) {
963     ok_dial_box ("no-credit-rocket.mes", BAD, 0L);
964     return;
965   }
966 #endif
967   return;
968 }
969 
970 void
choose_residence(void)971 choose_residence (void)
972 {
973     int cost;
974     FILE* tempfile;
975     char* s = (char*) malloc (lc_save_dir_len + 9);
976 
977     sprintf (s, "%s%c%s", lc_save_dir, PATH_SLASH, "res.tmp");
978     if ((tempfile = fopen (s, "w")) == 0)
979 	do_error ("Can't write res.tmp");
980     free (s);
981 
982     fprintf (tempfile,
983 	     /* TRANSLATORS: Don't translate the leading "text" */
984 	     _("text -1 20 Choose the type of residence you want\n"));
985     fprintf (tempfile,
986 	     "text -1 30 =====================================\n");
987     fprintf (tempfile,
988 	     _("text -1 45 (LB=Low Birthrate HB=High Birthrate)\n"));
989     fprintf (tempfile,
990 	     _("text -1 55 (LD=Low Deathrate HD=High Deathrate)\n"));
991     fprintf (tempfile,
992 	     _("text -1 85 Low Tech\n"));
993 
994     cost = get_group_cost(GROUP_RESIDENCE_LL);
995     fprintf (tempfile, _("text 68 106 Cost %4d\n"), cost);
996     fprintf (tempfile, "icon 85 120 reslowlow.csi\n");
997     fprintf (tempfile, "button 83 118 52 52 return1\n");
998     /* TRANSLATORS: Only translate "pop" <<for population>> */
999     fprintf (tempfile, _("tbutton 82 180 return1 pop 50\n"));
1000     /* TRANSLATORS: Only translate LB, HD (low birth, high death) */
1001     fprintf (tempfile, _("text 89 195 LB HD\n"));
1002 
1003     cost = get_group_cost(GROUP_RESIDENCE_ML);
1004     fprintf (tempfile, _("text 155 106 Cost %4d\n"), cost);
1005     fprintf (tempfile, "icon 170 120 resmedlow.csi\n");
1006     fprintf (tempfile, "button 168 118 52 52 return2\n");
1007     fprintf (tempfile, _("tbutton 164 180 return2 pop 100\n"));
1008     fprintf (tempfile, _("text 175 195 HB LD\n"));
1009 
1010     cost = get_group_cost(GROUP_RESIDENCE_HL);
1011     fprintf (tempfile, _("text 238 106 Cost %4d\n"), cost);
1012     fprintf (tempfile, "icon 255 120 reshilow.csi\n");
1013     fprintf (tempfile, "button 253 118 52 52 return3\n");
1014     fprintf (tempfile, _("tbutton 250 180 return3 pop 200\n"));
1015     fprintf (tempfile, _("text 261 195 HB HD\n"));
1016 
1017     fprintf (tempfile, _("text -1 215 Click on one to select\n"));
1018     fprintf (tempfile, "text -1 225 ======================\n");
1019 
1020     if (((tech_level * 10) / MAX_TECH_LEVEL) > 2) {
1021 	fprintf (tempfile, _("text -1 255 High Tech\n"));
1022 
1023 	cost = get_group_cost(GROUP_RESIDENCE_LH);
1024 	fprintf (tempfile, _("text 68 276 Cost %4d\n"), cost);
1025 	fprintf (tempfile, "icon 85 290 reslowhi.csi\n");
1026 	fprintf (tempfile, "button 83 288 52 52 return4\n");
1027 	fprintf (tempfile, _("tbutton 78 350 return4 pop 100\n"));
1028 	fprintf (tempfile, _("text 89 365 LB HD\n"));
1029 
1030 	cost = get_group_cost(GROUP_RESIDENCE_MH);
1031 	fprintf (tempfile, _("text 155 276 Cost %4d\n"), cost);
1032 	fprintf (tempfile, "icon 170 290 resmedhi.csi\n");
1033 	fprintf (tempfile, "button 168 288 52 52 return5\n");
1034 	fprintf (tempfile, _("tbutton 164 350 return5 pop 200\n"));
1035 	fprintf (tempfile, _("text 175 365 HB LD\n"));
1036 
1037 	cost = get_group_cost(GROUP_RESIDENCE_HH);
1038 	fprintf (tempfile, _("text 238 276 Cost %4d\n"), cost);
1039 	fprintf (tempfile, "icon 255 290 reshihi.csi\n");
1040 	fprintf (tempfile, "button 253 288 52 52 return6\n");
1041 	fprintf (tempfile, _("tbutton 250 350 return6 pop 400\n"));
1042 	fprintf (tempfile, _("text 261 365 HB HD\n"));
1043     }
1044 
1045     fclose (tempfile);
1046     block_help_exit = 1;
1047     activate_help ("res.tmp");
1048 }
1049 
1050 
1051 /* We can only draw temporary transport on GROUP_TRACK, GROUP_ROAD,
1052    GROUP_RAIL, or GROUP_BARE.  For temporary draws over GROUP_BARE,
1053    FLAG_IS_TRANSPORT is not set.  For temporary draws over existing
1054    transport of a different type, FLAG_IS_TRANSPORT is set, and
1055    FLAG_MULTI_TRANSPORT_PREV will be set to 0 if the existing transport is
1056    of the cheaper sort (e.g. GROUP_TRACK when overwriting with GROUP_ROAD),
1057    and set to 1 if the existing transport if the more expensive sort
1058    (e.g. GROUP_RAIL when overwriting GROUP_ROAD).
1059 */
1060 int
mt_erase(int x,int y)1061 mt_erase(int x, int y)
1062 {
1063     if (x < 0 || y < 0 || x >= WORLD_SIDE_LEN || y >= WORLD_SIDE_LEN)
1064 	return 1;
1065     if (MP_INFO(x,y).flags & FLAG_MULTI_TRANSPORT) {
1066 	if (MP_INFO(x,y).flags & FLAG_IS_TRANSPORT) {
1067 	    if (!(MP_INFO(x,y).flags & FLAG_MULTI_TRANS_PREV)) {
1068 		if (mt_grp == GROUP_TRACK) {
1069 		    MP_TYPE(x,y) = CST_ROAD_LR;
1070 		    MP_GROUP(x,y) = GROUP_ROAD;
1071 		} else {
1072 		    MP_TYPE(x,y) = CST_TRACK_LR;
1073 		    MP_GROUP(x,y) = GROUP_TRACK;
1074 		}
1075 	    } else {
1076 		if (mt_grp == GROUP_RAIL) {
1077 		    MP_TYPE(x,y) = CST_ROAD_LR;
1078 		    MP_GROUP(x,y) = GROUP_ROAD;
1079 		} else {
1080 		    MP_TYPE(x,y) = CST_RAIL_LR;
1081 		    MP_GROUP(x,y) = GROUP_RAIL;
1082 		}
1083 	    }
1084 	} else {
1085 	    MP_TYPE(x,y) = CST_GREEN;
1086 	    MP_GROUP(x,y) = GROUP_BARE;
1087 	}
1088 	MP_INFO(x,y).flags &= ~FLAG_MULTI_TRANSPORT;
1089 	return 1;
1090     } else if ((MP_INFO(x,y).flags & FLAG_IS_TRANSPORT)
1091 	       && (mt_grp == MP_GROUP(x,y))) {
1092 	return 1;
1093     }
1094     return 0;
1095 }
1096 
1097 int
mt_temp(int x,int y)1098 mt_temp(int x, int y)
1099 {
1100     if (x < 0 || y < 0 || x >= WORLD_SIDE_LEN || y >= WORLD_SIDE_LEN)
1101 	return 1;
1102     if (MP_INFO(x,y).flags & FLAG_IS_TRANSPORT) {
1103 	if (MP_GROUP(x,y) == mt_grp) {
1104 	    return 1;
1105 	} else if (!overwrite_transport_flag) {
1106 	    return 0;
1107 	} else {
1108 	    if ((MP_GROUP(x,y) == GROUP_TRACK) ||
1109 		((MP_GROUP(x,y) == GROUP_ROAD) && (mt_grp == GROUP_TRACK)))
1110 	    {
1111 		MP_INFO(x,y).flags &= ~FLAG_MULTI_TRANS_PREV;
1112 	    } else {
1113 		MP_INFO(x,y).flags |= FLAG_MULTI_TRANS_PREV;
1114 	    }
1115 	    mt_length++;
1116 	    MP_TYPE(x,y) = selected_module_type;
1117 	    MP_GROUP(x,y) = mt_grp;
1118 	    MP_INFO(x,y).flags |= FLAG_MULTI_TRANSPORT;
1119 	    return 1;
1120 	}
1121     } else if (MP_GROUP(x,y) == GROUP_BARE) {
1122 	mt_length++;
1123 	MP_TYPE(x,y) = selected_module_type;
1124 	MP_GROUP(x,y) = mt_grp;
1125 	MP_INFO(x,y).flags |= FLAG_MULTI_TRANSPORT;
1126 	return 1;
1127     }
1128     return 0;
1129 }
1130 
1131 int
mt_perm(int x,int y)1132 mt_perm(int x, int y)
1133 {
1134     /* By now, it has already been mt_erase()'d */
1135     if (x < 0 || y < 0 || x >= WORLD_SIDE_LEN || y >= WORLD_SIDE_LEN)
1136 	return 1;
1137     if (MP_INFO(x,y).flags & FLAG_IS_TRANSPORT) {
1138 	if (MP_GROUP(x,y) == mt_grp) {
1139 	    return 1;
1140 	} else if (!overwrite_transport_flag) {
1141 	    return 0;
1142 	} else {
1143 	    bulldoze_item(x,y);
1144 	    place_item (x,y,selected_module_type);
1145 	    return 1;
1146 	}
1147     } else if (MP_GROUP(x,y) == GROUP_BARE) {
1148 	place_item (x,y,selected_module_type);
1149 	return 1;
1150     }
1151     return 0;
1152 }
1153 
1154 int
do_mt_draw(int x1,int x2,int y1,int y2,int (* mode)())1155 do_mt_draw (int x1, int x2, int y1, int y2, int (*mode)())
1156 {
1157     int dir = 1;
1158     int horiz = 1;
1159     int vert = 2;
1160     int x_dir = cmp(x1, x2);
1161     int y_dir = cmp(y1, y2);
1162     int ix = x1;
1163     int iy = y1;
1164 
1165     mt_length = 0;
1166 
1167     if (!mode(ix, iy))
1168 	return 0;
1169 
1170     while ((ix != x2 || iy != y2) && dir) {
1171 	/* try horizontal, unless already vertical */
1172 	if (dir == 1) {
1173 	    if (ix == x2) {
1174 		horiz = 0;
1175 		dir = vert;
1176 	    } else if (mode(ix+x_dir, iy)) {
1177 		horiz = 1;
1178 		vert = 2;
1179 		ix += x_dir;
1180 	    } else {
1181 		horiz = 0;
1182 		dir = vert;
1183 	    }
1184 	} else if (dir == 2) {
1185 	    if (iy == y2) {
1186 		vert = 0;
1187 		dir = horiz;
1188 	    } else if (mode(ix, iy+y_dir)) {
1189 		horiz = 1;
1190 		vert = 2;
1191 		iy += y_dir;
1192 	    } else {
1193 		vert = 0;
1194 		dir = horiz;
1195 	    }
1196 	}
1197     }
1198     if (dir) {  /* still had one direction to pick from, must have succeeded */
1199 	return 1;
1200     } else {
1201 	return 0;
1202     }
1203 }
1204 
1205 int
mt_draw(int cxp,int cyp,int flag)1206 mt_draw (int cxp, int cyp, int flag) /* c[xy]p are pixel coordinates */
1207 {
1208 
1209 #define STATUS_MESSAGE_LENGTH 80
1210     static int dx, dy; /* old current point; drawn point */
1211     static int ox, oy; /* coordinates for original button press */
1212     int cx, cy;   /* current mappoint coordinates */
1213     int draw_ret;
1214     char s[STATUS_MESSAGE_LENGTH];
1215 
1216     if (flag != MT_START && !mt_flag)
1217 	return 0;
1218 
1219     pixel_to_mappoint(cxp, cyp,  &cx, &cy);
1220 
1221     switch(flag) {
1222     case MT_SUCCESS:
1223 	if (ox == 0)
1224 	    return 0;
1225 	draw_ret = do_mt_draw(ox, dx, oy, dy, mt_erase);
1226 
1227 	if (!draw_ret) {
1228 	    /* If mt_erase failed it is because we don't have clearance
1229 	       to build the road.  So clean up and exit. */
1230 	    mt_flag = 0;
1231 	    draw_main_window_box (green (8));
1232 	    status_message(0,0);
1233 	}
1234 	else if ((draw_ret = do_mt_draw(ox, cx, oy, cy, mt_perm))) {
1235 
1236 	    print_total_money ();
1237 	    mt_flag = 0;
1238 	    draw_main_window_box (green (8));
1239 	    status_message(0,0);
1240 	} else {
1241 	    /* This shouldn't happen.  Clean up and continue anyway.  */
1242 	    mt_flag = 0;
1243 	    status_message(0,0);
1244 	    draw_main_window_box (green (8));
1245 	}
1246 	dx = 0; dy = 0;
1247 	ox = 0; oy = 0;
1248 	break;
1249 
1250     case MT_FAIL:
1251 	mt_flag = 0;
1252 	draw_main_window_box (green (8));
1253 	draw_ret = do_mt_draw(ox, dx, oy, dy, mt_erase);
1254 	status_message(0,0);
1255 
1256 	dx = 0; dy = 0;
1257 	ox = 0; oy = 0;
1258 	break;
1259 
1260     case MT_CONTINUE:
1261 	if ((dx == cx && dy == cy) || ox == 0)
1262 	    return 0;
1263 	draw_ret = do_mt_draw(ox, dx, oy, dy, mt_erase);
1264 
1265 	draw_ret = do_mt_draw(ox, cx, oy, cy, mt_temp);
1266 
1267 	if (!draw_ret) {
1268 	    draw_ret = do_mt_draw(ox, cx, oy, cy, mt_erase);
1269 	    snprintf(s,STATUS_MESSAGE_LENGTH-1,
1270 		     _("Can't build %s over that!"), mt_name);
1271 	} else {
1272 	    snprintf(s,STATUS_MESSAGE_LENGTH-1,
1273 		     _("%d sections of %s will cost %3d to build"),
1274 		     mt_length, mt_name,
1275 		     mt_length * get_type_cost(selected_module_type));
1276 	}
1277 
1278 	status_message(0,s);
1279 	dx = cx; dy = cy;
1280 	break;
1281 
1282     case MT_START:
1283 	/* XXX: we assume that a transport type is selected.   */
1284 
1285         if ((mt_grp = get_group_of_type(selected_module_type)) < 0 )
1286 	  return 0;
1287 
1288 	get_type_name(selected_module_type,mt_name);
1289 
1290 	dx = dy = 0;
1291 	ox = buttons[LC_MOUSE_LEFTBUTTON-1].mappoint_x;
1292 	oy = buttons[LC_MOUSE_LEFTBUTTON-1].mappoint_y;
1293 	draw_ret = do_mt_draw(ox, cx, oy, cy, mt_temp);
1294 
1295 	if (!draw_ret) {
1296 	    draw_ret = do_mt_draw(ox, cx, oy, cy, mt_erase);
1297 	    return 0;
1298 	}
1299 	dx = cx;
1300 	dy = cy;
1301 	mt_flag = 1;
1302 	draw_main_window_box (cyan (20));
1303 	break;
1304 
1305     default:
1306 	;
1307     }
1308 
1309     connect_transport_main_screen ();
1310     update_main_screen (0);
1311     return (1);
1312 }
1313 
1314 int
cmp(int n1,int n2)1315 cmp(int n1, int n2)
1316 {
1317     if (n1 != n2)
1318 	return (n1 < n2) ? 1 : -1;
1319     else
1320 	return 0;
1321 }
1322 
1323 void
init_mouse_registry()1324 init_mouse_registry()
1325 {
1326     mhandle_first = NULL;
1327     mhandle_last = NULL;
1328     mhandle_current = NULL;
1329     mhandle_count = 0;
1330 }
1331 
1332 /* Add and return an entry in the registry.  Add it at the beginning, so
1333    it supercedes earlier entries in mouse_handle_click() */
1334 Mouse_Handle *
mouse_register(Rect * r,void (* function)(int,int,int))1335 mouse_register(Rect * r, void (*function)(int, int, int))
1336 {
1337     mhandle_current = (Mouse_Handle *)lcalloc(sizeof(Mouse_Handle));
1338     mhandle_count++;
1339     if (mhandle_first == NULL) {
1340 	mhandle_current->next = NULL;
1341 	mhandle_current->prev = NULL;
1342     } else {
1343 	mhandle_current->next = mhandle_first;
1344 	mhandle_first->prev = mhandle_current;
1345 	mhandle_current->prev = NULL;
1346     }
1347 
1348     mhandle_first = mhandle_current;
1349 
1350     mhandle_current->r = r;
1351     mhandle_current->handler = function;
1352 
1353     return mhandle_current;
1354 }
1355 
1356 
1357 /* Remove an entry from the registry */
1358 void
mouse_unregister(Mouse_Handle * mhandle)1359 mouse_unregister(Mouse_Handle * mhandle)
1360 {
1361     if (mhandle->prev == NULL) {
1362 	if (mhandle_first != mhandle)
1363 	    printf("debug: mhandle_first != mhandle\n");
1364 	if (mhandle->next != NULL) {
1365 	    mhandle_first = mhandle->next;
1366 	    mhandle_first->prev = NULL;
1367 	} else {
1368 	    mhandle_first = NULL;
1369 	}
1370     } else if (mhandle->next == NULL) {
1371 	mhandle->prev->next = NULL;
1372     } else {
1373 	mhandle->prev->next = mhandle->next;
1374 	mhandle->next->prev = mhandle->prev;
1375     }
1376 
1377     free(mhandle);
1378     mhandle_count--;
1379 }
1380 
1381 /* Loop through the registry until we find a handler for an area.
1382    BEWARE!!!  Some handlers unregister themselves when called.  Assume
1383    mhandle_current is undefined after calling mhandle_current->handler()
1384 */
1385 int
mouse_handle_click(int x,int y,int button)1386 mouse_handle_click(int x, int y, int button)
1387 {
1388     mhandle_current = mhandle_first;
1389 
1390     while (mhandle_current != NULL) {
1391 	if (mouse_in_rect(mhandle_current->r,x,y)) {
1392 	    mhandle_current->handler(x - mhandle_current->r->x,
1393 				     y - mhandle_current->r->y, button);
1394 	    return 1;
1395 	}
1396 
1397 	mhandle_current = mhandle_current->next;
1398     }
1399 
1400     return 0;
1401 }
1402 
1403