00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <iostream>
00027 #include <cstdio>
00028 #include <time.h>
00029 #include <unistd.h>
00030 #include <dirent.h>
00031 #include <sys/stat.h>
00032
00033 #include "audio.h"
00034 #include "gamedata.h"
00035 #include "python_class.h"
00036 #include "event_handler.h"
00037
00038
00039
00040 #define ENGINE_DAT_VER 5
00041 #define AUDIO_DAT_VER 2
00042 #define CHAR_DAT_VER 4
00043 #define QUEST_DAT_VER 1
00044 #define SAVE_DAT_VER 3
00045
00046 vector<gamedata*> gamedata::saves;
00047 string gamedata::user_data_dir_;
00048 string gamedata::game_data_dir_;
00049 string gamedata::game_name;
00050 u_int8 gamedata::quick_load;
00051
00052 using namespace std;
00053
00054
00055 gamedata::gamedata ()
00056 {
00057 }
00058
00059 gamedata::gamedata (string dir, string desc, string time)
00060 {
00061 Timestamp = 0;
00062 Directory = dir;
00063 Description = desc;
00064 Gametime = time;
00065 }
00066
00067 gamedata::~gamedata ()
00068 {
00069 }
00070
00071 bool gamedata::get (igzstream& file)
00072 {
00073 if (!fileops::get_version (file, SAVE_DAT_VER, SAVE_DAT_VER, "save.data"))
00074 return false;
00075
00076 Timestamp << file;
00077 Description << file;
00078 Location << file;
00079 Gametime << file;
00080
00081 return true;
00082 }
00083
00084 void gamedata::put (ogzstream& file)
00085 {
00086 fileops::put_version (file, SAVE_DAT_VER);
00087
00088
00089 Timestamp = time (NULL);
00090
00091 Timestamp >> file;
00092 Description >> file;
00093 Location >> file;
00094 Gametime >> file;
00095 }
00096
00097 void gamedata::set_description (string desc)
00098 {
00099 Description = desc;
00100 }
00101
00102 void gamedata::set_directory (string dir)
00103 {
00104 Directory = dir;
00105 }
00106
00107 void gamedata::set_gametime (string time)
00108 {
00109 Gametime = time;
00110 }
00111
00112 bool gamedata::load_characters (u_int32 pos)
00113 {
00114 igzstream in;
00115
00116 string filepath;
00117 character *mynpc;
00118
00119
00120 filepath = saves[pos]->directory ();
00121 filepath += "/character.data";
00122 in.open (filepath);
00123
00124 if (!in.is_open ())
00125 {
00126 cerr << "Couldn't open \"" << filepath << "\" - stopping\n" << endl;
00127 return false;
00128 }
00129
00130 if (!fileops::get_version (in, CHAR_DAT_VER, CHAR_DAT_VER, filepath))
00131 return false;
00132
00133
00134 char ctemp;
00135
00136
00137 data::the_player = new character ();
00138 data::the_player->character_base::get_state (in);
00139 data::characters[data::the_player->get_id ().c_str ()] = data::the_player;
00140
00141
00142 while (ctemp << in)
00143 {
00144 mynpc = new character;
00145 mynpc->character_base::get_state (in);
00146
00147
00148 data::characters[mynpc->get_id ().c_str ()] = mynpc;
00149 }
00150 in.close ();
00151
00152 return true;
00153 }
00154
00155 bool gamedata::load_quests (u_int32 pos)
00156 {
00157 igzstream in;
00158
00159 string filepath;
00160 quest *myquest;
00161
00162
00163 filepath = saves[pos]->directory ();
00164 filepath += "/quest.data";
00165 in.open (filepath);
00166
00167 if (!in.is_open ())
00168 {
00169 cerr << "Couldn't open \"" << filepath << " - stopping\n" << endl;
00170 return false;
00171 }
00172
00173 if (!fileops::get_version (in, QUEST_DAT_VER, QUEST_DAT_VER, filepath))
00174 return false;
00175
00176
00177 char ctemp;
00178 while (ctemp << in)
00179 {
00180 myquest = new quest;
00181 myquest->load (in);
00182
00183
00184 data::quests[myquest->name.c_str ()] = myquest;
00185 }
00186
00187 in.close ();
00188
00189 return true;
00190 }
00191
00192 bool gamedata::load_mapengine (u_int32 pos)
00193 {
00194 igzstream in;
00195
00196 string filepath;
00197
00198
00199 filepath = saves[pos]->directory();
00200 filepath += "/mapengine.data";
00201 in.open (filepath);
00202
00203 if (!in.is_open ())
00204 {
00205 cerr << "Couldn't open \"" << filepath << " - stopping\n" << endl;
00206 return false;
00207 }
00208
00209 if (!fileops::get_version (in, ENGINE_DAT_VER, ENGINE_DAT_VER, filepath))
00210 return false;
00211
00212 if (!data::engine->get_state(in))
00213 {
00214 cerr << "Couldn't load \"" << filepath << " - stopping\n" << endl;
00215 return false;
00216 }
00217
00218 in.close ();
00219
00220 return true;
00221 }
00222
00223 bool gamedata::load_audio (u_int32 pos)
00224 {
00225 igzstream in;
00226 string filepath;
00227
00228
00229 filepath = saves[pos]->directory();
00230 filepath += "/audio.data";
00231 in.open (filepath);
00232
00233 if (!in.is_open ())
00234 {
00235 cerr << "Couldn't open \"" << filepath << " - stopping\n" << endl;
00236 return false;
00237 }
00238
00239 if (!fileops::get_version (in, AUDIO_DAT_VER, AUDIO_DAT_VER, filepath))
00240 return false;
00241
00242 if (!audio::get_state (in))
00243 {
00244 cerr << "Couldn't load \"" << filepath << " - stopping\n" << endl;
00245 return false;
00246 }
00247
00248 in.close ();
00249
00250 return true;
00251 }
00252
00253 bool gamedata::load (u_int32 pos)
00254 {
00255
00256 unload ();
00257
00258 if (!load_characters (pos)) return false;
00259 if (!load_quests (pos)) return false;
00260 if (!load_mapengine (pos)) return false;
00261 if (!load_audio (pos)) return false;
00262
00263 return true;
00264 }
00265
00266 bool gamedata::load_newest ()
00267 {
00268
00269 if (!quick_load || saves.size () <= 1) return false;
00270
00271 u_int32 timestamp = 0;
00272 u_int32 index = 0;
00273 u_int32 newest;
00274
00275 for (vector<gamedata*>::iterator i = saves.begin (); i != saves.end (); i++)
00276 {
00277 if ((*i)->timestamp () > timestamp)
00278 {
00279 timestamp = (*i)->timestamp ();
00280 newest = index;
00281 }
00282
00283 index++;
00284 }
00285
00286 return load (newest);
00287 }
00288
00289 bool gamedata::save (u_int32 pos, string desc, string time)
00290 {
00291 gamedata *gdata;
00292 string filepath;
00293 char t[10];
00294 ogzstream file;
00295 char vnbr;
00296
00297
00298 if (pos == 0) return false;
00299
00300
00301 if (pos >= saves.size ())
00302 {
00303 int success = 1;
00304
00305
00306 while (success)
00307 {
00308
00309 sprintf(t, "%03i", pos++);
00310 filepath = user_data_dir ();
00311 filepath += "/" + game_name + "-save-";
00312 filepath += t;
00313
00314 #ifdef WIN32
00315 success = mkdir (filepath.c_str());
00316 #else
00317 success = mkdir (filepath.c_str(), 0700);
00318 #endif
00319
00320
00321 if (pos >= 1000)
00322 {
00323 cerr << "Save failed - seems like you have no write permission in\n"
00324 << user_data_dir () << endl;
00325 return false;
00326 }
00327 }
00328
00329
00330 gdata = new gamedata (filepath, desc, time);
00331 }
00332 else
00333 {
00334 gdata = saves[pos];
00335 gdata->set_description (desc);
00336 gdata->set_gametime (time);
00337 }
00338
00339
00340 filepath = gdata->directory ();
00341 filepath += "/character.data";
00342 file.open (filepath);
00343
00344 if (!file.is_open ())
00345 {
00346 cerr << "Couldn't create \"" << filepath << "\" - save failed\n";
00347 return false;
00348 }
00349
00350 fileops::put_version (file, CHAR_DAT_VER);
00351
00352
00353 data::the_player->character_base::put_state (file);
00354
00355
00356 dictionary <character *>::iterator itc;
00357 for (itc = data::characters.begin (); itc != data::characters.end (); itc++)
00358 {
00359
00360 if (itc->second == (character*) data::the_player) continue;
00361
00362
00363 vnbr = 1;
00364 vnbr >> file;
00365
00366
00367 itc->second->character_base::put_state (file);
00368 }
00369
00370
00371 vnbr = 0;
00372 vnbr >> file;
00373 file.close ();
00374
00375
00376 filepath = gdata->directory ();
00377 filepath += "/quest.data";
00378 file.open (filepath);
00379
00380 if (!file.is_open ())
00381 {
00382 cerr << "Couldn't create \"" << filepath << "\" - save failed\n";
00383 return false;
00384 }
00385
00386 fileops::put_version (file, QUEST_DAT_VER);
00387
00388 dictionary <quest *>::iterator itq;
00389 for (itq = data::quests.begin (); itq != data::quests.end (); itq++)
00390 {
00391
00392 vnbr = 1;
00393 vnbr >> file;
00394
00395
00396 itq->second->save (file);
00397 }
00398
00399
00400 vnbr = 0;
00401 vnbr >> file;
00402 file.close ();
00403
00404
00405 filepath = gdata->directory();
00406 filepath += "/mapengine.data";
00407 file.open (filepath);
00408
00409 if (!file.is_open ())
00410 {
00411 cerr << "Couldn't create \"" << filepath << "\" - save failed\n";
00412 return false;
00413 }
00414
00415 fileops::put_version (file, ENGINE_DAT_VER);
00416 data::engine->put_state(file);
00417 file.close ();
00418
00419
00420 filepath = gdata->directory ();
00421 filepath += "/audio.data";
00422 file.open (filepath);
00423
00424 if (!file.is_open ())
00425 {
00426 cerr << "Couldn't create \"" << filepath << "\" - save failed\n";
00427 return false;
00428 }
00429
00430 fileops::put_version (file, AUDIO_DAT_VER);
00431 audio::put_state (file);
00432 file.close ();
00433
00434
00435 filepath = gdata->directory ();
00436 filepath += "/save.data";
00437
00438 file.open (filepath);
00439 if (!file.is_open ())
00440 {
00441 cerr << "Couldn't create \"" << filepath << "\" - save failed\n";
00442 return false;
00443 }
00444
00445 gdata->put (file);
00446 file.close ();
00447
00448
00449 if (pos >= saves.size ()) saves.push_back (gdata);
00450
00451 return true;
00452 }
00453
00454 gamedata* gamedata::next_save ()
00455 {
00456 static vector<gamedata*>::iterator i = saves.begin ();
00457 static u_int32 size = saves.size ();
00458
00459
00460 if (size != saves.size ())
00461 {
00462 size = saves.size ();
00463 i = saves.begin ();
00464 }
00465
00466
00467 if (++i == saves.end ())
00468 {
00469 i = saves.begin ();
00470 return NULL;
00471 }
00472
00473 return *i;
00474 }
00475
00476
00477 bool gamedata::init (string udir, string gdir, string gname, u_int8 qload)
00478 {
00479 DIR *dir;
00480 igzstream in;
00481 struct dirent *dirent;
00482 struct stat statbuf;
00483 gamedata *gdata;
00484
00485 user_data_dir_ = udir;
00486 game_data_dir_ = gdir;
00487 game_name = gname;
00488 quick_load = qload;
00489
00490
00491 if (chdir (game_data_dir ().c_str ()))
00492 {
00493 fprintf (stderr, "Seems like %s is no valid data directory.\n", game_data_dir ().c_str ());
00494 fprintf (stderr, "Please make sure that your Adonthell installation is correct.\n");
00495 return false;
00496 }
00497
00498
00499 gdata = new gamedata (gdir, "Start New Game", "Day 0 - 00:00");
00500 saves.push_back (gdata);
00501
00502
00503
00504 if ((dir = opendir (user_data_dir ().c_str ())) != NULL)
00505 {
00506 while ((dirent = readdir (dir)) != NULL)
00507 {
00508 string filepath = user_data_dir () + "/";
00509 filepath += dirent->d_name;
00510
00511 string name_save = game_name + "-save-";
00512
00513 if (stat (filepath.c_str (), &statbuf) != -1 && S_ISDIR (statbuf.st_mode) &&
00514 strncmp (name_save.c_str (), dirent->d_name, name_save.length ()) == 0)
00515 {
00516
00517 filepath += "/save.data";
00518
00519 in.open (filepath);
00520
00521 if (in.is_open ())
00522 {
00523
00524 filepath = user_data_dir ();
00525 filepath += "/";
00526 filepath += dirent->d_name;
00527
00528 gdata = new gamedata;
00529 if (gdata->get (in))
00530 {
00531 gdata->set_directory (filepath);
00532 saves.push_back (gdata);
00533 }
00534 else delete gdata;
00535
00536 in.close ();
00537 }
00538 }
00539 }
00540 closedir (dir);
00541 }
00542 return true;
00543 }
00544
00545 void gamedata::cleanup ()
00546 {
00547 for (vector<gamedata*>::iterator i = saves.begin (); i != saves.end (); i++)
00548 delete *i;
00549 saves.clear ();
00550 unload ();
00551 }
00552
00553 void gamedata::unload ()
00554 {
00555
00556 audio::fade_out_background (500);
00557
00558
00559 dictionary <character *>::iterator itc;
00560 for (itc = data::characters.begin (); itc != data::characters.end (); itc++)
00561 {
00562 itc->second->remove_from_map ();
00563 delete itc->second;
00564 }
00565 data::characters.clear ();
00566
00567 data::the_player = NULL;
00568
00569
00570 dictionary <quest *>::iterator itq;
00571 for (itq = data::quests.begin (); itq != data::quests.end (); itq++)
00572 delete itq->second;
00573 data::quests.clear ();
00574 }