1 //=============================================================================
2 //
3 // Adventure Game Studio (AGS)
4 //
5 // Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
6 // The full list of copyright holders can be found in the Copyright.txt
7 // file, which is part of this source code distribution.
8 //
9 // The AGS source code is provided under the Artistic License 2.0.
10 // A copy of this license can be found in the file License.txt and at
11 // http://www.opensource.org/licenses/artistic-license-2.0.php
12 //
13 //=============================================================================
14 
15 //
16 // Game data file management
17 //
18 
19 #include "main/mainheader.h"
20 #include "main/game_file.h"
21 #include "ac/common.h"
22 #include "ac/character.h"
23 #include "ac/charactercache.h"
24 #include "ac/dialogtopic.h"
25 #include "ac/draw.h"
26 #include "ac/game.h"
27 #include "ac/gamesetupstruct.h"
28 #include "ac/gamestate.h"
29 #include "ac/gamestructdefines.h"
30 #include "ac/gui.h"
31 #include "ac/viewframe.h"
32 #include "debug/debug_log.h"
33 #include "debug/out.h"
34 #include "gui/guilabel.h"
35 #include "main/main.h"
36 #include "platform/base/agsplatformdriver.h"
37 #include "util/stream.h"
38 #include "gfx/bitmap.h"
39 #include "gfx/blender.h"
40 #include "core/assetmanager.h"
41 #include "util/alignedstream.h"
42 #include "ac/gamesetup.h"
43 #include "game/main_game_file.h"
44 #include "game/game_init.h"
45 #include "plugin/agsplugin.h"
46 #include "script/script.h"
47 
48 using namespace AGS::Common;
49 using namespace AGS::Engine;
50 
51 extern int ifacepopped;
52 
53 extern GameSetupStruct game;
54 extern ViewStruct*views;
55 extern DialogTopic *dialog;
56 
57 extern AGSPlatformDriver *platform;
58 extern int numScriptModules;
59 
60 String game_file_name;
61 
62 
63 // Test if engine supports extended capabilities required to run the game
test_game_caps(const std::set<String> & caps,std::set<String> & failed_caps)64 bool test_game_caps(const std::set<String> &caps, std::set<String> &failed_caps)
65 {
66     // Currently we support nothing special
67     failed_caps = caps;
68     return caps.size() == 0;
69 }
70 
71 // Forms a simple list of capability names
get_caps_list(const std::set<String> & caps)72 String get_caps_list(const std::set<String> &caps)
73 {
74     String caps_list;
75     for (std::set<String>::const_iterator it = caps.begin(); it != caps.end(); ++it)
76     {
77         caps_list.Append("\n\t");
78         caps_list.Append(*it);
79     }
80     return caps_list;
81 }
82 
83 // Called when the game file is opened for the first time (when preloading game data);
84 // it logs information on data version and reports first found errors, if any.
game_file_first_open(MainGameSource & src)85 MainGameFileError game_file_first_open(MainGameSource &src)
86 {
87     MainGameFileError err = OpenMainGameFileFromDefaultAsset(src);
88     if (err == kMGFErr_NoError ||
89         err == kMGFErr_SignatureFailed ||
90         err == kMGFErr_FormatVersionTooOld ||
91         err == kMGFErr_FormatVersionNotSupported)
92     {
93         // Log data description for debugging
94         Debug::Printf(kDbgMsg_Init, "Opened game data file: %s", src.Filename.GetCStr());
95         Debug::Printf(kDbgMsg_Init, "Game data version: %d", src.DataVersion);
96         Debug::Printf(kDbgMsg_Init, "Compiled with: %s", src.CompiledWith.GetCStr());
97         if (src.Caps.size() > 0)
98         {
99             String caps_list = get_caps_list(src.Caps);
100             Debug::Printf(kDbgMsg_Init, "Requested engine caps: %s", caps_list.GetCStr());
101         }
102     }
103     // Quit in case of error
104     if (err != kMGFErr_NoError)
105         return err;
106 
107     // Test the extended caps
108     std::set<String> failed_caps;
109     if (!test_game_caps(src.Caps, failed_caps))
110     {
111         String caps_list = get_caps_list(failed_caps);
112         Debug::Printf(kDbgMsg_Init, "Missing engine caps: %s", caps_list.GetCStr());
113         return kMGFErr_CapsNotSupported;
114     }
115     return kMGFErr_NoError;
116 }
117 
PreReadSaveFileInfo(Stream * in,GameDataVersion data_ver)118 void PreReadSaveFileInfo(Stream *in, GameDataVersion data_ver)
119 {
120     AlignedStream align_s(in, Common::kAligned_Read);
121     game.ReadFromFile(&align_s);
122     // Discard game messages we do not need here
123     delete [] game.load_messages;
124     game.load_messages = NULL;
125     game.read_savegame_info(in, data_ver);
126 }
127 
preload_game_data(String & err_str)128 bool preload_game_data(String &err_str)
129 {
130     MainGameSource src;
131     MainGameFileError err = game_file_first_open(src);
132     if (err != kMGFErr_NoError)
133     {
134         err_str = GetMainGameFileErrorText(err);
135         return false;
136     }
137     // Read only the particular data we need for preliminary game analysis
138     PreReadSaveFileInfo(src.InputStream.get(), src.DataVersion);
139     FixupSaveDirectory(game);
140     return true;
141 }
142 
load_game_file(String & err_str)143 bool load_game_file(String &err_str)
144 {
145     MainGameSource src;
146     LoadedGameEntities ents(game, dialog, views);
147     MainGameFileError load_err = OpenMainGameFileFromDefaultAsset(src);
148     if (load_err == kMGFErr_NoError)
149     {
150         load_err = ReadGameData(ents, src.InputStream.get(), src.DataVersion);
151         if (load_err == kMGFErr_NoError)
152             load_err = UpdateGameData(ents, src.DataVersion);
153     }
154     if (load_err != kMGFErr_NoError)
155     {
156         err_str = GetMainGameFileErrorText(load_err);
157         return false;
158     }
159     GameInitError init_err = InitGameState(ents, src.DataVersion);
160     if (init_err != kGameInitErr_NoError)
161     {
162         err_str = GetGameInitErrorText(init_err);
163         return false;
164     }
165     return true;
166 }
167 
display_game_file_error(const String & err_str)168 void display_game_file_error(const String &err_str)
169 {
170     platform->DisplayAlert(String::FromFormat("Loading game failed with error:\n%s.\n\nThe game files may be incomplete, corrupt or from unsupported version of AGS.",
171         err_str.GetCStr()));
172 }
173