|
|
1.1 root 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 [email protected].
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.