1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "ags/shared/ac/character_info.h"
24 #include "ags/shared/ac/game_setup_struct_base.h"
25 #include "ags/shared/ac/game_version.h"
26 #include "ags/shared/ac/words_dictionary.h"
27 #include "ags/shared/script/cc_script.h"
28 #include "ags/shared/util/stream.h"
29 
30 namespace AGS3 {
31 
32 using AGS::Shared::Stream;
33 
GameSetupStructBase()34 GameSetupStructBase::GameSetupStructBase()
35 	: numviews(0)
36 	, numcharacters(0)
37 	, playercharacter(-1)
38 	, totalscore(0)
39 	, numinvitems(0)
40 	, numdialog(0)
41 	, numdlgmessage(0)
42 	, numfonts(0)
43 	, color_depth(0)
44 	, target_win(0)
45 	, dialog_bullet(0)
46 	, hotdot(0)
47 	, hotdotouter(0)
48 	, uniqueid(0)
49 	, numgui(0)
50 	, numcursors(0)
51 	, default_lipsync_frame(0)
52 	, invhotdotsprite(0)
53 	, dict(nullptr)
54 	, globalscript(nullptr)
55 	, chars(nullptr)
56 	, compiled_script(nullptr)
57 	, load_messages(nullptr)
58 	, load_dictionary(false)
59 	, load_compiled_script(false)
60 	, _resolutionType(kGameResolution_Undefined)
61 	, _dataUpscaleMult(1)
62 	, _screenUpscaleMult(1) {
63 	memset(gamename, 0, sizeof(gamename));
64 	memset(options, 0, sizeof(options));
65 	memset(paluses, 0, sizeof(paluses));
66 	memset(defpal, 0, sizeof(defpal));
67 	memset(reserved, 0, sizeof(reserved));
68 	memset(messages, 0, sizeof(messages));
69 }
70 
~GameSetupStructBase()71 GameSetupStructBase::~GameSetupStructBase() {
72 	Free();
73 }
74 
Free()75 void GameSetupStructBase::Free() {
76 	for (int i = 0; i < MAXGLOBALMES; ++i) {
77 		delete[] messages[i];
78 		messages[i] = nullptr;
79 	}
80 	delete[] load_messages;
81 	load_messages = nullptr;
82 	delete dict;
83 	dict = nullptr;
84 	delete globalscript;
85 	globalscript = nullptr;
86 	delete compiled_script;
87 	compiled_script = nullptr;
88 	delete[] chars;
89 	chars = nullptr;
90 }
91 
SetDefaultResolution(GameResolutionType type)92 void GameSetupStructBase::SetDefaultResolution(GameResolutionType type) {
93 	SetDefaultResolution(type, Size());
94 }
95 
SetDefaultResolution(Size size)96 void GameSetupStructBase::SetDefaultResolution(Size size) {
97 	SetDefaultResolution(kGameResolution_Custom, size);
98 }
99 
SetDefaultResolution(GameResolutionType type,Size size)100 void GameSetupStructBase::SetDefaultResolution(GameResolutionType type, Size size) {
101 	// Calculate native res first then remember it
102 	SetNativeResolution(type, size);
103 	_defGameResolution = _gameResolution;
104 	// Setup data resolution according to legacy settings (if set)
105 	_dataResolution = _defGameResolution;
106 	if (IsLegacyHiRes() && options[OPT_NATIVECOORDINATES] == 0) {
107 		_dataResolution = _defGameResolution / HIRES_COORD_MULTIPLIER;
108 	}
109 	OnResolutionSet();
110 }
111 
SetNativeResolution(GameResolutionType type,Size game_res)112 void GameSetupStructBase::SetNativeResolution(GameResolutionType type, Size game_res) {
113 	if (type == kGameResolution_Custom) {
114 		_resolutionType = kGameResolution_Custom;
115 		_gameResolution = game_res;
116 		_letterboxSize = _gameResolution;
117 	} else {
118 		_resolutionType = type;
119 		_gameResolution = ResolutionTypeToSize(_resolutionType, IsLegacyLetterbox());
120 		_letterboxSize = ResolutionTypeToSize(_resolutionType, false);
121 	}
122 }
123 
SetGameResolution(GameResolutionType type)124 void GameSetupStructBase::SetGameResolution(GameResolutionType type) {
125 	SetNativeResolution(type, Size());
126 	OnResolutionSet();
127 }
128 
SetGameResolution(Size game_res)129 void GameSetupStructBase::SetGameResolution(Size game_res) {
130 	SetNativeResolution(kGameResolution_Custom, game_res);
131 	OnResolutionSet();
132 }
133 
OnResolutionSet()134 void GameSetupStructBase::OnResolutionSet() {
135 	// The final data-to-game multiplier is always set after actual game resolution (not default one)
136 	if (!_dataResolution.IsNull())
137 		_dataUpscaleMult = _gameResolution.Width / _dataResolution.Width;
138 	else
139 		_dataUpscaleMult = 1;
140 	if (!_defGameResolution.IsNull())
141 		_screenUpscaleMult = _gameResolution.Width / _defGameResolution.Width;
142 	else
143 		_screenUpscaleMult = 1;
144 	_relativeUIMult = IsLegacyHiRes() ? HIRES_COORD_MULTIPLIER : 1;
145 }
146 
ReadFromFile(Stream * in)147 void GameSetupStructBase::ReadFromFile(Stream *in) {
148 	in->Read(&gamename[0], GAME_NAME_LENGTH);
149 	in->ReadArrayOfInt32(options, MAX_OPTIONS);
150 	if (_G(loaded_game_file_version) < kGameVersion_340_4) { // TODO: this should probably be possible to deduce script API level
151 		// using game data version and other options like OPT_STRICTSCRIPTING
152 		options[OPT_BASESCRIPTAPI] = kScriptAPI_Undefined;
153 		options[OPT_SCRIPTCOMPATLEV] = kScriptAPI_Undefined;
154 	}
155 	in->Read(&paluses[0], 256);
156 	// colors are an array of chars
157 	in->Read(&defpal[0], sizeof(RGB) * 256);
158 	numviews = in->ReadInt32();
159 	numcharacters = in->ReadInt32();
160 	playercharacter = in->ReadInt32();
161 	totalscore = in->ReadInt32();
162 	numinvitems = in->ReadInt16();
163 	numdialog = in->ReadInt32();
164 	numdlgmessage = in->ReadInt32();
165 	numfonts = in->ReadInt32();
166 	color_depth = in->ReadInt32();
167 	target_win = in->ReadInt32();
168 	dialog_bullet = in->ReadInt32();
169 	hotdot = in->ReadInt16();
170 	hotdotouter = in->ReadInt16();
171 	uniqueid = in->ReadInt32();
172 	numgui = in->ReadInt32();
173 	numcursors = in->ReadInt32();
174 	GameResolutionType resolution_type = (GameResolutionType)in->ReadInt32();
175 	Size game_size;
176 	if (resolution_type == kGameResolution_Custom && _G(loaded_game_file_version) >= kGameVersion_330) {
177 		game_size.Width = in->ReadInt32();
178 		game_size.Height = in->ReadInt32();
179 	}
180 	SetDefaultResolution(resolution_type, game_size);
181 
182 	default_lipsync_frame = in->ReadInt32();
183 	invhotdotsprite = in->ReadInt32();
184 	in->ReadArrayOfInt32(reserved, NUM_INTS_RESERVED);
185 	load_messages = new int32_t[MAXGLOBALMES];
186 	in->ReadArrayOfInt32(load_messages, MAXGLOBALMES);
187 
188 	// - GameSetupStruct::read_words_dictionary() checks load_dictionary
189 	// - load_game_file() checks load_compiled_script
190 	load_dictionary = in->ReadInt32() != 0;
191 	in->ReadInt32(); // globalscript
192 	in->ReadInt32(); // chars
193 	load_compiled_script = in->ReadInt32() != 0;
194 }
195 
WriteToFile(Stream * out)196 void GameSetupStructBase::WriteToFile(Stream *out) {
197 	out->Write(&gamename[0], 50);
198 	out->WriteArrayOfInt32(options, 100);
199 	out->Write(&paluses[0], 256);
200 	// colors are an array of chars
201 	out->Write(&defpal[0], sizeof(RGB) * 256);
202 	out->WriteInt32(numviews);
203 	out->WriteInt32(numcharacters);
204 	out->WriteInt32(playercharacter);
205 	out->WriteInt32(totalscore);
206 	out->WriteInt16(numinvitems);
207 	out->WriteInt32(numdialog);
208 	out->WriteInt32(numdlgmessage);
209 	out->WriteInt32(numfonts);
210 	out->WriteInt32(color_depth);
211 	out->WriteInt32(target_win);
212 	out->WriteInt32(dialog_bullet);
213 	out->WriteInt16(hotdot);
214 	out->WriteInt16(hotdotouter);
215 	out->WriteInt32(uniqueid);
216 	out->WriteInt32(numgui);
217 	out->WriteInt32(numcursors);
218 	out->WriteInt32(_resolutionType);
219 	if (_resolutionType == kGameResolution_Custom) {
220 		out->WriteInt32(_defGameResolution.Width);
221 		out->WriteInt32(_defGameResolution.Height);
222 	}
223 	out->WriteInt32(default_lipsync_frame);
224 	out->WriteInt32(invhotdotsprite);
225 	out->WriteArrayOfInt32(reserved, 17);
226 	for (int i = 0; i < MAXGLOBALMES; ++i) {
227 		out->WriteInt32(messages[i] ? 1 : 0);
228 	}
229 	out->WriteInt32(dict ? 1 : 0);
230 	out->WriteInt32(0); // globalscript
231 	out->WriteInt32(0); // chars
232 	out->WriteInt32(compiled_script ? 1 : 0);
233 }
234 
ResolutionTypeToSize(GameResolutionType resolution,bool letterbox)235 Size ResolutionTypeToSize(GameResolutionType resolution, bool letterbox) {
236 	switch (resolution) {
237 	case kGameResolution_Default:
238 	case kGameResolution_320x200:
239 		return letterbox ? Size(320, 240) : Size(320, 200);
240 	case kGameResolution_320x240:
241 		return Size(320, 240);
242 	case kGameResolution_640x400:
243 		return letterbox ? Size(640, 480) : Size(640, 400);
244 	case kGameResolution_640x480:
245 		return Size(640, 480);
246 	case kGameResolution_800x600:
247 		return Size(800, 600);
248 	case kGameResolution_1024x768:
249 		return Size(1024, 768);
250 	case kGameResolution_1280x720:
251 		return Size(1280, 720);
252 	default:
253 		break;
254 	}
255 	return Size();
256 }
257 
GetScriptAPIName(ScriptAPIVersion v)258 const char *GetScriptAPIName(ScriptAPIVersion v) {
259 	switch (v) {
260 	case kScriptAPI_v321: return "v3.2.1";
261 	case kScriptAPI_v330: return "v3.3.0";
262 	case kScriptAPI_v334: return "v3.3.4";
263 	case kScriptAPI_v335: return "v3.3.5";
264 	case kScriptAPI_v340: return "v3.4.0";
265 	case kScriptAPI_v341: return "v3.4.1";
266 	case kScriptAPI_v350: return "v3.5.0-alpha";
267 	case kScriptAPI_v3507: return "v3.5.0-final";
268 	case kScriptAPI_v351: return "v3.5.1";
269 	case kScriptAPI_v360: return "v3.6.0";
270 	case kScriptAPI_Undefined: return "undefined";
271 	}
272 	return "unknown";
273 }
274 
275 } // namespace AGS3
276