]> git.zerfleddert.de Git - micropolis/blob - src/sim/s_sim.c
6f4b0bb73f771e42ae53d1dd48beb24e222b4f57
[micropolis] / src / sim / s_sim.c
1 /* s_sim.c
2 *
3 * Micropolis, Unix Version. This game was released for the Unix platform
4 * in or about 1990 and has been modified for inclusion in the One Laptop
5 * Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
6 * you need assistance with this program, you may contact:
7 * http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or (at
12 * your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details. You should have received a
18 * copy of the GNU General Public License along with this program. If
19 * not, see <http://www.gnu.org/licenses/>.
20 *
21 * ADDITIONAL TERMS per GNU GPL Section 7
22 *
23 * No trademark or publicity rights are granted. This license does NOT
24 * give you any right, title or interest in the trademark SimCity or any
25 * other Electronic Arts trademark. You may not distribute any
26 * modification of this program using the trademark SimCity or claim any
27 * affliation or association with Electronic Arts Inc. or its employees.
28 *
29 * Any propagation or conveyance of this program must include this
30 * copyright notice and these terms.
31 *
32 * If you convey this program (or any modifications of it) and assume
33 * contractual liability for the program to recipients of it, you agree
34 * to indemnify Electronic Arts for any liability that those contractual
35 * assumptions impose on Electronic Arts.
36 *
37 * You may not misrepresent the origins of this program; modified
38 * versions of the program must be marked as such and not identified as
39 * the original program.
40 *
41 * This disclaimer supplements the one included in the General Public
42 * License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
43 * PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
44 * OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
45 * SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
46 * DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
47 * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
48 * FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
49 * RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
50 * USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
51 * INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
52 * MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
53 * UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
54 * WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
55 * CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
56 * ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
57 * JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
58 * WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
59 * CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
60 * NOT APPLY TO YOU.
61 */
62 #include "sim.h"
63
64
65 /* Simulation */
66
67
68 short ValveFlag;
69 short CrimeRamp, PolluteRamp ;
70 short RValve, CValve, IValve;
71 short ResCap, ComCap, IndCap;
72 short CashFlow;
73 float EMarket = 4.0;
74 short DisasterEvent;
75 short DisasterWait;
76 short ScoreType;
77 short ScoreWait;
78 short PwrdZCnt;
79 short unPwrdZCnt;
80 short NewPower; /* post */
81 short AvCityTax;
82 short Scycle = 0;
83 short Fcycle = 0;
84 short Spdcycle = 0;
85 short DoInitialEval = 0;
86 short MeltX, MeltY;
87
88
89 /* comefrom: doEditWindow scoreDoer doMapInFront graphDoer doNilEvent */
90 SimFrame(void)
91 {
92 short i;
93
94 if (SimSpeed == 0)
95 return;
96
97 if (++Spdcycle > 1023)
98 Spdcycle = 0;
99
100 if (SimSpeed == 1 && Spdcycle % 5)
101 return;
102
103 if (SimSpeed == 2 && Spdcycle % 3)
104 return;
105
106 if (++Fcycle > 1023) Fcycle = 0;
107 /* if (InitSimLoad) Fcycle = 0; */
108 Simulate(Fcycle & 15);
109 }
110
111
112 /* comefrom: SimFrame */
113 Simulate(int mod16)
114 {
115 static short SpdPwr[4] = { 1, 2, 4, 5 };
116 static short SpdPtl[4] = { 1, 2, 7, 17 };
117 static short SpdCri[4] = { 1, 1, 8, 18 };
118 static short SpdPop[4] = { 1, 1, 9, 19 };
119 static short SpdFir[4] = { 1, 1, 10, 20 };
120 short x;
121
122 x = SimSpeed;
123 if (x > 3) x = 3;
124
125 switch (mod16) {
126 case 0:
127 if (++Scycle > 1023) Scycle = 0; /* this is cosmic */
128 if (DoInitialEval) {
129 DoInitialEval = 0;
130 CityEvaluation();
131 }
132 CityTime++;
133 AvCityTax += CityTax; /* post */
134 if (!(Scycle & 1)) SetValves();
135 ClearCensus();
136 break;
137 case 1:
138 MapScan(0, 1 * WORLD_X / 8);
139 break;
140 case 2:
141 MapScan(1 * WORLD_X / 8, 2 * WORLD_X / 8);
142 break;
143 case 3:
144 MapScan(2 * WORLD_X / 8, 3 * WORLD_X / 8);
145 break;
146 case 4:
147 MapScan(3 * WORLD_X / 8, 4 * WORLD_X / 8);
148 break;
149 case 5:
150 MapScan(4 * WORLD_X / 8, 5 * WORLD_X / 8);
151 break;
152 case 6:
153 MapScan(5 * WORLD_X / 8, 6 * WORLD_X / 8);
154 break;
155 case 7:
156 MapScan(6 * WORLD_X / 8, 7 * WORLD_X / 8);
157 break;
158 case 8:
159 MapScan(7 * WORLD_X / 8, WORLD_X);
160 break;
161 case 9:
162 if (!(CityTime % CENSUSRATE)) TakeCensus();
163 if (!(CityTime % (CENSUSRATE * 12))) Take2Census();
164
165 if (!(CityTime % TAXFREQ)) {
166 CollectTax();
167 CityEvaluation();
168 }
169 break;
170 case 10:
171 if (!(Scycle % 5)) DecROGMem();
172 DecTrafficMem();
173 NewMapFlags[TDMAP] = 1;
174 NewMapFlags[RDMAP] = 1;
175 NewMapFlags[ALMAP] = 1;
176 NewMapFlags[REMAP] = 1;
177 NewMapFlags[COMAP] = 1;
178 NewMapFlags[INMAP] = 1;
179 NewMapFlags[DYMAP] = 1;
180 SendMessages();
181 break;
182 case 11:
183 if (!(Scycle % SpdPwr[x])) {
184 DoPowerScan();
185 NewMapFlags[PRMAP] = 1;
186 NewPower = 1; /* post-release change */
187 }
188 break;
189 case 12:
190 if (!(Scycle % SpdPtl[x])) PTLScan();
191 break;
192 case 13:
193 if (!(Scycle % SpdCri[x])) CrimeScan();
194 break;
195 case 14:
196 if (!(Scycle % SpdPop[x])) PopDenScan();
197 break;
198 case 15:
199 if (!(Scycle % SpdFir[x])) FireAnalysis();
200 DoDisasters();
201 break;
202 }
203 }
204
205
206 /* comefrom: Simulate */
207 DoSimInit(void)
208 {
209 Fcycle = 0;
210 Scycle = 0;
211
212 if (InitSimLoad == 2) /* if new city */
213 InitSimMemory();
214
215 if (InitSimLoad == 1) /* if city just loaded */
216 SimLoadInit();
217
218 SetValves();
219 ClearCensus();
220 #if 1
221 MapScan(0, WORLD_X); /* XXX are you sure ??? */
222 #endif
223 DoPowerScan();
224 NewPower = 1; /* post rel */
225 PTLScan();
226 CrimeScan();
227 PopDenScan();
228 FireAnalysis();
229 NewMap = 1;
230 doAllGraphs();
231 NewGraph = 1;
232 TotalPop = 1;
233 DoInitialEval = 1;
234 }
235
236
237 /* comefrom: SimLoadInit */
238 DoNilPower(void)
239 {
240 register short x, y, z;
241
242 for (x = 0; x < WORLD_X; x++)
243 for (y = 0; y < WORLD_Y; y++) {
244 z = Map[x][y];
245 if (z & ZONEBIT) {
246 SMapX = x;
247 SMapY = y;
248 CChr = z;
249 SetZPower();
250 }
251 }
252 }
253
254
255 /* comefrom: Simulate */
256 DecTrafficMem(void) /* tends to empty TrfDensity */
257 {
258 register short x, y, z;
259
260 for (x = 0; x < HWLDX; x++)
261 for (y = 0; y < HWLDY; y++)
262 if (z = TrfDensity[x][y]) {
263 if (z > 24) {
264 if (z > 200) TrfDensity[x][y] = z - 34;
265 else TrfDensity[x][y] = z - 24;
266 }
267 else TrfDensity[x][y] = 0;
268 }
269 }
270
271
272 /* comefrom: Simulate */
273 DecROGMem(void) /* tends to empty RateOGMem */
274 {
275 register short x, y, z;
276
277 for (x = 0; x < SmX; x++)
278 for (y = 0; y < SmY; y++) {
279 z = RateOGMem[x][y];
280 if (z == 0) continue;
281 if (z > 0) {
282 --RateOGMem[x][y];
283 if (z > 200) RateOGMem[x][y] = 200; /* prevent overflow */
284 continue;
285 }
286 if (z < 0) {
287 ++RateOGMem[x][y];
288 if (z < -200) RateOGMem[x][y] = -200;
289 }
290 }
291 }
292
293
294 /* comefrom: DoSimInit */
295 InitSimMemory(void)
296 {
297 register short x, z;
298
299 z = 0;
300 SetCommonInits();
301 for (x = 0; x < 240; x++) {
302 ResHis[x] = z;
303 ComHis[x] = z;
304 IndHis[x] = z;
305 MoneyHis[x] = 128;
306 CrimeHis[x] = z;
307 PollutionHis[x] = z;
308 }
309 CrimeRamp = z;
310 PolluteRamp = z;
311 TotalPop = z;
312 RValve = z;
313 CValve = z;
314 IValve = z;
315 ResCap = z;
316 ComCap = z;
317 IndCap = z;
318
319 EMarket = 6.0;
320 DisasterEvent = 0;
321 ScoreType = 0;
322
323 /* This clears powermem */
324 PowerStackNum = z;
325 DoPowerScan();
326 NewPower = 1; /* post rel */
327
328 InitSimLoad = 0;
329 }
330
331
332 /* comefrom: DoSimInit */
333 SimLoadInit(void)
334 {
335 static short DisTab[9] = { 0, 2, 10, 5, 20, 3, 5, 5, 2 * 48};
336 static short ScoreWaitTab[9] = { 0, 30 * 48, 5 * 48, 5 * 48, 10 * 48,
337 5 * 48, 10 * 48, 5 * 48, 10 * 48 };
338 register int z;
339
340 z = 0;
341 EMarket = (float)MiscHis[1];
342 ResPop = MiscHis[2];
343 ComPop = MiscHis[3];
344 IndPop = MiscHis[4];
345 RValve = MiscHis[5];
346 CValve = MiscHis[6];
347 IValve = MiscHis[7];
348 CrimeRamp = MiscHis[10];
349 PolluteRamp = MiscHis[11];
350 LVAverage = MiscHis[12];
351 CrimeAverage = MiscHis[13];
352 PolluteAverage = MiscHis[14];
353 GameLevel = MiscHis[15];
354
355 if (CityTime < 0) CityTime = 0;
356 if (!EMarket) EMarket = 4.0;
357 if ((GameLevel > 2) || (GameLevel < 0)) GameLevel = 0;
358 SetGameLevel(GameLevel);
359
360 SetCommonInits();
361
362 CityClass = MiscHis[16];
363 CityScore = MiscHis[17];
364
365 if ((CityClass > 5) || (CityClass < 0)) CityClass = 0;
366 if ((CityScore > 999) || (CityScore < 1)) CityScore = 500;
367
368 ResCap = 0;
369 ComCap = 0;
370 IndCap = 0;
371
372 AvCityTax = (CityTime % 48) * 7; /* post */
373
374 for (z = 0; z < PWRMAPSIZE; z++)
375 PowerMap[z] = ~0; /* set power Map */
376 DoNilPower();
377
378 if (ScenarioID > 8) ScenarioID = 0;
379
380 if (ScenarioID) {
381 DisasterEvent = ScenarioID;
382 DisasterWait = DisTab[DisasterEvent];
383 ScoreType = DisasterEvent;
384 ScoreWait = ScoreWaitTab[DisasterEvent];
385 } else {
386 DisasterEvent = 0;
387 ScoreType = 0;
388 }
389
390 RoadEffect = 32;
391 PoliceEffect = 1000; /*post*/
392 FireEffect = 1000;
393 InitSimLoad = 0;
394 }
395
396
397 /* comefrom: InitSimMemory SimLoadInit */
398 SetCommonInits(void)
399 {
400 EvalInit();
401 RoadEffect = 32;
402 PoliceEffect = 1000;
403 FireEffect = 1000;
404 TaxFlag = 0;
405 TaxFund = 0;
406 /*
407 if ((GameLevel > 2) || (GameLevel < 0)) GameLevel = 0;
408 setGameLevel(GameLevel);
409 */
410 }
411
412
413 /* comefrom: Simulate DoSimInit */
414 SetValves(void)
415 {
416 static short TaxTable[21] = {
417 200, 150, 120, 100, 80, 50, 30, 0, -10, -40, -100,
418 -150, -200, -250, -300, -350, -400, -450, -500, -550, -600 };
419 float Employment, Migration, Births, LaborBase, IntMarket;
420 float Rratio, Cratio, Iratio, temp;
421 float NormResPop, PjResPop, PjComPop, PjIndPop;
422 register short z;
423
424 MiscHis[1] = (short)EMarket;
425 MiscHis[2] = ResPop;
426 MiscHis[3] = ComPop;
427 MiscHis[4] = IndPop;
428 MiscHis[5] = RValve;
429 MiscHis[6] = CValve;
430 MiscHis[7] = IValve;
431 MiscHis[10] = CrimeRamp;
432 MiscHis[11] = PolluteRamp;
433 MiscHis[12] = LVAverage;
434 MiscHis[13] = CrimeAverage;
435 MiscHis[14] = PolluteAverage;
436 MiscHis[15] = GameLevel;
437 MiscHis[16] = CityClass;
438 MiscHis[17] = CityScore;
439
440 NormResPop = ResPop / 8;
441 LastTotalPop = TotalPop;
442 TotalPop = NormResPop + ComPop + IndPop;
443
444 if (NormResPop) Employment = ((ComHis[1] + IndHis[1]) / NormResPop);
445 else Employment = 1;
446
447 Migration = NormResPop * (Employment - 1);
448 Births = NormResPop * (.02); /* Birth Rate */
449 PjResPop = NormResPop + Migration + Births; /* Projected Res.Pop */
450
451 if (temp = (ComHis[1] + IndHis[1])) LaborBase = (ResHis[1] / temp);
452 else LaborBase = 1;
453 if (LaborBase > 1.3) LaborBase = 1.3;
454 if (LaborBase < 0) LaborBase = 0; /* LB > 1 - .1 */
455
456 for (z = 0; z < 2; z++)
457 temp = ResHis[z] + ComHis[z] + IndHis[z];
458 IntMarket = (NormResPop + ComPop + IndPop) / 3.7;
459
460 PjComPop = IntMarket * LaborBase;
461
462 z = GameLevel; /* New ExtMarket */
463 temp = 1;
464 switch (z) {
465 case 0:
466 temp = 1.2;
467 break;
468 case 1:
469 temp = 1.1;
470 break;
471 case 2:
472 temp = .98;
473 break;
474 }
475
476 PjIndPop = IndPop * LaborBase * temp;
477 if (PjIndPop < 5) PjIndPop = 5;
478
479 if (NormResPop) Rratio = (PjResPop / NormResPop); /* projected -vs- actual */
480 else Rratio = 1.3;
481 if (ComPop) Cratio = (PjComPop / ComPop);
482 else Cratio = PjComPop;
483 if (IndPop) Iratio = (PjIndPop / IndPop);
484 else Iratio = PjIndPop;
485
486 if (Rratio > 2) Rratio = 2;
487 if (Cratio > 2) Cratio = 2;
488 if (Iratio > 2) Iratio = 2;
489
490 z = CityTax + GameLevel;
491 if (z > 20) z = 20;
492 Rratio = ((Rratio -1) * 600) + TaxTable[z]; /* global tax/Glevel effects */
493 Cratio = ((Cratio -1) * 600) + TaxTable[z];
494 Iratio = ((Iratio -1) * 600) + TaxTable[z];
495
496 if (Rratio > 0) /* ratios are velocity changes to valves */
497 if (RValve < 2000) RValve += Rratio;
498 if (Rratio < 0)
499 if (RValve > -2000) RValve += Rratio;
500 if (Cratio > 0)
501 if (CValve < 1500) CValve += Cratio;
502 if (Cratio < 0)
503 if (CValve > -1500) CValve += Cratio;
504 if (Iratio > 0)
505 if (IValve < 1500) IValve += Iratio;
506 if (Iratio < 0)
507 if (IValve > -1500) IValve += Iratio;
508
509 if (RValve > 2000) RValve = 2000;
510 if (RValve < -2000) RValve = -2000;
511 if (CValve > 1500) CValve = 1500;
512 if (CValve < -1500) CValve = -1500;
513 if (IValve > 1500) IValve = 1500;
514 if (IValve < -1500) IValve = -1500;
515
516 if ((ResCap) && (RValve > 0)) RValve = 0; /* Stad, Prt, Airprt */
517 if ((ComCap) && (CValve > 0)) CValve = 0;
518 if ((IndCap) && (IValve > 0)) IValve = 0;
519 ValveFlag = 1;
520 }
521
522
523 /* comefrom: Simulate DoSimInit */
524 ClearCensus(void)
525 {
526 register short x, y, z;
527
528 z = 0;
529 PwrdZCnt = z;
530 unPwrdZCnt = z;
531 FirePop = z;
532 RoadTotal = z;
533 RailTotal = z;
534 ResPop = z;
535 ComPop = z;
536 IndPop = z;
537 ResZPop = z;
538 ComZPop = z;
539 IndZPop = z;
540 HospPop = z;
541 ChurchPop = z;
542 PolicePop = z;
543 FireStPop = z;
544 StadiumPop = z;
545 CoalPop = z;
546 NuclearPop = z;
547 PortPop = z;
548 APortPop = z;
549 PowerStackNum = z; /* Reset before Mapscan */
550 for (x = 0; x < SmX; x++)
551 for (y = 0; y < SmY; y++) {
552 FireStMap[x][y] = z;
553 PoliceMap[x][y] = z;
554 }
555 }
556
557
558 /* comefrom: Simulate */
559 TakeCensus(void)
560 {
561 short x;
562
563 /* put census#s in Historical Graphs and scroll data */
564 ResHisMax = 0;
565 ComHisMax = 0;
566 IndHisMax = 0;
567 for (x = 118; x >= 0; x--) {
568 if ((ResHis[x + 1] = ResHis[x]) > ResHisMax) ResHisMax = ResHis[x];
569 if ((ComHis[x + 1] = ComHis[x]) > ComHisMax) ComHisMax = ComHis[x];
570 if ((IndHis[x + 1] = IndHis[x]) > IndHisMax) IndHisMax = IndHis[x];
571 CrimeHis[x + 1] = CrimeHis[x];
572 PollutionHis[x + 1] = PollutionHis[x];
573 MoneyHis[x + 1] = MoneyHis[x];
574 }
575
576 Graph10Max = ResHisMax;
577 if (ComHisMax > Graph10Max) Graph10Max = ComHisMax;
578 if (IndHisMax > Graph10Max) Graph10Max = IndHisMax;
579
580 ResHis[0] = ResPop / 8;
581 ComHis[0] = ComPop;
582 IndHis[0] = IndPop;
583
584 CrimeRamp += (CrimeAverage - CrimeRamp) / 4;
585 CrimeHis[0] = CrimeRamp;
586
587 PolluteRamp += (PolluteAverage - PolluteRamp) / 4;
588 PollutionHis[0] = PolluteRamp;
589
590 x = (CashFlow / 20) + 128; /* scale to 0..255 */
591 if (x < 0) x = 0;
592 if (x > 255) x = 255;
593
594 MoneyHis[0] = x;
595 if (CrimeHis[0] > 255) CrimeHis[0] = 255;
596 if (PollutionHis[0] > 255) PollutionHis[0] = 255;
597
598 ChangeCensus(); /* XXX: if 10 year graph view */
599
600 if (HospPop < (ResPop >>8)) NeedHosp = TRUE;
601 if (HospPop > (ResPop >>8)) NeedHosp = -1;
602 if (HospPop == (ResPop >>8)) NeedHosp = FALSE;
603
604 if (ChurchPop < (ResPop >>8)) NeedChurch = TRUE;
605 if (ChurchPop > (ResPop >>8)) NeedChurch = -1;
606 if (ChurchPop == (ResPop >>8)) NeedChurch = FALSE;
607 }
608
609
610 /* comefrom: Simulate */
611 Take2Census(void) /* Long Term Graphs */
612 {
613 short x;
614
615 Res2HisMax = 0;
616 Com2HisMax = 0;
617 Ind2HisMax = 0;
618 for (x = 238; x >= 120; x--) {
619 if ((ResHis[x + 1] = ResHis[x]) > Res2HisMax) Res2HisMax = ResHis[x];
620 if ((ComHis[x + 1] = ComHis[x]) > Com2HisMax) Com2HisMax = ComHis[x];
621 if ((IndHis[x + 1] = IndHis[x]) > Ind2HisMax) Ind2HisMax = IndHis[x];
622 CrimeHis[x + 1] = CrimeHis[x];
623 PollutionHis[x + 1] = PollutionHis[x];
624 MoneyHis[x + 1] = MoneyHis[x];
625 }
626 Graph120Max = Res2HisMax;
627 if (Com2HisMax > Graph120Max) Graph120Max = Com2HisMax;
628 if (Ind2HisMax > Graph120Max) Graph120Max = Ind2HisMax;
629
630 ResHis[120] = ResPop / 8;
631 ComHis[120] = ComPop;
632 IndHis[120] = IndPop;
633 CrimeHis[120] = CrimeHis[0] ;
634 PollutionHis[120] = PollutionHis[0];
635 MoneyHis[120] = MoneyHis[0];
636 ChangeCensus(); /* XXX: if 120 year graph view */
637 }
638
639
640 /* comefrom: Simulate */
641 CollectTax(void)
642 {
643 static float RLevels[3] = { 0.7, 0.9, 1.2 };
644 static float FLevels[3] = { 1.4, 1.2, 0.8 };
645 short z;
646
647 CashFlow = 0;
648 if (!TaxFlag) { /* if the Tax Port is clear */
649 /* XXX: do something with z */
650 z = AvCityTax / 48; /* post */
651 AvCityTax = 0;
652 PoliceFund = PolicePop * 100;
653 FireFund = FireStPop * 100;
654 RoadFund = (RoadTotal + (RailTotal * 2)) * RLevels[GameLevel];
655 TaxFund = (((QUAD)TotalPop * LVAverage) / 120) *
656 CityTax * FLevels[GameLevel];
657 if (TotalPop) { /* if there are people to tax */
658 CashFlow = TaxFund - (PoliceFund + FireFund + RoadFund);
659
660 DoBudget();
661 } else {
662 RoadEffect = 32;
663 PoliceEffect = 1000;
664 FireEffect = 1000;
665 }
666 }
667 }
668
669
670 UpdateFundEffects(void)
671 {
672 if (RoadFund)
673 RoadEffect = (short)(((float)RoadSpend /
674 (float)RoadFund) * 32.0);
675 else
676 RoadEffect = 32;
677
678 if (PoliceFund)
679 PoliceEffect = (short)(((float)PoliceSpend /
680 (float)PoliceFund) * 1000.0);
681 else
682 PoliceEffect = 1000;
683
684 if (FireFund)
685 FireEffect = (short)(((float)FireSpend /
686 (float)FireFund) * 1000.0);
687 else
688 FireEffect = 1000;
689
690 drawCurrPercents();
691 }
692
693
694 /* comefrom: Simulate DoSimInit */
695 MapScan(int x1, int x2)
696 {
697 register short x, y;
698
699 for (x = x1; x < x2; x++) {
700 for (y = 0; y < WORLD_Y; y++) {
701 if (CChr = Map[x][y]) {
702 CChr9 = CChr & LOMASK; /* Mask off status bits */
703 if (CChr9 >= FLOOD) {
704 SMapX = x;
705 SMapY = y;
706 if (CChr9 < ROADBASE) {
707 if (CChr9 >= FIREBASE) {
708 FirePop++;
709 if (!(Rand16() & 3)) DoFire(); /* 1 in 4 times */
710 continue;
711 }
712 if (CChr9 < RADTILE) DoFlood();
713 else DoRadTile();
714 continue;
715 }
716
717 if (NewPower && (CChr & CONDBIT))
718 SetZPower();
719
720 if ((CChr9 >= ROADBASE) &&
721 (CChr9 < POWERBASE)) {
722 DoRoad();
723 continue;
724 }
725
726 if (CChr & ZONEBIT) { /* process Zones */
727 DoZone();
728 continue;
729 }
730
731 if ((CChr9 >= RAILBASE) &&
732 (CChr9 < RESBASE)) {
733 DoRail();
734 continue;
735 }
736 if ((CChr9 >= SOMETINYEXP) &&
737 (CChr9 <= LASTTINYEXP)) /* clear AniRubble */
738 Map[x][y] = RUBBLE + (Rand16() & 3) + BULLBIT;
739 }
740 }
741 }
742 }
743 }
744
745
746 /* comefrom: MapScan */
747 DoRail(void)
748 {
749 RailTotal++;
750 GenerateTrain(SMapX, SMapY);
751 if (RoadEffect < 30) /* Deteriorating Rail */
752 if (!(Rand16() & 511))
753 if (!(CChr & CONDBIT))
754 if (RoadEffect < (Rand16() & 31)) {
755 if (CChr9 < (RAILBASE + 2))
756 Map[SMapX][SMapY] = RIVER;
757 else
758 Map[SMapX][SMapY] = RUBBLE + (Rand16() & 3) + BULLBIT;
759 return;
760 }
761 }
762
763
764 /* comefrom: MapScan */
765 DoRadTile(void)
766 {
767 if (!(Rand16() & 4095)) Map[SMapX][SMapY] = 0; /* Radioactive decay */
768 }
769
770
771 /* comefrom: MapScan */
772 DoRoad(void)
773 {
774 register short Density, tden, z;
775 static short DenTab[3] = { ROADBASE, LTRFBASE, HTRFBASE };
776
777 RoadTotal++;
778 /* GenerateBus(SMapX, SMapY); */
779 if (RoadEffect < 30) /* Deteriorating Roads */
780 if (!(Rand16() & 511))
781 if (!(CChr & CONDBIT))
782 if (RoadEffect < (Rand16() & 31)) {
783 if (((CChr9 & 15) < 2) || ((CChr9 & 15) == 15))
784 Map[SMapX][SMapY] = RIVER;
785 else
786 Map[SMapX][SMapY] = RUBBLE + (Rand16() & 3) + BULLBIT;
787 return;
788 }
789
790 if (!(CChr & BURNBIT)) { /* If Bridge */
791 RoadTotal += 4;
792 if (DoBridge()) return;
793 }
794 if (CChr9 < LTRFBASE) tden = 0;
795 else if (CChr9 < HTRFBASE) tden = 1;
796 else {
797 RoadTotal++;
798 tden = 2;
799 }
800
801 Density = (TrfDensity[SMapX >>1][SMapY >>1]) >>6; /* Set Traf Density */
802 if (Density > 1) Density--;
803 if (tden != Density) { /* tden 0..2 */
804 z = ((CChr9 - ROADBASE) & 15) + DenTab[Density];
805 z += CChr & (ALLBITS - ANIMBIT);
806 if (Density) z += ANIMBIT;
807 Map[SMapX][SMapY] = z;
808 }
809 }
810
811
812 /* comefrom: MapScan */
813 DoBridge(void)
814 {
815 static short HDx[7] = { -2, 2, -2, -1, 0, 1, 2 };
816 static short HDy[7] = { -1, -1, 0, 0, 0, 0, 0 };
817 static short HBRTAB[7] = {
818 HBRDG1 | BULLBIT, HBRDG3 | BULLBIT, HBRDG0 | BULLBIT,
819 RIVER, BRWH | BULLBIT, RIVER, HBRDG2 | BULLBIT };
820 static short HBRTAB2[7] = {
821 RIVER, RIVER, HBRIDGE | BULLBIT, HBRIDGE | BULLBIT, HBRIDGE | BULLBIT,
822 HBRIDGE | BULLBIT, HBRIDGE | BULLBIT };
823 static short VDx[7] = { 0, 1, 0, 0, 0, 0, 1 };
824 static short VDy[7] = { -2, -2, -1, 0, 1, 2, 2 };
825 static short VBRTAB[7] = {
826 VBRDG0 | BULLBIT, VBRDG1 | BULLBIT, RIVER, BRWV | BULLBIT,
827 RIVER, VBRDG2 | BULLBIT, VBRDG3 | BULLBIT };
828 static short VBRTAB2[7] = {
829 VBRIDGE | BULLBIT, RIVER, VBRIDGE | BULLBIT, VBRIDGE | BULLBIT,
830 VBRIDGE | BULLBIT, VBRIDGE | BULLBIT, RIVER };
831 register z, x, y, MPtem;
832
833 if (CChr9 == BRWV) { /* Vertical bridge close */
834 if ((!(Rand16() & 3)) &&
835 (GetBoatDis() > 340))
836 for (z = 0; z < 7; z++) { /* Close */
837 x = SMapX + VDx[z];
838 y = SMapY + VDy[z];
839 if (TestBounds(x, y))
840 if ((Map[x][y] & LOMASK) == (VBRTAB[z] & LOMASK))
841 Map[x][y] = VBRTAB2[z];
842 }
843 return (TRUE);
844 }
845 if (CChr9 == BRWH) { /* Horizontal bridge close */
846 if ((!(Rand16() & 3)) &&
847 (GetBoatDis() > 340))
848 for (z = 0; z < 7; z++) { /* Close */
849 x = SMapX + HDx[z];
850 y = SMapY + HDy[z];
851 if (TestBounds(x, y))
852 if ((Map[x][y] & LOMASK) == (HBRTAB[z] & LOMASK))
853 Map[x][y] = HBRTAB2[z];
854 }
855 return (TRUE);
856 }
857
858 if ((GetBoatDis() < 300) || (!(Rand16() & 7))) {
859 if (CChr9 & 1) {
860 if (SMapX < (WORLD_X - 1))
861 if (Map[SMapX + 1][SMapY] == CHANNEL) { /* Vertical open */
862 for (z = 0; z < 7; z++) {
863 x = SMapX + VDx[z];
864 y = SMapY + VDy[z];
865 if (TestBounds(x, y)) {
866 MPtem = Map[x][y];
867 if ((MPtem == CHANNEL) ||
868 ((MPtem & 15) == (VBRTAB2[z] & 15)))
869 Map[x][y] = VBRTAB[z];
870 }
871 }
872 return (TRUE);
873 }
874 return (FALSE);
875 } else {
876 if (SMapY > 0)
877 if (Map[SMapX][SMapY - 1] == CHANNEL) { /* Horizontal open */
878 for (z = 0; z < 7; z++) {
879 x = SMapX + HDx[z];
880 y = SMapY + HDy[z];
881 if (TestBounds(x, y)) {
882 MPtem = Map[x][y];
883 if (((MPtem & 15) == (HBRTAB2[z] & 15)) ||
884 (MPtem == CHANNEL))
885 Map[x][y] = HBRTAB[z];
886 }
887 }
888 return (TRUE);
889 }
890 return (FALSE);
891 }
892 }
893 return (FALSE);
894 }
895
896
897 int
898 GetBoatDis(void)
899 {
900 register int dist, mx, my, dx, dy;
901 SimSprite *sprite;
902
903 dist = 99999;
904 mx = (SMapX <<4) + 8;
905 my = (SMapY <<4) + 8;
906
907 for (sprite = sim->sprite; sprite != NULL; sprite = sprite->next) {
908 if ((sprite->type == SHI) &&
909 (sprite->frame != 0)) {
910 if ((dx = sprite->x + sprite->x_hot - mx) < 0) dx = -dx;
911 if ((dy = sprite->y + sprite->y_hot - my) < 0) dy = -dy;
912 dx += dy;
913 if (dx < dist) dist = dx;
914 }
915 }
916 return (dist);
917 }
918
919
920 /* comefrom: MapScan */
921 DoFire(void)
922 {
923 static short DX[4] = { -1, 0, 1, 0 };
924 static short DY[4] = { 0, -1, 0, 1 };
925 register short z, Xtem, Ytem, Rate, c;
926
927 for (z = 0; z < 4; z++) {
928 if (!(Rand16() & 7)) {
929 Xtem = SMapX + DX[z];
930 Ytem = SMapY + DY[z];
931 if (TestBounds(Xtem, Ytem)) {
932 c = Map[Xtem][Ytem];
933 if (c & BURNBIT) {
934 if (c & ZONEBIT) {
935 FireZone(Xtem, Ytem, c);
936 if ((c & LOMASK) > IZB) { /* Explode */
937 MakeExplosionAt((Xtem <<4) + 8, (Ytem <<4) + 8);
938 }
939 }
940 Map[Xtem][Ytem] = FIRE + (Rand16() & 3) + ANIMBIT;
941 }
942 }
943 }
944 }
945 z = FireRate[SMapX >>3][SMapY >>3];
946 Rate = 10;
947 if (z) {
948 Rate = 3;
949 if (z > 20) Rate = 2;
950 if (z > 100) Rate = 1;
951 }
952 if (!Rand(Rate))
953 Map[SMapX][SMapY] = RUBBLE + (Rand16() & 3) + BULLBIT;
954 }
955
956
957 /* comefrom: DoFire MakeFlood */
958 FireZone(int Xloc, int Yloc, int ch)
959 {
960 register short Xtem, Ytem;
961 short x, y, XYmax;
962
963 RateOGMem[Xloc >>3][Yloc >>3] -= 20;
964
965 ch = ch & LOMASK;
966 if (ch < PORTBASE)
967 XYmax = 2;
968 else
969 if (ch == AIRPORT)
970 XYmax = 5;
971 else
972 XYmax = 4;
973
974 for (x = -1; x < XYmax; x++)
975 for (y = -1; y < XYmax; y++) {
976 Xtem = Xloc + x;
977 Ytem = Yloc + y;
978 if ((Xtem < 0) || (Xtem > (WORLD_X - 1)) ||
979 (Ytem < 0) || (Ytem > (WORLD_Y - 1)))
980 continue;
981 if ((short)(Map[Xtem][Ytem] & LOMASK) >= ROADBASE) /* post release */
982 Map[Xtem][Ytem] |= BULLBIT;
983 }
984 }
985
986
987 /* comefrom: DoSPZone DoHospChur */
988 RepairZone(short ZCent, short zsize)
989 {
990 short cnt;
991 register short x, y, ThCh;
992
993 zsize--;
994 cnt = 0;
995 for (y = -1; y < zsize; y++)
996 for (x = -1; x < zsize; x++) {
997 int xx = SMapX + x;
998 int yy = SMapY + y;
999 cnt++;
1000 if (TestBounds(xx, yy)) {
1001 ThCh = Map[xx][yy];
1002 if (ThCh & ZONEBIT) continue;
1003 if (ThCh & ANIMBIT) continue;
1004 ThCh = ThCh & LOMASK;
1005 if ((ThCh < RUBBLE) || (ThCh >= ROADBASE)) {
1006 Map[xx][yy] = ZCent - 3 - zsize + cnt + CONDBIT + BURNBIT;
1007 }
1008 }
1009 }
1010 }
1011
1012
1013 /* comefrom: DoZone */
1014 DoSPZone(short PwrOn)
1015 {
1016 static short MltdwnTab[3] = { 30000, 20000, 10000 }; /* simadj */
1017 register z;
1018
1019 switch (CChr9) {
1020
1021 case POWERPLANT:
1022 CoalPop++;
1023 if (!(CityTime & 7))
1024 RepairZone(POWERPLANT, 4); /* post */
1025 PushPowerStack();
1026 CoalSmoke(SMapX, SMapY);
1027 return;
1028
1029 case NUCLEAR:
1030 if (!NoDisasters && !Rand(MltdwnTab[GameLevel])) {
1031 DoMeltdown(SMapX, SMapY);
1032 return;
1033 }
1034 NuclearPop++;
1035 if (!(CityTime & 7))
1036 RepairZone(NUCLEAR, 4); /* post */
1037 PushPowerStack();
1038 return;
1039
1040 case FIRESTATION:
1041 FireStPop++;
1042 if (!(CityTime & 7))
1043 RepairZone(FIRESTATION, 3); /* post */
1044
1045 if (PwrOn)
1046 z = FireEffect; /* if powered get effect */
1047 else
1048 z = FireEffect >>1; /* from the funding ratio */
1049
1050 if (!FindPRoad())
1051 z = z >>1; /* post FD's need roads */
1052
1053 FireStMap[SMapX >>3][SMapY >>3] += z;
1054 return;
1055
1056 case POLICESTATION:
1057 PolicePop++;
1058 if (!(CityTime & 7))
1059 RepairZone(POLICESTATION, 3); /* post */
1060
1061 if (PwrOn)
1062 z = PoliceEffect;
1063 else
1064 z = PoliceEffect >>1;
1065
1066 if (!FindPRoad())
1067 z = z >>1; /* post PD's need roads */
1068
1069 PoliceMap[SMapX >>3][SMapY >>3] += z;
1070 return;
1071
1072 case STADIUM:
1073 StadiumPop++;
1074 if (!(CityTime & 15))
1075 RepairZone(STADIUM, 4);
1076 if (PwrOn)
1077 if (!((CityTime + SMapX + SMapY) & 31)) { /* post release */
1078 DrawStadium(FULLSTADIUM);
1079 Map[SMapX + 1][SMapY] = FOOTBALLGAME1 + ANIMBIT;
1080 Map[SMapX + 1][SMapY + 1] = FOOTBALLGAME2 + ANIMBIT;
1081 }
1082 return;
1083
1084 case FULLSTADIUM:
1085 StadiumPop++;
1086 if (!((CityTime + SMapX + SMapY) & 7)) /* post release */
1087 DrawStadium(STADIUM);
1088 return;
1089
1090 case AIRPORT:
1091 APortPop++;
1092 if (!(CityTime & 7))
1093 RepairZone(AIRPORT, 6);
1094
1095 if (PwrOn) { /* post */
1096 if ((Map[SMapX + 1][SMapY - 1] & LOMASK) == RADAR)
1097 Map[SMapX + 1][SMapY - 1] = RADAR + ANIMBIT + CONDBIT + BURNBIT;
1098 } else
1099 Map[SMapX + 1][SMapY - 1] = RADAR + CONDBIT + BURNBIT;
1100
1101 if (PwrOn)
1102 DoAirport();
1103 return;
1104
1105 case PORT:
1106 PortPop++;
1107 if ((CityTime & 15) == 0) {
1108 RepairZone(PORT, 4);
1109 }
1110 if (PwrOn &&
1111 (GetSprite(SHI) == NULL)) {
1112 GenerateShip();
1113 }
1114 return;
1115 }
1116 }
1117
1118
1119 /* comefrom: DoSPZone */
1120 DrawStadium(int z)
1121 {
1122 register int x, y;
1123
1124 z = z - 5;
1125 for (y = (SMapY - 1); y < (SMapY + 3); y++)
1126 for (x = (SMapX - 1); x < (SMapX + 3); x++)
1127 Map[x][y] = (z++) | BNCNBIT;
1128 Map[SMapX][SMapY] |= ZONEBIT | PWRBIT;
1129 }
1130
1131
1132 /* comefrom: DoSPZone */
1133 DoAirport(void)
1134 {
1135 if (!(Rand(5))) {
1136 GeneratePlane(SMapX, SMapY);
1137 return;
1138 }
1139 if (!(Rand(12)))
1140 GenerateCopter(SMapX, SMapY);
1141 }
1142
1143
1144 /* comefrom: DoSPZone */
1145 CoalSmoke(int mx, int my)
1146 {
1147 static short SmTb[4] = { COALSMOKE1, COALSMOKE2, COALSMOKE3, COALSMOKE4 };
1148 static short dx[4] = { 1, 2, 1, 2 };
1149 static short dy[4] = { -1, -1, 0, 0 };
1150 register short x;
1151
1152 for (x = 0; x < 4; x++)
1153 Map[mx + dx[x]][my + dy[x]] =
1154 SmTb[x] | ANIMBIT | CONDBIT | PWRBIT | BURNBIT;
1155 }
1156
1157
1158 /* comefrom: DoSPZone MakeMeltdown */
1159 DoMeltdown(int SX, int SY)
1160 {
1161 register x, y, z, t;
1162
1163 MeltX = SX; MeltY = SY;
1164
1165 MakeExplosion(SX - 1, SY - 1);
1166 MakeExplosion(SX - 1, SY + 2);
1167 MakeExplosion(SX + 2, SY - 1);
1168 MakeExplosion(SX + 2, SY + 2);
1169
1170 for (x = (SX - 1); x < (SX + 3); x++)
1171 for (y = (SY - 1); y < (SY + 3); y++)
1172 Map[x][y] = FIRE + (Rand16() & 3) + ANIMBIT;
1173
1174 for (z = 0; z < 200; z++) {
1175 x = SX - 20 + Rand(40);
1176 y = SY - 15 + Rand(30);
1177 if ((x < 0) || (x >= WORLD_X) ||
1178 (y < 0) || (y >= WORLD_Y))
1179 continue;
1180 t = Map[x][y];
1181 if (t & ZONEBIT)
1182 continue;
1183 if ((t & BURNBIT) || (t == 0))
1184 Map[x][y] = RADTILE;
1185 }
1186
1187 ClearMes();
1188 SendMesAt(-43, SX, SY);
1189 }
1190
1191
1192 #define RANDOM_RANGE 0xffff
1193
1194 short
1195 Rand(short range)
1196 {
1197 int maxMultiple, rnum;
1198
1199 range++;
1200 maxMultiple = RANDOM_RANGE / range;
1201 maxMultiple *= range;
1202 while ((rnum = Rand16()) >= maxMultiple)
1203 continue;
1204 return (rnum % range);
1205 }
1206
1207
1208 int
1209 Rand16(void)
1210 {
1211 return (sim_rand());
1212 }
1213
1214
1215 int
1216 Rand16Signed(void)
1217 {
1218 int i = sim_rand();
1219
1220 if (i > 32767) {
1221 i = 32767 - i;
1222 }
1223 return (i);
1224 }
1225
1226
1227 RandomlySeedRand()
1228 {
1229 struct timeval time;
1230
1231 gettimeofday(&time, NULL);
1232
1233 SeedRand(time.tv_usec ^ time.tv_sec ^ sim_rand());
1234 }
1235
1236
1237 SeedRand(int seed)
1238 {
1239 sim_srand(seed);
1240 }
Impressum, Datenschutz