Micropolis
fileio.cpp
Go to the documentation of this file.
1 /* fileio.cpp
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 
77 
78 
79 #include "micropolis.h"
80 
81 
83 
84 
85 #ifdef IS_INTEL
86 
92 #define SWAP_SHORTS(buf, len) swap_shorts(buf, len)
93 
99 #define HALF_SWAP_LONGS(buf, len) half_swap_longs(buf, len)
100 
106 static void swap_shorts(short *buf, int len)
107 {
108  int i;
109 
110  /* Flip bytes in each short! */
111  for (i = 0; i < len; i++) {
112  *buf = ((*buf & 0xFF) <<8) | ((*buf &0xFF00) >>8);
113  buf++;
114  }
115 }
116 
117 
123 static void half_swap_longs(long *buf, int len)
124 {
125  int i;
126 
127  /* Flip bytes in each long! */
128  for (i = 0; i < len; i++) {
129  long l = *buf;
130  *buf =
131  ((l & 0x0000ffff) << 16) |
132  ((l & 0xffff0000) >> 16);
133  buf++;
134  }
135 }
136 
137 
138 #else
139 
140 
148 #define SWAP_SHORTS(buf, len)
149 
157 #define HALF_SWAP_LONGS(buf, len)
158 
159 
160 #endif
161 
171 static bool load_short(short *buf, int len, FILE *f)
172 {
173  size_t result = fread(buf, sizeof(short), len, f);
174 
175  if ((int)result != len) {
176  return false;
177  }
178 
179  SWAP_SHORTS(buf, len); /* to intel */
180 
181  return true;
182 }
183 
184 
194 static bool save_short(short *buf, int len, FILE *f)
195 {
196  SWAP_SHORTS(buf, len); /* to MAC */
197 
198  if ((int)fwrite(buf, sizeof(short), len, f) != len) {
199  return false;
200  }
201 
202  SWAP_SHORTS(buf, len); /* back to intel */
203 
204  return true;
205 }
206 
213 bool Micropolis::loadFileData(const std::string &filename)
214 {
215  FILE *f;
216  Quad size;
217 
218  // Open the file.
219  f = fopen(filename.c_str(), "rb");
220 
221  // open() failed; report failure.
222  if (f == NULL) {
223  return false;
224  }
225 
226  fseek(f, 0L, SEEK_END);
227  size = ftell(f);
228  fseek(f, 0L, SEEK_SET);
229 
230  bool result =
231  (size == 27120) &&
232  load_short(resHist, HISTORY_LENGTH / sizeof(short), f) &&
233  load_short(comHist, HISTORY_LENGTH / sizeof(short), f) &&
234  load_short(indHist, HISTORY_LENGTH / sizeof(short), f) &&
235  load_short(crimeHist, HISTORY_LENGTH / sizeof(short), f) &&
236  load_short(pollutionHist, HISTORY_LENGTH / sizeof(short), f) &&
237  load_short(moneyHist, HISTORY_LENGTH / sizeof(short), f) &&
238  load_short(miscHist, MISC_HISTORY_LENGTH / sizeof(short), f) &&
239  load_short(((short *)&map[0][0]), WORLD_W * WORLD_H, f);
240 
241  fclose(f);
242 
243  return result;
244 }
245 
251 bool Micropolis::loadFile(const std::string &filename)
252 {
253  long n;
254 
255  if (!loadFileData(filename)) {
256  return false;
257  }
258 
259  /* total funds is a long..... miscHist is array of shorts */
260  /* total funds is being put in the 50th & 51th word of miscHist */
261  /* find the address, cast the ptr to a longPtr, take contents */
262 
263  n = *(Quad *)(miscHist + 50);
264  HALF_SWAP_LONGS(&n, 1);
265  setFunds(n);
266 
267  n = *(Quad *)(miscHist + 8);
268  HALF_SWAP_LONGS(&n, 1);
269  cityTime = n;
270 
271  setAutoBulldoze(miscHist[52] != 0); // flag for autoBulldoze
272  setAutoBudget(miscHist[53] != 0); // flag for autoBudget
273  setAutoGoto(miscHist[54] != 0); // flag for auto-goto
274  setEnableSound(miscHist[55] != 0); // flag for the sound on/off
275  setCityTax(miscHist[56]);
276  setSpeed(miscHist[57]);
277  changeCensus();
278  mustUpdateOptions = true;
279 
280  /* yayaya */
281 
282  n = *(Quad *)(miscHist + 58);
283  HALF_SWAP_LONGS(&n, 1);
284  policePercent = ((float)n) / ((float)65536);
285 
286  n = *(Quad *)(miscHist + 60);
287  HALF_SWAP_LONGS(&n, 1);
288  firePercent = (float)n / (float)65536.0;
289 
290  n = *(Quad *)(miscHist + 62);
291  HALF_SWAP_LONGS(&n, 1);
292  roadPercent = (float)n / (float)65536.0;
293 
294  policePercent =
295  (float)(*(Quad*)(miscHist + 58)) /
296  (float)65536.0; /* and 59 */
297  firePercent =
298  (float)(*(Quad*)(miscHist + 60)) /
299  (float)65536.0; /* and 61 */
300  roadPercent =
301  (float)(*(Quad*)(miscHist + 62)) /
302  (float)65536.0; /* and 63 */
303 
304  cityTime = max((Quad)0, cityTime);
305 
306  // If the tax is nonsensical, set it to a reasonable value.
307  if (cityTax > 20 || cityTax < 0) {
308  setCityTax(7);
309  }
310 
311  // If the speed is nonsensical, set it to a reasonable value.
312  if (simSpeed < 0 || simSpeed > 3) {
313  setSpeed(3);
314  }
315 
316  setSpeed(simSpeed);
317  setPasses(1);
318  initFundingLevel();
319 
320  // Set the scenario id to 0.
321  initWillStuff();
322  scenario = SC_NONE;
323  initSimLoad = 1;
324  doInitialEval = false;
325  doSimInit();
326  invalidateMaps();
327 
328  return true;
329 }
330 
331 
337 bool Micropolis::saveFile(const std::string &filename)
338 {
339  long n;
340  FILE *f;
341 
342  if ((f = fopen(filename.c_str(), "wb")) == NULL) {
344  return false;
345  }
346 
347  /* total funds is a long..... miscHist is array of ints */
348  /* total funds is bien put in the 50th & 51th word of miscHist */
349  /* find the address, cast the ptr to a longPtr, take contents */
350 
351  n = totalFunds;
352  HALF_SWAP_LONGS(&n, 1);
353  (*(Quad *)(miscHist + 50)) = n;
354 
355  n = cityTime;
356  HALF_SWAP_LONGS(&n, 1);
357  (*(Quad *)(miscHist + 8)) = n;
358 
359  miscHist[52] = autoBulldoze; // flag for autoBulldoze
360  miscHist[53] = autoBudget; // flag for autoBudget
361  miscHist[54] = autoGoto; // flag for auto-goto
362  miscHist[55] = enableSound; // flag for the sound on/off
363  miscHist[57] = simSpeed;
364  miscHist[56] = cityTax; /* post release */
365 
366  /* yayaya */
367 
368  n = (int)(policePercent * 65536);
369  HALF_SWAP_LONGS(&n, 1);
370  (*(Quad *)(miscHist + 58)) = n;
371 
372  n = (int)(firePercent * 65536);
373  HALF_SWAP_LONGS(&n, 1);
374  (*(Quad *)(miscHist + 60)) = n;
375 
376  n = (int)(roadPercent * 65536);
377  HALF_SWAP_LONGS(&n, 1);
378  (*(Quad *)(miscHist + 62)) = n;
379 
380  bool result =
381  save_short(resHist, HISTORY_LENGTH / 2, f) &&
382  save_short(comHist, HISTORY_LENGTH / 2, f) &&
383  save_short(indHist, HISTORY_LENGTH / 2, f) &&
388  save_short(((short *)&map[0][0]), WORLD_W * WORLD_H, f);
389 
390  fclose(f);
391 
392  return result;
393 }
394 
395 
402 {
403  std::string name = NULL;
404  std::string fname = NULL;
405 
406  cityFileName = "";
407 
409 
410  if (s < SC_DULLSVILLE || s > SC_RIO) {
411  s = SC_DULLSVILLE;
412  }
413 
414  switch (s) {
415  case SC_DULLSVILLE:
416  name = "Dullsville";
417  fname = "cities/scenario_dullsville.cty";
419  cityTime = ((1900 - 1900) * 48) + 2;
420  setFunds(5000);
421  break;
422  case SC_SAN_FRANCISCO:
423  name = "San Francisco";
424  fname = "cities/scenario_san_francisco.cty";
426  cityTime = ((1906 - 1900) * 48) + 2;
427  setFunds(20000);
428  break;
429  case SC_HAMBURG:
430  name = "Hamburg";
431  fname = "cities/scenario_hamburg.cty";
433  cityTime = ((1944 - 1900) * 48) + 2;
434  setFunds(20000);
435  break;
436  case SC_BERN:
437  name = "Bern";
438  fname = "cities/scenario_bern.cty";
439  scenario = SC_BERN;
440  cityTime = ((1965 - 1900) * 48) + 2;
441  setFunds(20000);
442  break;
443  case SC_TOKYO:
444  name = "Tokyo";
445  fname = "cities/scenario_tokyo.cty";
446  scenario = SC_TOKYO;
447  cityTime = ((1957 - 1900) * 48) + 2;
448  setFunds(20000);
449  break;
450  case SC_DETROIT:
451  name = "Detroit";
452  fname = "cities/scenario_detroit.cty";
454  cityTime = ((1972 - 1900) * 48) + 2;
455  setFunds(20000);
456  break;
457  case SC_BOSTON:
458  name = "Boston";
459  fname = "cities/scenario_boston.cty";
461  cityTime = ((2010 - 1900) * 48) + 2;
462  setFunds(20000);
463  break;
464  case SC_RIO:
465  name = "Rio de Janeiro";
466  fname = "cities/scenario_rio_de_janeiro.cty";
467  scenario = SC_RIO;
468  cityTime = ((2047 - 1900) * 48) + 2;
469  setFunds(20000);
470  break;
471  default:
472  NOT_REACHED();
473  break;
474  }
475 
476  setCleanCityName(name);
477  setSpeed(3);
478  setCityTax(7);
479 
480  loadFileData(fname);
481 
482  initWillStuff();
483  initFundingLevel();
484  updateFunds();
485  invalidateMaps();
486  initSimLoad = 1;
487  doInitialEval = false;
488  doSimInit();
489  didLoadScenario(s, name, fname);
490 }
491 
492 
494 void Micropolis::didLoadScenario(int s, const std::string name, const std::string fname)
495 {
496  callback->didLoadScenario(this, callbackVal, name, fname);
497 }
498 
508 bool Micropolis::loadCity(const std::string &filename)
509 {
510  if (loadFile(filename)) {
511 
512  cityFileName = filename;
513 
514  size_t lastSlash = cityFileName.find_last_of('/');
515  size_t pos = (lastSlash == std::string::npos) ? 0 : lastSlash + 1;
516 
517  size_t lastDot = cityFileName.find_last_of('.');
518  size_t last =
519  (lastDot == std::string::npos) ? cityFileName.length() : lastDot;
520 
521  std::string newCityName = cityFileName.substr(pos, last - pos);
522  setCityName(newCityName);
523 
524  didLoadCity(filename);
525 
526  return true;
527 
528  } else {
529 
530  didntLoadCity(filename);
531 
532  return false;
533 
534  }
535 }
536 
538 void Micropolis::didLoadCity(const std::string &filename)
539 {
540  callback->didLoadCity(this, callbackVal, filename);
541 }
542 
543 
548 void Micropolis::didntLoadCity(const std::string &filename)
549 {
550  callback->didntLoadCity(this, callbackVal, filename);
551 }
552 
553 
560 {
561  if (cityFileName.length() > 0) {
562 
564 
565  } else {
566  if (saveFile(cityFileName)) {
567 
569 
570  } else {
571 
573 
574  }
575  }
576 }
577 
578 
583 void Micropolis::doSaveCityAs(const std::string &filename)
584 {
585  callback->saveCityAs(this, callbackVal, filename);
586 }
587 
588 
593 void Micropolis::didSaveCity(const std::string &filename)
594 {
595  callback->didSaveCity(this, callbackVal, filename);
596 }
597 
598 
603 void Micropolis::didntSaveCity(const std::string &filename)
604 {
605  callback->didntSaveCity(this, callbackVal, filename);
606 }
607 
608 
616 void Micropolis::saveCityAs(const std::string &filename)
617 {
618  cityFileName = filename;
619 
620  if (saveFile(cityFileName)) {
621 
622  size_t lastDot = cityFileName.find_last_of('.');
623  size_t lastSlash = cityFileName.find_last_of('/');
624 
625  size_t pos =
626  (lastSlash == std::string::npos) ? 0 : lastSlash + 1;
627  size_t last =
628  (lastDot == std::string::npos) ? cityFileName.length() : lastDot;
629  size_t len =
630  last - pos;
631  std::string newCityName =
632  cityFileName.substr(pos, len);
633 
634  setCityName(newCityName);
635 
637 
638  } else {
639 
641 
642  }
643 }
644 
645 
float firePercent
Definition: micropolis.h:1443
bool doInitialEval
Need to perform initial city evaluation.
Definition: micropolis.h:2120
void didntLoadCity(const std::string &msg)
Definition: fileio.cpp:548
bool loadFileData(const std::string &filename)
Definition: fileio.cpp:213
void doSaveCityAs(const std::string &filename)
Definition: fileio.cpp:583
void didSaveCity(const std::string &filename)
Definition: fileio.cpp:593
Scenario scenario
Scenario being played.
Definition: micropolis.h:2338
short * resHist
Definition: micropolis.h:1341
void changeCensus()
Definition: graph.cpp:122
Callback * callback
Definition: micropolis.h:954
void saveCity()
Definition: fileio.cpp:559
std::string cityFileName
Filename of the last loaded city.
Definition: micropolis.h:1904
short * moneyHist
Definition: micropolis.h:1356
Quad cityTime
Definition: micropolis.h:1092
float roadPercent
Definition: micropolis.h:1427
void loadScenario(Scenario s)
Definition: fileio.cpp:401
void didntSaveCity(const std::string &msg)
Definition: fileio.cpp:603
void setAutoGoto(bool value)
Definition: utilities.cpp:356
bool loadFile(const std::string &filename)
Definition: fileio.cpp:251
short * crimeHist
Definition: micropolis.h:1366
short * pollutionHist
Definition: micropolis.h:1361
std::string cityName
Name of the city.
Definition: micropolis.h:1909
void setFunds(int dollars)
void updateFunds()
Definition: update.cpp:127
void didLoadCity(const std::string &filename)
Definition: fileio.cpp:538
void setAutoBulldoze(bool value)
Definition: utilities.cpp:342
void setEnableSound(bool value)
Definition: utilities.cpp:370
bool mustUpdateOptions
Options displayed at user need updating.
Definition: micropolis.h:2639
void saveCityAs(const std::string &filename)
Definition: fileio.cpp:616
unsigned short * map[WORLD_W]
Definition: micropolis.h:1120
short * indHist
Definition: micropolis.h:1351
short * comHist
Definition: micropolis.h:1346
bool enableSound
Enable sound.
Definition: micropolis.h:2344
bool saveFile(const std::string &filename)
Definition: fileio.cpp:337
void setGameLevel(GameLevel level)
Definition: utilities.cpp:235
bool autoBudget
Definition: micropolis.h:2330
void invalidateMaps()
void didLoadScenario(int s, const std::string name, const std::string fname)
Definition: fileio.cpp:494
void setCleanCityName(const std::string &name)
Definition: utilities.cpp:272
void initWillStuff()
Definition: initialize.cpp:85
bool loadCity(const std::string &filename)
Definition: fileio.cpp:508
bool autoGoto
Definition: micropolis.h:1960
short cityTax
Definition: micropolis.h:1224
short * miscHist
Definition: micropolis.h:1371
float policePercent
Definition: micropolis.h:1435
Quad totalFunds
Funds of the player.
Definition: micropolis.h:2315
bool autoBulldoze
Definition: micropolis.h:2323
void doSimInit()
Definition: simulate.cpp:286
void setAutoBudget(bool value)
Definition: utilities.cpp:328
static bool load_short(short *buf, int len, FILE *f)
Definition: fileio.cpp:171
static void half_swap_longs(long *buf, int len)
Definition: fileio.cpp:123
#define HALF_SWAP_LONGS(buf, len)
Definition: fileio.cpp:99
static void swap_shorts(short *buf, int len)
Definition: fileio.cpp:106
#define SWAP_SHORTS(buf, len)
Definition: fileio.cpp:92
static bool save_short(short *buf, int len, FILE *f)
Definition: fileio.cpp:194
static const int WORLD_H
Definition: map_type.h:95
static const int WORLD_W
Definition: map_type.h:90
Header file for Micropolis game engine.
Scenario
Definition: micropolis.h:697
@ SC_TOKYO
Tokyo (scary monster)
Definition: micropolis.h:704
@ SC_NONE
No scenario (free playing)
Definition: micropolis.h:698
@ SC_BOSTON
Boston (nuclear meltdown)
Definition: micropolis.h:706
@ SC_BERN
Bern (traffic)
Definition: micropolis.h:703
@ SC_SAN_FRANCISCO
San francisco (earthquake)
Definition: micropolis.h:701
@ SC_RIO
Rio (flooding)
Definition: micropolis.h:707
@ SC_HAMBURG
Hamburg (fire bombs)
Definition: micropolis.h:702
@ SC_DULLSVILLE
Dullsville (boredom)
Definition: micropolis.h:700
@ SC_DETROIT
Detroit (crime)
Definition: micropolis.h:705
static const int HISTORY_LENGTH
Definition: micropolis.h:210
#define NOT_REACHED()
Definition: micropolis.h:847
@ LEVEL_EASY
Simple game level.
Definition: micropolis.h:763
static const int MISC_HISTORY_LENGTH
Definition: micropolis.h:215
static T max(const T a, const T b)
Definition: micropolis.h:795