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