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 #ifndef AGS_ENGINE_AC_GAME_STATE_H
24 #define AGS_ENGINE_AC_GAME_STATE_H
25 
26 #include "ags/lib/std/memory.h"
27 #include "ags/lib/std/vector.h"
28 #include "ags/shared/ac/character_info.h"
29 #include "ags/engine/ac/runtime_defines.h"
30 #include "ags/shared/game/room_struct.h"
31 #include "ags/engine/game/viewport.h"
32 #include "ags/engine/media/audio/queued_audio_item.h"
33 #include "ags/shared/util/geometry.h"
34 #include "ags/shared/util/string_types.h"
35 #include "ags/shared/util/string.h"
36 #include "ags/engine/ac/timer.h"
37 
38 namespace AGS3 {
39 
40 // Forward declaration
41 namespace AGS {
42 namespace Shared {
43 class Bitmap;
44 class Stream;
45 typedef std::shared_ptr<Bitmap> PBitmap;
46 } // namespace Shared
47 
48 namespace Engine {
49 struct RestoredData;
50 } // namespace Engine
51 } // namespace AGS
52 
53 using namespace AGS; // FIXME later
54 struct ScriptViewport;
55 struct ScriptCamera;
56 struct ScriptOverlay;
57 
58 #define GAME_STATE_RESERVED_INTS 5
59 
60 // Savegame data format
61 enum GameStateSvgVersion {
62 	kGSSvgVersion_OldFormat = -1, // TODO: remove after old save support is dropped
63 	kGSSvgVersion_Initial = 0,
64 	kGSSvgVersion_350 = 1,
65 	kGSSvgVersion_350_9 = 2,
66 	kGSSvgVersion_350_10 = 3,
67 };
68 
69 
70 
71 // Adding to this might need to modify AGSDEFNS.SH and AGSPLUGIN.H
72 struct GameState {
73 	int  score = 0;      // player's current score
74 	int  usedmode = 0;   // set by ProcessClick to last cursor mode used
75 	int  disabled_user_interface = 0;  // >0 while in cutscene/etc
76 	int  gscript_timer = 0;    // obsolete
77 	int  debug_mode = 0;       // whether we're in debug mode
78 	int32_t globalvars[MAXGLOBALVARS];  // obsolete
79 	int  messagetime = 0;      // time left for auto-remove messages
80 	int  usedinv = 0;          // inventory item last used
81 	int  inv_top = 0, inv_numdisp = 0, obsolete_inv_numorder = 0, inv_numinline = 0;
82 	int  text_speed = 0;       // how quickly text is removed
83 	int  sierra_inv_color = 0; // background used to paint defualt inv window
84 	int  talkanim_speed = 0;   // animation speed of talking anims
85 	int  inv_item_wid = 0, inv_item_hit = 0;  // set by SetInvDimensions
86 	int  speech_text_shadow = 0;         // colour of outline fonts (default black)
87 	int  swap_portrait_side = 0;         // sierra-style speech swap sides
88 	int  speech_textwindow_gui = 0;      // textwindow used for sierra-style speech
89 	int  follow_change_room_timer = 0;   // delay before moving following characters into new room
90 	int  totalscore = 0;           // maximum possible score
91 	int  skip_display = 0;         // how the user can skip normal Display windows
92 	int  no_multiloop_repeat = 0;  // for backwards compatibility
93 	int  roomscript_finished = 0;  // on_call finished in room
94 	int  used_inv_on = 0;          // inv item they clicked on
95 	int  no_textbg_when_voice = 0; // no textwindow bgrnd when voice speech is used
96 	int  max_dialogoption_width = 0; // max width of dialog options text window
97 	int  no_hicolor_fadein = 0;      // fade out but instant in for hi-color
98 	int  bgspeech_game_speed = 0;    // is background speech relative to game speed
99 	int  bgspeech_stay_on_display = 0; // whether to remove bg speech when DisplaySpeech is used
100 	int  unfactor_speech_from_textlength = 0; // remove "&10" when calculating time for text to stay
101 	int  mp3_loop_before_end = 0;    // (UNUSED!) loop this time before end of track (ms)
102 	int  speech_music_drop = 0;      // how much to drop music volume by when speech is played
103 	int  in_cutscene = 0;            // we are between a StartCutscene and EndCutscene
104 	int  fast_forward = 0;           // player has elected to skip cutscene
105 	int  room_width = 0;      // width of current room
106 	int  room_height = 0;     // height of current room
107 	// ** up to here is referenced in the plugin interface
108 	int  game_speed_modifier = 0;
109 	int  score_sound = 0;
110 	int  takeover_data = 0;  // value passed to RunAGSGame in previous game
111 	int  replay_hotkey_unused = 0;  // (UNUSED!) StartRecording: not supported
112 	int  dialog_options_x = 0;
113 	int  dialog_options_y = 0;
114 	int  narrator_speech = 0;
115 	int  ambient_sounds_persist = 0;
116 	int  lipsync_speed = 0;
117 	int  close_mouth_speech_time = 0; // stop speech animation at (messagetime - close_mouth_speech_time)
118 	// (this is designed to work in text-only mode)
119 	int  disable_antialiasing = 0;
120 	int  text_speed_modifier = 0;
121 	HorAlignment text_align = (HorAlignment)0;
122 	int  speech_bubble_width = 0;
123 	int  min_dialogoption_width = 0;
124 	int  disable_dialog_parser = 0;
125 	int  anim_background_speed = 0;  // the setting for this room
126 	int  top_bar_backcolor = 0;
127 	int  top_bar_textcolor = 0;
128 	int  top_bar_bordercolor = 0;
129 	int  top_bar_borderwidth = 0;
130 	int  top_bar_ypos = 0;
131 	int  screenshot_width = 0;
132 	int  screenshot_height = 0;
133 	int  top_bar_font = 0;
134 	HorAlignment speech_text_align = (HorAlignment)0;
135 	int  auto_use_walkto_points = 0;
136 	int  inventory_greys_out = 0;
137 	int  skip_speech_specific_key = 0;
138 	int  abort_key = 0;
139 	int  fade_to_red = 0;
140 	int  fade_to_green = 0;
141 	int  fade_to_blue = 0;
142 	int  show_single_dialog_option = 0;
143 	int  keep_screen_during_instant_transition = 0;
144 	int  read_dialog_option_colour = 0;
145 	int  stop_dialog_at_end = 0;
146 	int  speech_portrait_placement = 0; // speech portrait placement mode (automatic/custom)
147 	int  speech_portrait_x = 0; // a speech portrait x offset from corresponding screen side
148 	int  speech_portrait_y = 0; // a speech portrait y offset
149 	int  speech_display_post_time_ms = 0; // keep speech text/portrait on screen after text/voice has finished playing = 0;
150 	// no speech animation is supposed to be played at this time
151 	int  dialog_options_highlight_color = 0; // The colour used for highlighted (hovered over) text in dialog options
152 	int32_t reserved[GAME_STATE_RESERVED_INTS];  // make sure if a future version adds a var, it doesn't mess anything up
153 	// ** up to here is referenced in the script "game." object
154 	long  randseed = 0;    // random seed
155 	int   player_on_region = 0;    // player's current region
156 	int   screen_is_faded_out = 0; // the screen is currently black
157 	int   check_interaction_only = 0;
158 	int   bg_frame = 0, bg_anim_delay = 0;  // for animating backgrounds
159 	int   music_vol_was = 0;  // before the volume drop
160 	short wait_counter = 0;
161 	int8  wait_skipped_by = 0; // tells how last blocking wait was skipped [not serialized]
162 	int   wait_skipped_by_data = 0; // extended data telling how last blocking wait was skipped [not serialized]
163 	short mboundx1 = 0, mboundx2 = 0, mboundy1 = 0, mboundy2 = 0;
164 	int   fade_effect = 0;
165 	int   bg_frame_locked = 0;
166 	int32_t globalscriptvars[MAXGSVALUES];
167 	int   cur_music_number = 0, music_repeat = 0;
168 	int   music_master_volume = 0;
169 	int   digital_master_volume = 0;
170 	char  walkable_areas_on[MAX_WALK_AREAS + 1];
171 	short screen_flipped = 0;
172 	int   entered_at_x = 0, entered_at_y = 0, entered_edge = 0;
173 	int   want_speech = 0;
174 	int   cant_skip_speech = 0;
175 	int32_t   script_timers[MAX_TIMERS];
176 	int   sound_volume = 0, speech_volume = 0;
177 	int   normal_font = 0, speech_font = 0;
178 	int8  key_skip_wait = 0;
179 	int   swap_portrait_lastchar = 0;
180 	int   swap_portrait_lastlastchar = 0;
181 	int   separate_music_lib = 0;
182 	int   in_conversation = 0;
183 	int   screen_tint = 0;
184 	int   num_parsed_words = 0;
185 	short parsed_words[MAX_PARSED_WORDS];
186 	char  bad_parsed_word[100];
187 	int   raw_color = 0;
188 	int32_t raw_modified[MAX_ROOM_BGFRAMES];
189 	Shared::PBitmap raw_drawing_surface = 0;
190 	short filenumbers[MAXSAVEGAMES];
191 	int   room_changes = 0;
192 	int   mouse_cursor_hidden = 0;
193 	int   silent_midi = 0;
194 	int   silent_midi_channel = 0;
195 	int   current_music_repeating = 0;  // remember what the loop flag was when this music started
196 	unsigned long shakesc_delay = 0;  // unsigned long to match _G(loopcounter)
197 	int   shakesc_amount = 0, shakesc_length = 0;
198 	int   rtint_red = 0, rtint_green = 0, rtint_blue = 0;
199 	int   rtint_level = 0, rtint_light = 0;
200 	bool  rtint_enabled = 0;
201 	int   end_cutscene_music = 0;
202 	int   skip_until_char_stops = 0;
203 	int   get_loc_name_last_time = 0;
204 	int   get_loc_name_save_cursor = 0;
205 	int   restore_cursor_mode_to = 0;
206 	int   restore_cursor_image_to = 0;
207 	short music_queue_size = 0;
208 	short music_queue[MAX_QUEUED_MUSIC];
209 	short new_music_queue_size = 0;
210 	short crossfading_out_channel = 0;
211 	short crossfade_step = 0;
212 	short crossfade_out_volume_per_step = 0;
213 	short crossfade_initial_volume_out = 0;
214 	short crossfading_in_channel = 0;
215 	short crossfade_in_volume_per_step = 0;
216 	short crossfade_final_volume_in = 0;
217 	QueuedAudioItem new_music_queue[MAX_QUEUED_MUSIC];
218 	char  takeover_from[50];
219 	char  playmp3file_name[PLAYMP3FILE_MAX_FILENAME_LEN];
220 	char  globalstrings[MAXGLOBALSTRINGS][MAX_MAXSTRLEN];
221 	char  lastParserEntry[MAX_MAXSTRLEN];
222 	char  game_name[100];
223 	int   ground_level_areas_disabled = 0;
224 	int   next_screen_transition = 0;
225 	int   gamma_adjustment = 0;
226 	short temporarily_turned_off_character = 0;  // Hide Player Charactr ticked
227 	short inv_backwards_compatibility = 0;
228 	int32_t *gui_draw_order = 0;
229 	std::vector<AGS::Shared::String> do_once_tokens = 0;
230 	int   text_min_display_time_ms = 0;
231 	int   ignore_user_input_after_text_timeout_ms = 0;
232 	int32_t default_audio_type_volumes[MAX_AUDIO_TYPES];
233 
234 	// Dynamic custom property values for characters and items
235 	std::vector<AGS::Shared::StringIMap> charProps;
236 	AGS::Shared::StringIMap invProps[MAX_INV];
237 
238 	// Dynamic speech state
239 	//
240 	// Tells whether there is a voice-over played during current speech
241 	bool  speech_has_voice = false;
242 	// Tells whether the voice was played in blocking mode;
243 	// atm blocking speech handles itself, and we only need to finalize
244 	// non-blocking voice speech during game update; speech refactor would be
245 	// required to get rid of this rule.
246 	bool  speech_voice_blocking = false;
247 	// Tells whether character speech stays on screen not animated for additional time
248 	bool  speech_in_post_state = false;
249 
250 	// Special overlays
251 	//
252 	// Is there a QFG4-style dialog overlay on screen (contains overlay ID)
253 	int  complete_overlay_on = 0;
254 	// Is there a blocking text overlay on screen (contains overlay ID)
255 	int  text_overlay_on = 0;
256 	// Blocking speech overlay managed object, for accessing in scripts
257 	ScriptOverlay *speech_text_scover = nullptr;
258 	// Speech portrait overlay managed object
259 	ScriptOverlay *speech_face_scover = nullptr;
260 
261 	int shake_screen_yoff = 0; // y offset of the shaking screen
262 
263 
264 	GameState();
265 	// Free game resources
266 	void Free();
267 
268 	//
269 	// Viewport and camera control.
270 	// Viewports are positioned in game screen coordinates, related to the "game size",
271 	// while cameras are positioned in room coordinates.
272 	//
273 	// Tells if the room viewport should be adjusted automatically each time a new room is loaded
274 	bool IsAutoRoomViewport() const;
275 	// Returns main viewport position on screen, this is the overall game view
276 	const Rect &GetMainViewport() const;
277 	// Returns UI viewport position on screen, this is the GUI layer
278 	const Rect &GetUIViewport() const;
279 	// Returns Room viewport object by it's main index
280 	PViewport  GetRoomViewport(int index) const;
281 	// Returns Room viewport object by index in z-order
282 	const std::vector<PViewport> &GetRoomViewportsZOrdered() const;
283 	// Finds room viewport at the given screen coordinates; returns nullptr if non found
284 	PViewport  GetRoomViewportAt(int x, int y) const;
285 	// Returns UI viewport position in absolute coordinates (with main viewport offset)
286 	Rect       GetUIViewportAbs() const;
287 	// Returns Room viewport position in absolute coordinates (with main viewport offset)
288 	Rect       GetRoomViewportAbs(int index) const;
289 	// Sets if the room viewport should be adjusted automatically each time a new room is loaded
290 	void SetAutoRoomViewport(bool on);
291 	// Main viewport defines the location of all things drawn and interactable on the game screen.
292 	// Other viewports are defined relative to the main viewports.
293 	void SetMainViewport(const Rect &viewport);
294 	// UI viewport is a formal dummy viewport for GUI and Overlays (like speech).
295 	void SetUIViewport(const Rect &viewport);
296 	// Applies all the pending changes to viewports and cameras;
297 	// NOTE: this function may be slow, thus recommended to be called only once
298 	// and during the main game update.
299 	void UpdateViewports();
300 	// Notifies game state that viewports need z-order resorting upon next update.
301 	void InvalidateViewportZOrder();
302 	// Returns room camera object chosen by index
303 	PCamera GetRoomCamera(int index) const;
304 	// Runs cameras behaviors
305 	void UpdateRoomCameras();
306 	// Converts room coordinates to the game screen coordinates through the room viewport
307 	// This group of functions always tries to pass a point through the **primary** room viewport
308 	// TODO: also support using arbitrary viewport (for multiple viewports).
309 	Point RoomToScreen(int roomx, int roomy);
310 	int  RoomToScreenX(int roomx);
311 	int  RoomToScreenY(int roomy);
312 	// Converts game screen coordinates to the room coordinates through the room viewport
313 	// This pair of functions tries to find if there is any viewport at the given coords and results
314 	// in failure if there is none.
315 	// TODO: find out if possible to refactor and get rid of "variadic" variants;
316 	// usually this depends on how the arguments are created (whether they are in "variadic" or true coords)
317 	VpPoint ScreenToRoom(int scrx, int scry);
318 	VpPoint ScreenToRoomDivDown(int scrx, int scry); // native "variadic" coords variant
319 
320 	// Makes sure primary viewport and camera are created and linked together
321 	void CreatePrimaryViewportAndCamera();
322 	// Creates new room viewport
323 	PViewport CreateRoomViewport();
324 	// Register camera in the managed system; optionally links to existing handle
325 	ScriptViewport *RegisterRoomViewport(int index, int32_t handle = 0);
326 	// Deletes existing room viewport
327 	void DeleteRoomViewport(int index);
328 	// Get number of room viewports
329 	int GetRoomViewportCount() const;
330 	// Creates new room camera
331 	PCamera CreateRoomCamera();
332 	// Register camera in the managed system; optionally links to existing handle
333 	ScriptCamera *RegisterRoomCamera(int index, int32_t handle = 0);
334 	// Deletes existing room camera
335 	void DeleteRoomCamera(int index);
336 	// Get number of room cameras
337 	int GetRoomCameraCount() const;
338 	// Gets script viewport reference; does NOT increment refcount
339 	// because script interpreter does this when acquiring managed pointer.
340 	ScriptViewport *GetScriptViewport(int index);
341 	// Gets script camera reference; does NOT increment refcount
342 	// because script interpreter does this when acquiring managed pointer.
343 	ScriptCamera *GetScriptCamera(int index);
344 
345 	//
346 	// User input management
347 	//
348 	// Tells if game should ignore user input right now. Note that some of the parent states
349 	// may not ignore it at the same time, such as cutscene state, which may still be skipped
350 	// with a key press or a mouse button.
351 	bool IsIgnoringInput() const;
352 	// Sets ignore input state, for the given time; if there's one already, chooses max timeout
353 	void SetIgnoreInput(int timeout_ms);
354 	// Clears ignore input state
355 	void ClearIgnoreInput();
356 
357 	// Set how the last blocking wait was skipped
358 	void SetWaitSkipResult(int how, int data = 0);
359 	// Returns the code of the latest blocking wait skip method.
360 	// * positive value means a key code;
361 	// * negative value means a -(mouse code + 1);
362 	// * 0 means timeout.
363 	int GetWaitSkipResult() const;
364 
365 	//
366 	// Voice speech management
367 	//
368 	// Tells if there's a blocking voice speech playing right now
369 	bool IsBlockingVoiceSpeech() const;
370 	// Tells whether we have to finalize voice speech when stopping or reusing the channel
371 	bool IsNonBlockingVoiceSpeech() const;
372 	// Speech helpers
373 	bool ShouldPlayVoiceSpeech() const;
374 
375 	//
376 	// Serialization
377 	//
378 	void ReadQueuedAudioItems_Aligned(Shared::Stream *in);
379 	void ReadCustomProperties_v340(Shared::Stream *in);
380 	void WriteCustomProperties_v340(Shared::Stream *out) const;
381 	void ReadFromSavegame(Shared::Stream *in, GameStateSvgVersion svg_ver, AGS::Engine::RestoredData &r_data);
382 	void WriteForSavegame(Shared::Stream *out) const;
383 	void FreeProperties();
384 	void FreeViewportsAndCameras();
385 
386 private:
387 	VpPoint ScreenToRoomImpl(int scrx, int scry, int view_index, bool clip_viewport, bool convert_cam_to_data);
388 	void UpdateRoomCamera(int index);
389 
390 	// Defines if the room viewport should be adjusted to the room size automatically.
391 	bool _isAutoRoomViewport = false;
392 	// Main viewport defines the rectangle of the drawn and interactable area
393 	// in the most basic case it will be equal to the game size.
394 	Viewport _mainViewport;
395 	// UI viewport defines the render and interaction rectangle of game's UI.
396 	Viewport _uiViewport;
397 	// Room viewports define place on screen where the room camera's
398 	// contents are drawn.
399 	std::vector<PViewport> _roomViewports;
400 	// Vector of viewports sorted in z-order.
401 	std::vector<PViewport> _roomViewportsSorted;
402 	// Cameras defines the position of a "looking eye" inside the room.
403 	std::vector<PCamera> _roomCameras;
404 	// Script viewports and cameras are references to real data export to
405 	// user script. They became invalidated as the actual object gets
406 	// destroyed, but are kept in memory to prevent script errors.
407 	std::vector<std::pair<ScriptViewport *, int32_t>> _scViewportRefs;
408 	std::vector<std::pair<ScriptCamera *, int32_t>> _scCameraRefs;
409 
410 	// Tells that the main viewport's position has changed since last game update
411 	bool  _mainViewportHasChanged = false;
412 	// Tells that room viewports need z-order resort
413 	bool  _roomViewportZOrderChanged = false;
414 
415 	AGS_Clock::time_point _ignoreUserInputUntilTime = 0;
416 };
417 
418 // Converts legacy alignment type used in script API
419 HorAlignment ConvertLegacyScriptAlignment(LegacyScriptAlignment align);
420 // Reads legacy alignment type from the value set in script depending on the
421 // current Script API level. This is made to make it possible to change
422 // Alignment constants in the Script API and still support old version.
423 HorAlignment ReadScriptAlignment(int32_t align);
424 
425 
426 
427 } // namespace AGS3
428 
429 #endif
430