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