]>
Commit | Line | Data |
---|---|---|
1 | /* s_fileio.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 | #if defined(MSDOS) || defined(OSF1) || defined(IS_INTEL) | |
66 | ||
67 | #define SWAP_SHORTS(a,b) _swap_shorts(a,b) | |
68 | #define SWAP_LONGS(a,b) _swap_longs(a,b) | |
69 | #define HALF_SWAP_LONGS(a,b) _half_swap_longs(a,b) | |
70 | ||
71 | static void | |
72 | _swap_shorts(short *buf, int len) | |
73 | { | |
74 | int i; | |
75 | ||
76 | /* Flip bytes in each short! */ | |
77 | for (i = 0; i < len; i++) { | |
78 | *buf = ((*buf & 0xFF) <<8) | ((*buf &0xFF00) >>8); | |
79 | buf++; | |
80 | } | |
81 | } | |
82 | ||
83 | static void | |
84 | _swap_longs(long *buf, int len) | |
85 | { | |
86 | int i; | |
87 | ||
88 | /* Flip bytes in each long! */ | |
89 | for (i = 0; i < len; i++) { | |
90 | long l = *buf; | |
91 | *buf = | |
92 | ((l & 0x000000ff) << 24) | | |
93 | ((l & 0x0000ff00) << 8) | | |
94 | ((l & 0x00ff0000) >> 8) | | |
95 | ((l & 0xff000000) >> 24); | |
96 | buf++; | |
97 | } | |
98 | } | |
99 | ||
100 | static void | |
101 | _half_swap_longs(long *buf, int len) | |
102 | { | |
103 | int i; | |
104 | ||
105 | /* Flip bytes in each long! */ | |
106 | for (i = 0; i < len; i++) { | |
107 | long l = *buf; | |
108 | *buf = | |
109 | ((l & 0x0000ffff) << 16) | | |
110 | ((l & 0xffff0000) >> 16); | |
111 | buf++; | |
112 | } | |
113 | } | |
114 | ||
115 | #else | |
116 | ||
117 | #define SWAP_SHORTS(a, b) | |
118 | #define SWAP_LONGS(a, b) | |
119 | #define HALF_SWAP_LONGS(a, b) | |
120 | ||
121 | #endif | |
122 | ||
123 | ||
124 | static int | |
125 | _load_short(short *buf, int len, FILE *f) | |
126 | { | |
127 | if (fread(buf, sizeof(short), len, f) != len) | |
128 | return 0; | |
129 | ||
130 | SWAP_SHORTS(buf, len); /* to intel */ | |
131 | ||
132 | return 1; | |
133 | } | |
134 | ||
135 | ||
136 | static int | |
137 | _load_long(long *buf, int len, FILE *f) | |
138 | { | |
139 | if (fread(buf, sizeof(long), len, f) != len) | |
140 | return 0; | |
141 | ||
142 | SWAP_LONGS(buf, len); /* to intel */ | |
143 | ||
144 | return 1; | |
145 | } | |
146 | ||
147 | ||
148 | static int | |
149 | _save_short(short *buf, int len, FILE *f) | |
150 | { | |
151 | ||
152 | SWAP_SHORTS(buf, len); /* to MAC */ | |
153 | ||
154 | if (fwrite(buf, sizeof(short), len, f) != len) | |
155 | return 0; | |
156 | ||
157 | SWAP_SHORTS(buf, len); /* back to intel */ | |
158 | ||
159 | return 1; | |
160 | } | |
161 | ||
162 | ||
163 | static int | |
164 | _save_long(long *buf, int len, FILE *f) | |
165 | { | |
166 | ||
167 | SWAP_LONGS(buf, len); /* to MAC */ | |
168 | ||
169 | if (fwrite(buf, sizeof(long), len, f) != len) | |
170 | return 0; | |
171 | ||
172 | SWAP_LONGS(buf, len); /* back to intel */ | |
173 | ||
174 | return 1; | |
175 | } | |
176 | ||
177 | ||
178 | static | |
179 | int | |
180 | _load_file(char *filename, char *dir) | |
181 | { | |
182 | FILE *f; | |
183 | char path[512]; | |
184 | QUAD size; | |
185 | ||
186 | #ifdef MSDOS | |
187 | if (dir != NULL) { | |
188 | sprintf(path, "%s\\%s", dir, filename); | |
189 | filename = path; | |
190 | } | |
191 | if ((f = fopen(filename, "rb")) == NULL) { | |
192 | return 0; | |
193 | } | |
194 | #else | |
195 | if (dir != NULL) { | |
196 | sprintf(path, "%s/%s", dir, filename); | |
197 | filename = path; | |
198 | } | |
199 | if ((f = fopen(filename, "r")) == NULL) { | |
200 | return (0); | |
201 | } | |
202 | #endif | |
203 | ||
204 | fseek(f, 0L, SEEK_END); | |
205 | size = ftell(f); | |
206 | fseek(f, 0L, SEEK_SET); | |
207 | ||
208 | switch (size) { | |
209 | case 27120: /* Normal city */ | |
210 | break; | |
211 | ||
212 | case 99120: /* 2x2 city */ | |
213 | break; | |
214 | ||
215 | case 219120: /* 3x3 city */ | |
216 | break; | |
217 | ||
218 | default: | |
219 | return (0); | |
220 | } | |
221 | ||
222 | if ((_load_short(ResHis, HISTLEN / 2, f) == 0) || | |
223 | (_load_short(ComHis, HISTLEN / 2, f) == 0) || | |
224 | (_load_short(IndHis, HISTLEN / 2, f) == 0) || | |
225 | (_load_short(CrimeHis, HISTLEN / 2, f) == 0) || | |
226 | (_load_short(PollutionHis, HISTLEN / 2, f) == 0) || | |
227 | (_load_short(MoneyHis, HISTLEN / 2, f) == 0) || | |
228 | (_load_short(MiscHis, MISCHISTLEN / 2, f) == 0) || | |
229 | (_load_short((&Map[0][0]), WORLD_X * WORLD_Y, f) < 0)) { | |
230 | ||
231 | /* TODO: report error */ | |
232 | fclose(f); | |
233 | return(0); | |
234 | } | |
235 | ||
236 | fclose(f); | |
237 | return(1); | |
238 | } | |
239 | ||
240 | ||
241 | int loadFile(char *filename) | |
242 | { | |
243 | long l; | |
244 | ||
245 | if (_load_file(filename, NULL) == 0) | |
246 | return(0); | |
247 | ||
248 | /* total funds is a long..... MiscHis is array of shorts */ | |
249 | /* total funds is being put in the 50th & 51th word of MiscHis */ | |
250 | /* find the address, cast the ptr to a lontPtr, take contents */ | |
251 | ||
252 | l = *(QUAD *)(MiscHis + 50); | |
253 | HALF_SWAP_LONGS(&l, 1); | |
254 | SetFunds(l); | |
255 | ||
256 | l = *(QUAD *)(MiscHis + 8); | |
257 | HALF_SWAP_LONGS(&l, 1); | |
258 | CityTime = l; | |
259 | ||
260 | autoBulldoze = MiscHis[52]; /* flag for autoBulldoze */ | |
261 | autoBudget = MiscHis[53]; /* flag for autoBudget */ | |
262 | autoGo = MiscHis[54]; /* flag for autoGo */ | |
263 | UserSoundOn = MiscHis[55]; /* flag for the sound on/off */ | |
264 | CityTax = MiscHis[56]; | |
265 | SimSpeed = MiscHis[57]; | |
266 | // sim_skips = sim_skip = 0; | |
267 | ChangeCensus(); | |
268 | MustUpdateOptions = 1; | |
269 | ||
270 | /* yayaya */ | |
271 | ||
272 | l = *(QUAD *)(MiscHis + 58); | |
273 | HALF_SWAP_LONGS(&l, 1); | |
274 | policePercent = l / 65536.0; | |
275 | ||
276 | l = *(QUAD *)(MiscHis + 60); | |
277 | HALF_SWAP_LONGS(&l, 1); | |
278 | firePercent = l / 65536.0; | |
279 | ||
280 | l = *(QUAD *)(MiscHis + 62); | |
281 | HALF_SWAP_LONGS(&l, 1); | |
282 | roadPercent = l / 65536.0; | |
283 | ||
284 | policePercent = (*(QUAD*)(MiscHis + 58)) / 65536.0; /* and 59 */ | |
285 | firePercent = (*(QUAD*)(MiscHis + 60)) / 65536.0; /* and 61 */ | |
286 | roadPercent =(*(QUAD*)(MiscHis + 62)) / 65536.0; /* and 63 */ | |
287 | ||
288 | if (CityTime < 0) | |
289 | CityTime = 0; | |
290 | if ((CityTax > 20) || (CityTax < 0)) | |
291 | CityTax = 7; | |
292 | if ((SimSpeed < 0) || (SimSpeed > 3)) | |
293 | SimSpeed = 3; | |
294 | ||
295 | setSpeed(SimSpeed); | |
296 | setSkips(0); | |
297 | ||
298 | InitFundingLevel(); | |
299 | ||
300 | /* set the scenario id to 0 */ | |
301 | InitWillStuff(); | |
302 | ScenarioID = 0; | |
303 | InitSimLoad = 1; | |
304 | DoInitialEval = 0; | |
305 | DoSimInit(); | |
306 | InvalidateEditors(); | |
307 | InvalidateMaps(); | |
308 | ||
309 | return (1); | |
310 | } | |
311 | ||
312 | ||
313 | int saveFile(char *filename) | |
314 | { | |
315 | long l; | |
316 | FILE *f; | |
317 | ||
318 | #ifdef MSDOS | |
319 | if ((f = fopen(filename, "wb")) == NULL) { | |
320 | #else | |
321 | if ((f = fopen(filename, "w")) == NULL) { | |
322 | #endif | |
323 | /* TODO: report error */ | |
324 | return(0); | |
325 | } | |
326 | ||
327 | /* total funds is a long..... MiscHis is array of ints */ | |
328 | /* total funds is bien put in the 50th & 51th word of MiscHis */ | |
329 | /* find the address, cast the ptr to a lontPtr, take contents */ | |
330 | ||
331 | l = TotalFunds; | |
332 | HALF_SWAP_LONGS(&l, 1); | |
333 | (*(QUAD *)(MiscHis + 50)) = l; | |
334 | ||
335 | l = CityTime; | |
336 | HALF_SWAP_LONGS(&l, 1); | |
337 | (*(QUAD *)(MiscHis + 8)) = l; | |
338 | ||
339 | MiscHis[52] = autoBulldoze; /* flag for autoBulldoze */ | |
340 | MiscHis[53] = autoBudget; /* flag for autoBudget */ | |
341 | MiscHis[54] = autoGo; /* flag for autoGo */ | |
342 | MiscHis[55] = UserSoundOn; /* flag for the sound on/off */ | |
343 | MiscHis[57] = SimSpeed; | |
344 | MiscHis[56] = CityTax; /* post release */ | |
345 | ||
346 | /* yayaya */ | |
347 | ||
348 | l = (int)(policePercent * 65536); | |
349 | HALF_SWAP_LONGS(&l, 1); | |
350 | (*(QUAD *)(MiscHis + 58)) = l; | |
351 | ||
352 | l = (int)(firePercent * 65536); | |
353 | HALF_SWAP_LONGS(&l, 1); | |
354 | (*(QUAD *)(MiscHis + 60)) = l; | |
355 | ||
356 | l = (int)(roadPercent * 65536); | |
357 | HALF_SWAP_LONGS(&l, 1); | |
358 | (*(QUAD *)(MiscHis + 62)) = l; | |
359 | ||
360 | if ((_save_short(ResHis, HISTLEN / 2, f) == 0) || | |
361 | (_save_short(ComHis, HISTLEN / 2, f) == 0) || | |
362 | (_save_short(IndHis, HISTLEN / 2, f) == 0) || | |
363 | (_save_short(CrimeHis, HISTLEN / 2, f) == 0) || | |
364 | (_save_short(PollutionHis, HISTLEN / 2, f) == 0) || | |
365 | (_save_short(MoneyHis, HISTLEN / 2, f) == 0) || | |
366 | (_save_short(MiscHis, MISCHISTLEN / 2, f) == 0) || | |
367 | (_save_short((&Map[0][0]), WORLD_X * WORLD_Y, f) < 0)) { | |
368 | ||
369 | /* TODO: report error */ | |
370 | fclose(f); | |
371 | return(0); | |
372 | } | |
373 | ||
374 | fclose(f); | |
375 | return(1); | |
376 | } | |
377 | ||
378 | ||
379 | LoadScenario(short s) | |
380 | { | |
381 | char *name, *fname; | |
382 | ||
383 | if (CityFileName != NULL) { | |
384 | ckfree(CityFileName); | |
385 | CityFileName = NULL; | |
386 | } | |
387 | ||
388 | SetGameLevel(0); | |
389 | ||
390 | if ((s < 1) || (s > 8)) s = 1; | |
391 | ||
392 | switch (s) { | |
393 | case 1: | |
394 | name = "Dullsville"; | |
395 | fname = "snro.111"; | |
396 | ScenarioID = 1; | |
397 | CityTime = ((1900 - 1900) * 48) + 2; | |
398 | SetFunds(5000); | |
399 | break; | |
400 | case 2: | |
401 | name = "San Francisco"; | |
402 | fname = "snro.222"; | |
403 | ScenarioID = 2; | |
404 | CityTime = ((1906 - 1900) * 48) + 2; | |
405 | SetFunds(20000); | |
406 | break; | |
407 | case 3: | |
408 | name = "Hamburg"; | |
409 | fname = "snro.333"; | |
410 | ScenarioID = 3; | |
411 | CityTime = ((1944 - 1900) * 48) + 2; | |
412 | SetFunds(20000); | |
413 | break; | |
414 | case 4: | |
415 | name = "Bern"; | |
416 | fname = "snro.444"; | |
417 | ScenarioID = 4; | |
418 | CityTime = ((1965 - 1900) * 48) + 2; | |
419 | SetFunds(20000); | |
420 | break; | |
421 | case 5: | |
422 | name = "Tokyo"; | |
423 | fname = "snro.555"; | |
424 | ScenarioID = 5; | |
425 | CityTime = ((1957 - 1900) * 48) + 2; | |
426 | SetFunds(20000); | |
427 | break; | |
428 | case 6: | |
429 | name = "Detroit"; | |
430 | fname = "snro.666"; | |
431 | ScenarioID = 6; | |
432 | CityTime = ((1972 - 1900) * 48) + 2; | |
433 | SetFunds(20000); | |
434 | break; | |
435 | case 7: | |
436 | name = "Boston"; | |
437 | fname = "snro.777"; | |
438 | ScenarioID = 7; | |
439 | CityTime = ((2010 - 1900) * 48) + 2; | |
440 | SetFunds(20000); | |
441 | break; | |
442 | case 8: | |
443 | name = "Rio de Janeiro"; | |
444 | fname = "snro.888"; | |
445 | ScenarioID = 8; | |
446 | CityTime = ((2047 - 1900) * 48) + 2; | |
447 | SetFunds(20000); | |
448 | break; | |
449 | } | |
450 | ||
451 | setAnyCityName(name); | |
452 | // sim_skips = sim_skip = 0; | |
453 | InvalidateMaps(); | |
454 | InvalidateEditors(); | |
455 | setSpeed(3); | |
456 | CityTax = 7; | |
457 | gettimeofday(&start_time, NULL); | |
458 | ||
459 | _load_file(fname, ResourceDir); | |
460 | ||
461 | InitWillStuff(); | |
462 | InitFundingLevel(); | |
463 | UpdateFunds(); | |
464 | InvalidateEditors(); | |
465 | InvalidateMaps(); | |
466 | InitSimLoad = 1; | |
467 | DoInitialEval = 0; | |
468 | DoSimInit(); | |
469 | DidLoadScenario(); | |
470 | Kick(); | |
471 | } | |
472 | ||
473 | ||
474 | DidLoadScenario() | |
475 | { | |
476 | Eval("UIDidLoadScenario"); | |
477 | } | |
478 | ||
479 | ||
480 | int LoadCity(char *filename) | |
481 | { | |
482 | char *cp; | |
483 | char msg[256]; | |
484 | ||
485 | if (loadFile(filename)) { | |
486 | if (CityFileName != NULL) | |
487 | ckfree(CityFileName); | |
488 | CityFileName = (char *)ckalloc(strlen(filename) + 1); | |
489 | strcpy(CityFileName, filename); | |
490 | ||
491 | if (cp = (char *)rindex(filename, '.')) | |
492 | *cp = 0; | |
493 | #ifdef MSDOS | |
494 | if (cp = (char *)rindex(filename, '\\')) | |
495 | #else | |
496 | if (cp = (char *)rindex(filename, '/')) | |
497 | #endif | |
498 | cp++; | |
499 | else | |
500 | cp = filename; | |
501 | filename = (char *)ckalloc(strlen(cp) + 1); | |
502 | strcpy(filename, cp); | |
503 | setCityName(filename); | |
504 | gettimeofday(&start_time, NULL); | |
505 | ||
506 | InvalidateMaps(); | |
507 | InvalidateEditors(); | |
508 | DidLoadCity(); | |
509 | return (1); | |
510 | } else { | |
511 | sprintf(msg, "Unable to load a city from the file named \"%s\". %s", | |
512 | filename ? filename : "(null)", | |
513 | errno ? strerror(errno) : ""); | |
514 | DidntLoadCity(msg); | |
515 | return (0); | |
516 | } | |
517 | } | |
518 | ||
519 | ||
520 | DidLoadCity() | |
521 | { | |
522 | Eval("UIDidLoadCity"); | |
523 | } | |
524 | ||
525 | ||
526 | DidntLoadCity(char *msg) | |
527 | { | |
528 | char buf[1024]; | |
529 | sprintf(buf, "UIDidntLoadCity {%s}", msg); | |
530 | Eval(buf); | |
531 | } | |
532 | ||
533 | ||
534 | SaveCity() | |
535 | { | |
536 | char msg[256]; | |
537 | ||
538 | if (CityFileName == NULL) { | |
539 | DoSaveCityAs(); | |
540 | } else { | |
541 | if (saveFile(CityFileName)) | |
542 | DidSaveCity(); | |
543 | else { | |
544 | sprintf(msg, "Unable to save the city to the file named \"%s\". %s", | |
545 | CityFileName ? CityFileName : "(null)", | |
546 | errno ? strerror(errno) : ""); | |
547 | DidntSaveCity(msg); | |
548 | } | |
549 | } | |
550 | } | |
551 | ||
552 | ||
553 | DoSaveCityAs() | |
554 | { | |
555 | Eval("UISaveCityAs"); | |
556 | } | |
557 | ||
558 | ||
559 | DidSaveCity() | |
560 | { | |
561 | Eval("UIDidSaveCity"); | |
562 | } | |
563 | ||
564 | ||
565 | DidntSaveCity(char *msg) | |
566 | { | |
567 | char buf[1024]; | |
568 | sprintf(buf, "UIDidntSaveCity {%s}", msg); | |
569 | Eval(buf); | |
570 | } | |
571 | ||
572 | ||
573 | SaveCityAs(char *filename) | |
574 | { | |
575 | char msg[256]; | |
576 | char *cp; | |
577 | ||
578 | if (CityFileName != NULL) | |
579 | ckfree(CityFileName); | |
580 | CityFileName = (char *)ckalloc(strlen(filename) + 1); | |
581 | strcpy(CityFileName, filename); | |
582 | ||
583 | if (saveFile(CityFileName)) { | |
584 | if (cp = (char *)rindex(filename, '.')) | |
585 | *cp = 0; | |
586 | #ifdef MSDOS | |
587 | if (cp = (char *)rindex(filename, '\\')) | |
588 | #else | |
589 | if (cp = (char *)rindex(filename, '/')) | |
590 | #endif | |
591 | cp++; | |
592 | else | |
593 | cp = filename; | |
594 | filename = (char *)ckalloc(strlen(cp) + 1); | |
595 | strcpy(filename, cp); | |
596 | setCityName(cp); | |
597 | DidSaveCity(); | |
598 | } else { | |
599 | sprintf(msg, "Unable to save the city to the file named \"%s\". %s", | |
600 | CityFileName ? CityFileName : "(null)", | |
601 | errno ? strerror(errno) : ""); | |
602 | DidntSaveCity(msg); | |
603 | } | |
604 | } | |
605 | ||
606 |