1 /* ---------------------------------------------------------------------- *
2  * mps.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 <math.h>
10 #include "lcstring.h"
11 #include "common.h"
12 #include "lctypes.h"
13 #include "lin-city.h"
14 #include "mps.h"
15 #include "engglobs.h"
16 #include "mouse.h"
17 #include "screen.h"
18 #include "power.h"
19 #include "engine.h"
20 #include "lclib.h"
21 #include "lcintl.h"
22 #include "stats.h"
23 #include <modules.h>
24 #include <mouse.h>
25 #include <lclib.h>
26 
27 char mps_info[MAPPOINT_STATS_LINES][MPS_INFO_CHARS];
28 int mps_global_style;
29 
30 static int mps_style;
31 
32 static int mps_x;
33 static int mps_y;
34 
35 static Mouse_Handle * mps_handle;
36 
37 
38 /*
39  * ----------------------------------------------------------------------
40  * * New, simplified mps routines.  All drawing is offloaded to
41  * mps_refresh and mps_redraw, with the various mps_module routines -
42  * called from mps_update - merely updating an array of strings:
43  * mps_info (see above)
44  * ----------------------------------------------------------------------
45  * */
46 
47 void
mps_handler(int x,int y,int button)48 mps_handler(int x, int y, int button)
49 {
50     if (button == LC_MOUSE_LEFTBUTTON) {
51 	if (mps_style == MPS_GLOBAL) {
52 	    mps_global_advance();
53 	} else {
54 	    mps_set(0,0,MPS_GLOBAL);
55 	}
56     } else if (button == LC_MOUSE_RIGHTBUTTON) {
57 	/* XXX: Pop help here, depending on selected style */
58     }
59 }
60 
61 /* mps_init(): Initialize mps vars and mouse handles */
62 
63 void
mps_init()64 mps_init()
65 {
66     mps_style = MPS_GLOBAL;
67     mps_global_style = MPS_GLOBAL_FINANCE;
68 
69     mps_x = 0;
70     mps_y = 0;
71 
72     mps_handle = mouse_register(&scr.mappoint_stats,&mps_handler);
73 }
74 
75 
76 /* mps_set(): Main entry to mps system.  Sets mps to display status
77    for a square or global information.  If we are setting mps to
78    the same square it was set for, return 1, otherwise 0.
79 */
80 
81 int
mps_set(int x,int y,int style)82 mps_set(int x, int y, int style)
83 {
84     int same_square = 0;
85     mps_style = style;
86     switch(style) {
87     case MPS_MAP:
88     case MPS_ENV:
89 	if (mps_x == x && mps_y == y) {
90 	    same_square = 1;
91 	}
92 	mps_x = x;
93 	mps_y = y;
94 	break;
95     default:
96 	mps_x = 0;
97 	mps_y = 0;
98     }
99 
100     mps_update();
101     mps_refresh();
102     return same_square;
103 }
104 
105 
106 void
mps_redraw(void)107 mps_redraw(void)
108 {
109     Rect* mps = &scr.mappoint_stats;
110 
111     draw_small_bezel (mps->x, mps->y, mps->w, mps->h, yellow(0));
112     mps_refresh();
113 }
114 
115 void
mps_refresh(void)116 mps_refresh(void)
117 {
118     int i;
119 
120     Rect * mps = &scr.mappoint_stats;
121 
122     Fgl_fillbox (mps->x, mps->y, mps->w + 1, mps->h + 1, 14);
123     Fgl_setfontcolors (14, TEXT_FG_COLOUR);
124 
125     for (i = 0; i < MAPPOINT_STATS_LINES; i++) {
126 	Fgl_write (mps->x + 4, mps->y + (i * 8) + 4, mps_info[i]);
127     }
128 
129     Fgl_setfontcolors (TEXT_BG_COLOUR, TEXT_FG_COLOUR);
130 
131 
132 }
133 
134 void
mps_update(void)135 mps_update(void)
136 {
137     int i;
138 
139     for (i = 0; i < MAPPOINT_STATS_LINES; i++) {
140 	strcpy(mps_info[i],"");
141     }
142 
143     switch (mps_style) {
144     case MPS_MAP:
145 	{
146 	    switch(MP_GROUP(mps_x, mps_y)) {
147 	    case (GROUP_BLACKSMITH):
148 	        mps_blacksmith (mps_x, mps_y);
149 		break;
150 	    case (GROUP_COALMINE):
151 		mps_coalmine (mps_x, mps_y);
152 		break;
153 	    case GROUP_COAL_POWER:
154 		mps_coal_power (mps_x, mps_y);
155 		break;
156 	    case (GROUP_COMMUNE):
157 	        mps_commune (mps_x, mps_y);
158 		break;
159 	    case (GROUP_CRICKET):
160 		mps_cricket (mps_x, mps_y);
161 		break;
162 	    case (GROUP_FIRESTATION):
163 	        mps_firestation (mps_x, mps_y);
164 		break;
165 	    case (GROUP_HEALTH):
166 		mps_health_centre (mps_x, mps_y);
167 		break;
168 	    case (GROUP_INDUSTRY_H):
169 		mps_heavy_industry (mps_x, mps_y);
170 		break;
171 	    case (GROUP_INDUSTRY_L):
172 		mps_light_industry (mps_x, mps_y);
173 		break;
174 	    case (GROUP_MILL):
175 	        mps_mill (mps_x, mps_y);
176 		break;
177 	    case (GROUP_MONUMENT):
178 	        mps_monument (mps_x, mps_y);
179 		break;
180 	    case (GROUP_OREMINE):
181 	        mps_oremine (mps_x, mps_y);
182 		break;
183 	    case GROUP_ORGANIC_FARM:
184 		mps_organic_farm(mps_x, mps_y);
185 		break;
186 	    case (GROUP_PORT):
187 	        mps_port (mps_x, mps_y);
188 		break;
189 	    case (GROUP_POTTERY):
190 	        mps_pottery (mps_x, mps_y);
191 		break;
192 	    case GROUP_POWER_LINE:
193 	        mps_power_line (mps_x, mps_y);
194 	        break;
195 	    case (GROUP_RAIL):
196 		mps_rail (mps_x, mps_y);
197 		break;
198 	    case (GROUP_RECYCLE):
199 	        mps_recycle (mps_x, mps_y);
200 		break;
201 	    case GROUP_RESIDENCE_LL:
202 	    case GROUP_RESIDENCE_ML:
203 	    case GROUP_RESIDENCE_HL:
204 	    case GROUP_RESIDENCE_LH:
205 	    case GROUP_RESIDENCE_MH:
206 	    case GROUP_RESIDENCE_HH:
207 		mps_residence(mps_x, mps_y);
208 		break;
209 	    case (GROUP_ROAD):
210 		mps_road (mps_x, mps_y);
211 		break;
212 	    case (GROUP_ROCKET):
213 	        mps_rocket (mps_x, mps_y);
214 		break;
215 	    case (GROUP_SCHOOL):
216 	        mps_school (mps_x, mps_y);
217 		break;
218 	    case GROUP_SOLAR_POWER:
219 	        mps_solar_power (mps_x, mps_y);
220 	        break;
221 	    case (GROUP_SUBSTATION):
222 	        mps_substation (mps_x, mps_y);
223 	        break;
224 	    case (GROUP_TIP):
225 	        mps_tip (mps_x, mps_y);
226 		break;
227 	    case (GROUP_TRACK):
228 		mps_track(mps_x, mps_y);
229 		break;
230 	    case (GROUP_MARKET):
231 		mps_market (mps_x, mps_y);
232 		break;
233 	    case (GROUP_UNIVERSITY):
234 	        mps_university (mps_x, mps_y);
235 	        break;
236 	    case (GROUP_WATER):
237 	        mps_water (mps_x, mps_y);
238 	    break;
239 	    case (GROUP_WINDMILL):
240 	        mps_windmill (mps_x, mps_y);
241 		break;
242 	    default:
243 		printf("MPS unimplemented for that module\n");
244 	    }
245 	}
246         break;
247     case MPS_ENV:
248 	mps_right (mps_x, mps_y);
249 	break;
250     case MPS_GLOBAL:
251 	{
252 	    switch (mps_global_style) {
253 	    case MPS_GLOBAL_FINANCE:
254 		mps_global_finance();
255 		break;
256 	    case MPS_GLOBAL_OTHER_COSTS:
257 		mps_global_other_costs();
258 		break;
259 	    case MPS_GLOBAL_HOUSING:
260 		mps_global_housing();
261 		break;
262 	    default:
263 		printf("MPS unimplemented for global display\n");
264 		break;
265 	    }
266 	}
267 	break;
268     }
269 
270     mps_refresh();
271 }
272 
273 /* Cycle through the various global styles, but only update and display
274    if global info display is active */
275 
276 void
mps_global_advance(void)277 mps_global_advance(void)
278 {
279     mps_global_style++;
280     mps_global_style %= MPS_GLOBAL_STYLES;
281 
282     if (mps_style == MPS_GLOBAL) {
283       mps_update();
284     }
285 }
286 
287 /* MPS String storage routines.
288    These handle the tedium of formatting
289    strings for mps display.  Single argument forms center that
290    argument.  Double arg forms offset them.  Triple arg forms divide
291    the space into three columns.
292 
293 */
294 
295 void
mps_store_title(int i,char * t)296 mps_store_title(int i, char * t)
297 {
298   int c;
299   int l;
300 
301   l = strlen(t);
302   c = (int)((MPS_INFO_CHARS - l) / 2) + l;
303   snprintf(mps_info[i],MPS_INFO_CHARS,"%*s", c, t);
304 }
305 
306 void
mps_store_fp(int i,double f)307 mps_store_fp(int i, double f)
308 {
309   int c;
310   int l;
311   char s[12];
312 
313   snprintf(s, sizeof(s), "%.1f%%",f);
314   l = strlen(s);
315   c = (int)((MPS_INFO_CHARS - l) / 2) + l;
316   snprintf(mps_info[i],MPS_INFO_CHARS,"%*s", c, s);
317 }
318 
319 void
mps_store_f(int i,double f)320 mps_store_f(int i, double f)
321 {
322   int c;
323   int l;
324   char s[12];
325 
326   snprintf(s, sizeof(s), "%.1f",f);
327   l = strlen(s);
328   c = (int)((MPS_INFO_CHARS - l) / 2) + l;
329   snprintf(mps_info[i],MPS_INFO_CHARS,"%*s", c, s);
330 }
331 
332 void
mps_store_d(int i,int d)333 mps_store_d(int i, int d)
334 {
335   int c;
336   int l;
337   char s[12];
338 
339   snprintf(s, sizeof(s), "%d",d);
340   l = strlen(s);
341   c = (int)((MPS_INFO_CHARS - l) / 2) + l;
342   snprintf(mps_info[i],MPS_INFO_CHARS,"%*s", c, s);
343 }
344 
345 void
mps_store_ss(int i,char * s1,char * s2)346 mps_store_ss(int i, char * s1, char * s2)
347 {
348     int l;
349     l = snprintf(mps_info[i], MPS_INFO_CHARS, "%s", s1);
350     snprintf(&mps_info[i][l], MPS_INFO_CHARS - l, "%*s",
351 	     (MPS_INFO_CHARS - l - 1), s2);
352 }
353 
354 void
mps_store_sss(int i,char * s1,char * s2,char * s3)355 mps_store_sss(int i, char * s1, char * s2, char * s3)
356 {
357 
358     int l, e;  /* Length and End of the strings */
359     int c = (MPS_INFO_CHARS) / 3;
360     int m = (MPS_INFO_CHARS) % 3;
361 
362     if (i > MAPPOINT_STATS_LINES) {
363 	return;
364     }
365 
366     l = snprintf(mps_info[i], c + m, "%s", s1);
367     e = l;
368     l = snprintf(&mps_info[i][e], (c * 2) + m - e, "%*s",
369 		 (c * 2) + m - e - 1, s2);
370     e += l;
371     snprintf(&mps_info[i][e],  (c * 3) + m - e, "%*s",
372 	     (c * 3) + m - e - 1, s3);
373 }
374 
375 void
mps_store_sd(int i,char * s,int d)376 mps_store_sd(int i, char * s, int d)
377 {
378     int l;
379 
380     if (i > MAPPOINT_STATS_LINES) {
381 	return;
382     }
383 
384     l = snprintf(mps_info[i], MPS_INFO_CHARS, "%s", s);
385     snprintf(&mps_info[i][l], MPS_INFO_CHARS, "%*d",
386 	     (MPS_INFO_CHARS - 1 - l), d);
387 }
388 
389 void
mps_store_sfp(int i,char * s,double fl)390 mps_store_sfp(int i, char * s, double fl)
391 {
392     int l;
393     l = snprintf(mps_info[i], MPS_INFO_CHARS, "%s", s);
394     snprintf(&mps_info[i][l], MPS_INFO_CHARS, "%*.1f%%",
395 	     MPS_INFO_CHARS - 2 - l, fl);
396 }
397 
398 /* MPS Global routines */
399 
400 void
mps_right(int x,int y)401 mps_right (int x, int y)
402 {
403     int i = 0;
404     char s[12];
405     char * p;
406     int g;
407 
408     snprintf(s,sizeof(s),"%d,%d",x,y);
409     mps_store_title(i++,s);
410     i++;
411     mps_store_title(i++,_("Coverage"));
412     p = (MP_INFO(x,y).flags & FLAG_FIRE_COVER) ? _("Yes") : _("No");
413     mps_store_ss(i++,_("Fire"),p);
414 
415     p = (MP_INFO(x,y).flags & FLAG_HEALTH_COVER) ? _("Yes") : _("No");
416     mps_store_ss(i++,_("Health"),p);
417 
418     p = (MP_INFO(x,y).flags & FLAG_CRICKET_COVER) ? _("Yes") : _("No");
419     mps_store_ss(i++,_("Cricket"),p);
420     i++;
421     mps_store_title(i++,_("Pollution"));
422 
423     if (MP_POL(x,y) < 10)
424 	p = _("clear");
425     else if (MP_POL(x,y) < 25)
426 	p = _("good");
427     else if (MP_POL(x,y) < 70)
428 	p = _("fair");
429     else if (MP_POL(x,y) < 190)
430 	p = _("smelly");
431     else if (MP_POL(x,y) < 450)
432 	p = _("smokey");
433     else if (MP_POL(x,y) < 1000)
434 	p = _("smoggy");
435     else if (MP_POL(x,y) < 1700)
436 	p = _("bad");
437     else if (MP_POL(x,y) < 3000)
438 	p = _("very bad");
439     else
440 	p = _("death!");
441 
442     mps_store_sd(i++,p,MP_POL(x,y));
443     i++;
444 
445     mps_store_title(i++,_("Bulldoze Cost"));
446     g = MP_GROUP(x,y);
447     if (g == 0) {	/* Can't bulldoze grass. */
448 	mps_store_title(i++,_("N/A"));
449     } else {
450 	if (g < 7)
451 	    g--;			/* translate into button type */
452 	mps_store_d(i++,main_groups[g].bul_cost);
453     }
454 }
455 
456 
457 
mps_global_finance(void)458 void mps_global_finance(void) {
459     int i = 0;
460     char s[12];
461 
462     int cashflow = 0;
463 
464     mps_store_title(i++,_("Tax Income"));
465 
466     cashflow += ly_income_tax;
467     num_to_ansi (s, 12, ly_income_tax);
468     mps_store_ss(i++,_("Income"), s);
469 
470     cashflow += ly_coal_tax;
471     num_to_ansi(s, 12, ly_coal_tax);
472     mps_store_ss(i++,_("Coal"), s);
473 
474     cashflow += ly_goods_tax;
475     num_to_ansi(s, 12, ly_goods_tax);
476     mps_store_ss(i++,_("Goods"), s);
477 
478     cashflow += ly_export_tax;
479     num_to_ansi(s, 12, ly_export_tax);
480     mps_store_ss(i++,_("Export"), s);
481 
482     i++;
483 
484     mps_store_title(i++,_("Expenses"));
485 
486     cashflow -= ly_unemployment_cost;
487     num_to_ansi(s, 12, ly_unemployment_cost);
488     mps_store_ss(i++,_("Unemp."), s);
489 
490     cashflow -= ly_transport_cost;
491     num_to_ansi(s, 12, ly_transport_cost);
492     mps_store_ss(i++,_("Transport"), s);
493 
494     cashflow -= ly_import_cost;
495     num_to_ansi(s, 12, ly_import_cost);
496     mps_store_ss(i++,_("Imports"), s);
497 
498     cashflow -= ly_other_cost;
499     num_to_ansi(s, 12, ly_other_cost);
500     mps_store_ss(i++,_("Others"), s);
501 
502     i++;
503 
504     num_to_ansi(s, 12, cashflow);
505     mps_store_ss(i++,_("Net"), s);
506 }
507 
508 void
mps_global_other_costs(void)509 mps_global_other_costs (void)
510 {
511     int i = 0;
512     int year;
513     char s[12];
514 
515     mps_store_title(i++,_("Other Costs"));
516 
517     /* Don't write year if it's negative. */
518     year = (total_time / NUMOF_DAYS_IN_YEAR) - 1;
519     if (year >= 0) {
520 	mps_store_sd(i++, _("For year"), year);
521     }
522     i++;
523     num_to_ansi(s,sizeof(s),ly_interest);
524     mps_store_ss(i++,_("Interest"),s);
525     num_to_ansi(s,sizeof(s),ly_school_cost);
526     mps_store_ss(i++,_("Schools"),s);
527     num_to_ansi(s,sizeof(s),ly_university_cost);
528     mps_store_ss(i++,_("Univers."),s);
529     num_to_ansi(s,sizeof(s),ly_deaths_cost);
530     mps_store_ss(i++,_("Deaths"),s);
531     num_to_ansi(s,sizeof(s),ly_windmill_cost);
532     mps_store_ss(i++,_("Windmill"),s);
533     num_to_ansi(s,sizeof(s),ly_health_cost);
534     mps_store_ss(i++,_("Hospital"),s);
535     num_to_ansi(s,sizeof(s),ly_rocket_pad_cost);
536     mps_store_ss(i++,_("Rockets"),s);
537     num_to_ansi(s,sizeof(s),ly_fire_cost);
538     mps_store_ss(i++,_("Fire Stn"),s);
539     num_to_ansi(s,sizeof(s),ly_cricket_cost);
540     mps_store_ss(i++,_("Cricket"),s);
541     num_to_ansi(s,sizeof(s),ly_recycle_cost);
542     mps_store_ss(i++,_("Recycle"),s);
543 }
544 
545 
546 void
mps_global_housing(void)547 mps_global_housing (void)
548 {
549     int i = 0;
550     int tp = housed_population + people_pool;
551 
552     mps_store_title(i++,_("Population"));
553     i++;
554     mps_store_sd(i++,_("Total"),tp);
555     mps_store_sd(i++,_("Housed"),housed_population);
556     mps_store_sd(i++,_("Homeless"),people_pool);
557     mps_store_sd(i++,_("Shanties"),numof_shanties);
558     mps_store_sd(i++,_("Unn Dths"),unnat_deaths);
559     mps_store_title(i++,_("Unemployment"));
560     mps_store_sd(i++,_("Claims"),tunemployed_population);
561     mps_store_sfp(i++,_("Rate"),
562 		  ((tunemployed_population * 100.0) / tp));
563     mps_store_title(i++,_("Starvation"));
564     mps_store_sd(i++,_("Cases"),tstarving_population);
565 
566     mps_store_sfp(i++,_("Rate"),
567 		  ((tstarving_population * 100.0) / tp));
568 }
569 
570 
571 #ifdef old_mps
572 
573 void
mps_global_pop_setup(void)574 mps_global_pop_setup (void)
575 {
576     Rect* mps = &scr.mappoint_stats;
577     Fgl_write (mps->x + 32, mps->y + 2, _("PEOPLE"));
578     Fgl_write (mps->x + 4, mps->y + 14, _("Pop"));
579     Fgl_write (mps->x + 4, mps->y + 30, _("Unnat death"));
580 }
581 
582 
583 
584 void
mps_global_tech_setup(void)585 mps_global_tech_setup (void)
586 {
587     Rect* mps = &scr.mappoint_stats;
588     Fgl_write (mps->x + 32, mps->y + 2, "TECH");
589     Fgl_write (mps->x + 4, mps->y + 14, "Tech lvl");
590     Fgl_write (mps->x + 4, mps->y + 22, "Schools");
591     Fgl_write (mps->x + 4, mps->y + 30, "Univers");
592     Fgl_write (mps->x + 4, mps->y + 38, "Rockets");
593 }
594 
595 void
mps_global_food_setup(void)596 mps_global_food_setup (void)
597 {
598     Rect* mps = &scr.mappoint_stats;
599     Fgl_write (mps->x + 32, mps->y + 2, "FOOD");
600     Fgl_write (mps->x + 4, mps->y + 14, "Foodstore");
601     Fgl_write (mps->x + 4, mps->y + 22, "Farms");
602     Fgl_write (mps->x + 4, mps->y + 30, "Starv %");
603 }
604 
605 void
mps_global_jobs_setup(void)606 mps_global_jobs_setup (void)
607 {
608     Rect* mps = &scr.mappoint_stats;
609     Fgl_write (mps->x + 32, mps->y + 2, "JOBS");
610     Fgl_write (mps->x + 4, mps->y + 14, "Jobs");
611     Fgl_write (mps->x + 4, mps->y + 22, "% Unemp");
612 }
613 
614 
615 #endif
616 
617 
618 
619 
620