1 /* ---------------------------------------------------------------------- *
2 * engine.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 <stdio.h>
7 #include <stdlib.h>
8 #include <time.h>
9 #include "common.h"
10 #include "lctypes.h"
11 #include "lin-city.h"
12 #include "engine.h"
13 #include "engglobs.h"
14 #include "cliglobs.h"
15 #include "simulate.h"
16 #include "lcintl.h"
17 #include "power.h"
18 #include "mouse.h"
19 #include "module_buttons.h"
20 #include "pbar.h"
21 #include "stats.h"
22 #include "screen.h"
23 #include "dialbox.h"
24 #include "modules.h"
25 #include <mps.h>
26
27 extern int selected_type_cost;
28
29 int
adjust_money(int value)30 adjust_money(int value)
31 {
32 total_money += value;
33 print_total_money();
34 mps_update();
35 update_pbar (PMONEY, total_money, 0);
36 refresh_pbars(); /* This could be more specific */
37 return total_money;
38 }
39
40 int is_real_river (int x, int y);
41
42 int
no_credit_build(int selected_group)43 no_credit_build (int selected_group)
44 {
45 if (total_money >= 0)
46 return (0);
47
48 #ifdef GROUP_POWER_SOURCE_NO_CREDIT
49 if (selected_group == GROUP_POWER_SOURCE) {
50 return (1);
51 }
52 #endif
53 #ifdef GROUP_UNIVERSITY_NO_CREDIT
54 if (selected_group == GROUP_UNIVERSITY) {
55 return (1);
56 }
57 #endif
58 #ifdef GROUP_PARKLAND_NO_CREDIT
59 if (selected_group == GROUP_PARKLAND) {
60 return (1);
61 }
62 #endif
63 #ifdef GROUP_RECYCLE_NO_CREDIT
64 if (selected_group == GROUP_RECYCLE) {
65 return (1);
66 }
67 #endif
68 #ifdef GROUP_ROCKET
69 if (selected_group == GROUP_ROCKET) {
70 return (1);
71 }
72 #endif
73
74 if (main_groups[selected_group].no_credit == TRUE ) {
75 return (1);
76 }
77 return (0);
78 }
79
80 int
place_item(int x,int y,short type)81 place_item (int x, int y, short type)
82 {
83 int group;
84 int size;
85
86 group = get_group_of_type(type);
87 if (group < 0) return -1;
88
89 size = main_groups[group].size;
90
91 /* You can't build because credit not available. */
92 if (no_credit_build (group) != 0) {
93 return -1;
94 }
95
96 /* Not enough slots in the substation array */
97
98 switch (group) {
99 case GROUP_SUBSTATION:
100 case GROUP_WINDMILL:
101 {
102 if (add_a_substation (x, y) == 0)
103 return -3;
104 } break;
105 case GROUP_PORT:
106 {
107 if (is_real_river (x + 4, y) != 1
108 || is_real_river (x + 4, y + 1) != 1
109 || is_real_river (x + 4, y + 2) != 1
110 || is_real_river (x + 4, y + 3) != 1) {
111 return -2;
112 }
113 } break;
114 case GROUP_COMMUNE:
115 {
116 numof_communes++;
117 } break;
118 case GROUP_MARKET:
119 {
120 /* Test for enough slots in the market array */
121 if (add_a_market (x, y) == 0)
122 return -3;
123 MP_INFO(x,y).flags += (FLAG_MB_FOOD | FLAG_MB_JOBS
124 | FLAG_MB_COAL | FLAG_MB_ORE | FLAG_MB_STEEL
125 | FLAG_MB_GOODS | FLAG_MS_FOOD | FLAG_MS_JOBS
126 | FLAG_MS_COAL | FLAG_MS_GOODS | FLAG_MS_ORE
127 | FLAG_MS_STEEL);
128 } break;
129 case GROUP_TIP:
130 {
131 /* Don't build a tip if there has already been one. If we succeed,
132 mark the spot permanently by "doubling" the ore reserve */
133 int i,j;
134 int prev_tip = 0;
135 for (i=0;i<3;i++) {
136 for (j=0;j<3;j++) {
137 if (MP_INFO(x+i,y+j).ore_reserve > ORE_RESERVE) {
138 prev_tip = 1;
139 break;
140 }
141 }
142 }
143 if (prev_tip) {
144 dialog_box(red(12),3,
145 0,0,_("You can't build a tip here"),
146 0,0,_("This area was once a landfill"),
147 2,' ',_("OK"));
148 return -4;
149 } else {
150 for (i=0;i<3;i++) {
151 for (j=0;j<3;j++) {
152 MP_INFO(x+i,y+j).ore_reserve = ORE_RESERVE * 2;
153 }
154 }
155 }
156 } break;
157 case GROUP_OREMINE:
158 {
159 /* Don't allow new mines on old mines or old tips */
160 /* GCS: mines over old mines is OK if there is enough remaining
161 ore, as is the case when there is partial overlap. */
162 int i,j;
163 int prev_tip = 0;
164 int total_ore = 0;
165 for (i=0;i<3;i++) {
166 for (j=0;j<3;j++) {
167 total_ore += MP_INFO(x+i,y+j).ore_reserve;
168 if (MP_INFO(x+i,y+j).ore_reserve > ORE_RESERVE) {
169 prev_tip = 1;
170 break;
171 }
172 }
173 }
174 if (prev_tip) {
175 dialog_box(red(12),3,
176 0,0,_("You can't build a mine here"),
177 0,0,_("This area was once a landfill"),
178 2,' ',_("OK"));
179 return -4;
180 }
181 if (total_ore < MIN_ORE_RESERVE_FOR_MINE) {
182 dialog_box(red(12),3,
183 0,0,_("You can't build a mine here"),
184 0,0,_("There is no ore left at this site"),
185 2,' ',_("OK"));
186 return -4;
187 }
188 }
189 } /* end case */
190
191 /* Store last_built for refund on "mistakes" */
192 last_built_x = x;
193 last_built_y = y;
194
195 /* Make sure that the correct windmill graphic shows up */
196 if (group == GROUP_WINDMILL) {
197 if (tech_level > MODERN_WINDMILL_TECH) {
198 type = CST_WINDMILL_1_R;
199 } else {
200 type = CST_WINDMILL_1_W;
201 }
202 }
203
204 if (group == GROUP_SOLAR_POWER || group == GROUP_WINDMILL) {
205 MP_INFO(x,y).int_2 = tech_level;
206 let_one_through = 1;
207 }
208 else if (group == GROUP_RECYCLE || group == GROUP_COAL_POWER)
209 MP_INFO(x,y).int_4 = tech_level;
210 else if (group == GROUP_ORGANIC_FARM)
211 MP_INFO(x,y).int_1 = tech_level;
212 else if (group == GROUP_TRACK
213 || group == GROUP_ROAD
214 || group == GROUP_RAIL)
215 MP_INFO(x,y).flags |= FLAG_IS_TRANSPORT;
216 else if (group == GROUP_COALMINE
217 || group == GROUP_OREMINE)
218 let_one_through = 1;
219
220 set_mappoint (x, y, type);
221
222 update_tech_dep (x, y);
223
224 if (group == GROUP_RIVER)
225 connect_rivers ();
226
227 connect_transport (x-2,y-2,x+size+1,y+size+1);
228
229 adjust_money(-selected_module_cost);
230 map_power_grid();
231 return 0;
232 }
233
234 int
bulldoze_item(int x,int y)235 bulldoze_item (int x, int y)
236 {
237 int g, size;
238
239 if (MP_TYPE(x,y) == CST_USED) {
240 /* This is considered "improper" input. Silently ignore. */
241 return -1;
242 }
243
244 size = MP_SIZE(x,y);
245 g = MP_GROUP(x,y);
246
247 if (g == GROUP_BARE) {
248 /* Nothing to do. */
249 return -1;
250 }
251 else if (g == GROUP_SHANTY) {
252 fire_area (x, y);
253 adjust_money(-GROUP_SHANTY_BUL_COST);
254 }
255 else if (g == GROUP_FIRE) {
256 if (MP_INFO(x,y).int_2 >= FIRE_LENGTH)
257 return -1; /* Can't bulldoze ? */
258 MP_INFO(x,y).int_2 = FIRE_LENGTH + 1;
259 MP_TYPE(x,y) = CST_FIRE_DONE1;
260 MP_GROUP(x,y) = GROUP_BURNT;
261 adjust_money(-GROUP_BURNT_BUL_COST);
262 }
263 else {
264 adjust_money(-main_groups[g].bul_cost);
265 do_bulldoze_area (CST_GREEN, x, y);
266 if (g == GROUP_OREMINE)
267 {
268 int i, j;
269 for (j = 0; j < 4; j++)
270 for (i = 0; i < 4; i++)
271 if (MP_INFO(x + i,y + j).ore_reserve < ORE_RESERVE / 2)
272 do_bulldoze_area (CST_WATER, x + i, y + j);
273 }
274 }
275 return size; /* No longer used... */
276 }
277
278 void
init_mappoint_array(void)279 init_mappoint_array (void)
280 {
281 int x;
282 for (x = 0; x < WORLD_SIDE_LEN; x++) {
283 mappoint_array_x[x] = x;
284 mappoint_array_y[x] = x;
285 }
286 }
287
288 void
shuffle_mappoint_array(void)289 shuffle_mappoint_array (void)
290 {
291 int i, x, a;
292 for (i = 0; i < SHUFFLE_MAPPOINT_COUNT; i++)
293 {
294 x = rand () % WORLD_SIDE_LEN;
295 a = mappoint_array_x[i];
296 mappoint_array_x[i] = mappoint_array_x[x];
297 mappoint_array_x[x] = a;
298 x = rand () % WORLD_SIDE_LEN;
299 a = mappoint_array_y[i];
300 mappoint_array_y[i] = mappoint_array_y[x];
301 mappoint_array_y[x] = a;
302 }
303 }
304
305
306 int
buy_food(int xt,int yt)307 buy_food (int xt, int yt)
308 {
309 int i = 0;
310 if (MP_GROUP(xt,yt) == GROUP_TRACK)
311 {
312 if (MP_INFO(xt,yt).int_1 < MAX_FOOD_ON_TRACK)
313 i = MAX_FOOD_ON_TRACK - MP_INFO(xt,yt).int_1;
314 }
315 else if (MP_GROUP(xt,yt) == GROUP_ROAD)
316 {
317 if (MP_INFO(xt,yt).int_1 < MAX_FOOD_ON_ROAD)
318 i = MAX_FOOD_ON_ROAD - MP_INFO(xt,yt).int_1;
319 }
320 else if (MP_GROUP(xt,yt) == GROUP_RAIL)
321 {
322 if (MP_INFO(xt,yt).int_1 < MAX_FOOD_ON_RAIL)
323 i = MAX_FOOD_ON_RAIL - MP_INFO(xt,yt).int_1;
324 }
325 i = (i * PORT_IMPORT_RATE) / 1000;
326 MP_INFO(xt,yt).int_1 += i;
327 return (i * PORT_FOOD_RATE);
328 }
329
330 int
buy_coal(int xt,int yt)331 buy_coal (int xt, int yt)
332 {
333 int i = 0;
334 if (MP_GROUP(xt,yt) == GROUP_TRACK)
335 {
336 if (MP_INFO(xt,yt).int_3 < MAX_COAL_ON_TRACK)
337 i = MAX_COAL_ON_TRACK - MP_INFO(xt,yt).int_3;
338 }
339 else if (MP_GROUP(xt,yt) == GROUP_ROAD)
340 {
341 if (MP_INFO(xt,yt).int_3 < MAX_COAL_ON_ROAD)
342 i = MAX_COAL_ON_ROAD - MP_INFO(xt,yt).int_3;
343 }
344 else if (MP_GROUP(xt,yt) == GROUP_RAIL)
345 {
346 if (MP_INFO(xt,yt).int_3 < MAX_COAL_ON_RAIL)
347 i = MAX_COAL_ON_RAIL - MP_INFO(xt,yt).int_3;
348 }
349 i = (i * PORT_IMPORT_RATE) / 1000;
350 MP_INFO(xt,yt).int_3 += i;
351 return (i * PORT_COAL_RATE);
352 }
353
354 int
buy_ore(int xt,int yt)355 buy_ore (int xt, int yt)
356 {
357 int i = 0;
358 if (MP_GROUP(xt,yt) == GROUP_TRACK)
359 {
360 if (MP_INFO(xt,yt).int_5 < MAX_ORE_ON_TRACK)
361 i = MAX_ORE_ON_TRACK - MP_INFO(xt,yt).int_5;
362 }
363 else if (MP_GROUP(xt,yt) == GROUP_ROAD)
364 {
365 if (MP_INFO(xt,yt).int_5 < MAX_ORE_ON_ROAD)
366 i = MAX_ORE_ON_ROAD - MP_INFO(xt,yt).int_5;
367 }
368 else if (MP_GROUP(xt,yt) == GROUP_RAIL)
369 {
370 if (MP_INFO(xt,yt).int_5 < MAX_ORE_ON_RAIL)
371 i = MAX_ORE_ON_RAIL - MP_INFO(xt,yt).int_5;
372 }
373 i = (i * PORT_IMPORT_RATE) / 1000;
374 MP_INFO(xt,yt).int_5 += i;
375 return (i * PORT_ORE_RATE);
376 }
377
378 int
buy_goods(int xt,int yt)379 buy_goods (int xt, int yt)
380 {
381 int i = 0;
382 if (MP_GROUP(xt,yt) == GROUP_TRACK)
383 {
384 if (MP_INFO(xt,yt).int_4 < MAX_GOODS_ON_TRACK)
385 i = MAX_GOODS_ON_TRACK - MP_INFO(xt,yt).int_4;
386 }
387 else if (MP_GROUP(xt,yt) == GROUP_ROAD)
388 {
389 if (MP_INFO(xt,yt).int_4 < MAX_GOODS_ON_ROAD)
390 i = MAX_GOODS_ON_ROAD - MP_INFO(xt,yt).int_4;
391 }
392 else if (MP_GROUP(xt,yt) == GROUP_RAIL)
393 {
394 if (MP_INFO(xt,yt).int_4 < MAX_GOODS_ON_RAIL)
395 i = MAX_GOODS_ON_RAIL - MP_INFO(xt,yt).int_4;
396 }
397 i = (i * PORT_IMPORT_RATE) / 1000;
398 MP_INFO(xt,yt).int_4 += i;
399 return (i * PORT_GOODS_RATE);
400 }
401
402
403 int
buy_steel(int xt,int yt)404 buy_steel (int xt, int yt)
405 {
406 int i = 0;
407 if (MP_GROUP(xt,yt) == GROUP_TRACK)
408 {
409 if (MP_INFO(xt,yt).int_6 < MAX_STEEL_ON_TRACK)
410 i = MAX_STEEL_ON_TRACK - MP_INFO(xt,yt).int_6;
411 }
412 else if (MP_GROUP(xt,yt) == GROUP_ROAD)
413 {
414 if (MP_INFO(xt,yt).int_6 < MAX_STEEL_ON_ROAD)
415 i = MAX_STEEL_ON_ROAD - MP_INFO(xt,yt).int_6;
416 }
417 else if (MP_GROUP(xt,yt) == GROUP_RAIL)
418 {
419 if (MP_INFO(xt,yt).int_6 < MAX_STEEL_ON_RAIL)
420 i = MAX_STEEL_ON_RAIL - MP_INFO(xt,yt).int_6;
421 }
422 i = (i * PORT_IMPORT_RATE) / 1000;
423 MP_INFO(xt,yt).int_6 += i;
424 return (i * PORT_STEEL_RATE);
425 }
426
427 int
sell_food(int xt,int yt)428 sell_food (int xt, int yt)
429 {
430 int i = 0;
431 i = (MP_INFO(xt,yt).int_1 * PORT_EXPORT_RATE) / 1000;
432 MP_INFO(xt,yt).int_1 -= i;
433 return (i * PORT_FOOD_RATE);
434 }
435
436 int
sell_coal(int xt,int yt)437 sell_coal (int xt, int yt)
438 {
439 int i = 0;
440 i = (MP_INFO(xt,yt).int_3 * PORT_EXPORT_RATE) / 1000;
441 MP_INFO(xt,yt).int_3 -= i;
442 return (i * PORT_COAL_RATE);
443 }
444
445 int
sell_ore(int xt,int yt)446 sell_ore (int xt, int yt)
447 {
448 int i = 0;
449 i = (MP_INFO(xt,yt).int_5 * PORT_EXPORT_RATE) / 1000;
450 MP_INFO(xt,yt).int_5 -= i;
451 return (i * PORT_ORE_RATE);
452 }
453
454 int
sell_goods(int xt,int yt)455 sell_goods (int xt, int yt)
456 {
457 int i = 0;
458 i = (MP_INFO(xt,yt).int_4 * PORT_EXPORT_RATE) / 1000;
459 MP_INFO(xt,yt).int_4 -= i;
460 return (i * PORT_GOODS_RATE);
461 }
462
463 int
sell_steel(int xt,int yt)464 sell_steel (int xt, int yt)
465 {
466 int i = 0;
467 i = (MP_INFO(xt,yt).int_6 * PORT_EXPORT_RATE) / 1000;
468 MP_INFO(xt,yt).int_6 -= i;
469 return (i * PORT_STEEL_RATE);
470 }
471
472 void
do_pollution()473 do_pollution ()
474 {
475 int x, p;
476 int* pol = &map.pollution[0][0];
477
478 /* Kill pollution from top edge of map */
479 do {
480 if (*pol > 0)
481 *pol /= POL_DIV;
482 } while (++pol < &map.pollution[1][0]);
483
484
485 x= 1;
486 do
487 {
488 /* Kill some pollution from left edge of map */
489 if (*pol++ > 0)
490 *(pol-1) /= POL_DIV;
491 do {
492 if (*pol > 10) {
493 p = *pol / 16;
494 *pol -= p;
495 switch ( rand() % 11)
496 { /* prevailing wind is *from* SW ie right down */
497 case 0:
498 case 1: /* up */
499 case 2:
500 *(pol - 1) += p;
501 break;
502 case 3:
503 case 4: /* right */
504 case 5:
505 *(pol + WORLD_SIDE_LEN) += p;
506 break;
507 case 6: /* down */
508 case 7:
509 *(pol + 1) += p;
510 break;
511 case 8: /* left */
512 case 9:
513 *(pol - WORLD_SIDE_LEN) += p;
514 break;
515 case 10:
516 *pol += p- 2;
517 break;
518 }
519 }
520 } while (++pol < &map.pollution[x][WORLD_SIDE_LEN-1]);
521 /* Kill some pollution from right edge of map */
522 if (*pol > 0)
523 *pol /= POL_DIV;
524 ++x;
525 }
526 while (++pol < &map.pollution[WORLD_SIDE_LEN-1][0]);
527
528 /* Kill pollution from bottom edge of map */
529 do {
530 if (*pol > 0)
531 *pol /= POL_DIV;
532 } while (++pol < &map.pollution[WORLD_SIDE_LEN][0]);
533 }
534
535
536 /* XXX: remove_people is only used by rocket_pad, perhaps it should go there */
537
538 void
remove_people(int num)539 remove_people (int num)
540 {
541 #if defined (commentout)
542 int x, y, f;
543 time_t t;
544 f = 1;
545 t = time (0);
546 while (f && (num > 0)) {
547 for (y = 0; y < WORLD_SIDE_LEN; y++)
548 for (x = 0; x < WORLD_SIDE_LEN; x++)
549 if (MP_GROUP_IS_RESIDENCE(x,y) && MP_INFO(x,y).population > 0)
550 {
551 MP_INFO(x,y).population--;
552 // f = 1;
553 f |= (MP_INFO(x,y).population > 0);
554 num--;
555 total_evacuated++;
556 }
557 }
558 while (num > 0 && people_pool > 0) {
559 num--;
560 total_evacuated++;
561 people_pool--;
562 }
563 #endif
564
565 int x, y;
566 /* reset housed population so that we can display it correctly */
567 housed_population = 1;
568 while (housed_population && (num > 0)) {
569 housed_population = 0;
570 for (y = 0; y < WORLD_SIDE_LEN; y++)
571 for (x = 0; x < WORLD_SIDE_LEN; x++)
572 if (MP_GROUP_IS_RESIDENCE(x,y) && MP_INFO(x,y).population > 0) {
573 MP_INFO(x,y).population--;
574 housed_population += MP_INFO(x,y).population;
575 num--;
576 total_evacuated++;
577 }
578 }
579 while (num > 0 && people_pool > 0) {
580 num--;
581 total_evacuated++;
582 people_pool--;
583 }
584
585 refresh_population_text ();
586
587 #if defined (commentout)
588 /* last ship wasn't full so everyone has gone. */
589 if (num > 0)
590 {
591 if (t > HOF_START && t < HOF_STOP)
592 ok_dial_box ("launch-gone-mail.mes", GOOD, 0L);
593 else
594 ok_dial_box ("launch-gone.mes", GOOD, 0L);
595 housed_population = 0;
596 }
597 #endif
598
599 /* Note that the previous test was inaccurate. There could be
600 exactly 1000 people left. */
601 if (!housed_population && !people_pool) {
602 ok_dial_box ("launch-gone.mes", GOOD, 0L);
603 }
604 }
605
606
607
608 void
clear_fire_health_and_cricket_cover(void)609 clear_fire_health_and_cricket_cover (void)
610 {
611 int x, y, m;
612 m = 0xffffffff - (FLAG_FIRE_COVER | FLAG_HEALTH_COVER
613 | FLAG_CRICKET_COVER);
614 for (y = 0; y < WORLD_SIDE_LEN; y++)
615 for (x = 0; x < WORLD_SIDE_LEN; x++)
616 MP_INFO(x,y).flags &= m;
617 /* Wow... chache misses or what! */
618 }
619
620 void
do_fire_health_and_cricket_cover(void)621 do_fire_health_and_cricket_cover (void)
622 {
623 int x, y;
624 for (y = 0; y < WORLD_SIDE_LEN; y++)
625 for (x = 0; x < WORLD_SIDE_LEN; x++)
626 {
627 /* The next few lines need changing to test for */
628 /* the group if these areas are animated. */
629
630 if (MP_GROUP(x,y) == GROUP_FIRESTATION)
631 do_fire_cover (x, y);
632 else if (MP_TYPE(x,y) == CST_HEALTH)
633 do_health_cover (x, y);
634 else if (MP_GROUP(x,y) == GROUP_CRICKET)
635 do_cricket_cover (x, y);
636 }
637 }
638
639
640
641 void
do_random_fire(int x,int y,int pwarning)642 do_random_fire (int x, int y, int pwarning) /* well random if x=y=-1 */
643 {
644 int xx, yy;
645 if (x == -1 && y == -1)
646 {
647 x = rand () % WORLD_SIDE_LEN;
648 y = rand () % WORLD_SIDE_LEN;
649 }
650 else
651 {
652 if (x < 0 || x >= WORLD_SIDE_LEN || y < 0 || y >= WORLD_SIDE_LEN)
653 return;
654 }
655 if (MP_TYPE(x,y) == CST_USED)
656 {
657 xx = MP_INFO(x,y).int_1;
658 yy = MP_INFO(x,y).int_2;
659 x = xx;
660 y = yy;
661 }
662 xx = rand () % 100;
663 if (xx >= (main_groups[MP_GROUP(x,y)].fire_chance))
664 return;
665 if ((MP_INFO(x,y).flags & FLAG_FIRE_COVER) != 0)
666 return;
667 if (pwarning)
668 {
669 if (MP_GROUP(x,y) == GROUP_POWER_LINE)
670 ok_dial_box ("fire.mes", BAD, _("It's at a power line."));
671 else if (MP_GROUP(x,y) == GROUP_SOLAR_POWER)
672 ok_dial_box ("fire.mes", BAD, _("It's at a solar power station."));
673 else if (MP_GROUP(x,y) == GROUP_SUBSTATION)
674 ok_dial_box ("fire.mes", BAD, _("It's at a substation."));
675 else if (MP_GROUP_IS_RESIDENCE(x,y))
676 ok_dial_box ("fire.mes", BAD, _("It's at a residential area."));
677 else if (MP_GROUP(x,y) == GROUP_ORGANIC_FARM)
678 ok_dial_box ("fire.mes", BAD, _("It's at a farm."));
679 else if (MP_GROUP(x,y) == GROUP_MARKET)
680 ok_dial_box ("fire.mes", BAD, _("It's at a market."));
681 else if (MP_GROUP(x,y) == GROUP_TRACK)
682 ok_dial_box ("fire.mes", BAD, _("It's at a track."));
683 else if (MP_GROUP(x,y) == GROUP_COALMINE)
684 ok_dial_box ("fire.mes", BAD, _("It's at a coal mine."));
685 else if (MP_GROUP(x,y) == GROUP_RAIL)
686 ok_dial_box ("fire.mes", BAD, _("It's at a railway."));
687 else if (MP_GROUP(x,y) == GROUP_COAL_POWER)
688 ok_dial_box ("fire.mes", BAD, _("It's at a coal power station."));
689 else if (MP_GROUP(x,y) == GROUP_ROAD)
690 ok_dial_box ("fire.mes", BAD, _("It's at a road."));
691 else if (MP_GROUP(x,y) == GROUP_INDUSTRY_L)
692 ok_dial_box ("fire.mes", BAD, _("It's at light industry."));
693 else if (MP_GROUP(x,y) == GROUP_UNIVERSITY)
694 ok_dial_box ("fire.mes", BAD, _("It's at a university."));
695 else if (MP_GROUP(x,y) == GROUP_COMMUNE)
696 ok_dial_box ("fire.mes", BAD, _("It's at a commune."));
697 else if (MP_GROUP(x,y) == GROUP_TIP)
698 ok_dial_box ("fire.mes", BAD, _("It's at a tip."));
699 else if (MP_GROUP(x,y) == GROUP_PORT)
700 ok_dial_box ("fire.mes", BAD, _("It's at a port."));
701 else if (MP_GROUP(x,y) == GROUP_INDUSTRY_H)
702 ok_dial_box ("fire.mes", BAD, _("It's at a steel works."));
703 else if (MP_GROUP(x,y) == GROUP_RECYCLE)
704 ok_dial_box ("fire.mes", BAD, _("It's at a recycle centre."));
705 else if (MP_GROUP(x,y) == GROUP_HEALTH)
706 ok_dial_box ("fire.mes", BAD, _("It's at a health centre."));
707 else if (MP_GROUP(x,y) == GROUP_ROCKET)
708 ok_dial_box ("fire.mes", BAD, _("It's at a rocket site."));
709 else if (MP_GROUP(x,y) == GROUP_WINDMILL)
710 ok_dial_box ("fire.mes", BAD, _("It's at a windmill."));
711 else if (MP_GROUP(x,y) == GROUP_SCHOOL)
712 ok_dial_box ("fire.mes", BAD, _("It's at a school."));
713 else if (MP_GROUP(x,y) == GROUP_BLACKSMITH)
714 ok_dial_box ("fire.mes", BAD, _("It's at a blacksmith."));
715 else if (MP_GROUP(x,y) == GROUP_MILL)
716 ok_dial_box ("fire.mes", BAD, _("It's at a mill."));
717 else if (MP_GROUP(x,y) == GROUP_POTTERY)
718 ok_dial_box ("fire.mes", BAD, _("It's at a pottery."));
719 else if (MP_GROUP(x,y) == GROUP_FIRESTATION)
720 ok_dial_box ("fire.mes", BAD, _("It's at a fire station!!!."));
721 else if (MP_GROUP(x,y) == GROUP_CRICKET)
722 ok_dial_box ("fire.mes", BAD, _("It's at a cricket pitch!!!."));
723 else if (MP_GROUP(x,y) == GROUP_SHANTY)
724 ok_dial_box ("fire.mes", BAD, _("It's at a shanty town."));
725 else
726 ok_dial_box ("fire.mes", BAD, _("UNKNOWN!"));
727 }
728 fire_area (x, y);
729 }
730
731 /*
732 // spiral round from startx,starty until we hit something of group group.
733 // return the x y coords encoded as x+y*WORLD_SIDE_LEN
734 // return -1 if we don't find one.
735 */
736 int
spiral_find_group(int startx,int starty,int group)737 spiral_find_group (int startx, int starty, int group)
738 {
739 int i, j, x, y;
740 x = startx;
741 y = starty;
742 /* let's just do a complete spiral for now, work out the bounds later */
743 for (i = 1; i < (WORLD_SIDE_LEN + WORLD_SIDE_LEN); i++)
744 {
745 for (j = 0; j < i; j++)
746 {
747 x--;
748 if (x > 0 && x < WORLD_SIDE_LEN && y > 0 && y < WORLD_SIDE_LEN)
749 if (MP_GROUP(x,y) == group)
750 return (x + y * WORLD_SIDE_LEN);
751 }
752 for (j = 0; j < i; j++)
753 {
754 y--;
755 if (x > 0 && x < WORLD_SIDE_LEN && y > 0 && y < WORLD_SIDE_LEN)
756 if (MP_GROUP(x,y) == group)
757 return (x + y * WORLD_SIDE_LEN);
758 }
759 i++;
760 for (j = 0; j < i; j++)
761 {
762 x++;
763 if (x > 0 && x < WORLD_SIDE_LEN && y > 0 && y < WORLD_SIDE_LEN)
764 if (MP_GROUP(x,y) == group)
765 return (x + y * WORLD_SIDE_LEN);
766 }
767 for (j = 0; j < i; j++)
768 {
769 y++;
770 if (x > 0 && x < WORLD_SIDE_LEN && y > 0 && y < WORLD_SIDE_LEN)
771 if (MP_GROUP(x,y) == group)
772 return (x + y * WORLD_SIDE_LEN);
773 }
774 }
775 return (-1);
776 }
777
778 /*
779 // spiral round from startx,starty until we hit a 2x2 space.
780 // return the x y coords encoded as x+y*WORLD_SIDE_LEN
781 // return -1 if we don't find one.
782 */
783 int
spiral_find_2x2(int startx,int starty)784 spiral_find_2x2 (int startx, int starty)
785 {
786 int i, j, x, y;
787 x = startx;
788 y = starty;
789 /* let's just do a complete spiral for now, work out the bounds later */
790 for (i = 1; i < (WORLD_SIDE_LEN + WORLD_SIDE_LEN); i++)
791 {
792 for (j = 0; j < i; j++)
793 {
794 x--;
795 if (x > 1 && x < WORLD_SIDE_LEN - 2 && y > 1
796 && y < WORLD_SIDE_LEN - 2)
797 if (MP_TYPE(x,y) == CST_GREEN
798 && MP_TYPE(x + 1,y) == CST_GREEN
799 && MP_TYPE(x,y + 1) == CST_GREEN
800 && MP_TYPE(x + 1,y + 1) == CST_GREEN)
801 return (x + y * WORLD_SIDE_LEN);
802 }
803 for (j = 0; j < i; j++)
804 {
805 y--;
806 if (x > 1 && x < WORLD_SIDE_LEN - 2 && y > 1
807 && y < WORLD_SIDE_LEN - 2)
808 if (MP_TYPE(x,y) == CST_GREEN
809 && MP_TYPE(x + 1,y) == CST_GREEN
810 && MP_TYPE(x,y + 1) == CST_GREEN
811 && MP_TYPE(x + 1,y + 1) == CST_GREEN)
812 return (x + y * WORLD_SIDE_LEN);
813 }
814 i++;
815 for (j = 0; j < i; j++)
816 {
817 x++;
818 if (x > 1 && x < WORLD_SIDE_LEN - 2 && y > 1
819 && y < WORLD_SIDE_LEN - 2)
820 if (MP_TYPE(x,y) == CST_GREEN
821 && MP_TYPE(x + 1,y) == CST_GREEN
822 && MP_TYPE(x,y + 1) == CST_GREEN
823 && MP_TYPE(x + 1,y + 1) == CST_GREEN)
824 return (x + y * WORLD_SIDE_LEN);
825 }
826 for (j = 0; j < i; j++)
827 {
828 y++;
829 if (x > 1 && x < WORLD_SIDE_LEN - 2 && y > 1
830 && y < WORLD_SIDE_LEN - 2)
831 if (MP_TYPE(x,y) == CST_GREEN
832 && MP_TYPE(x + 1,y) == CST_GREEN
833 && MP_TYPE(x,y + 1) == CST_GREEN
834 && MP_TYPE(x + 1,y + 1) == CST_GREEN)
835 return (x + y * WORLD_SIDE_LEN);
836 }
837 }
838 return (-1);
839 }
840
841
842
843 void
do_bulldoze_area(short fill,int xx,int yy)844 do_bulldoze_area (short fill, int xx, int yy)
845 {
846 int size, x, y;
847 if (MP_TYPE(xx,yy) == CST_USED)
848 {
849 x = MP_INFO(xx,yy).int_1;
850 y = MP_INFO(xx,yy).int_2;
851 }
852 else
853 {
854 x = xx;
855 y = yy;
856 }
857 size = MP_SIZE(x,y);
858 if (MP_GROUP(x,y) == GROUP_SUBSTATION
859 || MP_GROUP(x,y) == GROUP_WINDMILL)
860 remove_a_substation (x, y);
861 else if (MP_GROUP(x,y) == GROUP_MARKET)
862 remove_a_market (x, y);
863 else if (MP_GROUP(x,y) == GROUP_SHANTY)
864 numof_shanties--;
865 else if (MP_GROUP(x,y) == GROUP_COMMUNE)
866 numof_communes--;
867
868 people_pool += MP_INFO(x,y).population;
869 clear_mappoint (fill, x, y);
870 if (size > 1) /* do size 2 */
871 {
872 clear_mappoint (fill, x + 1, y);
873 clear_mappoint (fill, x, y + 1);
874 clear_mappoint (fill, x + 1, y + 1);
875 }
876 if (size > 2) /* do size 3 */
877 {
878 clear_mappoint (fill, x + 2, y);
879 clear_mappoint (fill, x + 2, y + 1);
880 clear_mappoint (fill, x + 2, y + 2);
881 clear_mappoint (fill, x, y + 2);
882 clear_mappoint (fill, x + 1, y + 2);
883 }
884 if (size > 3) /* do size 4 */
885 {
886 clear_mappoint (fill, x + 3, y);
887 clear_mappoint (fill, x + 3, y + 1);
888 clear_mappoint (fill, x + 3, y + 2);
889 clear_mappoint (fill, x + 3, y + 3);
890 clear_mappoint (fill, x, y + 3);
891 clear_mappoint (fill, x + 1, y + 3);
892 clear_mappoint (fill, x + 2, y + 3);
893 }
894 }
895
896
897 void
update_tech_dep(int x,int y)898 update_tech_dep (int x, int y)
899 {
900 switch (MP_GROUP(x,y))
901 {
902 case (GROUP_ORGANIC_FARM):
903 MP_INFO(x,y).int_7 = ((double) MP_INFO(x,y).int_1
904 * ORGANIC_FARM_FOOD_OUTPUT) / MAX_TECH_LEVEL;
905 break;
906 case (GROUP_WINDMILL):
907 #ifdef OLD_POWER_CODE
908 MP_INFO(x,y).int_5 = WINDMILL_POWER
909 #else
910 MP_INFO(x,y).int_1 = WINDMILL_POWER
911 #endif
912 + (((double) MP_INFO(x,y).int_2 * WINDMILL_POWER) / MAX_TECH_LEVEL);
913 break;
914 case (GROUP_COAL_POWER):
915 #ifdef OLD_POWER_CODE
916 MP_INFO(x,y).int_5 = POWERS_COAL_OUTPUT
917 #else
918 MP_INFO(x,y).int_1 = POWERS_COAL_OUTPUT
919 #endif
920 + (((double) MP_INFO(x,y).int_4 * POWERS_COAL_OUTPUT)
921 / MAX_TECH_LEVEL);
922 break;
923 case (GROUP_SOLAR_POWER):
924 MP_INFO(x,y).int_3 = POWERS_SOLAR_OUTPUT
925 + (((double) MP_INFO(x,y).int_2 * POWERS_SOLAR_OUTPUT)
926 / MAX_TECH_LEVEL);
927 break;
928 }
929 }
930
931 void
connect_rivers(void)932 connect_rivers (void)
933 {
934 int x, y, count;
935 count = 1;
936 while (count > 0)
937 {
938 count = 0;
939 for (y = 0; y < WORLD_SIDE_LEN; y++)
940 for (x = 0; x < WORLD_SIDE_LEN; x++)
941 {
942 if (is_real_river (x, y) == 1)
943 {
944 if (is_real_river (x - 1, y) == -1)
945 {
946 MP_INFO(x - 1,y).flags |= FLAG_IS_RIVER;
947 count++;
948 }
949 if (is_real_river (x, y - 1) == -1)
950 {
951 MP_INFO(x,y - 1).flags |= FLAG_IS_RIVER;
952 count++;
953 }
954 if (is_real_river (x + 1, y) == -1)
955 {
956 MP_INFO(x + 1,y).flags |= FLAG_IS_RIVER;
957 count++;
958 }
959 if (is_real_river (x, y + 1) == -1)
960 {
961 MP_INFO(x,y + 1).flags |= FLAG_IS_RIVER;
962 count++;
963 }
964 }
965 }
966 }
967 }
968
969 int
is_real_river(int x,int y)970 is_real_river (int x, int y)
971 {
972 /* returns zero if not water at all or if out of bounds. */
973 if (x < 0 || x >= WORLD_SIDE_LEN || y < 0 || y >= WORLD_SIDE_LEN)
974 return (0);
975 if (MP_GROUP(x,y) != GROUP_WATER)
976 return (0);
977 if (MP_INFO(x,y).flags & FLAG_IS_RIVER)
978 return (1);
979 return (-1);
980 }
981
982 /* Feature: coal survey should vary in price and accuracy with technology */
983 void
do_coal_survey(void)984 do_coal_survey (void)
985 {
986 if (coal_survey_done == 0) {
987 adjust_money(-1000000);
988 coal_survey_done = 1;
989 }
990 }
991