00001
00005 #include <PalmOS.h>
00006 #include <StringMgr.h>
00007 #include <Form.h>
00008
00009 #include <stddef.h>
00010 #include <zakdef.h>
00011 #include <simcity.h>
00012 #include <globals.h>
00013 #include <handler.h>
00014 #include <locking.h>
00015 #include <logging.h>
00016 #include <palmutils.h>
00017 #include <simcity_resconsts.h>
00018 #include <resCompat.h>
00019 #include <savegame_be.h>
00020 #include <mem_compat.h>
00021 #include <pack.h>
00022 #include <beam.h>
00023
00024 #define MAXSAVEGAMECOUNT 50
00025 #define DEAD "PCNO"
00026
00027 static int ReadCityRecord(MemHandle rec, GameStruct *gs,
00028 MemPtr *wp, MemPtr *fp) SAVE_SECTION;
00029 static void WriteCityRecord(MemHandle rec, GameStruct *gs,
00030 MemPtr wp, MemPtr fp) SAVE_SECTION;
00031 static int SaveGameByIndex(UInt16 index) SAVE_SECTION;
00032 static int LoadGameByIndex(UInt16 index) SAVE_SECTION;
00033 static void getAutoSaveName(char *name) SAVE_SECTION;
00034 static void DeleteGameByIndex(UInt16 index) SAVE_SECTION;
00035 static Int16 comparator(void *p1, void *p2, Int32 other) SAVE_SECTION;
00036
00037 static DmOpenRef sgref = 0;
00038
00039 DmOpenRef
00040 OpenMyDB(void)
00041 {
00042 Err err = 0;
00043
00044 if (sgref != NULL)
00045 return (sgref);
00046 sgref = DmOpenDatabaseByTypeCreator(SGTYP, GetCreatorID(),
00047 dmModeReadWrite);
00048 if (!sgref) {
00049 err = DmCreateDatabase(0, SGNAME, GetCreatorID(), SGTYP, false);
00050 if (err)
00051 return (NULL);
00052 sgref = DmOpenDatabaseByTypeCreator(SGTYP, GetCreatorID(),
00053 dmModeReadWrite);
00054 }
00055 if (!sgref) {
00056
00057 }
00058 if (DmNumRecords(sgref) == 0) {
00059
00060
00061
00062
00063
00064 UInt16 index = dmMaxRecordIndex;
00065 Char name[CITYNAMELEN];
00066 MemHandle rec = DmNewRecord(sgref, &index, CITYNAMELEN);
00067 MemSet(name, CITYNAMELEN, 0);
00068 if (rec) {
00069 MemPtr mp = MemHandleLock(rec);
00070 DmWrite(mp, 0, name, CITYNAMELEN);
00071 MemHandleUnlock(rec);
00072 DmReleaseRecord(sgref, index, true);
00073 }
00074 }
00075 return (sgref);
00076 }
00077
00078 void
00079 CloseMyDB(void)
00080 {
00081 if (sgref) {
00082 DmCloseDatabase(sgref);
00083 sgref = 0;
00084 }
00085 }
00086
00087 UInt16
00088 FindGameByName(char *name)
00089 {
00090 DmOpenRef db = NULL;
00091 MemHandle rec;
00092 GameStruct *pRec;
00093 UInt16 nRec;
00094 UInt16 gameindex = LASTGAME;
00095
00096 db = OpenMyDB();
00097 if (db == NULL) {
00098 FrmCustomAlert(alertID_majorbad,
00099 "Can't Open/Create the savegame database", NULL, NULL);
00100 return (gameindex);
00101 }
00102 nRec = DmNumRecords(db);
00103 for (gameindex = 1; gameindex < nRec; gameindex++) {
00104 rec = DmQueryRecord(db, gameindex);
00105 if (rec == NULL)
00106 continue;
00107 pRec = (GameStruct *)MemHandleLock(rec);
00108 if (StrCaselessCompare((const Char *)pRec->cityname,
00109 name) == 0) {
00110 MemHandleUnlock(rec);
00111 break;
00112 }
00113 MemHandleUnlock(rec);
00114 }
00115
00116 if (gameindex >= nRec)
00117 return (LASTGAME);
00118 else
00119 return (gameindex);
00120 }
00121
00127 void
00128 ResetViewable(void)
00129 {
00130 WriteLog("Reset viewable\n");
00131 setVisibleX((UInt16)(sWidth / gameTileSize()));
00132 setVisibleY((UInt16)((sHeight / gameTileSize()) - 2));
00133 }
00134
00135 UInt32
00136 saveGameSize(GameStruct *gs)
00137 {
00138
00139 UInt32 size = (sizeof (GameStruct) +
00140 gs->mapx * gs->mapy +
00141 ((gs->mapx * gs->mapy + ( (8 / 2) - 1)) / ( 8 / 2 )));
00142 return (size);
00143 }
00144
00153 static int
00154 ReadCityRecord(MemHandle rec, GameStruct *gs, MemPtr *wp, MemPtr *fp)
00155 {
00156 char *ptemp;
00157 int rv = -1;
00158
00159 ptemp = (char *)MemHandleLock(rec);
00160 if (ptemp == NULL)
00161 return (-1);
00162 if (MemCmp(DEAD, (char *)ptemp, 4) == 0)
00163 goto leave_me;
00164 if (MemCmp(SAVEGAMEVERSION, (char *)ptemp, 4) == 0) {
00165 UInt32 size;
00166 MemMove((void *)gs, ptemp, sizeof (GameStruct));
00167 size = gs->mapx * gs->mapy;
00168 ptemp += sizeof (GameStruct);
00169 *wp = gRealloc(*wp, size);
00170 MemMove(*wp, ptemp, (Int32)size);
00171 *fp = gRealloc(*fp, size);
00172 ptemp += size;
00173 UnpackBits(ptemp, *fp, 2, (Int32)size);
00174 MemMove(*fp, ptemp, (Int32)size);
00175 rv = 0;
00176 } else {
00177 FrmAlert(alertID_invalidSaveVersion);
00178 rv = -1;
00179 }
00180
00181 leave_me:
00182 MemHandleUnlock(rec);
00183 return (rv);
00184 }
00185
00193 static void
00194 WriteCityRecord(MemHandle rec, GameStruct *gs, MemPtr wp, MemPtr fp)
00195 {
00196 void *pRec;
00197 void *pRec2;
00198 UInt32 size;
00199
00200 pRec = MemHandleLock(rec);
00201
00202 DmWrite(pRec, 0, gs, sizeof (GameStruct));
00203 DmWrite(pRec, sizeof (GameStruct), (void *)wp,
00204 gs->mapx * gs->mapy);
00205 size = (gs->mapx * gs->mapy + ((8 / 2) - 1)) / (8 / 2);
00206 pRec2 = gMalloc(size);
00207 PackBits(fp, pRec2, 2, gs->mapx * gs->mapy);
00208 DmWrite(pRec, sizeof (GameStruct) + gs->mapx * gs->mapy,
00209 (void *)pRec2, size);
00210 gFree(pRec2);
00211 MemHandleUnlock(rec);
00212 }
00213
00219 static int
00220 SaveGameByIndex(UInt16 index)
00221 {
00222 DmOpenRef db = NULL;
00223 MemHandle rec;
00224 UInt16 attr = dmHdrAttrBackup;
00225
00226 if (index == 0)
00227 return (0);
00228
00229 db = OpenMyDB();
00230 if (db == NULL)
00231 return (-1);
00232 if (index <= DmNumRecords(db)) {
00233 rec = DmResizeRecord(db, index, saveGameSize(&game));
00234 rec = DmGetRecord(db, index);
00235 } else {
00236 index = DmNumRecords(db) + 1;
00237 rec = DmNewRecord(db, &index, saveGameSize(&game));
00238 }
00239 if (rec) {
00240 LockZone(lz_world);
00241 LockZone(lz_flags);
00242 WriteCityRecord(rec, &game, worldPtr, flagPtr);
00243 UnlockZone(lz_flags);
00244 UnlockZone(lz_world);
00245 DmReleaseRecord(db, index, true);
00246 }
00247
00248
00249 DmSetDatabaseInfo(0, DmFindDatabase(0, SGNAME), NULL, &attr, NULL,
00250 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
00251
00252 return ((int)index);
00253 }
00254
00255 int
00256 GameExists(char *name)
00257 {
00258 return (FindGameByName(name) != LASTGAME);
00259 }
00260
00261 void
00262 SaveGameByName(char *name)
00263 {
00264 UInt16 index;
00265 index = FindGameByName(name);
00266
00267 SaveGameByIndex(index);
00268 }
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00308 static int
00309 LoadGameByIndex(UInt16 index)
00310 {
00311 DmOpenRef db;
00312 MemHandle rec;
00313 short int loaded = -1;
00314
00315 db = OpenMyDB();
00316
00317 if (!db)
00318 return (-1);
00319
00320 if (index == LASTGAME)
00321 index = DmNumRecords(db) - 1;
00322 rec = DmQueryRecord(db, index);
00323 if (rec) {
00324 LockZone(lz_world);
00325 LockZone(lz_flags);
00326 loaded = ReadCityRecord(rec, &game, &worldPtr, &flagPtr);
00327 UnlockZone(lz_flags);
00328 UnlockZone(lz_world);
00329 }
00330 if (loaded != -1) {
00331 PostLoadGame();
00332 game.units[NUM_OF_UNITS - 1].type = 0xbb;
00333 game.objects[0].x = 0x2222;
00334 game.objects[NUM_OF_OBJECTS - 1].dir = 0x3333;
00335 ResetViewable();
00336 }
00337
00338 return (loaded);
00339 }
00340
00341
00342 int
00343 LoadGameByName(char *name)
00344 {
00345 UInt16 gameindex = FindGameByName(name);
00346
00347 if (gameindex != LASTGAME)
00348 return (LoadGameByIndex(gameindex));
00349 else
00350 return (-1);
00351 }
00352
00353 Int32
00354 BeamCityByName(Char *cityName)
00355 {
00356 UInt16 gameindex = FindGameByName(cityName);
00357 MemHandle rec = NULL;
00358 MemPtr rp = NULL;
00359 DmOpenRef db = 0;
00360 Int32 rv = -1;
00361
00362 if (gameindex == LASTGAME)
00363 return (rv);
00364
00365 db = OpenMyDB();
00366 if (!db)
00367 goto exit_me;
00368 rec = DmQueryRecord(db, gameindex);
00369 if (rec == NULL)
00370 goto exit_me;
00371 rp = MemHandleLock(rec);
00372 if (rp == NULL)
00373 goto exit_me;
00374 rv = BeamSend((UInt8 *)rp);
00375 exit_me:
00376 if (rp)
00377 MemHandleUnlock(rec);
00378 return (rv);
00379 }
00380
00385 static void
00386 getAutoSaveName(char *name)
00387 {
00388 DmOpenRef db = OpenMyDB();
00389 MemHandle rec;
00390 MemPtr ptr;
00391
00392 *name = '\0';
00393 if (db == NULL)
00394 return;
00395
00396 rec = DmQueryRecord(db, 0);
00397 if (rec) {
00398 ptr = MemHandleLock(rec);
00399 MemMove(name, ptr, CITYNAMELEN);
00400 MemHandleUnlock(rec);
00401 }
00402 }
00403
00404 int
00405 LoadAutoSave(void)
00406 {
00407 char cityname[CITYNAMELEN];
00408
00409 getAutoSaveName(cityname);
00410
00411 if (*cityname != '\0') {
00412
00413 if (StrNCompare(cityname, SAVEGAMEVERSION, 4) == 0)
00414 return (LoadGameByIndex(0));
00415 } else {
00416 return (-1);
00417 }
00418
00419 return (LoadGameByName(cityname));
00420 }
00421
00422 void
00423 SetAutoSave(char *name)
00424 {
00425 DmOpenRef db = OpenMyDB();
00426 MemHandle mh;
00427 MemPtr mp;
00428
00429 if (db == NULL)
00430 return;
00431
00432 if (DmNumRecords(db) < 1)
00433 return;
00434
00435 mh = DmGetRecord(db, 0);
00436 if (mh == NULL) {
00437 return;
00438 } else {
00439 mh = DmResizeRecord(db, 0, CITYNAMELEN);
00440 }
00441
00442 mp = MemHandleLock(mh);
00443
00444 if (mp == NULL)
00445 goto release;
00446
00447 DmWrite(mp, 0, name, CITYNAMELEN);
00448
00449 MemHandleUnlock(mh);
00450
00451 release:
00452 DmReleaseRecord(db, 0, true);
00453 }
00454
00455 void
00456 DeleteAutoSave(void)
00457 {
00458 char buffer[CITYNAMELEN];
00459
00460 *buffer = '\0';
00461 SetAutoSave(buffer);
00462 }
00463
00471 static void
00472 DeleteGameByIndex(UInt16 index)
00473 {
00474 DmOpenRef db;
00475
00476 db = OpenMyDB();
00477 if (db == NULL) {
00478 return;
00479 }
00480
00481 if (DmNumRecords(db) < index)
00482 return;
00483
00484 if (index > 0)
00485 DmRemoveRecord(db, index);
00486 }
00487
00488 void
00489 DeleteGameByName(char *name)
00490 {
00491 UInt16 gameindex = FindGameByName(name);
00492
00493 if (gameindex != LASTGAME)
00494 DeleteGameByIndex(gameindex);
00495 }
00496
00497 int
00498 RenameCity(char *oldname, char *newname)
00499 {
00500 DmOpenRef db;
00501 MemHandle rec;
00502 GameStruct *pRec;
00503 UInt16 gameindex;
00504 UInt16 nRec;
00505 Boolean dirty = false;
00506
00507 db = OpenMyDB();
00508
00509 if (db == NULL)
00510 return (-1);
00511 nRec = DmNumRecords(db);
00512 for (gameindex = 0; gameindex < nRec; gameindex++) {
00513 rec = DmGetRecord(db, gameindex);
00514 if (rec == NULL)
00515 continue;
00516 pRec = MemHandleLock(rec);
00517 if (StrCompare((const Char *)pRec->cityname, oldname) == 0) {
00518 DmStrCopy(pRec, offsetof(GameStruct, cityname),
00519 newname);
00520 dirty = true;
00521 }
00522 DmReleaseRecord(db, gameindex, dirty);
00523 if (dirty)
00524 break;
00525 }
00526 return (dirty);
00527 }
00528
00529 int
00530 CopyCity(Char *name)
00531 {
00532 DmOpenRef db;
00533 MemHandle rec;
00534 GameStruct *pRec;
00535 UInt16 gameindex;
00536 UInt16 nRec;
00537 Boolean dirty = false;
00538
00539 db = OpenMyDB();
00540
00541 if (db == NULL)
00542 return (-1);
00543 nRec = DmNumRecords(db);
00544 for (gameindex = 0; gameindex < nRec; gameindex++) {
00545 rec = DmQueryRecord(db, gameindex);
00546 if (rec == NULL)
00547 continue;
00548 pRec = MemHandleLock(rec);
00549 if (StrCompare((const Char *)pRec->cityname, name) == 0) {
00550 UInt16 reci;
00551 UInt32 len;
00552 MemHandle mhp;
00553 MemPtr pmhp;
00554 char newCity[CITYNAMELEN];
00555
00556 reci = dmMaxRecordIndex;
00557 len = MemHandleSize(rec);
00558 mhp = DmNewRecord(db, &reci, len);
00559 pmhp = MemHandleLock(mhp);
00560 *newCity = '\0';
00561 StrNCat(newCity, (char *)pRec->cityname, CITYNAMELEN);
00562 StrNCat(newCity, " Copy", CITYNAMELEN);
00563 DmWrite(pmhp, 0, pRec, len);
00564 DmStrCopy(pmhp, offsetof(GameStruct, cityname),
00565 newCity);
00566 MemHandleUnlock(mhp);
00567 DmReleaseRecord(db, reci, true);
00568 dirty = true;
00569 }
00570 MemHandleUnlock(rec);
00571 DmReleaseRecord(db, gameindex, false);
00572 if (dirty)
00573 break;
00574 }
00575 return (dirty);
00576 }
00577
00585 static Int16
00586 comparator(void *p1, void *p2, Int32 other)
00587 {
00588 return (StrNCaselessCompare(*(char **)p1, *(char **)p2, other));
00589 }
00590
00591 char **
00592 CityNames(int *count)
00593 {
00594 DmOpenRef db;
00595 UInt16 index = 0;
00596 MemHandle rec;
00597 unsigned char *pTemp;
00598 unsigned short int nRec;
00599 unsigned short int nsIndex = 0;
00600 char **cities;
00601 char *citystring;
00602
00603 db = OpenMyDB();
00604 if (db == NULL) {
00605 return (NULL);
00606 }
00607 nRec = DmNumRecords(db);
00608
00609 if (nRec < 2)
00610 return (NULL);
00611
00612 cities = (char **)MemPtrNew(nRec * sizeof (*cities));
00613 citystring = (char *)MemPtrNew(nRec * CITYNAMELEN);
00614
00615 for (index = 1; index < nRec; index++) {
00616 rec = DmQueryRecord(db, index);
00617 if (rec) {
00618 cities[nsIndex] = citystring;
00619 citystring += CITYNAMELEN;
00620 pTemp = (unsigned char *)MemHandleLock(rec);
00621 StrNCopy(cities[nsIndex], (char *)pTemp +
00622 offsetof(GameStruct, cityname), CITYNAMELEN);
00623 MemHandleUnlock(rec);
00624 nsIndex++;
00625 }
00626 }
00627 cities[nsIndex] = NULL;
00628 *count = (int)nsIndex;
00629 if (nsIndex > 10)
00630 SysQSort(cities, nsIndex, sizeof (*cities),
00631 comparator, CITYNAMELEN);
00632 else if (nsIndex >= 2)
00633 SysInsertionSort(cities, nsIndex, sizeof (*cities),
00634 comparator, CITYNAMELEN);
00635 return (cities);
00636 }
00637
00638 void
00639 FreeCityNames(char **names)
00640 {
00641 char **at = names;
00642 char *gnat;
00643
00644 if (names == NULL)
00645 return;
00646
00647 gnat = *at;
00648
00649 while (*at != NULL) {
00650 if (gnat > *at)
00651 gnat = *at;
00652 at++;
00653 }
00654 MemPtrFree(gnat);
00655 MemPtrFree(names);
00656 }
00657